diff options
author | David M <davidmj@users.sourceforge.net> | 2008-06-09 00:59:44 +0000 |
---|---|---|
committer | David M <davidmj@users.sourceforge.net> | 2008-06-09 00:59:44 +0000 |
commit | fc126eec663183279dfbb50b99eece2ee2872993 (patch) | |
tree | 5fc44f46dfa682d5c184e77cf13b852a90eacd54 /phpBB/develop | |
parent | 1aa40171e0677c5307f213f8c58b7156f5885d59 (diff) | |
download | forums-fc126eec663183279dfbb50b99eece2ee2872993.tar forums-fc126eec663183279dfbb50b99eece2ee2872993.tar.gz forums-fc126eec663183279dfbb50b99eece2ee2872993.tar.bz2 forums-fc126eec663183279dfbb50b99eece2ee2872993.tar.xz forums-fc126eec663183279dfbb50b99eece2ee2872993.zip |
Rewrote this stuff so that it is all multiple object oriented instead of looping single objects... The way it is written, there should be no speed decrease (and in some places, a speed increase) and maybe a miniscule amount of extra memory used in the move_topics function... Everything in there should be O(n) where n is the number of topics or posts being delete or moved or whatever. Multiple topic insertions are not supported as I cannot forsee where one would like to insert multiple topics into the same forum. Different forums I can understand but there is no way to optimize that _at all_. More work to come...
git-svn-id: file:///svn/phpbb/trunk@8625 89ea8834-ac86-4346-8a33-228a782c2dd0
Diffstat (limited to 'phpBB/develop')
-rw-r--r-- | phpBB/develop/posting-api.php | 544 |
1 files changed, 384 insertions, 160 deletions
diff --git a/phpBB/develop/posting-api.php b/phpBB/develop/posting-api.php index 494cb9773d..e57fc4b140 100644 --- a/phpBB/develop/posting-api.php +++ b/phpBB/develop/posting-api.php @@ -8,7 +8,6 @@ include(PHPBB_ROOT_PATH . 'common.' . PHP_EXT); class posting_api { - // ideas on global topics? I am stuck here :'-( /* topic table: topic_id @@ -381,234 +380,449 @@ class posting_api static function delete_topic($data) { + // just call the more powerful variant with just one topic :) + self::delete_topics(array('topic_ids' => array($data['topic_id']))); + } + + static function delete_topics($data) + { global $db; // lets get this party started $db->sql_transaction('begin'); - $topic_id = (int) $data['topic_id']; + $topic_ids = array_map('intval', $data['topic_ids']); // what kind of topic is this? lets find out how much we must tamper with the forum table... - $sql = 'SELECT topic_posts, topic_shadow_posts, topic_deleted_posts, topic_unapproved_posts, topic_shadow_id, forum_id + // TODO: investigate how aggregate functions can speed this up/reduce the number of results returned/misc. other benefits + $sql = 'SELECT topic_posts, topic_shadow_posts, topic_deleted_posts, topic_unapproved_posts, topic_shadow_id, forum_id, topic_status FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; + WHERE ' . $db->sql_in_set('topic_id', $topic_ids); $result = $db->sql_query($sql); - $topic_row = $db->sql_fetchrow($result); + // the following in an array, key'd by forum id that refers to topic rows + $forum_lookup = array(); + while ($topic_row = $db->sql_fetchrow($result)) + { + $forum_id = (int) $topic_row['forum_id']; + + // deal with posts + $forum_lookup[$forum_id]['forum_posts'] += $topic_row['topic_posts']; + $forum_lookup[$forum_id]['forum_shadow_posts'] += $topic_row['topic_shadow_posts']; + $forum_lookup[$forum_id]['forum_deleted_posts'] += $topic_row['topic_deleted_posts']; + $forum_lookup[$forum_id]['forum_unapproved_posts'] += $topic_row['topic_unapproved_posts']; + + // deal with topics + $topic_status = (int) $topic_row['topic_status']; + $forum_lookup[$forum_id]['forum_topics']++; // a topic is a topic + $forum_lookup[$forum_id]['forum_shadow_topics'] += ($topic_row['topic_shadow_id'] != 0); + $forum_lookup[$forum_id]['forum_deleted_topics'] += ($topic_status & self::DELETED); + $forum_lookup[$forum_id]['forum_unapproved_topics'] += ($topic_status & self::UNAPPROVED); + } $db->sql_freeresult($result); - // goodnight topic - $db->sql_query('DELETE FROM ' . TOPICS_TABLE . ' WHERE topic_id = ' . $topic_id); + // goodnight, topics + $db->sql_query('DELETE FROM ' . TOPICS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); - // goodnight post - $db->sql_query('DELETE FROM ' . POSTS_TABLE . ' WHERE topic_id = ' . $topic_id); + // goodnight, posts + $db->sql_query('DELETE FROM ' . POSTS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); - $forum_id = (int) $topic_row['forum_id']; + $forum_ids = array_keys($forum_lookup); // what kind of topic is this? lets find out how much we must tamper with the forum table... - $sql = 'SELECT forum_posts, forum_shadow_posts, forum_deleted_posts, forum_unapproved_posts + $sql = 'SELECT forum_posts, forum_shadow_posts, forum_deleted_posts, forum_unapproved_posts, forum_id FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $forum_id; + WHERE ' . $db->sql_in_set('forum_id', $forum_ids); $result = $db->sql_query($sql); - $forum_row = $db->sql_fetchrow($result); - - $forum_array = array( - 'forum_posts' => max($forum_row['forum_posts'] - $topic_id['forum_posts'], 0), - 'forum_shadow_posts' => max($forum_row['forum_shadow_posts'] - $topic_id['forum_shadow_posts'], 0), - 'forum_deleted_posts' => max($forum_row['forum_deleted_posts'] - $topic_id['forum_deleted_posts'], 0), - 'forum_unapproved_posts' => max($forum_row['forum_unapproved_posts'] - $topic_id['forum_unapproved_posts'], 0), - - 'forum_topics' => max($forum_row['forum_topics'] - 1, 0), - 'forum_shadow_topics' => max($forum_row['forum_shadow_topics'] - (($topic_type == self::SHADOW) ? 1 : 0), 0), - 'forum_deleted_topics' => max($forum_row['forum_deleted_topics'] - (($topic_status == self::DELETED) ? 1 : 0), 0), - 'forum_unapproved_topics' => max($forum_row['forum_unapproved_topics'] - (($topic_row['topic_shadow_id'] != 0) ? 1 : 0), 0), - ); - - // get the last "normal" post in the forum, we _must_ update it - $sql = 'SELECT MAX(post_id) as max_post_id - FROM ' . POSTS_TABLE . ' - WHERE post_status = ' . self::NORMAL . ' - AND forum_id = ' . $forum_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); + $forum_rows = array(); + while ($forum_row = $db->sql_fetchrow($result)) + { + $forum_id = (int) $forum_row['forum_id']; + $forum_rows[$forum_id] = $forum_row; + } $db->sql_freeresult($result); - // anything left? - if ($row) + $shadow_topic_ids = array(); + foreach ($forum_rows as $forum_id => $forum_row) { - // OK, lets go do some magick - $sql = 'SELECT post_username, poster_id, post_subject, post_time - FROM '. POSTS_TABLE . ' - WHERE post_id = ' . (int) $row['max_post_id']; + $topic_row = $forum_lookup[$forum_id]; + $forum_array = array( + 'forum_posts' => max($forum_row['forum_posts'] - $topic_row['forum_posts'], 0), + 'forum_shadow_posts' => max($forum_row['forum_shadow_posts'] - $topic_row['forum_shadow_posts'], 0), + 'forum_deleted_posts' => max($forum_row['forum_deleted_posts'] - $topic_row['forum_deleted_posts'], 0), + 'forum_unapproved_posts' => max($forum_row['forum_unapproved_posts'] - $topic_row['forum_unapproved_posts'], 0), + + 'forum_topics' => max($forum_row['forum_topics'] - $topic_row['forum_topics'], 0), + 'forum_shadow_topics' => max($forum_row['forum_shadow_topics'] - $topic_row['forum_shadow_topics'], 0), + 'forum_deleted_topics' => max($forum_row['forum_deleted_topics'] - $topic_row['forum_deleted_topics'], 0), + 'forum_unapproved_topics' => max($forum_row['forum_unapproved_topics'] - $topic_row['forum_unapproved_topics'], 0), + ); + + // get the last "normal" post in the forum, we _must_ update it + $sql = 'SELECT MAX(post_id) as max_post_id + FROM ' . POSTS_TABLE . ' + WHERE post_status = ' . self::NORMAL . ' + AND forum_id = ' . $forum_id; $result = $db->sql_query($sql); - $last_post = $db->sql_fetchrow($result); + $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - - $forum_array['forum_last_user_id'] = (int) $last_post['poster_id']; - $forum_array['forum_last_poster_name'] = $last_post['post_username']; - $forum_array['forum_last_post_title'] = $last_post['post_subject']; - $forum_array['forum_last_post_time'] = (int) $last_post['post_time']; - } - else - { - // reset forum state - $forum_array['forum_last_user_id'] = 0; - $forum_array['forum_last_poster_name'] = ''; - $forum_array['forum_last_post_title'] = ''; - $forum_array['forum_last_post_time'] = 0; + + // anything left? + if ($row) + { + // OK, lets go do some magick + $sql = 'SELECT post_username, poster_id, post_subject, post_time + FROM '. POSTS_TABLE . ' + WHERE post_id = ' . (int) $row['max_post_id']; + $result = $db->sql_query($sql); + $last_post = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + $forum_array['forum_last_user_id'] = (int) $last_post['poster_id']; + $forum_array['forum_last_poster_name'] = $last_post['post_username']; + $forum_array['forum_last_post_title'] = $last_post['post_subject']; + $forum_array['forum_last_post_time'] = (int) $last_post['post_time']; + } + else + { + // reset forum state + $forum_array['forum_last_user_id'] = 0; + $forum_array['forum_last_poster_name'] = ''; + $forum_array['forum_last_post_title'] = ''; + $forum_array['forum_last_post_time'] = 0; + } + + $db->sql_handle_data('UPDATE', FORUMS_TABLE, $forum_data, "forum_id = $forum_id"); } - $db->sql_handle_data('UPDATE', FORUMS_TABLE, $forum_data, "forum_id = $forum_id"); - - // lastly, kill off all the unbelievers... erm, I mean shadow topics... - $sql = 'SELECT topic_id, forum_id + // let's not get too hasty, we can kill off the shadows later, + // instead we compose a list of all shadows and then efficiently kill them off :) + $sql = 'SELECT topic_id FROM ' . TOPICS_TABLE . ' - WHERE topic_shadow_id = ' . $topic_id; + WHERE ' . $db->sql_in_set('topic_shadow_id', $topic_ids); $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { - $data['topic_id'] = (int) $topic_id; - self::delete_topic($data); + $shadow_topic_ids[] = $row['topic_id']; + } + + $db->sql_freeresult($result); + + // recursion, the other white meat. + if (sizeof($shadow_topic_ids)) + { + self::delete_topics(array('topic_ids' => $shadow_topic_ids)); } // goodnight, moon - $db->transaction('COMMIT'); + $db->transaction('commit'); } - static function move_topic($data) + static function delete_post($data) + { + // just call the more powerful variant with just one post :) + self::delete_posts(array('post_ids' => array($data['post_id']))); + } + + static function delete_posts($data) { global $db; // lets get this party started - $db->transaction('BEGIN'); + $db->sql_transaction('begin'); - $topic_id = (int) $data['topic_id']; - $to_forum_id = (int) $data['forum_id']; - $make_shadow = (bool) $data['make_shadow']; + $post_ids = array_map('intval', $data['post_ids']); - // let us first determine how many items we are removing from the pool - $sql = 'SELECT topic_posts, topic_shadow_posts, topic_deleted_posts, topic_unapproved_posts, forum_id as from_forum_id, topic_status, topic_type, topic_shadow_id + $sql = 'SELECT topic_id, post_status, post_id, post_shadow_id, forum_id + FROM ' . POSTS_TABLE . ' + WHERE ' . $db->sql_in_set('post_id', $post_ids); + $result = $db->sql_query($sql); + + // the following arrays are designed to allow for much faster updates + $topic_lookup = array(); + $forum_lookup = array(); + + while ($post_row = $db->sql_fetchrow($result)) + { + $topic_id = (int) $post_row['topic_id']; + $forum_id = (int) $post_row['forum_id']; + $post_status = (int) $post_row['post_status']; + + $topic_lookup[$topic_id]['topic_posts']++; // we remove a post, go figure + $topic_lookup[$topic_id]['topic_shadow_posts'] += ($post_row['post_shadow_id'] != 0); // did we just try to kill a shadow post?! + $topic_lookup[$topic_id]['topic_deleted_posts'] += ($post_status & self::DELETED); + $topic_lookup[$topic_id]['topic_unapproved_posts'] += ($post_status & self::UNAPPROVED); + + $forum_lookup[$forum_id]['forum_posts']++; + $forum_lookup[$topic_id]['forum_shadow_posts'] += ($post_row['post_shadow_id'] != 0); // did we just try to kill a shadow post?! + $forum_lookup[$topic_id]['forum_deleted_posts'] += ($post_status & self::DELETED); + $forum_lookup[$topic_id]['forum_unapproved_posts'] += ($post_status & self::UNAPPROVED); + } + $db->sql_freeresult($result); + + // goodnight, posts + $db->sql_query('DELETE FROM ' . POSTS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); + + // mangle the forums table + $sql = 'SELECT forum_posts, forum_shadow_posts, forum_deleted_posts, forum_unapproved_posts, forum_id + FROM ' . FORUMS_TABLE . ' + WHERE forum_id = ' . $forum_id; + $result = $db->sql_query($sql); + $forum_rows = array(); + while ($forum_row = $db->sql_fetchrow($result)) + { + $forum_id = (int) $forum_row['forum_id']; + $forum_rows[$forum_id] = $forum_row; + } + $db->sql_freeresult($result); + + $shadow_topic_ids = array(); + foreach ($forum_rows as $forum_id => $forum_row) + { + $topic_row = $forum_lookup[$forum_id]; + $forum_array = array( + 'forum_posts' => max($forum_row['forum_posts'] - $topic_row['forum_posts'], 0), + 'forum_shadow_posts' => max($forum_row['forum_shadow_posts'] - $topic_row['forum_shadow_posts'], 0), + 'forum_deleted_posts' => max($forum_row['forum_deleted_posts'] - $topic_row['forum_deleted_posts'], 0), + 'forum_unapproved_posts' => max($forum_row['forum_unapproved_posts'] - $topic_row['forum_unapproved_posts'], 0), + ); + + // get the last "normal" post in the forum, we _must_ update it + $sql = 'SELECT MAX(post_id) as max_post_id + FROM ' . POSTS_TABLE . ' + WHERE post_status = ' . self::NORMAL . ' + AND forum_id = ' . $forum_id; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + // anything left? + if ($row) + { + // OK, lets go do some magick + $sql = 'SELECT post_username, poster_id, post_subject, post_time + FROM '. POSTS_TABLE . ' + WHERE post_id = ' . (int) $row['max_post_id']; + $result = $db->sql_query($sql); + $last_post = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + $forum_array['forum_last_user_id'] = (int) $last_post['poster_id']; + $forum_array['forum_last_poster_name'] = $last_post['post_username']; + $forum_array['forum_last_post_title'] = $last_post['post_subject']; + $forum_array['forum_last_post_time'] = (int) $last_post['post_time']; + } + else + { + // reset forum state + $forum_array['forum_last_user_id'] = 0; + $forum_array['forum_last_poster_name'] = ''; + $forum_array['forum_last_post_title'] = ''; + $forum_array['forum_last_post_time'] = 0; + } + + $db->sql_handle_data('UPDATE', FORUMS_TABLE, $forum_data, "forum_id = $forum_id"); + } + + // mangle the topics table now :) + $sql = 'SELECT topic_posts, topic_shadow_posts, topic_deleted_posts, topic_unapproved_posts, topic_id FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $topic_id; + WHERE forum_id = ' . $forum_id; $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); + $topic_rows = array(); + while ($topic_row = $db->sql_fetchrow($result)) + { + $topic_id = (int) $topic_row['topic_id']; + $topic_rows[$topic_id] = $topic_row; + } $db->sql_freeresult($result); - $topic_status = (int) $row['topic_status']; - $topic_type = (int) $row['topic_type']; - $from_forum_id = (int) $row['from_forum_id']; + $empty_topic_ids = array(); + + foreach ($topic_rows as $topic_id => $topic_row) + { + $post_row = $topic_lookup[$topic_id]; + $topic_array = array( + 'topic_posts' => max($topic_row['topic_posts'] - $post_row['topic_posts'], 0), + 'topic_shadow_posts' => max($topic_row['topic_shadow_posts'] - $post_row['topic_shadow_posts'], 0), + 'topic_deleted_posts' => max($topic_row['topic_deleted_posts'] - $post_row['topic_deleted_posts'], 0), + 'topic_unapproved_posts' => max($topic_row['topic_unapproved_posts'] - $post_row['topic_unapproved_posts'], 0), + ); + + // get the last "normal" post in the topic, we _must_ update it + $sql = 'SELECT MAX(post_id) as max_post_id + FROM ' . POSTS_TABLE . ' + WHERE post_status = ' . self::NORMAL . ' + AND topic_id = ' . $topic_id; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + // anything left? + if ($row) + { + // OK, lets go do some magick + $sql = 'SELECT post_username, poster_id, post_subject, post_time + FROM '. POSTS_TABLE . ' + WHERE post_id = ' . (int) $row['max_post_id']; + $result = $db->sql_query($sql); + $last_post = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + $topic_array['topic_last_user_id'] = (int) $last_post['poster_id']; + $topic_array['topic_last_poster_name'] = $last_post['post_username']; + $topic_array['topic_last_post_title'] = $last_post['post_subject']; + $topic_array['topic_last_post_time'] = (int) $last_post['post_time']; + } + else + { + // mark this post for execution! + $empty_topic_ids[] = $topic_id; + } + + $db->sql_handle_data('UPDATE', TOPICS_TABLE, $topic_array, "topic_id = $topic_id"); + } - $topic_row['topic_posts'] = (int) $row['topic_posts']; - $topic_row['topic_shadow_posts'] = (int) $row['topic_shadow_posts']; - $topic_row['topic_deleted_posts'] = (int) $row['topic_deleted_posts']; - $topic_row['topic_unapproved_posts'] = (int) $row['topic_unapproved_posts']; + $shadow_post_ids = array(); - // let us first determine how many items we are removing from the pool - $sql = 'SELECT forum_posts, forum_shadow_posts, forum_deleted_posts, forum_unapproved_posts, forum_id, forum_topics, forum_deleted_topics, forum_unapproved_topics - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', array($to_forum_id, $from_forum_id)); + // let's not get too hasty, we can kill off the shadows later, + // instead we compose a list of all shadows and then efficiently kill them off :) + $sql = 'SELECT post_id + FROM ' . POSTS_TABLE . ' + WHERE ' . $db->sql_in_set('post_shadow_id', $topic_ids); $result = $db->sql_query($sql); - $forum_row = array(); while ($row = $db->sql_fetchrow($result)) { - $forum_id = (int) $row['forum_id']; + $shadow_post_ids[] = $row['post_id']; + } - $forum_row[$forum_id]['forum_posts'] = (int) $row['forum_posts']; - $forum_row[$forum_id]['forum_shadow_posts'] = (int) $row['forum_shadow_posts']; - $forum_row[$forum_id]['forum_deleted_posts'] = (int) $row['forum_deleted_posts']; - $forum_row[$forum_id]['forum_unapproved_posts'] = (int) $row['forum_unapproved_posts']; + $db->sql_freeresult($result); - $forum_row[$forum_id]['forum_topics'] = (int) $row['forum_topics']; - $forum_row[$forum_id]['forum_shadow_topics'] = (int) $row['forum_shadow_topics']; - $forum_row[$forum_id]['forum_deleted_topics'] = (int) $row['forum_deleted_topics']; - $forum_row[$forum_id]['forum_unapproved_topics'] = (int) $row['forum_unapproved_topics']; + // recursion, the other white meat. + if (sizeof($shadow_topic_ids)) + { + self::delete_posts(array('post_ids' => $shadow_post_ids)); } - $db->sql_freeresult($result); + // we killed all the posts in a topic, time to kill the topics! + if (sizeof($empty_topics)) + { + self::delete_topics(array('topic_ids' => $empty_topic_ids)); + } - // update the topic itself - $db->sql_handle_data('UPDATE', TOPICS_TABLE, array('forum_id' => $to_forum_id), "topic_id = $topic_id"); + // goodnight, moon + $db->transaction('commit'); + } - // update the posts now - $db->sql_handle_data('UPDATE', POSTS_TABLE, array('forum_id' => $to_forum_id), "topic_id = $topic_id"); + static function move_topic($data) + { + self::move_topics(array('topic_forum_mapping' => array(array('topic_id' => $data['topic_id'], 'forum_id' => $data['forum_id'], 'make_shadow' => $data['make_shadow'])))); + } - // remove the numbers from the old forum row - $from_forum_array = array( - 'forum_posts' => max($forum_row[$from_forum_id]['forum_posts'] - $topic_row['forum_posts'], 0), - 'forum_shadow_posts' => max($forum_row[$from_forum_id]['forum_shadow_posts'] - $topic_row['forum_shadow_posts'], 0), - 'forum_deleted_posts' => max($forum_row[$from_forum_id]['forum_deleted_posts'] - $topic_row['forum_deleted_posts'], 0), - 'forum_unapproved_posts' => max($forum_row[$from_forum_id]['forum_unapproved_posts'] - $topic_row['forum_unapproved_posts'], 0), + static function move_topics($data) + { + global $db; - 'forum_topics' => max($forum_row[$from_forum_id]['forum_topics'] - 1, 0), - 'forum_shadow_topics' => max($forum_row[$from_forum_id]['forum_shadow_topics'] - (($topic_row['topic_shadow_id'] != 0) ? 1 : 0), 0), - 'forum_deleted_topics' => max($forum_row[$from_forum_id]['forum_deleted_topics'] - (($topic_status == self::DELETED) ? 1 : 0), 0), - 'forum_unapproved_topics' => max($forum_row[$from_forum_id]['forum_unapproved_topics'] - (($topic_status == self::UNAPPROVED) ? 1 : 0), 0), - ); + // lets get this party started + $db->transaction('begin'); - // get the last "normal" post in the old forum, we _must_ update it - $sql = 'SELECT MAX(post_id) as max_post_id - FROM ' . POSTS_TABLE . ' - WHERE post_status = ' . self::NORMAL . ' - AND forum_id = ' . $from_forum_id; + // all of each are indexed by topic id + $to_forum_ids = $shadow_topic_ids = array(); + + foreach ($data['topic_forum_mapping'] as $mapping) + { + $topic_id = (int) $mapping['topic_id']; + $to_forum_ids[$topic_id] = (int) $mapping['forum_id']; + if ($mapping['make_shadow']) + { + $shadow_topic_ids[] = $topic_id; + } + } + + $forum_columns = array('forum_posts', 'forum_shadow_posts', 'forum_deleted_posts', 'forum_unapproved_posts', 'forum_topics', 'forum_shadow_topics', 'forum_deleted_topics', 'forum_unapproved_topics'); + + $topic_ids = array_keys($to_forum_ids); + + // let us first determine how many items we are removing from the pool + $sql = 'SELECT topic_posts, topic_shadow_posts, topic_deleted_posts, topic_unapproved_posts, forum_id, topic_status, topic_type, topic_shadow_id, topic_id + FROM ' . TOPICS_TABLE . ' + WHERE ' . $db->sql_in_set('topic_id', $topic_ids); $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); + $forum_lookup = array(); + while ($topic_row = $db->sql_fetchrow($result)) + { + $topic_id = $topic_row['topic_id']; + $from_forum_id = (int) $topic_row['forum_id']; + $topic_status = (int) $topic_row['topic_status']; + + $from_forum_ids[$topic_id] = $from_forum_id; + + $to_forum_id = $to_forum_ids[$topic_id]; + + // we are iterating one topic at a time... + $forum_lookup[$from_forum_id]['forum_topics'] = $forum_lookup[$to_forum_id]['forum_topics'] = 1; + + foreach ($forum_columns as $column) + { + $forum_lookup[$from_forum_id][$column] -= $topic_row['topic_posts']; + $forum_lookup[$to_forum_id][$column] += $topic_row['topic_posts']; + } + } $db->sql_freeresult($result); - // anything left? - if ($row) + // determine the totals + $sql = 'SELECT forum_posts, forum_shadow_posts, forum_deleted_posts, forum_unapproved_posts, forum_id, forum_topics, forum_deleted_topics, forum_unapproved_topics + FROM ' . FORUMS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', array_keys($forum_lookup)); + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) { - // OK, lets go do some magick - $sql = 'SELECT post_username, poster_id, post_subject, post_time - FROM '. POSTS_TABLE . ' - WHERE post_id = ' . (int) $row['max_post_id']; - $result = $db->sql_query($sql); - $last_post = $db->sql_fetchrow($result); - $db->sql_freeresult($result); + $forum_id = (int) $row['forum_id']; - $from_forum_array['forum_last_user_id'] = (int) $last_post['poster_id']; - $from_forum_array['forum_last_poster_name'] = $last_post['post_username']; - $from_forum_array['forum_last_post_title'] = $last_post['post_subject']; - $from_forum_array['forum_last_post_time'] = (int) $last_post['post_time']; + foreach ($forum_columns as $column) + { + $forum_lookup[$forum_id][$column] += (int) $row[$column]; + } } - else + + // create a listing of which topics are going in which forums + $update_list = array(); + + foreach ($to_forum_ids as $topic_id => $forum_id) { - // reset forum state - $from_forum_array['forum_last_user_id'] = 0; - $from_forum_array['forum_last_poster_name'] = ''; - $from_forum_array['forum_last_post_title'] = ''; - $from_forum_array['forum_last_post_time'] = 0; + $update_list[$forum_id][] = $topic_id; } - // update the old forum - $db->sql_handle_data('UPDATE', FORUMS_TABLE, $from_forum_array, "forum_id = $from_forum_id"); - - // add the numbers to the new forum row - $to_forum_array = array( - 'forum_posts' => $forum_row[$to_forum_id]['forum_posts'] + $topic_row['forum_posts'], - 'forum_shadow_posts' => $forum_row[$to_forum_id]['forum_shadow_posts'] + $topic_row['forum_shadow_posts'], - 'forum_deleted_posts' => $forum_row[$to_forum_id]['forum_deleted_posts'] + $topic_row['forum_deleted_posts'], - 'forum_unapproved_posts'=> $forum_row[$to_forum_id]['forum_unapproved_posts'] + $topic_row['forum_unapproved_posts'], + // we save as many queries as we can by updating all similar topics at once + foreach ($update_list as $forum_id => $topic_ids) + { + // update the topic itself + $db->sql_handle_data('UPDATE', TOPICS_TABLE, array('forum_id' => $to_forum_id), $db->sql_in_set('topic_id', $topic_ids)); - 'forum_topics' => $forum_row[$from_forum_id]['forum_topics'] + 1, - 'forum_shadow_topics' => $forum_row[$from_forum_id]['forum_shadow_topics'] + (($topic_row['topic_shadow_id'] != 0) ? 1 : 0), - 'forum_deleted_topics' => $forum_row[$from_forum_id]['forum_deleted_topics'] + (($topic_status === self::DELETED) ? 1 : 0), - 'forum_unapproved_topics' => $forum_row[$from_forum_id]['forum_unapproved_topics'] + (($topic_status === self::UNAPPROVED) ? 1 : 0), - ); + // update the posts now + $db->sql_handle_data('UPDATE', POSTS_TABLE, array('forum_id' => $to_forum_id), $db->sql_in_set('topic_id', $topic_ids)); + } - // the new topic is approved and is not soft deleted and is not unapproved, go and sync some status - if ($topic_status === self::NORMAL) + // start building the needed arrays for updating the forum data + foreach ($forum_lookup as $forum_id => $forum_data) { - // get the lastest "normal" post in the new forum, we _must_ update it + foreach ($forum_columns as $column) + { + $forum_data[$column] = max($forum_data[$column], 0); // ensure the result is unsigned + } + + // get the last "normal" post in the old forum, we _must_ update it $sql = 'SELECT MAX(post_id) as max_post_id FROM ' . POSTS_TABLE . ' WHERE post_status = ' . self::NORMAL . ' - AND forum_id = ' . $to_forum_id; + AND forum_id = ' . $forum_id; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - - // we better find something... after all, we just moved a topic here! + + // anything left? if ($row) { // OK, lets go do some magick @@ -619,17 +833,26 @@ class posting_api $last_post = $db->sql_fetchrow($result); $db->sql_freeresult($result); - $from_forum_array['forum_last_user_id'] = (int) $last_post['poster_id']; - $from_forum_array['forum_last_poster_name'] = $last_post['post_username']; - $from_forum_array['forum_last_post_title'] = $last_post['post_subject']; - $from_forum_array['forum_last_post_time'] = (int) $last_post['post_time']; + $forum_data['forum_last_user_id'] = (int) $last_post['poster_id']; + $forum_data['forum_last_poster_name'] = $last_post['post_username']; + $forum_data['forum_last_post_title'] = $last_post['post_subject']; + $forum_data['forum_last_post_time'] = (int) $last_post['post_time']; + } + else + { + // reset forum state + $forum_data['forum_last_user_id'] = 0; + $forum_data['forum_last_poster_name'] = ''; + $forum_data['forum_last_post_title'] = ''; + $forum_data['forum_last_post_time'] = 0; } + + // update the old forum + $db->sql_handle_data('UPDATE', FORUMS_TABLE, $forum_data, "forum_id = $forum_id"); } - // update the new forum - $db->sql_handle_data('UPDATE', FORUMS_TABLE, $to_forum_array, "forum_id = $to_forum_id"); - - if ($make_shadow === true) + // hooray for code reuse! + foreach ($shadow_topic_ids as $topic_id) { $data['shadow_topic_id'] = $topic_id; $data['forum_id'] = $from_forum_id; @@ -637,6 +860,7 @@ class posting_api } $db->sql_transaction('commit'); + } } |