Commit b8eaff85 by Scott

Coding style (db admin)

parent 4b284792
...@@ -20,583 +20,668 @@ ...@@ -20,583 +20,668 @@
More about this license: http://www.question2answer.org/license.php More about this license: http://www.question2answer.org/license.php
*/ */
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
function qa_db_mysql_version() /**
/* * Return the current version of MySQL
Return the current version of MySQL */
*/ function qa_db_mysql_version()
{ {
return qa_db_read_one_value(qa_db_query_raw('SELECT VERSION()')); return qa_db_read_one_value(qa_db_query_raw('SELECT VERSION()'));
} }
function qa_db_table_size() /**
/* * Return the total size in bytes of all relevant tables in the Q2A database
Return the total size in bytes of all relevant tables in the Q2A database */
*/ function qa_db_table_size()
{ {
if (defined('QA_MYSQL_USERS_PREFIX')) { // check if one of the prefixes is a prefix itself of the other if (defined('QA_MYSQL_USERS_PREFIX')) { // check if one of the prefixes is a prefix itself of the other
if (stripos(QA_MYSQL_USERS_PREFIX, QA_MYSQL_TABLE_PREFIX)===0) if (stripos(QA_MYSQL_USERS_PREFIX, QA_MYSQL_TABLE_PREFIX) === 0)
$prefixes=array(QA_MYSQL_TABLE_PREFIX); $prefixes = array(QA_MYSQL_TABLE_PREFIX);
elseif (stripos(QA_MYSQL_TABLE_PREFIX, QA_MYSQL_USERS_PREFIX)===0) elseif (stripos(QA_MYSQL_TABLE_PREFIX, QA_MYSQL_USERS_PREFIX) === 0)
$prefixes=array(QA_MYSQL_USERS_PREFIX); $prefixes = array(QA_MYSQL_USERS_PREFIX);
else
$prefixes=array(QA_MYSQL_TABLE_PREFIX, QA_MYSQL_USERS_PREFIX);
} else
$prefixes=array(QA_MYSQL_TABLE_PREFIX);
$size=0;
foreach ($prefixes as $prefix) {
$statuses=qa_db_read_all_assoc(qa_db_query_raw(
"SHOW TABLE STATUS LIKE '".$prefix."%'"
));
foreach ($statuses as $status)
$size+=$status['Data_length']+$status['Index_length'];
}
return $size;
}
function qa_db_count_posts($type=null, $fromuser=null)
/*
Return a count of the number of posts of $type in database.
Set $fromuser to true to only count non-anonymous posts, false to only count anonymous posts
*/
{
$wheresql='';
if (isset($type))
$wheresql.=' WHERE type='.qa_db_argument_to_mysql($type, true);
if (isset($fromuser))
$wheresql.=(strlen($wheresql) ? ' AND' : ' WHERE').' userid '.($fromuser ? 'IS NOT' : 'IS').' NULL';
return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^posts'.$wheresql
));
}
function qa_db_count_users()
/*
Return number of registered users in database.
*/
{
return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^users'
));
}
function qa_db_count_active_users($table)
/*
Return number of active users in database $table
*/
{
switch ($table) {
case 'posts':
case 'uservotes':
case 'userpoints':
break;
default:
qa_fatal_error('qa_db_count_active_users() called for unknown table');
break;
}
return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(DISTINCT(userid)) FROM ^'.$table
));
}
function qa_db_count_categories()
/*
Return number of categories in the database
*/
{
return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^categories'
));
}
function qa_db_count_categoryid_qs($categoryid)
/*
Return number of questions in the database in $categoryid exactly, and not one of its subcategories
*/
{
return qa_db_read_one_value(qa_db_query_sub(
"SELECT COUNT(*) FROM ^posts WHERE categoryid<=># AND type='Q'",
$categoryid
));
}
function qa_db_get_user_visible_postids($userid)
/*
Return list of postids of visible or queued posts by $userid
*/
{
return qa_db_read_all_values(qa_db_query_sub(
"SELECT postid FROM ^posts WHERE userid=# AND type IN ('Q', 'A', 'C', 'Q_QUEUED', 'A_QUEUED', 'C_QUEUED')",
$userid
));
}
function qa_db_get_ip_visible_postids($ip)
/*
Return list of postids of visible or queued posts from $ip address
*/
{
return qa_db_read_all_values(qa_db_query_sub(
"SELECT postid FROM ^posts WHERE createip=$ AND type IN ('Q', 'A', 'C', 'Q_QUEUED', 'A_QUEUED', 'C_QUEUED')",
@inet_pton($ip)
));
}
function qa_db_postids_count_dependents($postids)
/*
Return an array whose keys contain the $postids which exist, and whose elements contain the number of other posts depending on each one
*/
{
if (count($postids))
return qa_db_read_all_assoc(qa_db_query_sub(
"SELECT postid, COALESCE(childcount, 0) AS count FROM ^posts LEFT JOIN (SELECT parentid, COUNT(*) AS childcount FROM ^posts WHERE parentid IN (#) AND LEFT(type, 1) IN ('A', 'C') GROUP BY parentid) x ON postid=x.parentid WHERE postid IN (#)",
$postids, $postids
), 'postid', 'count');
else else
return array(); $prefixes = array(QA_MYSQL_TABLE_PREFIX, QA_MYSQL_USERS_PREFIX);
}
} else
$prefixes = array(QA_MYSQL_TABLE_PREFIX);
function qa_db_get_unapproved_users($count) $size = 0;
/* foreach ($prefixes as $prefix) {
Return an array of the (up to) $count most recently created users who are awaiting approval and have not been blocked. $statuses = qa_db_read_all_assoc(qa_db_query_raw(
The array element for each user includes a 'profile' key whose value is an array of non-empty profile fields of the user. "SHOW TABLE STATUS LIKE '" . $prefix . "%'"
*/
{
$results=qa_db_read_all_assoc(qa_db_query_sub(
"SELECT ^users.userid, UNIX_TIMESTAMP(created) AS created, createip, email, handle, flags, title, content FROM ^users LEFT JOIN ^userprofile ON ^users.userid=^userprofile.userid AND LENGTH(content)>0 WHERE level<# AND NOT (flags&#) ORDER BY created DESC LIMIT #",
QA_USER_LEVEL_APPROVED, QA_USER_FLAGS_USER_BLOCKED, $count
));
$users=array();
foreach ($results as $result) {
$userid=$result['userid'];
if (!isset($users[$userid])) {
$users[$result['userid']]=$result;
$users[$result['userid']]['profile']=array();
unset($users[$userid]['title']);
unset($users[$userid]['content']);
}
if (isset($result['title']) && isset($result['content']))
$users[$userid]['profile'][$result['title']]=$result['content'];
}
return $users;
}
function qa_db_has_blobs_on_disk()
/*
Return whether there are any blobs whose content has been stored as a file on disk
*/
{
return qa_db_read_one_value(qa_db_query_sub('SELECT blobid FROM ^blobs WHERE content IS NULL LIMIT 1'), true) != null;
}
function qa_db_has_blobs_in_db()
/*
Return whether there are any blobs whose content has been stored in the database
*/
{
return qa_db_read_one_value(qa_db_query_sub('SELECT blobid FROM ^blobs WHERE content IS NOT NULL LIMIT 1'), true) != null;
}
function qa_db_category_last_pos($parentid)
/*
Return the maximum position of the categories with $parentid
*/
{
return qa_db_read_one_value(qa_db_query_sub(
'SELECT COALESCE(MAX(position), 0) FROM ^categories WHERE parentid<=>#',
$parentid
));
}
function qa_db_category_child_depth($categoryid)
/*
Return how many levels of subcategory there are below $categoryid
*/
{
// This is potentially a very slow query since it counts all the multi-generational offspring of a particular category
// But it's only used for admin purposes when moving a category around so I don't think it's worth making more efficient
// (Incidentally, this could be done by keeping a count for every category of how many generations of offspring it has.)
$result=qa_db_read_one_assoc(qa_db_query_sub(
'SELECT COUNT(child1.categoryid) AS count1, COUNT(child2.categoryid) AS count2, COUNT(child3.categoryid) AS count3 FROM ^categories AS child1 LEFT JOIN ^categories AS child2 ON child2.parentid=child1.categoryid LEFT JOIN ^categories AS child3 ON child3.parentid=child2.categoryid WHERE child1.parentid=#;', // requires QA_CATEGORY_DEPTH=4
$categoryid
));
for ($depth=QA_CATEGORY_DEPTH-1; $depth>=1; $depth--)
if ($result['count'.$depth])
return $depth;
return 0;
}
function qa_db_category_create($parentid, $title, $tags)
/*
Create a new category with $parentid, $title (=name) and $tags (=slug) in the database
*/
{
$lastpos=qa_db_category_last_pos($parentid);
qa_db_query_sub(
'INSERT INTO ^categories (parentid, title, tags, position) VALUES (#, $, $, #)',
$parentid, $title, $tags, 1+$lastpos
);
$categoryid=qa_db_last_insert_id();
qa_db_categories_recalc_backpaths($categoryid);
return $categoryid;
}
function qa_db_categories_recalc_backpaths($firstcategoryid, $lastcategoryid=null)
/*
Recalculate the backpath columns for all categories from $firstcategoryid to $lastcategoryid (if specified)
*/
{
if (!isset($lastcategoryid))
$lastcategoryid=$firstcategoryid;
qa_db_query_sub(
"UPDATE ^categories AS x, (SELECT cat1.categoryid, CONCAT_WS('/', cat1.tags, cat2.tags, cat3.tags, cat4.tags) AS backpath FROM ^categories AS cat1 LEFT JOIN ^categories AS cat2 ON cat1.parentid=cat2.categoryid LEFT JOIN ^categories AS cat3 ON cat2.parentid=cat3.categoryid LEFT JOIN ^categories AS cat4 ON cat3.parentid=cat4.categoryid WHERE cat1.categoryid BETWEEN # AND #) AS a SET x.backpath=a.backpath WHERE x.categoryid=a.categoryid",
$firstcategoryid, $lastcategoryid // requires QA_CATEGORY_DEPTH=4
);
}
function qa_db_category_rename($categoryid, $title, $tags)
/*
Set the name of $categoryid to $title and its slug to $tags in the database
*/
{
qa_db_query_sub(
'UPDATE ^categories SET title=$, tags=$ WHERE categoryid=#',
$title, $tags, $categoryid
);
qa_db_categories_recalc_backpaths($categoryid); // may also require recalculation of its offspring's backpaths
}
function qa_db_category_set_content($categoryid, $content)
/*
Set the content (=description) of $categoryid to $content
*/
{
qa_db_query_sub(
'UPDATE ^categories SET content=$ WHERE categoryid=#',
$content, $categoryid
);
}
function qa_db_category_get_parent($categoryid)
/*
Return the parentid of $categoryid
*/
{
return qa_db_read_one_value(qa_db_query_sub(
'SELECT parentid FROM ^categories WHERE categoryid=#',
$categoryid
)); ));
}
function qa_db_category_set_position($categoryid, $newposition)
/*
Move the category $categoryid into position $newposition under its parent
*/
{
qa_db_ordered_move('categories', 'categoryid', $categoryid, $newposition,
qa_db_apply_sub('parentid<=>#', array(qa_db_category_get_parent($categoryid))));
}
function qa_db_category_set_parent($categoryid, $newparentid)
/*
Set the parent of $categoryid to $newparentid, placing it in last position (doesn't do necessary recalculations)
*/
{
$oldparentid=qa_db_category_get_parent($categoryid);
if (strcmp($oldparentid, $newparentid)) { // if we're changing parent, move to end of old parent, then end of new parent
$lastpos=qa_db_category_last_pos($oldparentid);
qa_db_ordered_move('categories', 'categoryid', $categoryid, $lastpos, qa_db_apply_sub('parentid<=>#', array($oldparentid)));
$lastpos=qa_db_category_last_pos($newparentid); foreach ($statuses as $status)
$size += $status['Data_length'] + $status['Index_length'];
qa_db_query_sub( }
'UPDATE ^categories SET parentid=#, position=# WHERE categoryid=#',
$newparentid, 1+$lastpos, $categoryid return $size;
); }
/**
* Return a count of the number of posts of $type in database.
* Set $fromuser to true to only count non-anonymous posts, false to only count anonymous posts
* @param $type
* @param $fromuser
* @return mixed|null
*/
function qa_db_count_posts($type = null, $fromuser = null)
{
$wheresql = '';
if (isset($type))
$wheresql .= ' WHERE type=' . qa_db_argument_to_mysql($type, true);
if (isset($fromuser))
$wheresql .= (strlen($wheresql) ? ' AND' : ' WHERE') . ' userid ' . ($fromuser ? 'IS NOT' : 'IS') . ' NULL';
return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^posts' . $wheresql
));
}
/**
* Return number of registered users in database.
*/
function qa_db_count_users()
{
return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^users'
));
}
/**
* Return number of active users in database $table
* @param $table
* @return mixed|null
*/
function qa_db_count_active_users($table)
{
switch ($table) {
case 'posts':
case 'uservotes':
case 'userpoints':
break;
default:
qa_fatal_error('qa_db_count_active_users() called for unknown table');
break;
}
return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(DISTINCT(userid)) FROM ^' . $table
));
}
/**
* Return number of categories in the database
*/
function qa_db_count_categories()
{
return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^categories'
));
}
/**
* Return number of questions in the database in $categoryid exactly, and not one of its subcategories
* @param $categoryid
* @return mixed|null
*/
function qa_db_count_categoryid_qs($categoryid)
{
return qa_db_read_one_value(qa_db_query_sub(
"SELECT COUNT(*) FROM ^posts WHERE categoryid<=># AND type='Q'",
$categoryid
));
}
/**
* Return list of postids of visible or queued posts by $userid
* @param $userid
* @return array
*/
function qa_db_get_user_visible_postids($userid)
{
return qa_db_read_all_values(qa_db_query_sub(
"SELECT postid FROM ^posts WHERE userid=# AND type IN ('Q', 'A', 'C', 'Q_QUEUED', 'A_QUEUED', 'C_QUEUED')",
$userid
));
}
/**
* Return list of postids of visible or queued posts from $ip address
* @param $ip
* @return array
*/
function qa_db_get_ip_visible_postids($ip)
{
return qa_db_read_all_values(qa_db_query_sub(
"SELECT postid FROM ^posts WHERE createip=$ AND type IN ('Q', 'A', 'C', 'Q_QUEUED', 'A_QUEUED', 'C_QUEUED')",
@inet_pton($ip)
));
}
/**
* Return an array whose keys contain the $postids which exist, and whose elements contain the number of other posts depending on each one
* @param $postids
* @return array
*/
function qa_db_postids_count_dependents($postids)
{
if (count($postids))
return qa_db_read_all_assoc(qa_db_query_sub(
"SELECT postid, COALESCE(childcount, 0) AS count FROM ^posts LEFT JOIN (SELECT parentid, COUNT(*) AS childcount FROM ^posts WHERE parentid IN (#) AND LEFT(type, 1) IN ('A', 'C') GROUP BY parentid) x ON postid=x.parentid WHERE postid IN (#)",
$postids, $postids
), 'postid', 'count');
else
return array();
}
/**
* Return an array of the (up to) $count most recently created users who are awaiting approval and have not been blocked.
* The array element for each user includes a 'profile' key whose value is an array of non-empty profile fields of the user.
* @param $count
* @return array
*/
function qa_db_get_unapproved_users($count)
{
$results = qa_db_read_all_assoc(qa_db_query_sub(
"SELECT ^users.userid, UNIX_TIMESTAMP(created) AS created, createip, email, handle, flags, title, content FROM ^users LEFT JOIN ^userprofile ON ^users.userid=^userprofile.userid AND LENGTH(content)>0 WHERE level<# AND NOT (flags&#) ORDER BY created DESC LIMIT #",
QA_USER_LEVEL_APPROVED, QA_USER_FLAGS_USER_BLOCKED, $count
));
$users = array();
foreach ($results as $result) {
$userid = $result['userid'];
if (!isset($users[$userid])) {
$users[$result['userid']] = $result;
$users[$result['userid']]['profile'] = array();
unset($users[$userid]['title']);
unset($users[$userid]['content']);
} }
}
if (isset($result['title']) && isset($result['content']))
function qa_db_category_reassign($categoryid, $reassignid) $users[$userid]['profile'][$result['title']] = $result['content'];
/* }
Change the categoryid of any posts with (exact) $categoryid to $reassignid
*/ return $users;
{ }
qa_db_query_sub('UPDATE ^posts SET categoryid=# WHERE categoryid<=>#', $reassignid, $categoryid);
}
/**
* Return whether there are any blobs whose content has been stored as a file on disk
function qa_db_category_delete($categoryid) */
/* function qa_db_has_blobs_on_disk()
Delete the category $categoryid in the database {
*/ return qa_db_read_one_value(qa_db_query_sub('SELECT blobid FROM ^blobs WHERE content IS NULL LIMIT 1'), true) != null;
{ }
qa_db_ordered_delete('categories', 'categoryid', $categoryid,
qa_db_apply_sub('parentid<=>#', array(qa_db_category_get_parent($categoryid))));
} /**
* Return whether there are any blobs whose content has been stored in the database
*/
function qa_db_category_slug_to_id($parentid, $slug) function qa_db_has_blobs_in_db()
/* {
Return the categoryid for the category with parent $parentid and $slug return qa_db_read_one_value(qa_db_query_sub('SELECT blobid FROM ^blobs WHERE content IS NOT NULL LIMIT 1'), true) != null;
*/ }
{
return qa_db_read_one_value(qa_db_query_sub(
'SELECT categoryid FROM ^categories WHERE parentid<=># AND tags=$', /**
$parentid, $slug * Return the maximum position of the categories with $parentid
), true); * @param $parentid
} * @return mixed|null
*/
function qa_db_category_last_pos($parentid)
function qa_db_page_create($title, $flags, $tags, $heading, $content, $permit=null) {
/* return qa_db_read_one_value(qa_db_query_sub(
Create a new custom page (or link) in the database 'SELECT COALESCE(MAX(position), 0) FROM ^categories WHERE parentid<=>#',
*/ $parentid
{ ));
$position=qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^pages')); }
/**
* Return how many levels of subcategory there are below $categoryid
* @param $categoryid
* @return int
*/
function qa_db_category_child_depth($categoryid)
{
// This is potentially a very slow query since it counts all the multi-generational offspring of a particular category
// But it's only used for admin purposes when moving a category around so I don't think it's worth making more efficient
// (Incidentally, this could be done by keeping a count for every category of how many generations of offspring it has.)
$result = qa_db_read_one_assoc(qa_db_query_sub(
'SELECT COUNT(child1.categoryid) AS count1, COUNT(child2.categoryid) AS count2, COUNT(child3.categoryid) AS count3 FROM ^categories AS child1 LEFT JOIN ^categories AS child2 ON child2.parentid=child1.categoryid LEFT JOIN ^categories AS child3 ON child3.parentid=child2.categoryid WHERE child1.parentid=#;', // requires QA_CATEGORY_DEPTH=4
$categoryid
));
for ($depth = QA_CATEGORY_DEPTH - 1; $depth >= 1; $depth--)
if ($result['count' . $depth])
return $depth;
return 0;
}
/**
* Create a new category with $parentid, $title (=name) and $tags (=slug) in the database
* @param $parentid
* @param $title
* @param $tags
* @return mixed
*/
function qa_db_category_create($parentid, $title, $tags)
{
$lastpos = qa_db_category_last_pos($parentid);
qa_db_query_sub(
'INSERT INTO ^categories (parentid, title, tags, position) VALUES (#, $, $, #)',
$parentid, $title, $tags, 1 + $lastpos
);
$categoryid = qa_db_last_insert_id();
qa_db_categories_recalc_backpaths($categoryid);
return $categoryid;
}
/**
* Recalculate the backpath columns for all categories from $firstcategoryid to $lastcategoryid (if specified)
* @param $firstcategoryid
* @param $lastcategoryid
*/
function qa_db_categories_recalc_backpaths($firstcategoryid, $lastcategoryid = null)
{
if (!isset($lastcategoryid))
$lastcategoryid = $firstcategoryid;
qa_db_query_sub(
"UPDATE ^categories AS x, (SELECT cat1.categoryid, CONCAT_WS('/', cat1.tags, cat2.tags, cat3.tags, cat4.tags) AS backpath FROM ^categories AS cat1 LEFT JOIN ^categories AS cat2 ON cat1.parentid=cat2.categoryid LEFT JOIN ^categories AS cat3 ON cat2.parentid=cat3.categoryid LEFT JOIN ^categories AS cat4 ON cat3.parentid=cat4.categoryid WHERE cat1.categoryid BETWEEN # AND #) AS a SET x.backpath=a.backpath WHERE x.categoryid=a.categoryid",
$firstcategoryid, $lastcategoryid // requires QA_CATEGORY_DEPTH=4
);
}
/**
* Set the name of $categoryid to $title and its slug to $tags in the database
* @param $categoryid
* @param $title
* @param $tags
*/
function qa_db_category_rename($categoryid, $title, $tags)
{
qa_db_query_sub(
'UPDATE ^categories SET title=$, tags=$ WHERE categoryid=#',
$title, $tags, $categoryid
);
qa_db_categories_recalc_backpaths($categoryid); // may also require recalculation of its offspring's backpaths
}
/**
* Set the content (=description) of $categoryid to $content
* @param $categoryid
* @param $content
*/
function qa_db_category_set_content($categoryid, $content)
{
qa_db_query_sub(
'UPDATE ^categories SET content=$ WHERE categoryid=#',
$content, $categoryid
);
}
/**
* Return the parentid of $categoryid
* @param $categoryid
* @return mixed|null
*/
function qa_db_category_get_parent($categoryid)
{
return qa_db_read_one_value(qa_db_query_sub(
'SELECT parentid FROM ^categories WHERE categoryid=#',
$categoryid
));
}
/**
* Move the category $categoryid into position $newposition under its parent
* @param $categoryid
* @param $newposition
*/
function qa_db_category_set_position($categoryid, $newposition)
{
qa_db_ordered_move('categories', 'categoryid', $categoryid, $newposition,
qa_db_apply_sub('parentid<=>#', array(qa_db_category_get_parent($categoryid))));
}
/**
* Set the parent of $categoryid to $newparentid, placing it in last position (doesn't do necessary recalculations)
* @param $categoryid
* @param $newparentid
*/
function qa_db_category_set_parent($categoryid, $newparentid)
{
$oldparentid = qa_db_category_get_parent($categoryid);
if (strcmp($oldparentid, $newparentid)) { // if we're changing parent, move to end of old parent, then end of new parent
$lastpos = qa_db_category_last_pos($oldparentid);
qa_db_ordered_move('categories', 'categoryid', $categoryid, $lastpos, qa_db_apply_sub('parentid<=>#', array($oldparentid)));
$lastpos = qa_db_category_last_pos($newparentid);
qa_db_query_sub( qa_db_query_sub(
'INSERT INTO ^pages (title, nav, flags, permit, tags, heading, content, position) VALUES ($, \'\', #, #, $, $, $, #)', 'UPDATE ^categories SET parentid=#, position=# WHERE categoryid=#',
$title, $flags, $permit, $tags, $heading, $content, $position $newparentid, 1 + $lastpos, $categoryid
); );
return qa_db_last_insert_id();
} }
}
function qa_db_page_set_fields($pageid, $title, $flags, $tags, $heading, $content, $permit=null)
/* /**
Set the fields of $pageid to the values provided in the database * Change the categoryid of any posts with (exact) $categoryid to $reassignid
*/ * @param $categoryid
{ * @param $reassignid
qa_db_query_sub( */
'UPDATE ^pages SET title=$, flags=#, permit=#, tags=$, heading=$, content=$ WHERE pageid=#', function qa_db_category_reassign($categoryid, $reassignid)
$title, $flags, $permit, $tags, $heading, $content, $pageid {
); qa_db_query_sub('UPDATE ^posts SET categoryid=# WHERE categoryid<=>#', $reassignid, $categoryid);
} }
function qa_db_page_move($pageid, $nav, $newposition) /**
/* * Delete the category $categoryid in the database
Move the page $pageid into navigation menu $nav and position $newposition in the database * @param $categoryid
*/ */
{ function qa_db_category_delete($categoryid)
qa_db_query_sub( {
'UPDATE ^pages SET nav=$ WHERE pageid=#', qa_db_ordered_delete('categories', 'categoryid', $categoryid,
$nav, $pageid qa_db_apply_sub('parentid<=>#', array(qa_db_category_get_parent($categoryid))));
); }
qa_db_ordered_move('pages', 'pageid', $pageid, $newposition);
} /**
* Return the categoryid for the category with parent $parentid and $slug
* @param $parentid
function qa_db_page_delete($pageid) * @param $slug
/* * @return mixed|null
Delete the page $pageid in the database */
*/ function qa_db_category_slug_to_id($parentid, $slug)
{ {
qa_db_ordered_delete('pages', 'pageid', $pageid); return qa_db_read_one_value(qa_db_query_sub(
} 'SELECT categoryid FROM ^categories WHERE parentid<=># AND tags=$',
$parentid, $slug
), true);
function qa_db_ordered_move($table, $idcolumn, $id, $newposition, $conditionsql=null) }
/*
Move the entity identified by $idcolumn=$id into position $newposition (within optional $conditionsql) in $table in the database
*/ /**
{ * Create a new custom page (or link) in the database
$andsql=isset($conditionsql) ? (' AND '.$conditionsql) : ''; * @param $title
* @param $flags
qa_db_query_sub('LOCK TABLES ^'.$table.' WRITE'); * @param $tags
* @param $heading
$oldposition=qa_db_read_one_value(qa_db_query_sub('SELECT position FROM ^'.$table.' WHERE '.$idcolumn.'=#'.$andsql, $id)); * @param $content
* @param $permit
if ($newposition!=$oldposition) { * @return mixed
$lastposition=qa_db_read_one_value(qa_db_query_sub('SELECT MAX(position) FROM ^'.$table.' WHERE TRUE'.$andsql)); */
function qa_db_page_create($title, $flags, $tags, $heading, $content, $permit = null)
$newposition=max(1, min($newposition, $lastposition)); // constrain it to within range {
$position = qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^pages'));
qa_db_query_sub('UPDATE ^'.$table.' SET position=# WHERE '.$idcolumn.'=#'.$andsql, 1+$lastposition, $id);
// move it temporarily off the top because we have a unique key on the position column qa_db_query_sub(
'INSERT INTO ^pages (title, nav, flags, permit, tags, heading, content, position) VALUES ($, \'\', #, #, $, $, $, #)',
if ($newposition<$oldposition) $title, $flags, $permit, $tags, $heading, $content, $position
qa_db_query_sub('UPDATE ^'.$table.' SET position=position+1 WHERE position BETWEEN # AND #'.$andsql.' ORDER BY position DESC', $newposition, $oldposition); );
else
qa_db_query_sub('UPDATE ^'.$table.' SET position=position-1 WHERE position BETWEEN # AND #'.$andsql.' ORDER BY position', $oldposition, $newposition); return qa_db_last_insert_id();
}
qa_db_query_sub('UPDATE ^'.$table.' SET position=# WHERE '.$idcolumn.'=#'.$andsql, $newposition, $id);
}
/**
qa_db_query_sub('UNLOCK TABLES'); * Set the fields of $pageid to the values provided in the database
} * @param $pageid
* @param $title
* @param $flags
function qa_db_ordered_delete($table, $idcolumn, $id, $conditionsql=null) * @param $tags
/* * @param $heading
Delete the entity identified by $idcolumn=$id (and optional $conditionsql) in $table in the database * @param $content
*/ * @param $permit
{ */
$andsql=isset($conditionsql) ? (' AND '.$conditionsql) : ''; function qa_db_page_set_fields($pageid, $title, $flags, $tags, $heading, $content, $permit = null)
{
qa_db_query_sub('LOCK TABLES ^'.$table.' WRITE'); qa_db_query_sub(
'UPDATE ^pages SET title=$, flags=#, permit=#, tags=$, heading=$, content=$ WHERE pageid=#',
$oldposition=qa_db_read_one_value(qa_db_query_sub('SELECT position FROM ^'.$table.' WHERE '.$idcolumn.'=#'.$andsql, $id)); $title, $flags, $permit, $tags, $heading, $content, $pageid
);
qa_db_query_sub('DELETE FROM ^'.$table.' WHERE '.$idcolumn.'=#'.$andsql, $id); }
qa_db_query_sub('UPDATE ^'.$table.' SET position=position-1 WHERE position>#'.$andsql.' ORDER BY position', $oldposition);
/**
qa_db_query_sub('UNLOCK TABLES'); * Move the page $pageid into navigation menu $nav and position $newposition in the database
} * @param $pageid
* @param $nav
* @param $newposition
function qa_db_userfield_create($title, $content, $flags, $permit=null) */
/* function qa_db_page_move($pageid, $nav, $newposition)
Create a new user field with (internal) tag $title, label $content, $flags and $permit in the database. {
*/ qa_db_query_sub(
{ 'UPDATE ^pages SET nav=$ WHERE pageid=#',
$position=qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^userfields')); $nav, $pageid
);
qa_db_query_sub(
'INSERT INTO ^userfields (title, content, position, flags, permit) VALUES ($, $, #, #, #)', qa_db_ordered_move('pages', 'pageid', $pageid, $newposition);
$title, $content, $position, $flags, $permit }
);
return qa_db_last_insert_id(); /**
} * Delete the page $pageid in the database
* @param $pageid
*/
function qa_db_userfield_set_fields($fieldid, $content, $flags, $permit=null) function qa_db_page_delete($pageid)
/* {
Change the user field $fieldid to have label $content, $flags and $permit in the database (the title column cannot be changed once set) qa_db_ordered_delete('pages', 'pageid', $pageid);
*/ }
{
qa_db_query_sub(
'UPDATE ^userfields SET content=$, flags=#, permit=# WHERE fieldid=#', /**
$content, $flags, $permit, $fieldid * Move the entity identified by $idcolumn=$id into position $newposition (within optional $conditionsql) in $table in the database
); * @param $table
} * @param $idcolumn
* @param $id
* @param $newposition
function qa_db_userfield_move($fieldid, $newposition) * @param $conditionsql
/* */
Move the user field $fieldid into position $newposition in the database function qa_db_ordered_move($table, $idcolumn, $id, $newposition, $conditionsql = null)
*/ {
{ $andsql = isset($conditionsql) ? (' AND ' . $conditionsql) : '';
qa_db_ordered_move('userfields', 'fieldid', $fieldid, $newposition);
} qa_db_query_sub('LOCK TABLES ^' . $table . ' WRITE');
$oldposition = qa_db_read_one_value(qa_db_query_sub('SELECT position FROM ^' . $table . ' WHERE ' . $idcolumn . '=#' . $andsql, $id));
function qa_db_userfield_delete($fieldid)
/* if ($newposition != $oldposition) {
Delete the user field $fieldid in the database $lastposition = qa_db_read_one_value(qa_db_query_sub('SELECT MAX(position) FROM ^' . $table . ' WHERE TRUE' . $andsql));
*/
{ $newposition = max(1, min($newposition, $lastposition)); // constrain it to within range
qa_db_ordered_delete('userfields', 'fieldid', $fieldid);
} // move it temporarily off the top because we have a unique key on the position column
qa_db_query_sub('UPDATE ^' . $table . ' SET position=# WHERE ' . $idcolumn . '=#' . $andsql, 1 + $lastposition, $id);
function qa_db_widget_create($title, $tags) if ($newposition < $oldposition)
/* qa_db_query_sub('UPDATE ^' . $table . ' SET position=position+1 WHERE position BETWEEN # AND #' . $andsql . ' ORDER BY position DESC', $newposition, $oldposition);
Return the ID of a new widget, to be displayed by the widget module named $title on templates within $tags (comma-separated list) else
*/ qa_db_query_sub('UPDATE ^' . $table . ' SET position=position-1 WHERE position BETWEEN # AND #' . $andsql . ' ORDER BY position', $oldposition, $newposition);
{
$position=qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^widgets')); qa_db_query_sub('UPDATE ^' . $table . ' SET position=# WHERE ' . $idcolumn . '=#' . $andsql, $newposition, $id);
}
qa_db_query_sub(
'INSERT INTO ^widgets (place, position, tags, title) VALUES (\'\', #, $, $)', qa_db_query_sub('UNLOCK TABLES');
$position, $tags, $title }
);
return qa_db_last_insert_id(); /**
} * Delete the entity identified by $idcolumn=$id (and optional $conditionsql) in $table in the database
* @param $table
* @param $idcolumn
function qa_db_widget_set_fields($widgetid, $tags) * @param $id
/* * @param $conditionsql
Set the comma-separated list of templates for $widgetid to $tags */
*/ function qa_db_ordered_delete($table, $idcolumn, $id, $conditionsql = null)
{ {
qa_db_query_sub( $andsql = isset($conditionsql) ? (' AND ' . $conditionsql) : '';
'UPDATE ^widgets SET tags=$ WHERE widgetid=#',
$tags, $widgetid qa_db_query_sub('LOCK TABLES ^' . $table . ' WRITE');
);
} $oldposition = qa_db_read_one_value(qa_db_query_sub('SELECT position FROM ^' . $table . ' WHERE ' . $idcolumn . '=#' . $andsql, $id));
qa_db_query_sub('DELETE FROM ^' . $table . ' WHERE ' . $idcolumn . '=#' . $andsql, $id);
function qa_db_widget_move($widgetid, $place, $newposition)
/* qa_db_query_sub('UPDATE ^' . $table . ' SET position=position-1 WHERE position>#' . $andsql . ' ORDER BY position', $oldposition);
Move the widget $widgetit into position $position in the database's order, and show it in $place on the page
*/ qa_db_query_sub('UNLOCK TABLES');
{ }
qa_db_query_sub(
'UPDATE ^widgets SET place=$ WHERE widgetid=#',
$place, $widgetid /**
); * Create a new user field with (internal) tag $title, label $content, $flags and $permit in the database.
* @param $title
qa_db_ordered_move('widgets', 'widgetid', $widgetid, $newposition); * @param $content
} * @param $flags
* @param $permit
* @return mixed
function qa_db_widget_delete($widgetid) */
/* function qa_db_userfield_create($title, $content, $flags, $permit = null)
Delete the widget $widgetid in the database {
*/ $position = qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^userfields'));
{
qa_db_ordered_delete('widgets', 'widgetid', $widgetid); qa_db_query_sub(
} 'INSERT INTO ^userfields (title, content, position, flags, permit) VALUES ($, $, #, #, #)',
$title, $content, $position, $flags, $permit
);
/*
Omit PHP closing tag to help avoid accidental output return qa_db_last_insert_id();
*/ }
/**
* Change the user field $fieldid to have label $content, $flags and $permit in the database (the title column cannot be changed once set)
* @param $fieldid
* @param $content
* @param $flags
* @param $permit
*/
function qa_db_userfield_set_fields($fieldid, $content, $flags, $permit = null)
{
qa_db_query_sub(
'UPDATE ^userfields SET content=$, flags=#, permit=# WHERE fieldid=#',
$content, $flags, $permit, $fieldid
);
}
/**
* Move the user field $fieldid into position $newposition in the database
* @param $fieldid
* @param $newposition
*/
function qa_db_userfield_move($fieldid, $newposition)
{
qa_db_ordered_move('userfields', 'fieldid', $fieldid, $newposition);
}
/**
* Delete the user field $fieldid in the database
* @param $fieldid
*/
function qa_db_userfield_delete($fieldid)
{
qa_db_ordered_delete('userfields', 'fieldid', $fieldid);
}
/**
* Return the ID of a new widget, to be displayed by the widget module named $title on templates within $tags (comma-separated list)
* @param $title
* @param $tags
* @return mixed
*/
function qa_db_widget_create($title, $tags)
{
$position = qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^widgets'));
qa_db_query_sub(
'INSERT INTO ^widgets (place, position, tags, title) VALUES (\'\', #, $, $)',
$position, $tags, $title
);
return qa_db_last_insert_id();
}
/**
* Set the comma-separated list of templates for $widgetid to $tags
* @param $widgetid
* @param $tags
*/
function qa_db_widget_set_fields($widgetid, $tags)
{
qa_db_query_sub(
'UPDATE ^widgets SET tags=$ WHERE widgetid=#',
$tags, $widgetid
);
}
/**
* Move the widget $widgetit into position $position in the database's order, and show it in $place on the page
* @param $widgetid
* @param $place
* @param $newposition
*/
function qa_db_widget_move($widgetid, $place, $newposition)
{
qa_db_query_sub(
'UPDATE ^widgets SET place=$ WHERE widgetid=#',
$place, $widgetid
);
qa_db_ordered_move('widgets', 'widgetid', $widgetid, $newposition);
}
/**
* Delete the widget $widgetid in the database
* @param $widgetid
*/
function qa_db_widget_delete($widgetid)
{
qa_db_ordered_delete('widgets', 'widgetid', $widgetid);
}
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -20,405 +20,446 @@ ...@@ -20,405 +20,446 @@
More about this license: http://www.question2answer.org/license.php More about this license: http://www.question2answer.org/license.php
*/ */
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
header('Location: ../'); header('Location: ../');
exit; exit;
} }
require_once QA_INCLUDE_DIR.'db/post-create.php'; require_once QA_INCLUDE_DIR . 'db/post-create.php';
// For reindexing pages... // For reindexing pages...
function qa_db_count_pages() /**
/* * Return the number of custom pages currently in the database
Return the number of custom pages currently in the database */
*/ function qa_db_count_pages()
{ {
return qa_db_read_one_value(qa_db_query_sub( return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^pages' 'SELECT COUNT(*) FROM ^pages'
)); ));
} }
function qa_db_pages_get_for_reindexing($startpageid, $count) /**
/* * Return the information to reindex up to $count pages starting from $startpageid in the database
Return the information to reindex up to $count pages starting from $startpageid in the database * @param $startpageid
*/ * @param $count
{ * @return array
return qa_db_read_all_assoc(qa_db_query_sub( */
'SELECT pageid, flags, tags, heading, content FROM ^pages WHERE pageid>=# ORDER BY pageid LIMIT #', function qa_db_pages_get_for_reindexing($startpageid, $count)
$startpageid, $count {
), 'pageid'); return qa_db_read_all_assoc(qa_db_query_sub(
} 'SELECT pageid, flags, tags, heading, content FROM ^pages WHERE pageid>=# ORDER BY pageid LIMIT #',
$startpageid, $count
), 'pageid');
// For reindexing posts... }
function qa_db_posts_get_for_reindexing($startpostid, $count)
/* // For reindexing posts...
Return the information required to reindex up to $count posts starting from $startpostid in the database
*/ /**
{ * Return the information required to reindex up to $count posts starting from $startpostid in the database
return qa_db_read_all_assoc(qa_db_query_sub( * @param $startpostid
"SELECT ^posts.postid, ^posts.title, ^posts.content, ^posts.format, ^posts.tags, ^posts.categoryid, ^posts.type, IF (^posts.type='Q', ^posts.postid, IF(parent.type='Q', parent.postid, grandparent.postid)) AS questionid, ^posts.parentid FROM ^posts LEFT JOIN ^posts AS parent ON ^posts.parentid=parent.postid LEFT JOIN ^posts as grandparent ON parent.parentid=grandparent.postid WHERE ^posts.postid>=# AND ( (^posts.type='Q') OR (^posts.type='A' AND parent.type<=>'Q') OR (^posts.type='C' AND parent.type<=>'Q') OR (^posts.type='C' AND parent.type<=>'A' AND grandparent.type<=>'Q') ) ORDER BY postid LIMIT #", * @param $count
$startpostid, $count * @return array
), 'postid'); */
} function qa_db_posts_get_for_reindexing($startpostid, $count)
{
return qa_db_read_all_assoc(qa_db_query_sub(
function qa_db_prepare_for_reindexing($firstpostid, $lastpostid) "SELECT ^posts.postid, ^posts.title, ^posts.content, ^posts.format, ^posts.tags, ^posts.categoryid, ^posts.type, IF (^posts.type='Q', ^posts.postid, IF(parent.type='Q', parent.postid, grandparent.postid)) AS questionid, ^posts.parentid FROM ^posts LEFT JOIN ^posts AS parent ON ^posts.parentid=parent.postid LEFT JOIN ^posts as grandparent ON parent.parentid=grandparent.postid WHERE ^posts.postid>=# AND ( (^posts.type='Q') OR (^posts.type='A' AND parent.type<=>'Q') OR (^posts.type='C' AND parent.type<=>'Q') OR (^posts.type='C' AND parent.type<=>'A' AND grandparent.type<=>'Q') ) ORDER BY postid LIMIT #",
/* $startpostid, $count
Prepare posts $firstpostid to $lastpostid for reindexing in the database by removing their prior index entries ), 'postid');
*/ }
{
qa_db_query_sub(
'DELETE FROM ^titlewords WHERE postid>=# AND postid<=#', /**
$firstpostid, $lastpostid * Prepare posts $firstpostid to $lastpostid for reindexing in the database by removing their prior index entries
); * @param $firstpostid
* @param $lastpostid
qa_db_query_sub( */
'DELETE FROM ^contentwords WHERE postid>=# AND postid<=#', function qa_db_prepare_for_reindexing($firstpostid, $lastpostid)
$firstpostid, $lastpostid {
); qa_db_query_sub(
'DELETE FROM ^titlewords WHERE postid>=# AND postid<=#',
qa_db_query_sub( $firstpostid, $lastpostid
'DELETE FROM ^tagwords WHERE postid>=# AND postid<=#', );
$firstpostid, $lastpostid
); qa_db_query_sub(
'DELETE FROM ^contentwords WHERE postid>=# AND postid<=#',
qa_db_query_sub( $firstpostid, $lastpostid
'DELETE FROM ^posttags WHERE postid>=# AND postid<=#', );
$firstpostid, $lastpostid
); qa_db_query_sub(
} 'DELETE FROM ^tagwords WHERE postid>=# AND postid<=#',
$firstpostid, $lastpostid
);
function qa_db_truncate_indexes($firstpostid)
/* qa_db_query_sub(
Remove any rows in the database word indexes with postid from $firstpostid upwards 'DELETE FROM ^posttags WHERE postid>=# AND postid<=#',
*/ $firstpostid, $lastpostid
{ );
qa_db_query_sub( }
'DELETE FROM ^titlewords WHERE postid>=#',
$firstpostid
); /**
* Remove any rows in the database word indexes with postid from $firstpostid upwards
qa_db_query_sub( * @param $firstpostid
'DELETE FROM ^contentwords WHERE postid>=#', */
$firstpostid function qa_db_truncate_indexes($firstpostid)
); {
qa_db_query_sub(
qa_db_query_sub( 'DELETE FROM ^titlewords WHERE postid>=#',
'DELETE FROM ^tagwords WHERE postid>=#', $firstpostid
$firstpostid );
);
qa_db_query_sub(
qa_db_query_sub( 'DELETE FROM ^contentwords WHERE postid>=#',
'DELETE FROM ^posttags WHERE postid>=#', $firstpostid
$firstpostid );
);
} qa_db_query_sub(
'DELETE FROM ^tagwords WHERE postid>=#',
$firstpostid
function qa_db_count_words() );
/*
Return the number of words currently referenced in the database qa_db_query_sub(
*/ 'DELETE FROM ^posttags WHERE postid>=#',
{ $firstpostid
return qa_db_read_one_value(qa_db_query_sub( );
'SELECT COUNT(*) FROM ^words' }
));
}
/**
* Return the number of words currently referenced in the database
function qa_db_words_prepare_for_recounting($startwordid, $count) */
/* function qa_db_count_words()
Return the ids of up to $count words in the database starting from $startwordid {
*/ return qa_db_read_one_value(qa_db_query_sub(
{ 'SELECT COUNT(*) FROM ^words'
));
}
/**
* Return the ids of up to $count words in the database starting from $startwordid
* @param $startwordid
* @param $count
* @return array
*/
function qa_db_words_prepare_for_recounting($startwordid, $count)
{
return qa_db_read_all_values(qa_db_query_sub(
'SELECT wordid FROM ^words WHERE wordid>=# ORDER BY wordid LIMIT #',
$startwordid, $count
));
}
/**
* Recalculate the cached counts for words $firstwordid to $lastwordid in the database
* @param $firstwordid
* @param $lastwordid
*/
function qa_db_words_recount($firstwordid, $lastwordid)
{
qa_db_query_sub(
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^titlewords.wordid) AS titlecount FROM ^words LEFT JOIN ^titlewords ON ^titlewords.wordid=^words.wordid WHERE ^words.wordid>=# AND ^words.wordid<=# GROUP BY wordid) AS a SET x.titlecount=a.titlecount WHERE x.wordid=a.wordid',
$firstwordid, $lastwordid
);
qa_db_query_sub(
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^contentwords.wordid) AS contentcount FROM ^words LEFT JOIN ^contentwords ON ^contentwords.wordid=^words.wordid WHERE ^words.wordid>=# AND ^words.wordid<=# GROUP BY wordid) AS a SET x.contentcount=a.contentcount WHERE x.wordid=a.wordid',
$firstwordid, $lastwordid
);
qa_db_query_sub(
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^tagwords.wordid) AS tagwordcount FROM ^words LEFT JOIN ^tagwords ON ^tagwords.wordid=^words.wordid WHERE ^words.wordid>=# AND ^words.wordid<=# GROUP BY wordid) AS a SET x.tagwordcount=a.tagwordcount WHERE x.wordid=a.wordid',
$firstwordid, $lastwordid
);
qa_db_query_sub(
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^posttags.wordid) AS tagcount FROM ^words LEFT JOIN ^posttags ON ^posttags.wordid=^words.wordid WHERE ^words.wordid>=# AND ^words.wordid<=# GROUP BY wordid) AS a SET x.tagcount=a.tagcount WHERE x.wordid=a.wordid',
$firstwordid, $lastwordid
);
qa_db_query_sub(
'DELETE FROM ^words WHERE wordid>=# AND wordid<=# AND titlecount=0 AND contentcount=0 AND tagwordcount=0 AND tagcount=0',
$firstwordid, $lastwordid
);
}
// For recalculating numbers of votes and answers for questions...
/**
* Return the ids of up to $count posts in the database starting from $startpostid
* @param $startpostid
* @param $count
* @return array
*/
function qa_db_posts_get_for_recounting($startpostid, $count)
{
return qa_db_read_all_values(qa_db_query_sub(
'SELECT postid FROM ^posts WHERE postid>=# ORDER BY postid LIMIT #',
$startpostid, $count
));
}
/**
* Recalculate the cached vote counts for posts $firstpostid to $lastpostid in the database
* @param $firstpostid
* @param $lastpostid
*/
function qa_db_posts_votes_recount($firstpostid, $lastpostid)
{
qa_db_query_sub(
'UPDATE ^posts AS x, (SELECT ^posts.postid, COALESCE(SUM(GREATEST(0,^uservotes.vote)),0) AS upvotes, -COALESCE(SUM(LEAST(0,^uservotes.vote)),0) AS downvotes, COALESCE(SUM(IF(^uservotes.flag, 1, 0)),0) AS flagcount FROM ^posts LEFT JOIN ^uservotes ON ^uservotes.postid=^posts.postid WHERE ^posts.postid>=# AND ^posts.postid<=# GROUP BY postid) AS a SET x.upvotes=a.upvotes, x.downvotes=a.downvotes, x.netvotes=a.upvotes-a.downvotes, x.flagcount=a.flagcount WHERE x.postid=a.postid',
$firstpostid, $lastpostid
);
qa_db_hotness_update($firstpostid, $lastpostid);
}
/**
* Recalculate the cached answer counts for posts $firstpostid to $lastpostid in the database, along with the highest netvotes of any of their answers
* @param $firstpostid
* @param $lastpostid
*/
function qa_db_posts_answers_recount($firstpostid, $lastpostid)
{
require_once QA_INCLUDE_DIR . 'db/hotness.php';
qa_db_query_sub(
'UPDATE ^posts AS x, (SELECT parents.postid, COUNT(children.postid) AS acount, COALESCE(GREATEST(MAX(children.netvotes), 0), 0) AS amaxvote FROM ^posts AS parents LEFT JOIN ^posts AS children ON parents.postid=children.parentid AND children.type=\'A\' WHERE parents.postid>=# AND parents.postid<=# GROUP BY postid) AS a SET x.acount=a.acount, x.amaxvote=a.amaxvote WHERE x.postid=a.postid',
$firstpostid, $lastpostid
);
qa_db_hotness_update($firstpostid, $lastpostid);
}
// For recalculating user points...
/**
* Return the ids of up to $count users in the database starting from $startuserid
* If using single sign-on integration, base this on user activity rather than the users table which we don't have
* @param $startuserid
* @param $count
* @return array
*/
function qa_db_users_get_for_recalc_points($startuserid, $count)
{
if (QA_FINAL_EXTERNAL_USERS)
return qa_db_read_all_values(qa_db_query_sub( return qa_db_read_all_values(qa_db_query_sub(
'SELECT wordid FROM ^words WHERE wordid>=# ORDER BY wordid LIMIT #', 'SELECT userid FROM ((SELECT DISTINCT userid FROM ^posts WHERE userid>=# ORDER BY userid LIMIT #) UNION (SELECT DISTINCT userid FROM ^uservotes WHERE userid>=# ORDER BY userid LIMIT #)) x ORDER BY userid LIMIT #',
$startwordid, $count $startuserid, $count, $startuserid, $count, $count
)); ));
} else
function qa_db_words_recount($firstwordid, $lastwordid)
/*
Recalculate the cached counts for words $firstwordid to $lastwordid in the database
*/
{
qa_db_query_sub(
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^titlewords.wordid) AS titlecount FROM ^words LEFT JOIN ^titlewords ON ^titlewords.wordid=^words.wordid WHERE ^words.wordid>=# AND ^words.wordid<=# GROUP BY wordid) AS a SET x.titlecount=a.titlecount WHERE x.wordid=a.wordid',
$firstwordid, $lastwordid
);
qa_db_query_sub(
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^contentwords.wordid) AS contentcount FROM ^words LEFT JOIN ^contentwords ON ^contentwords.wordid=^words.wordid WHERE ^words.wordid>=# AND ^words.wordid<=# GROUP BY wordid) AS a SET x.contentcount=a.contentcount WHERE x.wordid=a.wordid',
$firstwordid, $lastwordid
);
qa_db_query_sub(
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^tagwords.wordid) AS tagwordcount FROM ^words LEFT JOIN ^tagwords ON ^tagwords.wordid=^words.wordid WHERE ^words.wordid>=# AND ^words.wordid<=# GROUP BY wordid) AS a SET x.tagwordcount=a.tagwordcount WHERE x.wordid=a.wordid',
$firstwordid, $lastwordid
);
qa_db_query_sub(
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^posttags.wordid) AS tagcount FROM ^words LEFT JOIN ^posttags ON ^posttags.wordid=^words.wordid WHERE ^words.wordid>=# AND ^words.wordid<=# GROUP BY wordid) AS a SET x.tagcount=a.tagcount WHERE x.wordid=a.wordid',
$firstwordid, $lastwordid
);
qa_db_query_sub(
'DELETE FROM ^words WHERE wordid>=# AND wordid<=# AND titlecount=0 AND contentcount=0 AND tagwordcount=0 AND tagcount=0',
$firstwordid, $lastwordid
);
}
// For recalculating numbers of votes and answers for questions...
function qa_db_posts_get_for_recounting($startpostid, $count)
/*
Return the ids of up to $count posts in the database starting from $startpostid
*/
{
return qa_db_read_all_values(qa_db_query_sub( return qa_db_read_all_values(qa_db_query_sub(
'SELECT postid FROM ^posts WHERE postid>=# ORDER BY postid LIMIT #', 'SELECT DISTINCT userid FROM ^users WHERE userid>=# ORDER BY userid LIMIT #',
$startpostid, $count $startuserid, $count
)); ));
} }
function qa_db_posts_votes_recount($firstpostid, $lastpostid)
/*
Recalculate the cached vote counts for posts $firstpostid to $lastpostid in the database
*/
{
qa_db_query_sub(
'UPDATE ^posts AS x, (SELECT ^posts.postid, COALESCE(SUM(GREATEST(0,^uservotes.vote)),0) AS upvotes, -COALESCE(SUM(LEAST(0,^uservotes.vote)),0) AS downvotes, COALESCE(SUM(IF(^uservotes.flag, 1, 0)),0) AS flagcount FROM ^posts LEFT JOIN ^uservotes ON ^uservotes.postid=^posts.postid WHERE ^posts.postid>=# AND ^posts.postid<=# GROUP BY postid) AS a SET x.upvotes=a.upvotes, x.downvotes=a.downvotes, x.netvotes=a.upvotes-a.downvotes, x.flagcount=a.flagcount WHERE x.postid=a.postid',
$firstpostid, $lastpostid
);
qa_db_hotness_update($firstpostid, $lastpostid);
}
function qa_db_posts_answers_recount($firstpostid, $lastpostid) /**
/* * Recalculate all userpoints columns for users $firstuserid to $lastuserid in the database
Recalculate the cached answer counts for posts $firstpostid to $lastpostid in the database, along with the highest netvotes of any of their answers * @param $firstuserid
*/ * @param $lastuserid
{ */
require_once QA_INCLUDE_DIR.'db/hotness.php'; function qa_db_users_recalc_points($firstuserid, $lastuserid)
{
require_once QA_INCLUDE_DIR . 'db/points.php';
qa_db_query_sub( $qa_userpoints_calculations = qa_db_points_calculations();
'UPDATE ^posts AS x, (SELECT parents.postid, COUNT(children.postid) AS acount, COALESCE(GREATEST(MAX(children.netvotes), 0), 0) AS amaxvote FROM ^posts AS parents LEFT JOIN ^posts AS children ON parents.postid=children.parentid AND children.type=\'A\' WHERE parents.postid>=# AND parents.postid<=# GROUP BY postid) AS a SET x.acount=a.acount, x.amaxvote=a.amaxvote WHERE x.postid=a.postid',
$firstpostid, $lastpostid
);
qa_db_hotness_update($firstpostid, $lastpostid); qa_db_query_sub(
} 'DELETE FROM ^userpoints WHERE userid>=# AND userid<=# AND bonus=0', // delete those with no bonus
$firstuserid, $lastuserid
);
$zeropoints = 'points=0';
foreach ($qa_userpoints_calculations as $field => $calculation)
$zeropoints .= ', ' . $field . '=0';
// For recalculating user points... qa_db_query_sub(
'UPDATE ^userpoints SET ' . $zeropoints . ' WHERE userid>=# AND userid<=#', // zero out the rest
function qa_db_users_get_for_recalc_points($startuserid, $count) $firstuserid, $lastuserid
/* );
Return the ids of up to $count users in the database starting from $startuserid
If using single sign-on integration, base this on user activity rather than the users table which we don't have
*/
{
if (QA_FINAL_EXTERNAL_USERS)
return qa_db_read_all_values(qa_db_query_sub(
'SELECT userid FROM ((SELECT DISTINCT userid FROM ^posts WHERE userid>=# ORDER BY userid LIMIT #) UNION (SELECT DISTINCT userid FROM ^uservotes WHERE userid>=# ORDER BY userid LIMIT #)) x ORDER BY userid LIMIT #',
$startuserid, $count, $startuserid, $count, $count
));
else
return qa_db_read_all_values(qa_db_query_sub(
'SELECT DISTINCT userid FROM ^users WHERE userid>=# ORDER BY userid LIMIT #',
$startuserid, $count
));
}
function qa_db_users_recalc_points($firstuserid, $lastuserid)
/*
Recalculate all userpoints columns for users $firstuserid to $lastuserid in the database
*/
{
require_once QA_INCLUDE_DIR.'db/points.php';
$qa_userpoints_calculations=qa_db_points_calculations();
if (QA_FINAL_EXTERNAL_USERS)
qa_db_query_sub( qa_db_query_sub(
'DELETE FROM ^userpoints WHERE userid>=# AND userid<=# AND bonus=0', // delete those with no bonus 'INSERT IGNORE INTO ^userpoints (userid) SELECT DISTINCT userid FROM ^posts WHERE userid>=# AND userid<=# UNION SELECT DISTINCT userid FROM ^uservotes WHERE userid>=# AND userid<=#',
$firstuserid, $lastuserid $firstuserid, $lastuserid, $firstuserid, $lastuserid
); );
else
$zeropoints='points=0';
foreach ($qa_userpoints_calculations as $field => $calculation)
$zeropoints.=', '.$field.'=0';
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^userpoints SET '.$zeropoints.' WHERE userid>=# AND userid<=#', // zero out the rest 'INSERT IGNORE INTO ^userpoints (userid) SELECT DISTINCT userid FROM ^users WHERE userid>=# AND userid<=#',
$firstuserid, $lastuserid $firstuserid, $lastuserid
); );
if (QA_FINAL_EXTERNAL_USERS) $updatepoints = (int)qa_opt('points_base');
qa_db_query_sub(
'INSERT IGNORE INTO ^userpoints (userid) SELECT DISTINCT userid FROM ^posts WHERE userid>=# AND userid<=# UNION SELECT DISTINCT userid FROM ^uservotes WHERE userid>=# AND userid<=#',
$firstuserid, $lastuserid, $firstuserid, $lastuserid
);
else
qa_db_query_sub(
'INSERT IGNORE INTO ^userpoints (userid) SELECT DISTINCT userid FROM ^users WHERE userid>=# AND userid<=#',
$firstuserid, $lastuserid
);
$updatepoints=(int)qa_opt('points_base');
foreach ($qa_userpoints_calculations as $field => $calculation) {
qa_db_query_sub(
'UPDATE ^userpoints, (SELECT userid_src.userid, '.str_replace('~', ' BETWEEN # AND #', $calculation['formula']).' GROUP BY userid) AS results '.
'SET ^userpoints.'.$field.'=results.'.$field.' WHERE ^userpoints.userid=results.userid',
$firstuserid, $lastuserid
);
$updatepoints.='+('.((int)$calculation['multiple']).'*'.$field.')';
}
foreach ($qa_userpoints_calculations as $field => $calculation) {
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^userpoints SET points='.$updatepoints.'+bonus WHERE userid>=# AND userid<=#', 'UPDATE ^userpoints, (SELECT userid_src.userid, ' . str_replace('~', ' BETWEEN # AND #', $calculation['formula']) . ' GROUP BY userid) AS results ' .
'SET ^userpoints.' . $field . '=results.' . $field . ' WHERE ^userpoints.userid=results.userid',
$firstuserid, $lastuserid $firstuserid, $lastuserid
); );
}
function qa_db_truncate_userpoints($lastuserid)
/*
Remove any rows in the userpoints table where userid is greater than $lastuserid
*/
{
qa_db_query_sub(
'DELETE FROM ^userpoints WHERE userid>#',
$lastuserid
);
}
// For refilling event streams...
function qa_db_qs_get_for_event_refilling($startpostid, $count) $updatepoints .= '+(' . ((int)$calculation['multiple']) . '*' . $field . ')';
/*
Return the ids of up to $count questions in the database starting from $startpostid
*/
{
return qa_db_read_all_values(qa_db_query_sub(
"SELECT postid FROM ^posts WHERE postid>=# AND LEFT(type, 1)='Q' ORDER BY postid LIMIT #",
$startpostid, $count
));
} }
qa_db_query_sub(
// For recalculating categories... 'UPDATE ^userpoints SET points=' . $updatepoints . '+bonus WHERE userid>=# AND userid<=#',
$firstuserid, $lastuserid
function qa_db_posts_get_for_recategorizing($startpostid, $count) );
/* }
Return the ids of up to $count posts (including queued/hidden) in the database starting from $startpostid
*/
{ /**
return qa_db_read_all_values(qa_db_query_sub( * Remove any rows in the userpoints table where userid is greater than $lastuserid
"SELECT postid FROM ^posts WHERE postid>=# ORDER BY postid LIMIT #", * @param $lastuserid
$startpostid, $count */
)); function qa_db_truncate_userpoints($lastuserid)
} {
qa_db_query_sub(
'DELETE FROM ^userpoints WHERE userid>#',
function qa_db_posts_recalc_categoryid($firstpostid, $lastpostid) $lastuserid
/* );
Recalculate the (exact) categoryid for the posts (including queued/hidden) between $firstpostid and $lastpostid }
in the database, where the category of comments and answers is set by the category of the antecedent question
*/
{ // For refilling event streams...
qa_db_query_sub(
"UPDATE ^posts AS x, (SELECT ^posts.postid, IF(LEFT(parent.type, 1)='Q', parent.categoryid, grandparent.categoryid) AS categoryid FROM ^posts LEFT JOIN ^posts AS parent ON ^posts.parentid=parent.postid LEFT JOIN ^posts AS grandparent ON parent.parentid=grandparent.postid WHERE ^posts.postid BETWEEN # AND # AND LEFT(^posts.type, 1)!='Q') AS a SET x.categoryid=a.categoryid WHERE x.postid=a.postid", /**
$firstpostid, $lastpostid * Return the ids of up to $count questions in the database starting from $startpostid
); * @param $startpostid
} * @param $count
* @return array
*/
function qa_db_categories_get_for_recalcs($startcategoryid, $count) function qa_db_qs_get_for_event_refilling($startpostid, $count)
/* {
Return the ids of up to $count categories in the database starting from $startcategoryid return qa_db_read_all_values(qa_db_query_sub(
*/ "SELECT postid FROM ^posts WHERE postid>=# AND LEFT(type, 1)='Q' ORDER BY postid LIMIT #",
{ $startpostid, $count
return qa_db_read_all_values(qa_db_query_sub( ));
"SELECT categoryid FROM ^categories WHERE categoryid>=# ORDER BY categoryid LIMIT #", }
$startcategoryid, $count
));
} // For recalculating categories...
/**
// For deleting hidden posts... * Return the ids of up to $count posts (including queued/hidden) in the database starting from $startpostid
* @param $startpostid
function qa_db_posts_get_for_deleting($type, $startpostid=0, $limit=null) * @param $count
/* * @return array
Return the ids of up to $limit posts of $type that can be deleted from the database (i.e. have no dependents) */
*/ function qa_db_posts_get_for_recategorizing($startpostid, $count)
{ {
$limitsql=isset($limit) ? (' ORDER BY ^posts.postid LIMIT '.(int)$limit) : ''; return qa_db_read_all_values(qa_db_query_sub(
"SELECT postid FROM ^posts WHERE postid>=# ORDER BY postid LIMIT #",
return qa_db_read_all_values(qa_db_query_sub( $startpostid, $count
"SELECT ^posts.postid FROM ^posts LEFT JOIN ^posts AS child ON child.parentid=^posts.postid LEFT JOIN ^posts AS dupe ON dupe.closedbyid=^posts.postid WHERE ^posts.type=$ AND ^posts.postid>=# AND child.postid IS NULL AND dupe.postid IS NULL".$limitsql, ));
$type.'_HIDDEN', $startpostid }
));
}
/**
* Recalculate the (exact) categoryid for the posts (including queued/hidden) between $firstpostid and $lastpostid
// For moving blobs between database and disk... * in the database, where the category of comments and answers is set by the category of the antecedent question
* @param $firstpostid
function qa_db_count_blobs_in_db() * @param $lastpostid
/* */
Return the number of blobs whose content is stored in the database, rather than on disk function qa_db_posts_recalc_categoryid($firstpostid, $lastpostid)
*/ {
{ qa_db_query_sub(
return qa_db_read_one_value(qa_db_query_sub('SELECT COUNT(*) FROM ^blobs WHERE content IS NOT NULL')); "UPDATE ^posts AS x, (SELECT ^posts.postid, IF(LEFT(parent.type, 1)='Q', parent.categoryid, grandparent.categoryid) AS categoryid FROM ^posts LEFT JOIN ^posts AS parent ON ^posts.parentid=parent.postid LEFT JOIN ^posts AS grandparent ON parent.parentid=grandparent.postid WHERE ^posts.postid BETWEEN # AND # AND LEFT(^posts.type, 1)!='Q') AS a SET x.categoryid=a.categoryid WHERE x.postid=a.postid",
} $firstpostid, $lastpostid
);
}
function qa_db_get_next_blob_in_db($startblobid)
/*
Return the id, content and format of the first blob whose content is stored in the database starting from $startblobid /**
*/ * Return the ids of up to $count categories in the database starting from $startcategoryid
{ * @param $startcategoryid
return qa_db_read_one_assoc(qa_db_query_sub( * @param $count
'SELECT blobid, content, format FROM ^blobs WHERE blobid>=# AND content IS NOT NULL LIMIT 1', * @return array
$startblobid */
), true); function qa_db_categories_get_for_recalcs($startcategoryid, $count)
} {
return qa_db_read_all_values(qa_db_query_sub(
"SELECT categoryid FROM ^categories WHERE categoryid>=# ORDER BY categoryid LIMIT #",
function qa_db_count_blobs_on_disk() $startcategoryid, $count
/* ));
Return the number of blobs whose content is stored on disk, rather than in the database }
*/
{
return qa_db_read_one_value(qa_db_query_sub('SELECT COUNT(*) FROM ^blobs WHERE content IS NULL')); // For deleting hidden posts...
}
/**
* Return the ids of up to $limit posts of $type that can be deleted from the database (i.e. have no dependents)
function qa_db_get_next_blob_on_disk($startblobid) * @param $type
/* * @param int $startpostid
Return the id and format of the first blob whose content is stored on disk starting from $startblobid * @param $limit
*/ * @return array
{ */
return qa_db_read_one_assoc(qa_db_query_sub( function qa_db_posts_get_for_deleting($type, $startpostid = 0, $limit = null)
'SELECT blobid, format FROM ^blobs WHERE blobid>=# AND content IS NULL LIMIT 1', {
$startblobid $limitsql = isset($limit) ? (' ORDER BY ^posts.postid LIMIT ' . (int)$limit) : '';
), true);
} return qa_db_read_all_values(qa_db_query_sub(
"SELECT ^posts.postid FROM ^posts LEFT JOIN ^posts AS child ON child.parentid=^posts.postid LEFT JOIN ^posts AS dupe ON dupe.closedbyid=^posts.postid WHERE ^posts.type=$ AND ^posts.postid>=# AND child.postid IS NULL AND dupe.postid IS NULL" . $limitsql,
$type . '_HIDDEN', $startpostid
/* ));
Omit PHP closing tag to help avoid accidental output }
*/
// For moving blobs between database and disk...
/**
* Return the number of blobs whose content is stored in the database, rather than on disk
*/
function qa_db_count_blobs_in_db()
{
return qa_db_read_one_value(qa_db_query_sub('SELECT COUNT(*) FROM ^blobs WHERE content IS NOT NULL'));
}
/**
* Return the id, content and format of the first blob whose content is stored in the database starting from $startblobid
* @param $startblobid
* @return array|null
*/
function qa_db_get_next_blob_in_db($startblobid)
{
return qa_db_read_one_assoc(qa_db_query_sub(
'SELECT blobid, content, format FROM ^blobs WHERE blobid>=# AND content IS NOT NULL LIMIT 1',
$startblobid
), true);
}
/**
* Return the number of blobs whose content is stored on disk, rather than in the database
*/
function qa_db_count_blobs_on_disk()
{
return qa_db_read_one_value(qa_db_query_sub('SELECT COUNT(*) FROM ^blobs WHERE content IS NULL'));
}
/**
* Return the id and format of the first blob whose content is stored on disk starting from $startblobid
* @param $startblobid
* @return array|null
*/
function qa_db_get_next_blob_on_disk($startblobid)
{
return qa_db_read_one_assoc(qa_db_query_sub(
'SELECT blobid, format FROM ^blobs WHERE blobid>=# AND content IS NULL LIMIT 1',
$startblobid
), true);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment