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
This commit is contained in:
David M 2008-06-09 00:59:44 +00:00
parent 1aa40171e0
commit fc126eec66

View file

@ -8,7 +8,6 @@ include(PHPBB_ROOT_PATH . 'common.' . PHP_EXT);
class posting_api class posting_api
{ {
// ideas on global topics? I am stuck here :'-(
/* /*
topic table: topic table:
topic_id topic_id
@ -380,47 +379,82 @@ class posting_api
} }
static function delete_topic($data) 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; global $db;
// lets get this party started // lets get this party started
$db->sql_transaction('begin'); $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... // 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 . ' FROM ' . TOPICS_TABLE . '
WHERE topic_id = ' . $topic_id; WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
$result = $db->sql_query($sql); $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
$db->sql_freeresult($result); $forum_lookup = array();
while ($topic_row = $db->sql_fetchrow($result))
// goodnight topic {
$db->sql_query('DELETE FROM ' . TOPICS_TABLE . ' WHERE topic_id = ' . $topic_id);
// goodnight post
$db->sql_query('DELETE FROM ' . POSTS_TABLE . ' WHERE topic_id = ' . $topic_id);
$forum_id = (int) $topic_row['forum_id']; $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, topics
$db->sql_query('DELETE FROM ' . TOPICS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids));
// goodnight, posts
$db->sql_query('DELETE FROM ' . POSTS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids));
$forum_ids = array_keys($forum_lookup);
// what kind of topic is this? lets find out how much we must tamper with the forum table... // 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 . ' FROM ' . FORUMS_TABLE . '
WHERE forum_id = ' . $forum_id; WHERE ' . $db->sql_in_set('forum_id', $forum_ids);
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
$forum_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);
$shadow_topic_ids = array();
foreach ($forum_rows as $forum_id => $forum_row)
{
$topic_row = $forum_lookup[$forum_id];
$forum_array = array( $forum_array = array(
'forum_posts' => max($forum_row['forum_posts'] - $topic_id['forum_posts'], 0), 'forum_posts' => max($forum_row['forum_posts'] - $topic_row['forum_posts'], 0),
'forum_shadow_posts' => max($forum_row['forum_shadow_posts'] - $topic_id['forum_shadow_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_id['forum_deleted_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_id['forum_unapproved_posts'], 0), 'forum_unapproved_posts' => max($forum_row['forum_unapproved_posts'] - $topic_row['forum_unapproved_posts'], 0),
'forum_topics' => max($forum_row['forum_topics'] - 1, 0), 'forum_topics' => max($forum_row['forum_topics'] - $topic_row['forum_topics'], 0),
'forum_shadow_topics' => max($forum_row['forum_shadow_topics'] - (($topic_type == self::SHADOW) ? 1 : 0), 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_status == self::DELETED) ? 1 : 0), 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['topic_shadow_id'] != 0) ? 1 : 0), 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 // get the last "normal" post in the forum, we _must_ update it
@ -458,99 +492,106 @@ class posting_api
} }
$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... // let's not get too hasty, we can kill off the shadows later,
$sql = 'SELECT topic_id, forum_id // instead we compose a list of all shadows and then efficiently kill them off :)
$sql = 'SELECT topic_id
FROM ' . TOPICS_TABLE . ' FROM ' . TOPICS_TABLE . '
WHERE topic_shadow_id = ' . $topic_id; WHERE ' . $db->sql_in_set('topic_shadow_id', $topic_ids);
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result)) while ($row = $db->sql_fetchrow($result))
{ {
$data['topic_id'] = (int) $topic_id; $shadow_topic_ids[] = $row['topic_id'];
self::delete_topic($data); }
$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 // 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; global $db;
// lets get this party started // lets get this party started
$db->transaction('BEGIN'); $db->sql_transaction('begin');
$topic_id = (int) $data['topic_id']; $post_ids = array_map('intval', $data['post_ids']);
$to_forum_id = (int) $data['forum_id'];
$make_shadow = (bool) $data['make_shadow'];
// let us first determine how many items we are removing from the pool $sql = 'SELECT topic_id, post_status, post_id, post_shadow_id, forum_id
$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 FROM ' . POSTS_TABLE . '
FROM ' . TOPICS_TABLE . ' WHERE ' . $db->sql_in_set('post_id', $post_ids);
WHERE topic_id = ' . $topic_id;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$topic_status = (int) $row['topic_status'];
$topic_type = (int) $row['topic_type'];
$from_forum_id = (int) $row['from_forum_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'];
// 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));
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
$forum_row = array(); // the following arrays are designed to allow for much faster updates
while ($row = $db->sql_fetchrow($result)) $topic_lookup = array();
$forum_lookup = array();
while ($post_row = $db->sql_fetchrow($result))
{ {
$forum_id = (int) $row['forum_id']; $topic_id = (int) $post_row['topic_id'];
$forum_id = (int) $post_row['forum_id'];
$post_status = (int) $post_row['post_status'];
$forum_row[$forum_id]['forum_posts'] = (int) $row['forum_posts']; $topic_lookup[$topic_id]['topic_posts']++; // we remove a post, go figure
$forum_row[$forum_id]['forum_shadow_posts'] = (int) $row['forum_shadow_posts']; $topic_lookup[$topic_id]['topic_shadow_posts'] += ($post_row['post_shadow_id'] != 0); // did we just try to kill a shadow post?!
$forum_row[$forum_id]['forum_deleted_posts'] = (int) $row['forum_deleted_posts']; $topic_lookup[$topic_id]['topic_deleted_posts'] += ($post_status & self::DELETED);
$forum_row[$forum_id]['forum_unapproved_posts'] = (int) $row['forum_unapproved_posts']; $topic_lookup[$topic_id]['topic_unapproved_posts'] += ($post_status & self::UNAPPROVED);
$forum_row[$forum_id]['forum_topics'] = (int) $row['forum_topics']; $forum_lookup[$forum_id]['forum_posts']++;
$forum_row[$forum_id]['forum_shadow_topics'] = (int) $row['forum_shadow_topics']; $forum_lookup[$topic_id]['forum_shadow_posts'] += ($post_row['post_shadow_id'] != 0); // did we just try to kill a shadow post?!
$forum_row[$forum_id]['forum_deleted_topics'] = (int) $row['forum_deleted_topics']; $forum_lookup[$topic_id]['forum_deleted_posts'] += ($post_status & self::DELETED);
$forum_row[$forum_id]['forum_unapproved_topics'] = (int) $row['forum_unapproved_topics']; $forum_lookup[$topic_id]['forum_unapproved_posts'] += ($post_status & self::UNAPPROVED);
} }
$db->sql_freeresult($result); $db->sql_freeresult($result);
// update the topic itself // goodnight, posts
$db->sql_handle_data('UPDATE', TOPICS_TABLE, array('forum_id' => $to_forum_id), "topic_id = $topic_id"); $db->sql_query('DELETE FROM ' . POSTS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids));
// update the posts now // mangle the forums table
$db->sql_handle_data('UPDATE', POSTS_TABLE, array('forum_id' => $to_forum_id), "topic_id = $topic_id"); $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);
// remove the numbers from the old forum row $shadow_topic_ids = array();
$from_forum_array = array( foreach ($forum_rows as $forum_id => $forum_row)
'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), $topic_row = $forum_lookup[$forum_id];
'forum_deleted_posts' => max($forum_row[$from_forum_id]['forum_deleted_posts'] - $topic_row['forum_deleted_posts'], 0), $forum_array = array(
'forum_unapproved_posts' => max($forum_row[$from_forum_id]['forum_unapproved_posts'] - $topic_row['forum_unapproved_posts'], 0), '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_topics' => max($forum_row[$from_forum_id]['forum_topics'] - 1, 0), 'forum_deleted_posts' => max($forum_row['forum_deleted_posts'] - $topic_row['forum_deleted_posts'], 0),
'forum_shadow_topics' => max($forum_row[$from_forum_id]['forum_shadow_topics'] - (($topic_row['topic_shadow_id'] != 0) ? 1 : 0), 0), 'forum_unapproved_posts' => max($forum_row['forum_unapproved_posts'] - $topic_row['forum_unapproved_posts'], 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),
); );
// get the last "normal" post in the old forum, we _must_ update it // get the last "normal" post in the forum, we _must_ update it
$sql = 'SELECT MAX(post_id) as max_post_id $sql = 'SELECT MAX(post_id) as max_post_id
FROM ' . POSTS_TABLE . ' FROM ' . POSTS_TABLE . '
WHERE post_status = ' . self::NORMAL . ' WHERE post_status = ' . self::NORMAL . '
AND forum_id = ' . $from_forum_id; AND forum_id = ' . $forum_id;
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result); $row = $db->sql_fetchrow($result);
$db->sql_freeresult($result); $db->sql_freeresult($result);
@ -566,49 +607,58 @@ class posting_api
$last_post = $db->sql_fetchrow($result); $last_post = $db->sql_fetchrow($result);
$db->sql_freeresult($result); $db->sql_freeresult($result);
$from_forum_array['forum_last_user_id'] = (int) $last_post['poster_id']; $forum_array['forum_last_user_id'] = (int) $last_post['poster_id'];
$from_forum_array['forum_last_poster_name'] = $last_post['post_username']; $forum_array['forum_last_poster_name'] = $last_post['post_username'];
$from_forum_array['forum_last_post_title'] = $last_post['post_subject']; $forum_array['forum_last_post_title'] = $last_post['post_subject'];
$from_forum_array['forum_last_post_time'] = (int) $last_post['post_time']; $forum_array['forum_last_post_time'] = (int) $last_post['post_time'];
} }
else else
{ {
// reset forum state // reset forum state
$from_forum_array['forum_last_user_id'] = 0; $forum_array['forum_last_user_id'] = 0;
$from_forum_array['forum_last_poster_name'] = ''; $forum_array['forum_last_poster_name'] = '';
$from_forum_array['forum_last_post_title'] = ''; $forum_array['forum_last_post_title'] = '';
$from_forum_array['forum_last_post_time'] = 0; $forum_array['forum_last_post_time'] = 0;
} }
// update the old forum $db->sql_handle_data('UPDATE', FORUMS_TABLE, $forum_data, "forum_id = $forum_id");
$db->sql_handle_data('UPDATE', FORUMS_TABLE, $from_forum_array, "forum_id = $from_forum_id"); }
// add the numbers to the new forum row // mangle the topics table now :)
$to_forum_array = array( $sql = 'SELECT topic_posts, topic_shadow_posts, topic_deleted_posts, topic_unapproved_posts, topic_id
'forum_posts' => $forum_row[$to_forum_id]['forum_posts'] + $topic_row['forum_posts'], FROM ' . TOPICS_TABLE . '
'forum_shadow_posts' => $forum_row[$to_forum_id]['forum_shadow_posts'] + $topic_row['forum_shadow_posts'], WHERE forum_id = ' . $forum_id;
'forum_deleted_posts' => $forum_row[$to_forum_id]['forum_deleted_posts'] + $topic_row['forum_deleted_posts'], $result = $db->sql_query($sql);
'forum_unapproved_posts'=> $forum_row[$to_forum_id]['forum_unapproved_posts'] + $topic_row['forum_unapproved_posts'], $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);
'forum_topics' => $forum_row[$from_forum_id]['forum_topics'] + 1, $empty_topic_ids = array();
'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), foreach ($topic_rows as $topic_id => $topic_row)
'forum_unapproved_topics' => $forum_row[$from_forum_id]['forum_unapproved_topics'] + (($topic_status === self::UNAPPROVED) ? 1 : 0), {
$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),
); );
// the new topic is approved and is not soft deleted and is not unapproved, go and sync some status // get the last "normal" post in the topic, we _must_ update it
if ($topic_status === self::NORMAL)
{
// get the lastest "normal" post in the new forum, we _must_ update it
$sql = 'SELECT MAX(post_id) as max_post_id $sql = 'SELECT MAX(post_id) as max_post_id
FROM ' . POSTS_TABLE . ' FROM ' . POSTS_TABLE . '
WHERE post_status = ' . self::NORMAL . ' WHERE post_status = ' . self::NORMAL . '
AND forum_id = ' . $to_forum_id; AND topic_id = ' . $topic_id;
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result); $row = $db->sql_fetchrow($result);
$db->sql_freeresult($result); $db->sql_freeresult($result);
// we better find something... after all, we just moved a topic here! // anything left?
if ($row) if ($row)
{ {
// OK, lets go do some magick // OK, lets go do some magick
@ -619,17 +669,190 @@ class posting_api
$last_post = $db->sql_fetchrow($result); $last_post = $db->sql_fetchrow($result);
$db->sql_freeresult($result); $db->sql_freeresult($result);
$from_forum_array['forum_last_user_id'] = (int) $last_post['poster_id']; $topic_array['topic_last_user_id'] = (int) $last_post['poster_id'];
$from_forum_array['forum_last_poster_name'] = $last_post['post_username']; $topic_array['topic_last_poster_name'] = $last_post['post_username'];
$from_forum_array['forum_last_post_title'] = $last_post['post_subject']; $topic_array['topic_last_post_title'] = $last_post['post_subject'];
$from_forum_array['forum_last_post_time'] = (int) $last_post['post_time']; $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");
}
$shadow_post_ids = array();
// 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);
while ($row = $db->sql_fetchrow($result))
{
$shadow_post_ids[] = $row['post_id'];
}
$db->sql_freeresult($result);
// recursion, the other white meat.
if (sizeof($shadow_topic_ids))
{
self::delete_posts(array('post_ids' => $shadow_post_ids));
}
// 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));
}
// goodnight, moon
$db->transaction('commit');
}
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']))));
}
static function move_topics($data)
{
global $db;
// lets get this party started
$db->transaction('begin');
// 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;
} }
} }
// update the new forum $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');
$db->sql_handle_data('UPDATE', FORUMS_TABLE, $to_forum_array, "forum_id = $to_forum_id");
if ($make_shadow === true) $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);
$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);
// 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))
{
$forum_id = (int) $row['forum_id'];
foreach ($forum_columns as $column)
{
$forum_lookup[$forum_id][$column] += (int) $row[$column];
}
}
// create a listing of which topics are going in which forums
$update_list = array();
foreach ($to_forum_ids as $topic_id => $forum_id)
{
$update_list[$forum_id][] = $topic_id;
}
// 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));
// 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));
}
// start building the needed arrays for updating the forum data
foreach ($forum_lookup as $forum_id => $forum_data)
{
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 = ' . $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_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");
}
// hooray for code reuse!
foreach ($shadow_topic_ids as $topic_id)
{ {
$data['shadow_topic_id'] = $topic_id; $data['shadow_topic_id'] = $topic_id;
$data['forum_id'] = $from_forum_id; $data['forum_id'] = $from_forum_id;
@ -637,6 +860,7 @@ class posting_api
} }
$db->sql_transaction('commit'); $db->sql_transaction('commit');
} }
} }