Skip to content

Commit 913215f

Browse files
committed
ommit multidelete syntax as it is not always supported among the DBMSs and some minor fixes (ref RobertHeim#41)
1 parent 2f86a8d commit 913215f

File tree

1 file changed

+132
-52
lines changed

1 file changed

+132
-52
lines changed

service/tags_manager.php

+132-52
Original file line numberDiff line numberDiff line change
@@ -60,24 +60,42 @@ public function remove_all_tags_from_topic($topic_id, $delete_unused_tags = true
6060
}
6161

6262
/**
63-
* Removes all tags that are not assigned to at least one topic (garbage collection).
64-
*
65-
* @return count of deleted tags
63+
* Gets the ids of all tags, that are not assigned to a topic.
6664
*/
67-
public function delete_unused_tags()
65+
private function get_unused_tag_ids()
6866
{
69-
// TODO maybe we are not allowed to use subqueries, because some DBALS supported by phpBB do not support them.
70-
// https://www.phpbb.com/community/viewtopic.php?f=461&t=2263646
71-
// so we would need 2 queries, but this is slow... so we use subqueries and hope - yeah! :D
72-
73-
$sql = 'DELETE
67+
$sql = 'SELECT t.id
7468
FROM ' . $this->table_prefix . TABLES::TAGS . ' t
7569
WHERE NOT EXISTS (
7670
SELECT 1
7771
FROM ' . $this->table_prefix . TABLES::TOPICTAGS . ' tt
7872
WHERE tt.tag_id = t.id
7973
)';
80-
74+
$result = $this->db->sql_query($sql);
75+
$ids = array();
76+
while ($row = $this->db->sql_fetchrow($result))
77+
{
78+
$ids[] = $row['id'];
79+
}
80+
$this->db->sql_freeresult($result);
81+
return $ids;
82+
}
83+
84+
/**
85+
* Removes all tags that are not assigned to at least one topic (garbage collection).
86+
*
87+
* @return count of deleted tags
88+
*/
89+
public function delete_unused_tags()
90+
{
91+
$ids = $this->get_unused_tag_ids();
92+
if (empty($ids))
93+
{
94+
// nothing to do
95+
return 0;
96+
}
97+
$sql = 'DELETE FROM ' . $this->table_prefix . TABLES::TAGS . '
98+
WHERE ' . $this->db->sql_in_set('id', $ids);
8199
$this->db->sql_query($sql);
82100
return $this->db->sql_affectedrows();
83101
}
@@ -92,18 +110,23 @@ public function delete_assignments_of_invalid_tags()
92110
// get all tags to check them
93111
$tags = $this->get_existing_tags(null);
94112

95-
$ids_of_invalid_tags_ = array();
113+
$ids_of_invalid_tags = array();
96114
foreach ($tags as $tag)
97115
{
98116
if (!$this->is_valid_tag($tag['tag']))
99117
{
100118
$ids_of_invalid_tags[] = (int) $tag['id'];
101119
}
102120
}
121+
if (empty($ids_of_invalid_tags))
122+
{
123+
// nothing to do
124+
return 0;
125+
}
126+
103127
// delete all tag-assignments where the tag is not valid
104-
$sql = 'DELETE
105-
FROM ' . $this->table_prefix . TABLES::TOPICTAGS . ' tt
106-
WHERE ' . $this->db->sql_in_set('tt.tag_id', $ids_of_invalid_tags);
128+
$sql = 'DELETE FROM ' . $this->table_prefix . TABLES::TOPICTAGS . '
129+
WHERE ' . $this->db->sql_in_set('tag_id', $ids_of_invalid_tags);
107130
$this->db->sql_query($sql);
108131
$removed_count = $this->db->sql_affectedrows();
109132

@@ -112,26 +135,46 @@ public function delete_assignments_of_invalid_tags()
112135
return $removed_count;
113136
}
114137

138+
private function get_assignment_ids_where_topic_does_not_exist()
139+
{
140+
$sql = 'SELECT tt.id
141+
FROM ' . $this->table_prefix . TABLES::TOPICTAGS . ' tt
142+
WHERE NOT EXISTS (
143+
SELECT 1
144+
FROM ' . TOPICS_TABLE . ' topics
145+
WHERE topics.topic_id = tt.topic_id
146+
)';
147+
$result = $this->db->sql_query($sql);
148+
$ids = array();
149+
while ($row = $this->db->sql_fetchrow($result))
150+
{
151+
$ids[] = $row['id'];
152+
}
153+
$this->db->sql_freeresult($result);
154+
return $ids;
155+
}
156+
115157
/**
116158
* Removes all topic-tag-assignments where the topic does not exist anymore.
117159
*
118160
* @return count of deleted assignments
119161
*/
120162
public function delete_assignments_where_topic_does_not_exist()
121163
{
164+
$ids = $this->get_assignment_ids_where_topic_does_not_exist();
165+
if (empty($ids))
166+
{
167+
// nothing to do
168+
return 0;
169+
}
122170
// delete all tag-assignments where the topic does not exist anymore
123-
$sql = 'DELETE
124-
FROM ' . $this->table_prefix . TABLES::TOPICTAGS . ' tt
125-
WHERE NOT EXISTS (
126-
SELECT 1
127-
FROM ' . TOPICS_TABLE . ' topics
128-
WHERE topics.topic_id = tt.topic_id
129-
)';
171+
$sql = 'DELETE FROM ' . $this->table_prefix . TABLES::TOPICTAGS . '
172+
WHERE ' . $this->db->sql_in_set('id', $ids);
130173
$this->db->sql_query($sql);
131174
$removed_count = $this->db->sql_affectedrows();
132175

133176
$this->calc_count_tags();
134-
177+
135178
return $removed_count;
136179
}
137180

@@ -152,16 +195,11 @@ public function delete_tags_from_tagdisabled_forums($forum_ids = null)
152195
// performance improvement because we already know the result of querying the db.
153196
return 0;
154197
}
155-
// ensure forum_ids are ints before using them in sql
156-
$int_ids = array();
157-
foreach ($forum_ids as $id)
158-
{
159-
$int_ids[] = (int) $id;
160-
}
161-
$forums_sql_where = ' AND ' . $this->db->sql_in_set('f.forum_id', $int_ids);
198+
$forums_sql_where = ' AND ' . $this->db->sql_in_set('f.forum_id', $forum_ids);
162199
}
163-
// Deletes all topic-assignments to topics that reside in a forum with tagging disabled.
164-
$sql = 'DELETE
200+
201+
// get ids of all topic-assignments to topics that reside in a forum with tagging disabled.
202+
$sql = 'SELECT tt.id
165203
FROM ' . $this->table_prefix . TABLES::TOPICTAGS . ' tt
166204
WHERE EXISTS (
167205
SELECT 1
@@ -172,6 +210,22 @@ public function delete_tags_from_tagdisabled_forums($forum_ids = null)
172210
AND f.rh_topictags_enabled = 0
173211
$forums_sql_where
174212
)";
213+
$result = $this->db->sql_query($sql);
214+
$delete_ids = array();
215+
while ($row = $this->db->sql_fetchrow($result))
216+
{
217+
$delete_ids[] = $row['id'];
218+
}
219+
$this->db->sql_freeresult($result);
220+
221+
if (empty($delete_ids))
222+
{
223+
// nothing to do
224+
return 0;
225+
}
226+
// delete these assignments
227+
$sql = 'DELETE FROM ' . $this->table_prefix . TABLES::TOPICTAGS . '
228+
WHERE ' . $this->db->sql_in_set('id', $delete_ids);
175229
$this->db->sql_query($sql);
176230
$removed_count = $this->db->sql_affectedrows();
177231

@@ -202,6 +256,7 @@ public function get_assigned_tags($topic_id)
202256
{
203257
$tags[] = $row['tag'];
204258
}
259+
$this->db->sql_freeresult($result);
205260
return $tags;
206261
}
207262

@@ -220,13 +275,18 @@ public function get_tag_suggestions($query, $exclude, $count)
220275
{
221276
return array();
222277
}
278+
$exclude_sql = '';
279+
if (!empty($exclude))
280+
{
281+
$exclude_sql = ' AND ' . $this->db->sql_in_set('t.tag', $exclude, true, true);
282+
}
223283
$sql_array = array(
224284
'SELECT' => 't.tag',
225285
'FROM' => array(
226286
$this->table_prefix . TABLES::TAGS => 't',
227287
),
228-
'WHERE' => 't.tag ' . $this->db->sql_like_expression($query . $this->db->get_any_char()) . '
229-
AND ' . $this->db->sql_in_set('t.tag', $exclude, true, true),
288+
'WHERE' => 't.tag ' . $this->db->sql_like_expression($query . $this->db->get_any_char()) . "
289+
$exclude_sql",
230290
'ORDER BY' => 't.count DESC',
231291
);
232292
$sql = $this->db->sql_build_query('SELECT_DISTINCT', $sql_array);
@@ -236,6 +296,7 @@ public function get_tag_suggestions($query, $exclude, $count)
236296
{
237297
$tags[] = array('text' => $row['tag']);
238298
}
299+
$this->db->sql_freeresult($result);
239300
return $tags;
240301
}
241302

@@ -359,6 +420,7 @@ public function get_existing_tags($tags = null, $only_ids = false)
359420
);
360421
}
361422
}
423+
$this->db->sql_freeresult($result);
362424
return $existing_tags;
363425
}
364426

@@ -377,6 +439,7 @@ private function get_used_tag_ids()
377439
{
378440
$ids[] = $row['tag_id'];
379441
}
442+
$this->db->sql_freeresult($result);
380443
return $ids;
381444
}
382445

@@ -471,9 +534,19 @@ private function get_topics_build_query(array $tags, $mode = 'AND', $casesensiti
471534
$forum_ary = array_unique($forum_ary);
472535

473536
// Get sql-source for the topics that reside in forums that the user can read and which are approved.
474-
$sql_where_topic_access = $this->db->sql_in_set('topics.forum_id', $forum_ary, false, true);
537+
$sql_where_topic_access = '';
538+
if (empty($forum_ary))
539+
{
540+
$sql_where_topic_access = ' 1=0 ';
541+
}
542+
else
543+
{
544+
$sql_where_topic_access = $this->db->sql_in_set('topics.forum_id', $forum_ary, false, true);
545+
}
475546
$sql_where_topic_access .= ' AND topics.topic_visibility = 1';
476547

548+
// TODO store a utf8_clean_string string and compare this, instead of LOWER(...) see http://phpcrossref.com/xref/phpbb/_functions/utf8_clean_string.html
549+
// tags is not an empty array here
477550
$sql_where_tag_in = $this->db->sql_in_set($casesensitive ? ' t.tag' : 'LOWER(t.tag)', $tags);
478551

479552
$sql = '';
@@ -610,9 +683,9 @@ public function clean_tag($tag)
610683
$tag = trim($tag);
611684

612685
// db-field is max 30 characters!
613-
$tag = substr($tag, 0, 30);
686+
$tag = utf8_substr($tag, 0, 30);
614687

615-
//might have a space at the end now, so trim again
688+
// might have a space at the end now, so trim again
616689
$tag = trim($tag);
617690

618691
if ($this->config[PREFIXES::CONFIG.'_convert_space_to_minus'])
@@ -636,7 +709,9 @@ public function is_tagging_enabled_in_forum($forum_id)
636709
FROM " . FORUMS_TABLE . '
637710
WHERE ' . $this->db->sql_build_array('SELECT', array('forum_id' => (int) $forum_id));
638711
$result = $this->db->sql_query($sql);
639-
return (int) $this->db->sql_fetchfield($field);
712+
$enabled = ((int) $this->db->sql_fetchfield($field)) > 0;
713+
$this->db->sql_freeresult($result);
714+
return $enabled;
640715
}
641716

642717
/**
@@ -697,7 +772,9 @@ public function is_enabled_in_all_forums()
697772
);
698773
$sql = $this->db->sql_build_query('SELECT', $sql_array);
699774
$this->db->sql_query($sql);
700-
return ((int) $this->db->sql_fetchfield('all_enabled')) == 0;
775+
$enabled = ((int) $this->db->sql_fetchfield('all_enabled')) == 0;
776+
$this->db->sql_freeresult($result);
777+
return $enabled;
701778
}
702779

703780
/**
@@ -718,7 +795,9 @@ public function is_disabled_in_all_forums()
718795
);
719796
$sql = $this->db->sql_build_query('SELECT', $sql_array);
720797
$this->db->sql_query($sql);
721-
return ((int) $this->db->sql_fetchfield('all_disabled')) == 0;
798+
$disabled = ((int) $this->db->sql_fetchfield('all_disabled')) == 0;
799+
$this->db->sql_freeresult($result);
800+
return $disabled;
722801
}
723802

724803
/**
@@ -783,11 +862,13 @@ public function merge($tag_to_delete, $tag_to_delete_id, $tag_to_keep, $tag_to_k
783862

784863
// delete assignments where the new tag is already assigned
785864
$topic_ids_already_assigned = $this->get_topic_ids_by_tag_id($tag_to_keep_id);
786-
$sql = 'DELETE FROM ' . $this->table_prefix . TABLES::TOPICTAGS. ' tt
787-
WHERE ' . $this->db->sql_in_set('tt.topic_id', $topic_ids_already_assigned) . '
788-
AND tt.tag_id = ' . (int) $tag_to_delete_id;
789-
$this->db->sql_query($sql);
790-
865+
if (!empty($topic_ids_already_assigned))
866+
{
867+
$sql = 'DELETE FROM ' . $this->table_prefix . TABLES::TOPICTAGS. '
868+
WHERE ' . $this->db->sql_in_set('topic_id', $topic_ids_already_assigned) . '
869+
AND tag_id = ' . (int) $tag_to_delete_id;
870+
$this->db->sql_query($sql);
871+
}
791872
// renew assignments where the new tag is not assigned, yet
792873
$sql_ary = array(
793874
'tt.tag_id' => $tag_to_keep_id,
@@ -809,14 +890,12 @@ public function merge($tag_to_delete, $tag_to_delete_id, $tag_to_keep, $tag_to_k
809890
*/
810891
public function delete_tag($tag_id)
811892
{
812-
$sql = 'DELETE
813-
FROM ' . $this->table_prefix . TABLES::TOPICTAGS . ' tt
814-
WHERE tt.tag_id = ' . ((int) $tag_id);
893+
$sql = 'DELETE FROM ' . $this->table_prefix . TABLES::TOPICTAGS . '
894+
WHERE tag_id = ' . ((int) $tag_id);
815895
$this->db->sql_query($sql);
816896

817-
$sql = 'DELETE
818-
FROM ' . $this->table_prefix . TABLES::TAGS . ' t
819-
WHERE t.id = ' . ((int) $tag_id);
897+
$sql = 'DELETE FROM ' . $this->table_prefix . TABLES::TAGS . '
898+
WHERE id = ' . ((int) $tag_id);
820899
$this->db->sql_query($sql);
821900
}
822901

@@ -900,11 +979,12 @@ public function get_all_tags($start, $limit, $sort_field = 'tag', $asc = true)
900979
*
901980
* @return int the count of all tags
902981
*/
903-
public function count_tags() {
982+
public function count_tags()
983+
{
904984
$sql = 'SELECT COUNT(*) as count_tags FROM ' . $this->table_prefix . TABLES::TAGS;
905985
$result = $this->db->sql_query($sql);
906986
$count = (int) $this->db->sql_fetchfield('count_tags');
907987
$this->db->sql_freeresult($result);
908-
return $count;
988+
return $count;
909989
}
910990
}

0 commit comments

Comments
 (0)