Commit b8eaff85 by Scott

Coding style (db admin)

parent 4b284792
...@@ -20,87 +20,92 @@ ...@@ -20,87 +20,92 @@
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 else
$prefixes=array(QA_MYSQL_TABLE_PREFIX, QA_MYSQL_USERS_PREFIX); $prefixes = array(QA_MYSQL_TABLE_PREFIX, QA_MYSQL_USERS_PREFIX);
} else } else
$prefixes=array(QA_MYSQL_TABLE_PREFIX); $prefixes = array(QA_MYSQL_TABLE_PREFIX);
$size=0; $size = 0;
foreach ($prefixes as $prefix) { foreach ($prefixes as $prefix) {
$statuses=qa_db_read_all_assoc(qa_db_query_raw( $statuses = qa_db_read_all_assoc(qa_db_query_raw(
"SHOW TABLE STATUS LIKE '".$prefix."%'" "SHOW TABLE STATUS LIKE '" . $prefix . "%'"
)); ));
foreach ($statuses as $status) foreach ($statuses as $status)
$size+=$status['Data_length']+$status['Index_length']; $size += $status['Data_length'] + $status['Index_length'];
} }
return $size; return $size;
} }
function qa_db_count_posts($type=null, $fromuser=null) /**
/* * Return a count of the number of posts of $type in database.
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
Set $fromuser to true to only count non-anonymous posts, false to only count anonymous posts * @param $type
*/ * @param $fromuser
{ * @return mixed|null
$wheresql=''; */
function qa_db_count_posts($type = null, $fromuser = null)
{
$wheresql = '';
if (isset($type)) if (isset($type))
$wheresql.=' WHERE type='.qa_db_argument_to_mysql($type, true); $wheresql .= ' WHERE type=' . qa_db_argument_to_mysql($type, true);
if (isset($fromuser)) if (isset($fromuser))
$wheresql.=(strlen($wheresql) ? ' AND' : ' WHERE').' userid '.($fromuser ? 'IS NOT' : 'IS').' NULL'; $wheresql .= (strlen($wheresql) ? ' AND' : ' WHERE') . ' userid ' . ($fromuser ? 'IS NOT' : 'IS') . ' NULL';
return qa_db_read_one_value(qa_db_query_sub( return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^posts'.$wheresql 'SELECT COUNT(*) FROM ^posts' . $wheresql
)); ));
} }
function qa_db_count_users() /**
/* * Return number of registered users in database.
Return number of registered users in database. */
*/ function qa_db_count_users()
{ {
return qa_db_read_one_value(qa_db_query_sub( return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^users' 'SELECT COUNT(*) FROM ^users'
)); ));
} }
function qa_db_count_active_users($table) /**
/* * Return number of active users in database $table
Return number of active users in database $table * @param $table
*/ * @return mixed|null
{ */
function qa_db_count_active_users($table)
{
switch ($table) { switch ($table) {
case 'posts': case 'posts':
case 'uservotes': case 'uservotes':
...@@ -113,63 +118,71 @@ ...@@ -113,63 +118,71 @@
} }
return qa_db_read_one_value(qa_db_query_sub( return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(DISTINCT(userid)) FROM ^'.$table 'SELECT COUNT(DISTINCT(userid)) FROM ^' . $table
)); ));
} }
function qa_db_count_categories() /**
/* * Return number of categories in the database
Return number of categories in the database */
*/ function qa_db_count_categories()
{ {
return qa_db_read_one_value(qa_db_query_sub( return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^categories' '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 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( return qa_db_read_one_value(qa_db_query_sub(
"SELECT COUNT(*) FROM ^posts WHERE categoryid<=># AND type='Q'", "SELECT COUNT(*) FROM ^posts WHERE categoryid<=># AND type='Q'",
$categoryid $categoryid
)); ));
} }
function qa_db_get_user_visible_postids($userid) /**
/* * Return list of postids of visible or queued posts by $userid
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( 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')", "SELECT postid FROM ^posts WHERE userid=# AND type IN ('Q', 'A', 'C', 'Q_QUEUED', 'A_QUEUED', 'C_QUEUED')",
$userid $userid
)); ));
} }
function qa_db_get_ip_visible_postids($ip) /**
/* * Return list of postids of visible or queued posts from $ip address
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( 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')", "SELECT postid FROM ^posts WHERE createip=$ AND type IN ('Q', 'A', 'C', 'Q_QUEUED', 'A_QUEUED', 'C_QUEUED')",
@inet_pton($ip) @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
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)) if (count($postids))
return qa_db_read_all_assoc(qa_db_query_sub( 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 (#)", "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 (#)",
...@@ -177,234 +190,270 @@ ...@@ -177,234 +190,270 @@
), 'postid', 'count'); ), 'postid', 'count');
else else
return array(); return array();
} }
function qa_db_get_unapproved_users($count) /**
/* * Return an array of the (up to) $count most recently created users who are awaiting approval and have not been blocked.
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.
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
{ */
$results=qa_db_read_all_assoc(qa_db_query_sub( 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 #", "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 QA_USER_LEVEL_APPROVED, QA_USER_FLAGS_USER_BLOCKED, $count
)); ));
$users=array(); $users = array();
foreach ($results as $result) { foreach ($results as $result) {
$userid=$result['userid']; $userid = $result['userid'];
if (!isset($users[$userid])) { if (!isset($users[$userid])) {
$users[$result['userid']]=$result; $users[$result['userid']] = $result;
$users[$result['userid']]['profile']=array(); $users[$result['userid']]['profile'] = array();
unset($users[$userid]['title']); unset($users[$userid]['title']);
unset($users[$userid]['content']); unset($users[$userid]['content']);
} }
if (isset($result['title']) && isset($result['content'])) if (isset($result['title']) && isset($result['content']))
$users[$userid]['profile'][$result['title']]=$result['content']; $users[$userid]['profile'][$result['title']] = $result['content'];
} }
return $users; 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 whether there are any blobs whose content has been stored as a file on disk */
*/ function qa_db_has_blobs_on_disk()
{ {
return qa_db_read_one_value(qa_db_query_sub('SELECT blobid FROM ^blobs WHERE content IS NULL LIMIT 1'), true) != null; 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 whether there are any blobs whose content has been stored in the database */
*/ function qa_db_has_blobs_in_db()
{ {
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 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 the maximum position of the categories with $parentid * @param $parentid
*/ * @return mixed|null
{ */
function qa_db_category_last_pos($parentid)
{
return qa_db_read_one_value(qa_db_query_sub( return qa_db_read_one_value(qa_db_query_sub(
'SELECT COALESCE(MAX(position), 0) FROM ^categories WHERE parentid<=>#', 'SELECT COALESCE(MAX(position), 0) FROM ^categories WHERE parentid<=>#',
$parentid $parentid
)); ));
} }
function qa_db_category_child_depth($categoryid) /**
/* * Return how many levels of subcategory there are below $categoryid
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 // 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 // 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.) // (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( $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 '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 $categoryid
)); ));
for ($depth=QA_CATEGORY_DEPTH-1; $depth>=1; $depth--) for ($depth = QA_CATEGORY_DEPTH - 1; $depth >= 1; $depth--)
if ($result['count'.$depth]) if ($result['count' . $depth])
return $depth; return $depth;
return 0; return 0;
} }
function qa_db_category_create($parentid, $title, $tags) /**
/* * Create a new category with $parentid, $title (=name) and $tags (=slug) in the database
Create a new category with $parentid, $title (=name) and $tags (=slug) in the database * @param $parentid
*/ * @param $title
{ * @param $tags
$lastpos=qa_db_category_last_pos($parentid); * @return mixed
*/
function qa_db_category_create($parentid, $title, $tags)
{
$lastpos = qa_db_category_last_pos($parentid);
qa_db_query_sub( qa_db_query_sub(
'INSERT INTO ^categories (parentid, title, tags, position) VALUES (#, $, $, #)', 'INSERT INTO ^categories (parentid, title, tags, position) VALUES (#, $, $, #)',
$parentid, $title, $tags, 1+$lastpos $parentid, $title, $tags, 1 + $lastpos
); );
$categoryid=qa_db_last_insert_id(); $categoryid = qa_db_last_insert_id();
qa_db_categories_recalc_backpaths($categoryid); qa_db_categories_recalc_backpaths($categoryid);
return $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)
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)) if (!isset($lastcategoryid))
$lastcategoryid=$firstcategoryid; $lastcategoryid = $firstcategoryid;
qa_db_query_sub( 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", "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 $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
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( qa_db_query_sub(
'UPDATE ^categories SET title=$, tags=$ WHERE categoryid=#', 'UPDATE ^categories SET title=$, tags=$ WHERE categoryid=#',
$title, $tags, $categoryid $title, $tags, $categoryid
); );
qa_db_categories_recalc_backpaths($categoryid); // may also require recalculation of its offspring's backpaths 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
Set the content (=description) of $categoryid to $content * @param $categoryid
*/ * @param $content
{ */
function qa_db_category_set_content($categoryid, $content)
{
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^categories SET content=$ WHERE categoryid=#', 'UPDATE ^categories SET content=$ WHERE categoryid=#',
$content, $categoryid $content, $categoryid
); );
} }
function qa_db_category_get_parent($categoryid) /**
/* * Return the parentid of $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( return qa_db_read_one_value(qa_db_query_sub(
'SELECT parentid FROM ^categories WHERE categoryid=#', 'SELECT parentid FROM ^categories WHERE categoryid=#',
$categoryid $categoryid
)); ));
} }
function qa_db_category_set_position($categoryid, $newposition) /**
/* * Move the category $categoryid into position $newposition under its parent
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_ordered_move('categories', 'categoryid', $categoryid, $newposition,
qa_db_apply_sub('parentid<=>#', array(qa_db_category_get_parent($categoryid)))); 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)
Set the parent of $categoryid to $newparentid, placing it in last position (doesn't do necessary recalculations) * @param $categoryid
*/ * @param $newparentid
{ */
$oldparentid=qa_db_category_get_parent($categoryid); 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 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); $lastpos = qa_db_category_last_pos($oldparentid);
qa_db_ordered_move('categories', 'categoryid', $categoryid, $lastpos, qa_db_apply_sub('parentid<=>#', array($oldparentid))); qa_db_ordered_move('categories', 'categoryid', $categoryid, $lastpos, qa_db_apply_sub('parentid<=>#', array($oldparentid)));
$lastpos=qa_db_category_last_pos($newparentid); $lastpos = qa_db_category_last_pos($newparentid);
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^categories SET parentid=#, position=# WHERE categoryid=#', 'UPDATE ^categories SET parentid=#, position=# WHERE categoryid=#',
$newparentid, 1+$lastpos, $categoryid $newparentid, 1 + $lastpos, $categoryid
); );
} }
} }
function qa_db_category_reassign($categoryid, $reassignid) /**
/* * Change the categoryid of any posts with (exact) $categoryid to $reassignid
Change the categoryid of any posts with (exact) $categoryid to $reassignid * @param $categoryid
*/ * @param $reassignid
{ */
function qa_db_category_reassign($categoryid, $reassignid)
{
qa_db_query_sub('UPDATE ^posts SET categoryid=# WHERE categoryid<=>#', $reassignid, $categoryid); qa_db_query_sub('UPDATE ^posts SET categoryid=# WHERE categoryid<=>#', $reassignid, $categoryid);
} }
function qa_db_category_delete($categoryid) /**
/* * Delete the category $categoryid in the database
Delete the category $categoryid in the database * @param $categoryid
*/ */
{ function qa_db_category_delete($categoryid)
{
qa_db_ordered_delete('categories', 'categoryid', $categoryid, qa_db_ordered_delete('categories', 'categoryid', $categoryid,
qa_db_apply_sub('parentid<=>#', array(qa_db_category_get_parent($categoryid)))); qa_db_apply_sub('parentid<=>#', array(qa_db_category_get_parent($categoryid))));
} }
function qa_db_category_slug_to_id($parentid, $slug) /**
/* * Return the categoryid for the category with parent $parentid and $slug
Return the categoryid for the category with parent $parentid and $slug * @param $parentid
*/ * @param $slug
{ * @return mixed|null
*/
function qa_db_category_slug_to_id($parentid, $slug)
{
return qa_db_read_one_value(qa_db_query_sub( return qa_db_read_one_value(qa_db_query_sub(
'SELECT categoryid FROM ^categories WHERE parentid<=># AND tags=$', 'SELECT categoryid FROM ^categories WHERE parentid<=># AND tags=$',
$parentid, $slug $parentid, $slug
), true); ), true);
} }
function qa_db_page_create($title, $flags, $tags, $heading, $content, $permit=null) /**
/* * Create a new custom page (or link) in the database
Create a new custom page (or link) in the database * @param $title
*/ * @param $flags
{ * @param $tags
$position=qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^pages')); * @param $heading
* @param $content
* @param $permit
* @return mixed
*/
function qa_db_page_create($title, $flags, $tags, $heading, $content, $permit = null)
{
$position = qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^pages'));
qa_db_query_sub( qa_db_query_sub(
'INSERT INTO ^pages (title, nav, flags, permit, tags, heading, content, position) VALUES ($, \'\', #, #, $, $, $, #)', 'INSERT INTO ^pages (title, nav, flags, permit, tags, heading, content, position) VALUES ($, \'\', #, #, $, $, $, #)',
...@@ -412,100 +461,125 @@ ...@@ -412,100 +461,125 @@
); );
return qa_db_last_insert_id(); 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
Set the fields of $pageid to the values provided in the database * @param $pageid
*/ * @param $title
{ * @param $flags
* @param $tags
* @param $heading
* @param $content
* @param $permit
*/
function qa_db_page_set_fields($pageid, $title, $flags, $tags, $heading, $content, $permit = null)
{
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^pages SET title=$, flags=#, permit=#, tags=$, heading=$, content=$ WHERE pageid=#', 'UPDATE ^pages SET title=$, flags=#, permit=#, tags=$, heading=$, content=$ WHERE pageid=#',
$title, $flags, $permit, $tags, $heading, $content, $pageid $title, $flags, $permit, $tags, $heading, $content, $pageid
); );
} }
function qa_db_page_move($pageid, $nav, $newposition) /**
/* * Move the page $pageid into navigation menu $nav and position $newposition in the database
Move the page $pageid into navigation menu $nav and position $newposition in the database * @param $pageid
*/ * @param $nav
{ * @param $newposition
*/
function qa_db_page_move($pageid, $nav, $newposition)
{
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^pages SET nav=$ WHERE pageid=#', 'UPDATE ^pages SET nav=$ WHERE pageid=#',
$nav, $pageid $nav, $pageid
); );
qa_db_ordered_move('pages', 'pageid', $pageid, $newposition); qa_db_ordered_move('pages', 'pageid', $pageid, $newposition);
} }
function qa_db_page_delete($pageid) /**
/* * Delete the page $pageid in the database
Delete the page $pageid in the database * @param $pageid
*/ */
{ function qa_db_page_delete($pageid)
{
qa_db_ordered_delete('pages', 'pageid', $pageid); qa_db_ordered_delete('pages', 'pageid', $pageid);
} }
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
Move the entity identified by $idcolumn=$id into position $newposition (within optional $conditionsql) in $table in the database * @param $table
*/ * @param $idcolumn
{ * @param $id
$andsql=isset($conditionsql) ? (' AND '.$conditionsql) : ''; * @param $newposition
* @param $conditionsql
*/
function qa_db_ordered_move($table, $idcolumn, $id, $newposition, $conditionsql = null)
{
$andsql = isset($conditionsql) ? (' AND ' . $conditionsql) : '';
qa_db_query_sub('LOCK TABLES ^'.$table.' WRITE'); 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)); $oldposition = qa_db_read_one_value(qa_db_query_sub('SELECT position FROM ^' . $table . ' WHERE ' . $idcolumn . '=#' . $andsql, $id));
if ($newposition!=$oldposition) { if ($newposition != $oldposition) {
$lastposition=qa_db_read_one_value(qa_db_query_sub('SELECT MAX(position) FROM ^'.$table.' WHERE TRUE'.$andsql)); $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 $newposition = max(1, min($newposition, $lastposition)); // constrain it to within range
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 // 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);
if ($newposition<$oldposition) if ($newposition < $oldposition)
qa_db_query_sub('UPDATE ^'.$table.' SET position=position+1 WHERE position BETWEEN # AND #'.$andsql.' ORDER BY position DESC', $newposition, $oldposition); qa_db_query_sub('UPDATE ^' . $table . ' SET position=position+1 WHERE position BETWEEN # AND #' . $andsql . ' ORDER BY position DESC', $newposition, $oldposition);
else else
qa_db_query_sub('UPDATE ^'.$table.' SET position=position-1 WHERE position BETWEEN # AND #'.$andsql.' ORDER BY position', $oldposition, $newposition); qa_db_query_sub('UPDATE ^' . $table . ' SET position=position-1 WHERE position BETWEEN # AND #' . $andsql . ' ORDER BY position', $oldposition, $newposition);
qa_db_query_sub('UPDATE ^'.$table.' SET position=# WHERE '.$idcolumn.'=#'.$andsql, $newposition, $id); qa_db_query_sub('UPDATE ^' . $table . ' SET position=# WHERE ' . $idcolumn . '=#' . $andsql, $newposition, $id);
} }
qa_db_query_sub('UNLOCK TABLES'); qa_db_query_sub('UNLOCK TABLES');
} }
function qa_db_ordered_delete($table, $idcolumn, $id, $conditionsql=null) /**
/* * Delete the entity identified by $idcolumn=$id (and optional $conditionsql) in $table in the database
Delete the entity identified by $idcolumn=$id (and optional $conditionsql) in $table in the database * @param $table
*/ * @param $idcolumn
{ * @param $id
$andsql=isset($conditionsql) ? (' AND '.$conditionsql) : ''; * @param $conditionsql
*/
function qa_db_ordered_delete($table, $idcolumn, $id, $conditionsql = null)
{
$andsql = isset($conditionsql) ? (' AND ' . $conditionsql) : '';
qa_db_query_sub('LOCK TABLES ^'.$table.' WRITE'); 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)); $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); 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('UPDATE ^' . $table . ' SET position=position-1 WHERE position>#' . $andsql . ' ORDER BY position', $oldposition);
qa_db_query_sub('UNLOCK TABLES'); qa_db_query_sub('UNLOCK TABLES');
} }
function qa_db_userfield_create($title, $content, $flags, $permit=null) /**
/* * Create a new user field with (internal) tag $title, label $content, $flags and $permit in the database.
Create a new user field with (internal) tag $title, label $content, $flags and $permit in the database. * @param $title
*/ * @param $content
{ * @param $flags
$position=qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^userfields')); * @param $permit
* @return mixed
*/
function qa_db_userfield_create($title, $content, $flags, $permit = null)
{
$position = qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^userfields'));
qa_db_query_sub( qa_db_query_sub(
'INSERT INTO ^userfields (title, content, position, flags, permit) VALUES ($, $, #, #, #)', 'INSERT INTO ^userfields (title, content, position, flags, permit) VALUES ($, $, #, #, #)',
...@@ -513,45 +587,55 @@ ...@@ -513,45 +587,55 @@
); );
return qa_db_last_insert_id(); return qa_db_last_insert_id();
} }
function qa_db_userfield_set_fields($fieldid, $content, $flags, $permit=null) /**
/* * Change the user field $fieldid to have label $content, $flags and $permit in the database (the title column cannot be changed once set)
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( qa_db_query_sub(
'UPDATE ^userfields SET content=$, flags=#, permit=# WHERE fieldid=#', 'UPDATE ^userfields SET content=$, flags=#, permit=# WHERE fieldid=#',
$content, $flags, $permit, $fieldid $content, $flags, $permit, $fieldid
); );
} }
function qa_db_userfield_move($fieldid, $newposition) /**
/* * Move the user field $fieldid into position $newposition in the database
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); qa_db_ordered_move('userfields', 'fieldid', $fieldid, $newposition);
} }
function qa_db_userfield_delete($fieldid) /**
/* * Delete the user field $fieldid in the database
Delete the user field $fieldid in the database * @param $fieldid
*/ */
{ function qa_db_userfield_delete($fieldid)
{
qa_db_ordered_delete('userfields', 'fieldid', $fieldid); qa_db_ordered_delete('userfields', 'fieldid', $fieldid);
} }
function qa_db_widget_create($title, $tags) /**
/* * Return the ID of a new widget, to be displayed by the widget module named $title on templates within $tags (comma-separated list)
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
$position=qa_db_read_one_value(qa_db_query_sub('SELECT 1+COALESCE(MAX(position), 0) FROM ^widgets')); */
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( qa_db_query_sub(
'INSERT INTO ^widgets (place, position, tags, title) VALUES (\'\', #, $, $)', 'INSERT INTO ^widgets (place, position, tags, title) VALUES (\'\', #, $, $)',
...@@ -559,44 +643,45 @@ ...@@ -559,44 +643,45 @@
); );
return qa_db_last_insert_id(); return qa_db_last_insert_id();
} }
function qa_db_widget_set_fields($widgetid, $tags) /**
/* * Set the comma-separated list of templates for $widgetid to $tags
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( qa_db_query_sub(
'UPDATE ^widgets SET tags=$ WHERE widgetid=#', 'UPDATE ^widgets SET tags=$ WHERE widgetid=#',
$tags, $widgetid $tags, $widgetid
); );
} }
function qa_db_widget_move($widgetid, $place, $newposition) /**
/* * Move the widget $widgetit into position $position in the database's order, and show it in $place on the page
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( qa_db_query_sub(
'UPDATE ^widgets SET place=$ WHERE widgetid=#', 'UPDATE ^widgets SET place=$ WHERE widgetid=#',
$place, $widgetid $place, $widgetid
); );
qa_db_ordered_move('widgets', 'widgetid', $widgetid, $newposition); qa_db_ordered_move('widgets', 'widgetid', $widgetid, $newposition);
} }
function qa_db_widget_delete($widgetid) /**
/* * Delete the widget $widgetid in the database
Delete the widget $widgetid in the database * @param $widgetid
*/ */
{ function qa_db_widget_delete($widgetid)
{
qa_db_ordered_delete('widgets', 'widgetid', $widgetid); qa_db_ordered_delete('widgets', 'widgetid', $widgetid);
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
...@@ -20,20 +20,20 @@ ...@@ -20,20 +20,20 @@
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;
} }
define('QA_DB_VERSION_CURRENT', 64); define('QA_DB_VERSION_CURRENT', 64);
function qa_db_user_column_type_verify() /**
/* * Return the column type for user ids after verifying it is one of the legal options
Return the column type for user ids after verifying it is one of the legal options */
*/ function qa_db_user_column_type_verify()
{ {
$coltype=strtoupper(qa_get_mysql_user_column_type()); $coltype = strtoupper(qa_get_mysql_user_column_type());
switch ($coltype) { switch ($coltype) {
case 'SMALLINT': case 'SMALLINT':
...@@ -54,19 +54,19 @@ ...@@ -54,19 +54,19 @@
} }
return $coltype; return $coltype;
} }
function qa_db_table_definitions() /**
/* * Return an array of table definitions. For each element of the array, the key is the table name (without prefix)
Return an array of table definitions. For each element of the array, the key is the table name (without prefix) * and the value is an array of column definitions, [column name] => [definition]. The column name is omitted for indexes.
and the value is an array of column definitions, [column name] => [definition]. The column name is omitted for indexes. */
*/ function qa_db_table_definitions()
{ {
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); } if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
require_once QA_INCLUDE_DIR.'db/maxima.php'; require_once QA_INCLUDE_DIR . 'db/maxima.php';
require_once QA_INCLUDE_DIR.'app/users.php'; require_once QA_INCLUDE_DIR . 'app/users.php';
/* /*
Important note on character encoding in database and PHP connection to MySQL Important note on character encoding in database and PHP connection to MySQL
...@@ -94,15 +94,15 @@ ...@@ -94,15 +94,15 @@
queries together via a UNION in qa_db_multi_select() - see comments in qa-db.php for more information. queries together via a UNION in qa_db_multi_select() - see comments in qa-db.php for more information.
*/ */
$useridcoltype=qa_db_user_column_type_verify(); $useridcoltype = qa_db_user_column_type_verify();
$tables=array( $tables = array(
'users' => array( 'users' => array(
'userid' => $useridcoltype.' NOT NULL AUTO_INCREMENT', 'userid' => $useridcoltype . ' NOT NULL AUTO_INCREMENT',
'created' => 'DATETIME NOT NULL', 'created' => 'DATETIME NOT NULL',
'createip' => 'VARBINARY(16) NOT NULL', // INET_ATON of IP address when created 'createip' => 'VARBINARY(16) NOT NULL', // INET_ATON of IP address when created
'email' => 'VARCHAR('.QA_DB_MAX_EMAIL_LENGTH.') NOT NULL', 'email' => 'VARCHAR(' . QA_DB_MAX_EMAIL_LENGTH . ') NOT NULL',
'handle' => 'VARCHAR('.QA_DB_MAX_HANDLE_LENGTH.') NOT NULL', // username 'handle' => 'VARCHAR(' . QA_DB_MAX_HANDLE_LENGTH . ') NOT NULL', // username
'avatarblobid' => 'BIGINT UNSIGNED', // blobid of stored avatar 'avatarblobid' => 'BIGINT UNSIGNED', // blobid of stored avatar
'avatarwidth' => 'SMALLINT UNSIGNED', // pixel width of stored avatar 'avatarwidth' => 'SMALLINT UNSIGNED', // pixel width of stored avatar
'avatarheight' => 'SMALLINT UNSIGNED', // pixel height of stored avatar 'avatarheight' => 'SMALLINT UNSIGNED', // pixel height of stored avatar
...@@ -127,7 +127,7 @@ ...@@ -127,7 +127,7 @@
), ),
'userlogins' => array( 'userlogins' => array(
'userid' => $useridcoltype.' NOT NULL', 'userid' => $useridcoltype . ' NOT NULL',
'source' => 'VARCHAR (16) CHARACTER SET ascii NOT NULL', // e.g. facebook, openid, etc... 'source' => 'VARCHAR (16) CHARACTER SET ascii NOT NULL', // e.g. facebook, openid, etc...
'identifier' => 'VARBINARY (1024) NOT NULL', // depends on source, e.g. Facebook uid or OpenID url 'identifier' => 'VARBINARY (1024) NOT NULL', // depends on source, e.g. Facebook uid or OpenID url
'identifiermd5' => 'BINARY (16) NOT NULL', // used to reduce size of index on identifier 'identifiermd5' => 'BINARY (16) NOT NULL', // used to reduce size of index on identifier
...@@ -136,7 +136,7 @@ ...@@ -136,7 +136,7 @@
), ),
'userlevels' => array( 'userlevels' => array(
'userid' => $useridcoltype.' NOT NULL', // the user who has this level 'userid' => $useridcoltype . ' NOT NULL', // the user who has this level
'entitytype' => 'CHAR(1) CHARACTER SET ascii NOT NULL', // see qa-app-updates.php 'entitytype' => 'CHAR(1) CHARACTER SET ascii NOT NULL', // see qa-app-updates.php
'entityid' => 'INT UNSIGNED NOT NULL', // relevant postid / userid / tag wordid / categoryid 'entityid' => 'INT UNSIGNED NOT NULL', // relevant postid / userid / tag wordid / categoryid
'level' => 'TINYINT UNSIGNED', // if not NULL, special permission level for that user and that entity 'level' => 'TINYINT UNSIGNED', // if not NULL, special permission level for that user and that entity
...@@ -145,16 +145,16 @@ ...@@ -145,16 +145,16 @@
), ),
'userprofile' => array( 'userprofile' => array(
'userid' => $useridcoltype.' NOT NULL', 'userid' => $useridcoltype . ' NOT NULL',
'title' => 'VARCHAR('.QA_DB_MAX_PROFILE_TITLE_LENGTH.') NOT NULL', // profile field name 'title' => 'VARCHAR(' . QA_DB_MAX_PROFILE_TITLE_LENGTH . ') NOT NULL', // profile field name
'content' => 'VARCHAR('.QA_DB_MAX_PROFILE_CONTENT_LENGTH.') NOT NULL', // profile field value 'content' => 'VARCHAR(' . QA_DB_MAX_PROFILE_CONTENT_LENGTH . ') NOT NULL', // profile field value
'UNIQUE userid (userid,title)', 'UNIQUE userid (userid,title)',
), ),
'userfields' => array( 'userfields' => array(
'fieldid' => 'SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT', 'fieldid' => 'SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT',
'title' => 'VARCHAR('.QA_DB_MAX_PROFILE_TITLE_LENGTH.') NOT NULL', // to match title column in userprofile table 'title' => 'VARCHAR(' . QA_DB_MAX_PROFILE_TITLE_LENGTH . ') NOT NULL', // to match title column in userprofile table
'content' => 'VARCHAR('.QA_DB_MAX_PROFILE_TITLE_LENGTH.')', // label for display on user profile pages - NULL means use default 'content' => 'VARCHAR(' . QA_DB_MAX_PROFILE_TITLE_LENGTH . ')', // label for display on user profile pages - NULL means use default
'position' => 'SMALLINT UNSIGNED NOT NULL', 'position' => 'SMALLINT UNSIGNED NOT NULL',
'flags' => 'TINYINT UNSIGNED NOT NULL', // QA_FIELD_FLAGS_* at top of qa-app-users.php 'flags' => 'TINYINT UNSIGNED NOT NULL', // QA_FIELD_FLAGS_* at top of qa-app-users.php
'permit' => 'TINYINT UNSIGNED', // minimum user level required to view (uses QA_PERMIT_* constants), null means no restriction 'permit' => 'TINYINT UNSIGNED', // minimum user level required to view (uses QA_PERMIT_* constants), null means no restriction
...@@ -164,12 +164,12 @@ ...@@ -164,12 +164,12 @@
'messages' => array( 'messages' => array(
'messageid' => 'INT UNSIGNED NOT NULL AUTO_INCREMENT', 'messageid' => 'INT UNSIGNED NOT NULL AUTO_INCREMENT',
'type' => "ENUM('PUBLIC', 'PRIVATE') NOT NULL DEFAULT 'PRIVATE'", 'type' => "ENUM('PUBLIC', 'PRIVATE') NOT NULL DEFAULT 'PRIVATE'",
'fromuserid' => $useridcoltype.' NOT NULL', 'fromuserid' => $useridcoltype . ' NOT NULL',
'touserid' => $useridcoltype.' NOT NULL', 'touserid' => $useridcoltype . ' NOT NULL',
'fromhidden' => 'TINYINT(1) UNSIGNED NOT NULL DEFAULT 0', 'fromhidden' => 'TINYINT(1) UNSIGNED NOT NULL DEFAULT 0',
'tohidden' => 'TINYINT(1) UNSIGNED NOT NULL DEFAULT 0', 'tohidden' => 'TINYINT(1) UNSIGNED NOT NULL DEFAULT 0',
'content' => 'VARCHAR('.QA_DB_MAX_CONTENT_LENGTH.') NOT NULL', 'content' => 'VARCHAR(' . QA_DB_MAX_CONTENT_LENGTH . ') NOT NULL',
'format' => 'VARCHAR('.QA_DB_MAX_FORMAT_LENGTH.') CHARACTER SET ascii NOT NULL', 'format' => 'VARCHAR(' . QA_DB_MAX_FORMAT_LENGTH . ') CHARACTER SET ascii NOT NULL',
'created' => 'DATETIME NOT NULL', 'created' => 'DATETIME NOT NULL',
'PRIMARY KEY (messageid)', 'PRIMARY KEY (messageid)',
'KEY type (type, fromuserid, touserid, created)', 'KEY type (type, fromuserid, touserid, created)',
...@@ -179,7 +179,7 @@ ...@@ -179,7 +179,7 @@
), ),
'userfavorites' => array( 'userfavorites' => array(
'userid' => $useridcoltype.' NOT NULL', // the user who favorited the entity 'userid' => $useridcoltype . ' NOT NULL', // the user who favorited the entity
'entitytype' => 'CHAR(1) CHARACTER SET ascii NOT NULL', // see qa-app-updates.php 'entitytype' => 'CHAR(1) CHARACTER SET ascii NOT NULL', // see qa-app-updates.php
'entityid' => 'INT UNSIGNED NOT NULL', // favorited postid / userid / tag wordid / categoryid 'entityid' => 'INT UNSIGNED NOT NULL', // favorited postid / userid / tag wordid / categoryid
'nouserevents' => 'TINYINT UNSIGNED NOT NULL', // do we skip writing events to the user stream? 'nouserevents' => 'TINYINT UNSIGNED NOT NULL', // do we skip writing events to the user stream?
...@@ -190,17 +190,17 @@ ...@@ -190,17 +190,17 @@
'usernotices' => array( 'usernotices' => array(
'noticeid' => 'INT UNSIGNED NOT NULL AUTO_INCREMENT', 'noticeid' => 'INT UNSIGNED NOT NULL AUTO_INCREMENT',
'userid' => $useridcoltype.' NOT NULL', // the user to whom the notice is directed 'userid' => $useridcoltype . ' NOT NULL', // the user to whom the notice is directed
'content' => 'VARCHAR('.QA_DB_MAX_CONTENT_LENGTH.') NOT NULL', 'content' => 'VARCHAR(' . QA_DB_MAX_CONTENT_LENGTH . ') NOT NULL',
'format' => 'VARCHAR('.QA_DB_MAX_FORMAT_LENGTH.') CHARACTER SET ascii NOT NULL', 'format' => 'VARCHAR(' . QA_DB_MAX_FORMAT_LENGTH . ') CHARACTER SET ascii NOT NULL',
'tags' => 'VARCHAR('.QA_DB_MAX_CAT_PAGE_TAGS_LENGTH.')', // any additional information for a plugin to access 'tags' => 'VARCHAR(' . QA_DB_MAX_CAT_PAGE_TAGS_LENGTH . ')', // any additional information for a plugin to access
'created' => 'DATETIME NOT NULL', 'created' => 'DATETIME NOT NULL',
'PRIMARY KEY (noticeid)', 'PRIMARY KEY (noticeid)',
'KEY userid (userid, created)', 'KEY userid (userid, created)',
), ),
'userevents' => array( 'userevents' => array(
'userid' => $useridcoltype.' NOT NULL', // the user to be informed about this event in their updates 'userid' => $useridcoltype . ' NOT NULL', // the user to be informed about this event in their updates
'entitytype' => 'CHAR(1) CHARACTER SET ascii NOT NULL', // see qa-app-updates.php 'entitytype' => 'CHAR(1) CHARACTER SET ascii NOT NULL', // see qa-app-updates.php
'entityid' => 'INT UNSIGNED NOT NULL', // favorited source of event - see userfavorites table - 0 means not from a favorite 'entityid' => 'INT UNSIGNED NOT NULL', // favorited source of event - see userfavorites table - 0 means not from a favorite
'questionid' => 'INT UNSIGNED NOT NULL', // the affected question 'questionid' => 'INT UNSIGNED NOT NULL', // the affected question
...@@ -236,28 +236,28 @@ ...@@ -236,28 +236,28 @@
'categories' => array( 'categories' => array(
'categoryid' => 'INT UNSIGNED NOT NULL AUTO_INCREMENT', 'categoryid' => 'INT UNSIGNED NOT NULL AUTO_INCREMENT',
'parentid' => 'INT UNSIGNED', 'parentid' => 'INT UNSIGNED',
'title' => 'VARCHAR('.QA_DB_MAX_CAT_PAGE_TITLE_LENGTH.') NOT NULL', // category name 'title' => 'VARCHAR(' . QA_DB_MAX_CAT_PAGE_TITLE_LENGTH . ') NOT NULL', // category name
'tags' => 'VARCHAR('.QA_DB_MAX_CAT_PAGE_TAGS_LENGTH.') NOT NULL', // slug (url fragment) used to identify category 'tags' => 'VARCHAR(' . QA_DB_MAX_CAT_PAGE_TAGS_LENGTH . ') NOT NULL', // slug (url fragment) used to identify category
'content' => 'VARCHAR('.QA_DB_MAX_CAT_CONTENT_LENGTH.') NOT NULL DEFAULT \'\'', // description of category 'content' => 'VARCHAR(' . QA_DB_MAX_CAT_CONTENT_LENGTH . ') NOT NULL DEFAULT \'\'', // description of category
'qcount' => 'INT UNSIGNED NOT NULL DEFAULT 0', 'qcount' => 'INT UNSIGNED NOT NULL DEFAULT 0',
'position' => 'SMALLINT UNSIGNED NOT NULL', 'position' => 'SMALLINT UNSIGNED NOT NULL',
'backpath' => 'VARCHAR('.(QA_CATEGORY_DEPTH*(QA_DB_MAX_CAT_PAGE_TAGS_LENGTH+1)).') NOT NULL DEFAULT \'\'',
// full slug path for category, with forward slash separators, in reverse order to make index from effective // full slug path for category, with forward slash separators, in reverse order to make index from effective
'backpath' => 'VARCHAR(' . (QA_CATEGORY_DEPTH * (QA_DB_MAX_CAT_PAGE_TAGS_LENGTH + 1)) . ') NOT NULL DEFAULT \'\'',
'PRIMARY KEY (categoryid)', 'PRIMARY KEY (categoryid)',
'UNIQUE parentid (parentid, tags)', 'UNIQUE parentid (parentid, tags)',
'UNIQUE parentid_2 (parentid, position)', 'UNIQUE parentid_2 (parentid, position)',
'KEY backpath (backpath('.QA_DB_MAX_CAT_PAGE_TAGS_LENGTH.'))', 'KEY backpath (backpath(' . QA_DB_MAX_CAT_PAGE_TAGS_LENGTH . '))',
), ),
'pages' => array( 'pages' => array(
'pageid' => 'SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT', 'pageid' => 'SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT',
'title' => 'VARCHAR('.QA_DB_MAX_CAT_PAGE_TITLE_LENGTH.') NOT NULL', // title for navigation 'title' => 'VARCHAR(' . QA_DB_MAX_CAT_PAGE_TITLE_LENGTH . ') NOT NULL', // title for navigation
'nav' => 'CHAR(1) CHARACTER SET ascii NOT NULL', // which navigation does it go in (M=main, F=footer, B=before main, O=opposite main, other=none) 'nav' => 'CHAR(1) CHARACTER SET ascii NOT NULL', // which navigation does it go in (M=main, F=footer, B=before main, O=opposite main, other=none)
'position' => 'SMALLINT UNSIGNED NOT NULL', // global ordering, which allows links to be ordered within each nav area 'position' => 'SMALLINT UNSIGNED NOT NULL', // global ordering, which allows links to be ordered within each nav area
'flags' => 'TINYINT UNSIGNED NOT NULL', // local or external, open in new window? 'flags' => 'TINYINT UNSIGNED NOT NULL', // local or external, open in new window?
'permit' => 'TINYINT UNSIGNED', // is there a minimum user level required for it (uses QA_PERMIT_* constants), null means no restriction 'permit' => 'TINYINT UNSIGNED', // is there a minimum user level required for it (uses QA_PERMIT_* constants), null means no restriction
'tags' => 'VARCHAR('.QA_DB_MAX_CAT_PAGE_TAGS_LENGTH.') NOT NULL', // slug (url fragment) for page, or url for external pages 'tags' => 'VARCHAR(' . QA_DB_MAX_CAT_PAGE_TAGS_LENGTH . ') NOT NULL', // slug (url fragment) for page, or url for external pages
'heading' => 'VARCHAR('.QA_DB_MAX_TITLE_LENGTH.')', // for display within <h1> tags 'heading' => 'VARCHAR(' . QA_DB_MAX_TITLE_LENGTH . ')', // for display within <h1> tags
'content' => 'MEDIUMTEXT', // remainder of page HTML 'content' => 'MEDIUMTEXT', // remainder of page HTML
'PRIMARY KEY (pageid)', 'PRIMARY KEY (pageid)',
'KEY tags (tags)', 'KEY tags (tags)',
...@@ -266,13 +266,13 @@ ...@@ -266,13 +266,13 @@
'widgets' => array( 'widgets' => array(
'widgetid' => 'SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT', 'widgetid' => 'SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT',
'place' => 'CHAR(2) CHARACTER SET ascii NOT NULL',
// full region: FT=very top of page, FH=below nav area, FL=above footer, FB = very bottom of page // full region: FT=very top of page, FH=below nav area, FL=above footer, FB = very bottom of page
// side region: ST=top of side, SH=below sidebar, SL=below categories, SB=very bottom of side // side region: ST=top of side, SH=below sidebar, SL=below categories, SB=very bottom of side
// main region: MT=top of main, MH=below page title, ML=above links, MB=very bottom of main region // main region: MT=top of main, MH=below page title, ML=above links, MB=very bottom of main region
'place' => 'CHAR(2) CHARACTER SET ascii NOT NULL',
'position' => 'SMALLINT UNSIGNED NOT NULL', // global ordering, which allows widgets to be ordered within each place 'position' => 'SMALLINT UNSIGNED NOT NULL', // global ordering, which allows widgets to be ordered within each place
'tags' => 'VARCHAR('.QA_DB_MAX_WIDGET_TAGS_LENGTH.') CHARACTER SET ascii NOT NULL', // comma-separated list of templates to display on 'tags' => 'VARCHAR(' . QA_DB_MAX_WIDGET_TAGS_LENGTH . ') CHARACTER SET ascii NOT NULL', // comma-separated list of templates to display on
'title' => 'VARCHAR('.QA_DB_MAX_WIDGET_TITLE_LENGTH.') NOT NULL', // name of widget module that should be displayed 'title' => 'VARCHAR(' . QA_DB_MAX_WIDGET_TITLE_LENGTH . ') NOT NULL', // name of widget module that should be displayed
'PRIMARY KEY (widgetid)', 'PRIMARY KEY (widgetid)',
'UNIQUE position (position)', 'UNIQUE position (position)',
), ),
...@@ -288,9 +288,9 @@ ...@@ -288,9 +288,9 @@
'acount' => 'SMALLINT UNSIGNED NOT NULL DEFAULT 0', // number of answers (for questions) 'acount' => 'SMALLINT UNSIGNED NOT NULL DEFAULT 0', // number of answers (for questions)
'amaxvote' => 'SMALLINT UNSIGNED NOT NULL DEFAULT 0', // highest netvotes of child answers (for questions) 'amaxvote' => 'SMALLINT UNSIGNED NOT NULL DEFAULT 0', // highest netvotes of child answers (for questions)
'selchildid' => 'INT UNSIGNED', // selected answer (for questions) 'selchildid' => 'INT UNSIGNED', // selected answer (for questions)
'closedbyid' => 'INT UNSIGNED', // not null means question is closed
// if closed due to being a duplicate, this is the postid of that other question // if closed due to being a duplicate, this is the postid of that other question
// if closed for another reason, that reason should be added as a comment on the question, and this field is the comment's id // if closed for another reason, that reason should be added as a comment on the question, and this field is the comment's id
'closedbyid' => 'INT UNSIGNED', // not null means question is closed
'userid' => $useridcoltype, // which user wrote it 'userid' => $useridcoltype, // which user wrote it
'cookieid' => 'BIGINT UNSIGNED', // which cookie wrote it, if an anonymous post 'cookieid' => 'BIGINT UNSIGNED', // which cookie wrote it, if an anonymous post
'createip' => 'VARBINARY(16)', // INET_ATON of IP address used to create the post 'createip' => 'VARBINARY(16)', // INET_ATON of IP address used to create the post
...@@ -303,15 +303,15 @@ ...@@ -303,15 +303,15 @@
'views' => 'INT UNSIGNED NOT NULL DEFAULT 0', 'views' => 'INT UNSIGNED NOT NULL DEFAULT 0',
'hotness' => 'FLOAT', 'hotness' => 'FLOAT',
'flagcount' => 'TINYINT UNSIGNED NOT NULL DEFAULT 0', 'flagcount' => 'TINYINT UNSIGNED NOT NULL DEFAULT 0',
'format' => 'VARCHAR('.QA_DB_MAX_FORMAT_LENGTH.') CHARACTER SET ascii NOT NULL DEFAULT \'\'', // format of content, e.g. 'html' 'format' => 'VARCHAR(' . QA_DB_MAX_FORMAT_LENGTH . ') CHARACTER SET ascii NOT NULL DEFAULT \'\'', // format of content, e.g. 'html'
'created' => 'DATETIME NOT NULL', 'created' => 'DATETIME NOT NULL',
'updated' => 'DATETIME', // time of last update 'updated' => 'DATETIME', // time of last update
'updatetype' => 'CHAR(1) CHARACTER SET ascii', // see qa-app-updates.php 'updatetype' => 'CHAR(1) CHARACTER SET ascii', // see qa-app-updates.php
'title' => 'VARCHAR('.QA_DB_MAX_TITLE_LENGTH.')', 'title' => 'VARCHAR(' . QA_DB_MAX_TITLE_LENGTH . ')',
'content' => 'VARCHAR('.QA_DB_MAX_CONTENT_LENGTH.')', 'content' => 'VARCHAR(' . QA_DB_MAX_CONTENT_LENGTH . ')',
'tags' => 'VARCHAR('.QA_DB_MAX_TAGS_LENGTH.')', // string of tags separated by commas 'tags' => 'VARCHAR(' . QA_DB_MAX_TAGS_LENGTH . ')', // string of tags separated by commas
'name' => 'VARCHAR('.QA_DB_MAX_NAME_LENGTH.')', // name of author if post anonymonus 'name' => 'VARCHAR(' . QA_DB_MAX_NAME_LENGTH . ')', // name of author if post anonymonus
'notify' => 'VARCHAR('.QA_DB_MAX_EMAIL_LENGTH.')', // email address, or @ to get from user, or NULL for none 'notify' => 'VARCHAR(' . QA_DB_MAX_EMAIL_LENGTH . ')', // email address, or @ to get from user, or NULL for none
'PRIMARY KEY (postid)', 'PRIMARY KEY (postid)',
'KEY type (type, created)', // for getting recent questions, answers, comments 'KEY type (type, created)', // for getting recent questions, answers, comments
'KEY type_2 (type, acount, created)', // for getting unanswered questions 'KEY type_2 (type, acount, created)', // for getting unanswered questions
...@@ -343,9 +343,9 @@ ...@@ -343,9 +343,9 @@
'blobs' => array( 'blobs' => array(
'blobid' => 'BIGINT UNSIGNED NOT NULL', 'blobid' => 'BIGINT UNSIGNED NOT NULL',
'format' => 'VARCHAR('.QA_DB_MAX_FORMAT_LENGTH.') CHARACTER SET ascii NOT NULL', // format e.g. 'jpeg', 'gif', 'png' 'format' => 'VARCHAR(' . QA_DB_MAX_FORMAT_LENGTH . ') CHARACTER SET ascii NOT NULL', // format e.g. 'jpeg', 'gif', 'png'
'content' => 'MEDIUMBLOB', // null means it's stored on disk in QA_BLOBS_DIRECTORY 'content' => 'MEDIUMBLOB', // null means it's stored on disk in QA_BLOBS_DIRECTORY
'filename' => 'VARCHAR('.QA_DB_MAX_BLOB_FILE_NAME_LENGTH.')', // name of source file (if appropriate) 'filename' => 'VARCHAR(' . QA_DB_MAX_BLOB_FILE_NAME_LENGTH . ')', // name of source file (if appropriate)
'userid' => $useridcoltype, // which user created it 'userid' => $useridcoltype, // which user created it
'cookieid' => 'BIGINT UNSIGNED', // which cookie created it 'cookieid' => 'BIGINT UNSIGNED', // which cookie created it
'createip' => 'VARBINARY(16)', // INET_ATON of IP address that created it 'createip' => 'VARBINARY(16)', // INET_ATON of IP address that created it
...@@ -355,7 +355,7 @@ ...@@ -355,7 +355,7 @@
'words' => array( 'words' => array(
'wordid' => 'INT UNSIGNED NOT NULL AUTO_INCREMENT', 'wordid' => 'INT UNSIGNED NOT NULL AUTO_INCREMENT',
'word' => 'VARCHAR('.QA_DB_MAX_WORD_LENGTH.') NOT NULL', 'word' => 'VARCHAR(' . QA_DB_MAX_WORD_LENGTH . ') NOT NULL',
'titlecount' => 'INT UNSIGNED NOT NULL DEFAULT 0', // only counts one per post 'titlecount' => 'INT UNSIGNED NOT NULL DEFAULT 0', // only counts one per post
'contentcount' => 'INT UNSIGNED NOT NULL DEFAULT 0', // only counts one per post 'contentcount' => 'INT UNSIGNED NOT NULL DEFAULT 0', // only counts one per post
'tagwordcount' => 'INT UNSIGNED NOT NULL DEFAULT 0', // for words in tags - only counts one per post 'tagwordcount' => 'INT UNSIGNED NOT NULL DEFAULT 0', // for words in tags - only counts one per post
...@@ -407,7 +407,7 @@ ...@@ -407,7 +407,7 @@
'uservotes' => array( 'uservotes' => array(
'postid' => 'INT UNSIGNED NOT NULL', 'postid' => 'INT UNSIGNED NOT NULL',
'userid' => $useridcoltype.' NOT NULL', 'userid' => $useridcoltype . ' NOT NULL',
'vote' => 'TINYINT NOT NULL', // -1, 0 or 1 'vote' => 'TINYINT NOT NULL', // -1, 0 or 1
'flag' => 'TINYINT NOT NULL', // 0 or 1 'flag' => 'TINYINT NOT NULL', // 0 or 1
'UNIQUE userid (userid, postid)', 'UNIQUE userid (userid, postid)',
...@@ -418,7 +418,7 @@ ...@@ -418,7 +418,7 @@
// many userpoints columns could be unsigned but MySQL appears to mess up points calculations that go negative as a result // many userpoints columns could be unsigned but MySQL appears to mess up points calculations that go negative as a result
'userpoints' => array( 'userpoints' => array(
'userid' => $useridcoltype.' NOT NULL', 'userid' => $useridcoltype . ' NOT NULL',
'points' => 'INT NOT NULL DEFAULT 0', // user's points as displayed, after final multiple 'points' => 'INT NOT NULL DEFAULT 0', // user's points as displayed, after final multiple
'qposts' => 'MEDIUMINT NOT NULL DEFAULT 0', // number of questions by user (excluding hidden/queued) 'qposts' => 'MEDIUMINT NOT NULL DEFAULT 0', // number of questions by user (excluding hidden/queued)
'aposts' => 'MEDIUMINT NOT NULL DEFAULT 0', // number of answers by user (excluding hidden/queued) 'aposts' => 'MEDIUMINT NOT NULL DEFAULT 0', // number of answers by user (excluding hidden/queued)
...@@ -439,7 +439,7 @@ ...@@ -439,7 +439,7 @@
), ),
'userlimits' => array( 'userlimits' => array(
'userid' => $useridcoltype.' NOT NULL', 'userid' => $useridcoltype . ' NOT NULL',
'action' => 'CHAR(1) CHARACTER SET ascii NOT NULL', // see constants at top of qa-app-limits.php 'action' => 'CHAR(1) CHARACTER SET ascii NOT NULL', // see constants at top of qa-app-limits.php
'period' => 'INT UNSIGNED NOT NULL', // integer representing hour of last action 'period' => 'INT UNSIGNED NOT NULL', // integer representing hour of last action
'count' => 'SMALLINT UNSIGNED NOT NULL', // how many of this action has been performed within that hour 'count' => 'SMALLINT UNSIGNED NOT NULL', // how many of this action has been performed within that hour
...@@ -457,8 +457,8 @@ ...@@ -457,8 +457,8 @@
), ),
'options' => array( 'options' => array(
'title' => 'VARCHAR('.QA_DB_MAX_OPTION_TITLE_LENGTH.') NOT NULL', // name of option 'title' => 'VARCHAR(' . QA_DB_MAX_OPTION_TITLE_LENGTH . ') NOT NULL', // name of option
'content' => 'VARCHAR('.QA_DB_MAX_CONTENT_LENGTH.') NOT NULL', // value of option 'content' => 'VARCHAR(' . QA_DB_MAX_CONTENT_LENGTH . ') NOT NULL', // value of option
'PRIMARY KEY (title)', 'PRIMARY KEY (title)',
), ),
...@@ -473,32 +473,32 @@ ...@@ -473,32 +473,32 @@
), ),
'usermetas' => array( 'usermetas' => array(
'userid' => $useridcoltype.' NOT NULL', 'userid' => $useridcoltype . ' NOT NULL',
'title' => 'VARCHAR('.QA_DB_MAX_META_TITLE_LENGTH.') NOT NULL', 'title' => 'VARCHAR(' . QA_DB_MAX_META_TITLE_LENGTH . ') NOT NULL',
'content' => 'VARCHAR('.QA_DB_MAX_META_CONTENT_LENGTH.') NOT NULL', 'content' => 'VARCHAR(' . QA_DB_MAX_META_CONTENT_LENGTH . ') NOT NULL',
'PRIMARY KEY (userid, title)', 'PRIMARY KEY (userid, title)',
), ),
'postmetas' => array( 'postmetas' => array(
'postid' => 'INT UNSIGNED NOT NULL', 'postid' => 'INT UNSIGNED NOT NULL',
'title' => 'VARCHAR('.QA_DB_MAX_META_TITLE_LENGTH.') NOT NULL', 'title' => 'VARCHAR(' . QA_DB_MAX_META_TITLE_LENGTH . ') NOT NULL',
'content' => 'VARCHAR('.QA_DB_MAX_META_CONTENT_LENGTH.') NOT NULL', 'content' => 'VARCHAR(' . QA_DB_MAX_META_CONTENT_LENGTH . ') NOT NULL',
'PRIMARY KEY (postid, title)', 'PRIMARY KEY (postid, title)',
'CONSTRAINT ^postmetas_ibfk_1 FOREIGN KEY (postid) REFERENCES ^posts(postid) ON DELETE CASCADE', 'CONSTRAINT ^postmetas_ibfk_1 FOREIGN KEY (postid) REFERENCES ^posts(postid) ON DELETE CASCADE',
), ),
'categorymetas' => array( 'categorymetas' => array(
'categoryid' => 'INT UNSIGNED NOT NULL', 'categoryid' => 'INT UNSIGNED NOT NULL',
'title' => 'VARCHAR('.QA_DB_MAX_META_TITLE_LENGTH.') NOT NULL', 'title' => 'VARCHAR(' . QA_DB_MAX_META_TITLE_LENGTH . ') NOT NULL',
'content' => 'VARCHAR('.QA_DB_MAX_META_CONTENT_LENGTH.') NOT NULL', 'content' => 'VARCHAR(' . QA_DB_MAX_META_CONTENT_LENGTH . ') NOT NULL',
'PRIMARY KEY (categoryid, title)', 'PRIMARY KEY (categoryid, title)',
'CONSTRAINT ^categorymetas_ibfk_1 FOREIGN KEY (categoryid) REFERENCES ^categories(categoryid) ON DELETE CASCADE', 'CONSTRAINT ^categorymetas_ibfk_1 FOREIGN KEY (categoryid) REFERENCES ^categories(categoryid) ON DELETE CASCADE',
), ),
'tagmetas' => array( 'tagmetas' => array(
'tag' => 'VARCHAR('.QA_DB_MAX_WORD_LENGTH.') NOT NULL', 'tag' => 'VARCHAR(' . QA_DB_MAX_WORD_LENGTH . ') NOT NULL',
'title' => 'VARCHAR('.QA_DB_MAX_META_TITLE_LENGTH.') NOT NULL', 'title' => 'VARCHAR(' . QA_DB_MAX_META_TITLE_LENGTH . ') NOT NULL',
'content' => 'VARCHAR('.QA_DB_MAX_META_CONTENT_LENGTH.') NOT NULL', 'content' => 'VARCHAR(' . QA_DB_MAX_META_CONTENT_LENGTH . ') NOT NULL',
'PRIMARY KEY (tag, title)', 'PRIMARY KEY (tag, title)',
), ),
...@@ -512,136 +512,144 @@ ...@@ -512,136 +512,144 @@
unset($tables['messages']); unset($tables['messages']);
} else { } else {
$userforeignkey='FOREIGN KEY (userid) REFERENCES ^users(userid)'; $userforeignkey = 'FOREIGN KEY (userid) REFERENCES ^users(userid)';
$tables['userlogins'][]='CONSTRAINT ^userlogins_ibfk_1 '.$userforeignkey.' ON DELETE CASCADE'; $tables['userlogins'][] = 'CONSTRAINT ^userlogins_ibfk_1 ' . $userforeignkey . ' ON DELETE CASCADE';
$tables['userprofile'][]='CONSTRAINT ^userprofile_ibfk_1 '.$userforeignkey.' ON DELETE CASCADE'; $tables['userprofile'][] = 'CONSTRAINT ^userprofile_ibfk_1 ' . $userforeignkey . ' ON DELETE CASCADE';
$tables['posts'][]='CONSTRAINT ^posts_ibfk_1 '.$userforeignkey.' ON DELETE SET NULL'; $tables['posts'][] = 'CONSTRAINT ^posts_ibfk_1 ' . $userforeignkey . ' ON DELETE SET NULL';
$tables['uservotes'][]='CONSTRAINT ^uservotes_ibfk_2 '.$userforeignkey.' ON DELETE CASCADE'; $tables['uservotes'][] = 'CONSTRAINT ^uservotes_ibfk_2 ' . $userforeignkey . ' ON DELETE CASCADE';
$tables['userlimits'][]='CONSTRAINT ^userlimits_ibfk_1 '.$userforeignkey.' ON DELETE CASCADE'; $tables['userlimits'][] = 'CONSTRAINT ^userlimits_ibfk_1 ' . $userforeignkey . ' ON DELETE CASCADE';
$tables['userfavorites'][]='CONSTRAINT ^userfavorites_ibfk_1 '.$userforeignkey.' ON DELETE CASCADE'; $tables['userfavorites'][] = 'CONSTRAINT ^userfavorites_ibfk_1 ' . $userforeignkey . ' ON DELETE CASCADE';
$tables['usernotices'][]='CONSTRAINT ^usernotices_ibfk_1 '.$userforeignkey.' ON DELETE CASCADE'; $tables['usernotices'][] = 'CONSTRAINT ^usernotices_ibfk_1 ' . $userforeignkey . ' ON DELETE CASCADE';
$tables['userevents'][]='CONSTRAINT ^userevents_ibfk_1 '.$userforeignkey.' ON DELETE CASCADE'; $tables['userevents'][] = 'CONSTRAINT ^userevents_ibfk_1 ' . $userforeignkey . ' ON DELETE CASCADE';
$tables['userlevels'][]='CONSTRAINT ^userlevels_ibfk_1 '.$userforeignkey.' ON DELETE CASCADE'; $tables['userlevels'][] = 'CONSTRAINT ^userlevels_ibfk_1 ' . $userforeignkey . ' ON DELETE CASCADE';
$tables['usermetas'][]='CONSTRAINT ^usermetas_ibfk_1 '.$userforeignkey.' ON DELETE CASCADE'; $tables['usermetas'][] = 'CONSTRAINT ^usermetas_ibfk_1 ' . $userforeignkey . ' ON DELETE CASCADE';
} }
return $tables; return $tables;
} }
function qa_array_to_keys($array) /**
/* * Return array with all values from $array as keys
Return array with all values from $array as keys * @param $array
*/ * @return array
{ */
function qa_array_to_keys($array)
{
return empty($array) ? array() : array_combine($array, array_fill(0, count($array), true)); return empty($array) ? array() : array_combine($array, array_fill(0, count($array), true));
} }
function qa_db_missing_tables($definitions) /**
/* * Return a list of tables missing from the database, [table name] => [column/index definitions]
Return a list of tables missing from the database, [table name] => [column/index definitions] * @param $definitions
*/ * @return array
{ */
$keydbtables=qa_array_to_keys(qa_db_list_tables()); function qa_db_missing_tables($definitions)
{
$keydbtables = qa_array_to_keys(qa_db_list_tables());
$missing=array(); $missing = array();
foreach ($definitions as $rawname => $definition) foreach ($definitions as $rawname => $definition)
if (!isset($keydbtables[qa_db_add_table_prefix($rawname)])) if (!isset($keydbtables[qa_db_add_table_prefix($rawname)]))
$missing[$rawname]=$definition; $missing[$rawname] = $definition;
return $missing; return $missing;
} }
function qa_db_missing_columns($table, $definition) /**
/* * Return a list of columns missing from $table in the database, given the full definition set in $definition
Return a list of columns missing from $table in the database, given the full definition set in $definition * @param $table
*/ * @param $definition
{ * @return array
$keycolumns=qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^'.$table))); */
function qa_db_missing_columns($table, $definition)
{
$keycolumns = qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^' . $table)));
$missing=array(); $missing = array();
foreach ($definition as $colname => $coldefn) foreach ($definition as $colname => $coldefn)
if ( (!is_int($colname)) && !isset($keycolumns[$colname]) ) if ((!is_int($colname)) && !isset($keycolumns[$colname]))
$missing[$colname]=$coldefn; $missing[$colname] = $coldefn;
return $missing; return $missing;
} }
function qa_db_get_db_version() /**
/* * Return the current version of the Q2A database, to determine need for DB upgrades
Return the current version of the Q2A database, to determine need for DB upgrades */
*/ function qa_db_get_db_version()
{ {
$definitions=qa_db_table_definitions(); $definitions = qa_db_table_definitions();
if (count(qa_db_missing_columns('options', $definitions['options']))==0) { if (count(qa_db_missing_columns('options', $definitions['options'])) == 0) {
$version=(int)qa_db_read_one_value(qa_db_query_sub("SELECT content FROM ^options WHERE title='db_version'"), true); $version = (int)qa_db_read_one_value(qa_db_query_sub("SELECT content FROM ^options WHERE title='db_version'"), true);
if ($version>0) if ($version > 0)
return $version; return $version;
} }
return null; return null;
} }
function qa_db_set_db_version($version) /**
/* * Set the current version in the database
Set the current version in the database * @param $version
*/ */
{ function qa_db_set_db_version($version)
{
require_once QA_INCLUDE_DIR . 'db/options.php'; require_once QA_INCLUDE_DIR . 'db/options.php';
qa_db_set_option('db_version', $version); qa_db_set_option('db_version', $version);
} }
function qa_db_check_tables() /**
/* * Return a string describing what is wrong with the database, or false if everything is just fine
Return a string describing what is wrong with the database, or false if everything is just fine */
*/ function qa_db_check_tables()
{ {
qa_db_query_raw('UNLOCK TABLES'); // we could be inside a lock tables block qa_db_query_raw('UNLOCK TABLES'); // we could be inside a lock tables block
$version=qa_db_read_one_value(qa_db_query_raw('SELECT VERSION()')); $version = qa_db_read_one_value(qa_db_query_raw('SELECT VERSION()'));
if (((float)$version)<4.1) if (((float)$version) < 4.1)
qa_fatal_error('MySQL version 4.1 or later is required - you appear to be running MySQL '.$version); qa_fatal_error('MySQL version 4.1 or later is required - you appear to be running MySQL ' . $version);
$definitions=qa_db_table_definitions(); $definitions = qa_db_table_definitions();
$missing=qa_db_missing_tables($definitions); $missing = qa_db_missing_tables($definitions);
if (count($missing) == count($definitions)) if (count($missing) == count($definitions))
return 'none'; return 'none';
else { else {
if (!isset($missing['options'])) { if (!isset($missing['options'])) {
$version=qa_db_get_db_version(); $version = qa_db_get_db_version();
if (isset($version) && ($version<QA_DB_VERSION_CURRENT)) if (isset($version) && ($version < QA_DB_VERSION_CURRENT))
return 'old-version'; return 'old-version';
} }
if (count($missing)) { if (count($missing)) {
if (defined('QA_MYSQL_USERS_PREFIX')) { // special case if two installations sharing users if (defined('QA_MYSQL_USERS_PREFIX')) { // special case if two installations sharing users
$datacount=0; $datacount = 0;
$datamissing=0; $datamissing = 0;
foreach ($definitions as $rawname => $definition) foreach ($definitions as $rawname => $definition)
if (qa_db_add_table_prefix($rawname)==(QA_MYSQL_TABLE_PREFIX.$rawname)) { if (qa_db_add_table_prefix($rawname) == (QA_MYSQL_TABLE_PREFIX . $rawname)) {
$datacount++; $datacount++;
if (isset($missing[$rawname])) if (isset($missing[$rawname]))
$datamissing++; $datamissing++;
} }
if ( ($datacount==$datamissing) && ($datamissing==count($missing)) ) if (($datacount == $datamissing) && ($datamissing == count($missing)))
return 'non-users-missing'; return 'non-users-missing';
} }
...@@ -654,92 +662,95 @@ ...@@ -654,92 +662,95 @@
} }
return false; return false;
} }
function qa_db_install_tables() /**
/* * Install any missing database tables and/or columns and automatically set version as latest.
Install any missing database tables and/or columns and automatically set version as latest. * This is not suitable for use if the database needs upgrading.
This is not suitable for use if the database needs upgrading. */
*/ function qa_db_install_tables()
{ {
$definitions=qa_db_table_definitions(); $definitions = qa_db_table_definitions();
$missingtables=qa_db_missing_tables($definitions); $missingtables = qa_db_missing_tables($definitions);
foreach ($missingtables as $rawname => $definition) { foreach ($missingtables as $rawname => $definition) {
qa_db_query_sub(qa_db_create_table_sql($rawname, $definition)); qa_db_query_sub(qa_db_create_table_sql($rawname, $definition));
if ($rawname=='userfields') if ($rawname == 'userfields')
qa_db_query_sub(qa_db_default_userfields_sql()); qa_db_query_sub(qa_db_default_userfields_sql());
} }
foreach ($definitions as $table => $definition) { foreach ($definitions as $table => $definition) {
$missingcolumns=qa_db_missing_columns($table, $definition); $missingcolumns = qa_db_missing_columns($table, $definition);
foreach ($missingcolumns as $colname => $coldefn) foreach ($missingcolumns as $colname => $coldefn)
qa_db_query_sub('ALTER TABLE ^'.$table.' ADD COLUMN '.$colname.' '.$coldefn); qa_db_query_sub('ALTER TABLE ^' . $table . ' ADD COLUMN ' . $colname . ' ' . $coldefn);
} }
qa_db_set_db_version(QA_DB_VERSION_CURRENT); qa_db_set_db_version(QA_DB_VERSION_CURRENT);
} }
function qa_db_create_table_sql($rawname, $definition) /**
/* * Return the SQL command to create a table with $rawname and $definition obtained from qa_db_table_definitions()
Return the SQL command to create a table with $rawname and $definition obtained from qa_db_table_definitions() * @param $rawname
*/ * @param $definition
{ * @return string
$querycols=''; */
function qa_db_create_table_sql($rawname, $definition)
{
$querycols = '';
foreach ($definition as $colname => $coldef) foreach ($definition as $colname => $coldef)
if (isset($coldef)) if (isset($coldef))
$querycols.=(strlen($querycols) ? ', ' : '').(is_int($colname) ? $coldef : ($colname.' '.$coldef)); $querycols .= (strlen($querycols) ? ', ' : '') . (is_int($colname) ? $coldef : ($colname . ' ' . $coldef));
return 'CREATE TABLE ^'.$rawname.' ('.$querycols.') ENGINE=InnoDB CHARSET=utf8'; return 'CREATE TABLE ^' . $rawname . ' (' . $querycols . ') ENGINE=InnoDB CHARSET=utf8';
} }
function qa_db_default_userfields_sql() /**
/* * Return the SQL to create the default entries in the userfields table (before 1.3 these were hard-coded in PHP)
Return the SQL to create the default entries in the userfields table (before 1.3 these were hard-coded in PHP) */
*/ function qa_db_default_userfields_sql()
{ {
$oldprofileflags=array( $oldprofileflags = array(
'name' => 0, 'name' => 0,
'location' => 0, 'location' => 0,
'website' => QA_FIELD_FLAGS_LINK_URL, 'website' => QA_FIELD_FLAGS_LINK_URL,
'about' => QA_FIELD_FLAGS_MULTI_LINE, 'about' => QA_FIELD_FLAGS_MULTI_LINE,
); );
$sql='INSERT INTO ^userfields (title, position, flags) VALUES '; // content column will be NULL, meaning use default from lang files $sql = 'INSERT INTO ^userfields (title, position, flags) VALUES '; // content column will be NULL, meaning use default from lang files
$index=0; $index = 0;
foreach ($oldprofileflags as $title => $flags) foreach ($oldprofileflags as $title => $flags)
$sql.=($index ? ', ' : '')."('".qa_db_escape_string($title)."', ".(++$index).", ".(int)@$oldprofileflags[$title].")"; $sql .= ($index ? ', ' : '') . "('" . qa_db_escape_string($title) . "', " . (++$index) . ", " . (int)@$oldprofileflags[$title] . ")";
return $sql; return $sql;
} }
function qa_db_upgrade_tables() /**
/* * Upgrade the database schema to the latest version, outputting progress to the browser
Upgrade the database schema to the latest version, outputting progress to the browser */
*/ function qa_db_upgrade_tables()
{ {
require_once QA_INCLUDE_DIR.'app/recalc.php'; require_once QA_INCLUDE_DIR . 'app/recalc.php';
$definitions=qa_db_table_definitions(); $definitions = qa_db_table_definitions();
$keyrecalc=array(); $keyrecalc = array();
// Write-lock all Q2A tables before we start so no one can read or write anything // Write-lock all Q2A tables before we start so no one can read or write anything
$keydbtables=qa_array_to_keys(qa_db_list_tables()); $keydbtables = qa_array_to_keys(qa_db_list_tables());
foreach ($definitions as $rawname => $definition) foreach ($definitions as $rawname => $definition)
if (isset($keydbtables[qa_db_add_table_prefix($rawname)])) if (isset($keydbtables[qa_db_add_table_prefix($rawname)]))
$locks[]='^'.$rawname.' WRITE'; $locks[] = '^' . $rawname . ' WRITE';
$locktablesquery='LOCK TABLES '.implode(', ', $locks); $locktablesquery = 'LOCK TABLES ' . implode(', ', $locks);
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
...@@ -749,56 +760,56 @@ ...@@ -749,56 +760,56 @@
$skipMessage = 'Skipping upgrading %s table since it was already upgraded by another Q2A site sharing it.'; $skipMessage = 'Skipping upgrading %s table since it was already upgraded by another Q2A site sharing it.';
while (1) { while (1) {
$version=qa_db_get_db_version(); $version = qa_db_get_db_version();
if ($version>=QA_DB_VERSION_CURRENT) if ($version >= QA_DB_VERSION_CURRENT)
break; break;
$newversion=$version+1; $newversion = $version + 1;
qa_db_upgrade_progress(QA_DB_VERSION_CURRENT-$version.' upgrade step/s remaining...'); qa_db_upgrade_progress(QA_DB_VERSION_CURRENT - $version . ' upgrade step/s remaining...');
switch ($newversion) { switch ($newversion) {
// Up to here: Version 1.0 beta 1 // Up to here: Version 1.0 beta 1
case 2: case 2:
qa_db_upgrade_query('ALTER TABLE ^posts DROP COLUMN votes, ADD COLUMN upvotes '.$definitions['posts']['upvotes']. qa_db_upgrade_query('ALTER TABLE ^posts DROP COLUMN votes, ADD COLUMN upvotes ' . $definitions['posts']['upvotes'] .
' AFTER cookieid, ADD COLUMN downvotes '.$definitions['posts']['downvotes'].' AFTER upvotes'); ' AFTER cookieid, ADD COLUMN downvotes ' . $definitions['posts']['downvotes'] . ' AFTER upvotes');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorecountposts']=true; $keyrecalc['dorecountposts'] = true;
break; break;
case 3: case 3:
qa_db_upgrade_query('ALTER TABLE ^userpoints ADD COLUMN upvoteds '.$definitions['userpoints']['upvoteds']. qa_db_upgrade_query('ALTER TABLE ^userpoints ADD COLUMN upvoteds ' . $definitions['userpoints']['upvoteds'] .
' AFTER avoteds, ADD COLUMN downvoteds '.$definitions['userpoints']['downvoteds'].' AFTER upvoteds'); ' AFTER avoteds, ADD COLUMN downvoteds ' . $definitions['userpoints']['downvoteds'] . ' AFTER upvoteds');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorecalcpoints']=true; $keyrecalc['dorecalcpoints'] = true;
break; break;
case 4: case 4:
qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN lastuserid '.$definitions['posts']['lastuserid'].' AFTER cookieid, CHANGE COLUMN updated updated '.$definitions['posts']['updated']); qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN lastuserid ' . $definitions['posts']['lastuserid'] . ' AFTER cookieid, CHANGE COLUMN updated updated ' . $definitions['posts']['updated']);
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
qa_db_upgrade_query('UPDATE ^posts SET updated=NULL WHERE updated=0 OR updated=created'); qa_db_upgrade_query('UPDATE ^posts SET updated=NULL WHERE updated=0 OR updated=created');
break; break;
case 5: case 5:
qa_db_upgrade_query('ALTER TABLE ^contentwords ADD COLUMN type '.$definitions['contentwords']['type'].' AFTER count, ADD COLUMN questionid '.$definitions['contentwords']['questionid'].' AFTER type'); qa_db_upgrade_query('ALTER TABLE ^contentwords ADD COLUMN type ' . $definitions['contentwords']['type'] . ' AFTER count, ADD COLUMN questionid ' . $definitions['contentwords']['questionid'] . ' AFTER type');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['doreindexcontent']=true; $keyrecalc['doreindexcontent'] = true;
break; break;
// Up to here: Version 1.0 beta 2 // Up to here: Version 1.0 beta 2
case 6: case 6:
qa_db_upgrade_query('ALTER TABLE ^userpoints ADD COLUMN cposts '.$definitions['userpoints']['cposts'].' AFTER aposts'); qa_db_upgrade_query('ALTER TABLE ^userpoints ADD COLUMN cposts ' . $definitions['userpoints']['cposts'] . ' AFTER aposts');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorecalcpoints']=true; $keyrecalc['dorecalcpoints'] = true;
break; break;
case 7: case 7:
if (!QA_FINAL_EXTERNAL_USERS) { if (!QA_FINAL_EXTERNAL_USERS) {
qa_db_upgrade_query('ALTER TABLE ^users ADD COLUMN sessioncode '.$definitions['users']['sessioncode'].' AFTER writeip'); qa_db_upgrade_query('ALTER TABLE ^users ADD COLUMN sessioncode ' . $definitions['users']['sessioncode'] . ' AFTER writeip');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
} }
break; break;
...@@ -806,14 +817,14 @@ ...@@ -806,14 +817,14 @@
case 8: case 8:
qa_db_upgrade_query('ALTER TABLE ^posts ADD KEY (type, acount, created)'); qa_db_upgrade_query('ALTER TABLE ^posts ADD KEY (type, acount, created)');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorecountposts']=true; // for unanswered question count $keyrecalc['dorecountposts'] = true; // for unanswered question count
break; break;
// Up to here: Version 1.0 beta 3, 1.0, 1.0.1 beta, 1.0.1 // Up to here: Version 1.0 beta 3, 1.0, 1.0.1 beta, 1.0.1
case 9: case 9:
if (!QA_FINAL_EXTERNAL_USERS) { if (!QA_FINAL_EXTERNAL_USERS) {
qa_db_upgrade_query('ALTER TABLE ^users CHANGE COLUMN resetcode emailcode '.$definitions['users']['emailcode'].', ADD COLUMN flags '.$definitions['users']['flags'].' AFTER sessioncode'); qa_db_upgrade_query('ALTER TABLE ^users CHANGE COLUMN resetcode emailcode ' . $definitions['users']['emailcode'] . ', ADD COLUMN flags ' . $definitions['users']['flags'] . ' AFTER sessioncode');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
qa_db_upgrade_query('UPDATE ^users SET flags=1'); qa_db_upgrade_query('UPDATE ^users SET flags=1');
} }
...@@ -832,12 +843,12 @@ ...@@ -832,12 +843,12 @@
'UNIQUE position (position)', 'UNIQUE position (position)',
))); // hard-code list of columns and indexes to ensure we ignore any added at a later stage ))); // hard-code list of columns and indexes to ensure we ignore any added at a later stage
$locktablesquery.=', ^categories WRITE'; $locktablesquery .= ', ^categories WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
case 11: case 11:
qa_db_upgrade_query('ALTER TABLE ^posts ADD CONSTRAINT ^posts_ibfk_2 FOREIGN KEY (parentid) REFERENCES ^posts(postid), ADD COLUMN categoryid '.$definitions['posts']['categoryid'].' AFTER parentid, ADD KEY categoryid (categoryid, type, created), ADD CONSTRAINT ^posts_ibfk_3 FOREIGN KEY (categoryid) REFERENCES ^categories(categoryid) ON DELETE SET NULL'); qa_db_upgrade_query('ALTER TABLE ^posts ADD CONSTRAINT ^posts_ibfk_2 FOREIGN KEY (parentid) REFERENCES ^posts(postid), ADD COLUMN categoryid ' . $definitions['posts']['categoryid'] . ' AFTER parentid, ADD KEY categoryid (categoryid, type, created), ADD CONSTRAINT ^posts_ibfk_3 FOREIGN KEY (categoryid) REFERENCES ^categories(categoryid) ON DELETE SET NULL');
// foreign key on parentid important now that deletion is possible // foreign key on parentid important now that deletion is possible
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -857,19 +868,19 @@ ...@@ -857,19 +868,19 @@
'UNIQUE tags (tags)', 'UNIQUE tags (tags)',
'UNIQUE position (position)', 'UNIQUE position (position)',
))); // hard-code list of columns and indexes to ensure we ignore any added at a later stage ))); // hard-code list of columns and indexes to ensure we ignore any added at a later stage
$locktablesquery.=', ^pages WRITE'; $locktablesquery .= ', ^pages WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
case 13: case 13:
qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN createip '.$definitions['posts']['createip'].' AFTER cookieid, ADD KEY createip (createip, created)'); qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN createip ' . $definitions['posts']['createip'] . ' AFTER cookieid, ADD KEY createip (createip, created)');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
case 14: case 14:
qa_db_upgrade_query('ALTER TABLE ^userpoints DROP COLUMN qvotes, DROP COLUMN avotes, ADD COLUMN qupvotes '.$definitions['userpoints']['qupvotes'].' AFTER aselecteds, ADD COLUMN qdownvotes '.$definitions['userpoints']['qdownvotes'].' AFTER qupvotes, ADD COLUMN aupvotes '.$definitions['userpoints']['aupvotes'].' AFTER qdownvotes, ADD COLUMN adownvotes '.$definitions['userpoints']['adownvotes'].' AFTER aupvotes'); qa_db_upgrade_query('ALTER TABLE ^userpoints DROP COLUMN qvotes, DROP COLUMN avotes, ADD COLUMN qupvotes ' . $definitions['userpoints']['qupvotes'] . ' AFTER aselecteds, ADD COLUMN qdownvotes ' . $definitions['userpoints']['qdownvotes'] . ' AFTER qupvotes, ADD COLUMN aupvotes ' . $definitions['userpoints']['aupvotes'] . ' AFTER qdownvotes, ADD COLUMN adownvotes ' . $definitions['userpoints']['adownvotes'] . ' AFTER aupvotes');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorecalcpoints']=true; $keyrecalc['dorecalcpoints'] = true;
break; break;
// Up to here: Version 1.2 beta 1 // Up to here: Version 1.2 beta 1
...@@ -891,7 +902,7 @@ ...@@ -891,7 +902,7 @@
case 16: case 16:
qa_db_upgrade_table_columns($definitions, 'posts', array('format')); qa_db_upgrade_table_columns($definitions, 'posts', array('format'));
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['doreindexcontent']=true; // because of new treatment of apostrophes in words $keyrecalc['doreindexcontent'] = true; // because of new treatment of apostrophes in words
break; break;
case 17: case 17:
...@@ -900,13 +911,13 @@ ...@@ -900,13 +911,13 @@
break; break;
case 18: case 18:
qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN lastip '.$definitions['posts']['lastip'].' AFTER lastuserid, ADD KEY lastip (lastip, updated, type)'); qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN lastip ' . $definitions['posts']['lastip'] . ' AFTER lastuserid, ADD KEY lastip (lastip, updated, type)');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
case 19: case 19:
if (!QA_FINAL_EXTERNAL_USERS) if (!QA_FINAL_EXTERNAL_USERS)
qa_db_upgrade_query('ALTER TABLE ^users ADD COLUMN avatarblobid '.$definitions['users']['avatarblobid'].' AFTER handle, ADD COLUMN avatarwidth '.$definitions['users']['avatarwidth'].' AFTER avatarblobid, ADD COLUMN avatarheight '.$definitions['users']['avatarheight'].' AFTER avatarwidth'); qa_db_upgrade_query('ALTER TABLE ^users ADD COLUMN avatarblobid ' . $definitions['users']['avatarblobid'] . ' AFTER handle, ADD COLUMN avatarwidth ' . $definitions['users']['avatarwidth'] . ' AFTER avatarblobid, ADD COLUMN avatarheight ' . $definitions['users']['avatarheight'] . ' AFTER avatarwidth');
// hard-code list of columns and indexes to ensure we ignore any added at a later stage // hard-code list of columns and indexes to ensure we ignore any added at a later stage
...@@ -916,7 +927,7 @@ ...@@ -916,7 +927,7 @@
'blobid' => $definitions['blobs']['blobid'], 'blobid' => $definitions['blobs']['blobid'],
'format' => $definitions['blobs']['format'], 'format' => $definitions['blobs']['format'],
'content' => $definitions['blobs']['content'], 'content' => $definitions['blobs']['content'],
'PRIMARY KEY (blobid)' 'PRIMARY KEY (blobid)',
))); )));
qa_db_upgrade_query(qa_db_create_table_sql('cache', array( qa_db_upgrade_query(qa_db_create_table_sql('cache', array(
...@@ -929,7 +940,7 @@ ...@@ -929,7 +940,7 @@
'KEY (lastread)', 'KEY (lastread)',
))); // hard-code list of columns and indexes to ensure we ignore any added at a later stage ))); // hard-code list of columns and indexes to ensure we ignore any added at a later stage
$locktablesquery.=', ^blobs WRITE, ^cache WRITE'; $locktablesquery .= ', ^blobs WRITE, ^cache WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -947,9 +958,9 @@ ...@@ -947,9 +958,9 @@
'CONSTRAINT ^userlogins_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE', 'CONSTRAINT ^userlogins_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE',
))); )));
qa_db_upgrade_query('ALTER TABLE ^users CHANGE COLUMN passsalt passsalt '.$definitions['users']['passsalt'].', CHANGE COLUMN passcheck passcheck '.$definitions['users']['passcheck']); qa_db_upgrade_query('ALTER TABLE ^users CHANGE COLUMN passsalt passsalt ' . $definitions['users']['passsalt'] . ', CHANGE COLUMN passcheck passcheck ' . $definitions['users']['passcheck']);
$locktablesquery.=', ^userlogins WRITE'; $locktablesquery .= ', ^userlogins WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
} }
break; break;
...@@ -967,7 +978,7 @@ ...@@ -967,7 +978,7 @@
'PRIMARY KEY (fieldid)', 'PRIMARY KEY (fieldid)',
))); )));
$locktablesquery.=', ^userfields WRITE'; $locktablesquery .= ', ^userfields WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
qa_db_upgrade_query(qa_db_default_userfields_sql()); qa_db_upgrade_query(qa_db_default_userfields_sql());
...@@ -978,7 +989,7 @@ ...@@ -978,7 +989,7 @@
case 22: case 22:
if (!QA_FINAL_EXTERNAL_USERS) { if (!QA_FINAL_EXTERNAL_USERS) {
qa_db_upgrade_query('ALTER TABLE ^users ADD COLUMN sessionsource '.$definitions['users']['sessionsource'].' AFTER sessioncode'); qa_db_upgrade_query('ALTER TABLE ^users ADD COLUMN sessionsource ' . $definitions['users']['sessionsource'] . ' AFTER sessioncode');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
} }
break; break;
...@@ -998,7 +1009,7 @@ ...@@ -998,7 +1009,7 @@
'UNIQUE position (position)', 'UNIQUE position (position)',
))); )));
$locktablesquery.=', ^widgets WRITE'; $locktablesquery .= ', ^widgets WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1014,55 +1025,55 @@ ...@@ -1014,55 +1025,55 @@
'CONSTRAINT ^tagwords_ibfk_2 FOREIGN KEY (wordid) REFERENCES ^words(wordid)', 'CONSTRAINT ^tagwords_ibfk_2 FOREIGN KEY (wordid) REFERENCES ^words(wordid)',
))); )));
$locktablesquery.=', ^tagwords WRITE'; $locktablesquery .= ', ^tagwords WRITE';
qa_db_upgrade_query('ALTER TABLE ^words ADD COLUMN tagwordcount '.$definitions['words']['tagwordcount'].' AFTER contentcount'); qa_db_upgrade_query('ALTER TABLE ^words ADD COLUMN tagwordcount ' . $definitions['words']['tagwordcount'] . ' AFTER contentcount');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['doreindexcontent']=true; $keyrecalc['doreindexcontent'] = true;
break; break;
// Up to here: Version 1.4 developer preview // Up to here: Version 1.4 developer preview
case 25: case 25:
$keycolumns=qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^blobs'))); $keycolumns = qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^blobs')));
// might be using blobs table shared with another installation, so check if we need to upgrade // might be using blobs table shared with another installation, so check if we need to upgrade
if (isset($keycolumns['filename'])) if (isset($keycolumns['filename']))
qa_db_upgrade_progress('Skipping upgrading blobs table since it was already upgraded by another Q2A site sharing it.'); qa_db_upgrade_progress('Skipping upgrading blobs table since it was already upgraded by another Q2A site sharing it.');
else { else {
qa_db_upgrade_query('ALTER TABLE ^blobs ADD COLUMN filename '.$definitions['blobs']['filename'].' AFTER content, ADD COLUMN userid '.$definitions['blobs']['userid'].' AFTER filename, ADD COLUMN cookieid '.$definitions['blobs']['cookieid'].' AFTER userid, ADD COLUMN createip '.$definitions['blobs']['createip'].' AFTER cookieid, ADD COLUMN created '.$definitions['blobs']['created'].' AFTER createip'); qa_db_upgrade_query('ALTER TABLE ^blobs ADD COLUMN filename ' . $definitions['blobs']['filename'] . ' AFTER content, ADD COLUMN userid ' . $definitions['blobs']['userid'] . ' AFTER filename, ADD COLUMN cookieid ' . $definitions['blobs']['cookieid'] . ' AFTER userid, ADD COLUMN createip ' . $definitions['blobs']['createip'] . ' AFTER cookieid, ADD COLUMN created ' . $definitions['blobs']['created'] . ' AFTER createip');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
} }
break; break;
case 26: case 26:
qa_db_upgrade_query('ALTER TABLE ^uservotes ADD COLUMN flag '.$definitions['uservotes']['flag'].' AFTER vote'); qa_db_upgrade_query('ALTER TABLE ^uservotes ADD COLUMN flag ' . $definitions['uservotes']['flag'] . ' AFTER vote');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN flagcount '.$definitions['posts']['flagcount'].' AFTER downvotes, ADD KEY type_3 (type, flagcount, created)'); qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN flagcount ' . $definitions['posts']['flagcount'] . ' AFTER downvotes, ADD KEY type_3 (type, flagcount, created)');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorecountposts']=true; $keyrecalc['dorecountposts'] = true;
break; break;
case 27: case 27:
qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN netvotes '.$definitions['posts']['netvotes'].' AFTER downvotes, ADD KEY type_4 (type, netvotes, created)'); qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN netvotes ' . $definitions['posts']['netvotes'] . ' AFTER downvotes, ADD KEY type_4 (type, netvotes, created)');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorecountposts']=true; $keyrecalc['dorecountposts'] = true;
break; break;
case 28: case 28:
qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN views '.$definitions['posts']['views'].' AFTER netvotes, ADD COLUMN hotness '.$definitions['posts']['hotness'].' AFTER views, ADD KEY type_5 (type, views, created), ADD KEY type_6 (type, hotness)'); qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN views ' . $definitions['posts']['views'] . ' AFTER netvotes, ADD COLUMN hotness ' . $definitions['posts']['hotness'] . ' AFTER views, ADD KEY type_5 (type, views, created), ADD KEY type_6 (type, hotness)');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorecountposts']=true; $keyrecalc['dorecountposts'] = true;
break; break;
case 29: case 29:
qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN lastviewip '.$definitions['posts']['lastviewip'].' AFTER netvotes'); qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN lastviewip ' . $definitions['posts']['lastviewip'] . ' AFTER netvotes');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1073,10 +1084,10 @@ ...@@ -1073,10 +1084,10 @@
qa_db_upgrade_query('ALTER TABLE ^posts DROP KEY categoryid, DROP KEY categoryid_2'); qa_db_upgrade_query('ALTER TABLE ^posts DROP KEY categoryid, DROP KEY categoryid_2');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
qa_db_upgrade_query('ALTER TABLE ^categories CHANGE COLUMN categoryid categoryid '.$definitions['categories']['categoryid'].', ADD COLUMN parentid '.$definitions['categories']['parentid'].' AFTER categoryid, ADD COLUMN backpath '.$definitions['categories']['backpath'].' AFTER position, ADD COLUMN content '.$definitions['categories']['content'].' AFTER tags, DROP INDEX tags, DROP INDEX position, ADD UNIQUE parentid (parentid, tags), ADD UNIQUE parentid_2 (parentid, position), ADD KEY backpath (backpath('.QA_DB_MAX_CAT_PAGE_TAGS_LENGTH.'))'); qa_db_upgrade_query('ALTER TABLE ^categories CHANGE COLUMN categoryid categoryid ' . $definitions['categories']['categoryid'] . ', ADD COLUMN parentid ' . $definitions['categories']['parentid'] . ' AFTER categoryid, ADD COLUMN backpath ' . $definitions['categories']['backpath'] . ' AFTER position, ADD COLUMN content ' . $definitions['categories']['content'] . ' AFTER tags, DROP INDEX tags, DROP INDEX position, ADD UNIQUE parentid (parentid, tags), ADD UNIQUE parentid_2 (parentid, position), ADD KEY backpath (backpath(' . QA_DB_MAX_CAT_PAGE_TAGS_LENGTH . '))');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
qa_db_upgrade_query('ALTER TABLE ^posts CHANGE COLUMN categoryid categoryid '.$definitions['posts']['categoryid'].', ADD COLUMN catidpath1 '.$definitions['posts']['catidpath1'].' AFTER categoryid, ADD COLUMN catidpath2 '.$definitions['posts']['catidpath2'].' AFTER catidpath1, ADD COLUMN catidpath3 '.$definitions['posts']['catidpath3'].' AFTER catidpath2'); // QA_CATEGORY_DEPTH=4 qa_db_upgrade_query('ALTER TABLE ^posts CHANGE COLUMN categoryid categoryid ' . $definitions['posts']['categoryid'] . ', ADD COLUMN catidpath1 ' . $definitions['posts']['catidpath1'] . ' AFTER categoryid, ADD COLUMN catidpath2 ' . $definitions['posts']['catidpath2'] . ' AFTER catidpath1, ADD COLUMN catidpath3 ' . $definitions['posts']['catidpath3'] . ' AFTER catidpath2'); // QA_CATEGORY_DEPTH=4
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
qa_db_upgrade_query('ALTER TABLE ^posts ADD KEY catidpath1 (catidpath1, type, created), ADD KEY catidpath2 (catidpath2, type, created), ADD KEY catidpath3 (catidpath3, type, created), ADD KEY categoryid (categoryid, type, created), ADD KEY catidpath1_2 (catidpath1, updated, type), ADD KEY catidpath2_2 (catidpath2, updated, type), ADD KEY catidpath3_2 (catidpath3, updated, type), ADD KEY categoryid_2 (categoryid, updated, type)'); qa_db_upgrade_query('ALTER TABLE ^posts ADD KEY catidpath1 (catidpath1, type, created), ADD KEY catidpath2 (catidpath2, type, created), ADD KEY catidpath3 (catidpath3, type, created), ADD KEY categoryid (categoryid, type, created), ADD KEY catidpath1_2 (catidpath1, updated, type), ADD KEY catidpath2_2 (catidpath2, updated, type), ADD KEY catidpath3_2 (catidpath3, updated, type), ADD KEY categoryid_2 (categoryid, updated, type)');
...@@ -1085,13 +1096,13 @@ ...@@ -1085,13 +1096,13 @@
qa_db_upgrade_query('ALTER TABLE ^posts ADD CONSTRAINT ^posts_ibfk_3 FOREIGN KEY (categoryid) REFERENCES ^categories(categoryid) ON DELETE SET NULL'); qa_db_upgrade_query('ALTER TABLE ^posts ADD CONSTRAINT ^posts_ibfk_3 FOREIGN KEY (categoryid) REFERENCES ^categories(categoryid) ON DELETE SET NULL');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorecalccategories']=true; $keyrecalc['dorecalccategories'] = true;
break; break;
// Up to here: Version 1.4 betas and release // Up to here: Version 1.4 betas and release
case 31: case 31:
qa_db_upgrade_query('ALTER TABLE ^posts CHANGE COLUMN type type '.$definitions['posts']['type'].', ADD COLUMN updatetype '.$definitions['posts']['updatetype'].' AFTER updated, ADD COLUMN closedbyid '.$definitions['posts']['closedbyid'].' AFTER selchildid, ADD KEY closedbyid (closedbyid), ADD CONSTRAINT ^posts_ibfk_4 FOREIGN KEY (closedbyid) REFERENCES ^posts(postid)'); qa_db_upgrade_query('ALTER TABLE ^posts CHANGE COLUMN type type ' . $definitions['posts']['type'] . ', ADD COLUMN updatetype ' . $definitions['posts']['updatetype'] . ' AFTER updated, ADD COLUMN closedbyid ' . $definitions['posts']['closedbyid'] . ' AFTER selchildid, ADD KEY closedbyid (closedbyid), ADD CONSTRAINT ^posts_ibfk_4 FOREIGN KEY (closedbyid) REFERENCES ^posts(postid)');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1100,13 +1111,13 @@ ...@@ -1100,13 +1111,13 @@
break; break;
case 33: case 33:
qa_db_upgrade_query('ALTER TABLE ^contentwords CHANGE COLUMN type type '.$definitions['contentwords']['type']); qa_db_upgrade_query('ALTER TABLE ^contentwords CHANGE COLUMN type type ' . $definitions['contentwords']['type']);
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
case 34: case 34:
if (!QA_FINAL_EXTERNAL_USERS) { if (!QA_FINAL_EXTERNAL_USERS) {
$keytables=qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW TABLES'))); $keytables = qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW TABLES')));
// might be using messages table shared with another installation, so check if we need to upgrade // might be using messages table shared with another installation, so check if we need to upgrade
if (isset($keytables[qa_db_add_table_prefix('messages')])) if (isset($keytables[qa_db_add_table_prefix('messages')]))
...@@ -1126,7 +1137,7 @@ ...@@ -1126,7 +1137,7 @@
'KEY fromuserid (fromuserid, touserid, created)', 'KEY fromuserid (fromuserid, touserid, created)',
))); )));
$locktablesquery.=', ^messages WRITE'; $locktablesquery .= ', ^messages WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
} }
} }
...@@ -1146,7 +1157,7 @@ ...@@ -1146,7 +1157,7 @@
QA_FINAL_EXTERNAL_USERS ? null : 'CONSTRAINT ^userfavorites_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE', QA_FINAL_EXTERNAL_USERS ? null : 'CONSTRAINT ^userfavorites_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE',
))); )));
$locktablesquery.=', ^userfavorites WRITE'; $locktablesquery .= ', ^userfavorites WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1167,10 +1178,10 @@ ...@@ -1167,10 +1178,10 @@
QA_FINAL_EXTERNAL_USERS ? null : 'CONSTRAINT ^userevents_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE', QA_FINAL_EXTERNAL_USERS ? null : 'CONSTRAINT ^userevents_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE',
))); )));
$locktablesquery.=', ^userevents WRITE'; $locktablesquery .= ', ^userevents WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorefillevents']=true; $keyrecalc['dorefillevents'] = true;
break; break;
case 37: case 37:
...@@ -1188,10 +1199,10 @@ ...@@ -1188,10 +1199,10 @@
'KEY questionid (questionid, entitytype, entityid)', 'KEY questionid (questionid, entitytype, entityid)',
))); )));
$locktablesquery.=', ^sharedevents WRITE'; $locktablesquery .= ', ^sharedevents WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorefillevents']=true; $keyrecalc['dorefillevents'] = true;
break; break;
case 38: case 38:
...@@ -1205,12 +1216,12 @@ ...@@ -1205,12 +1216,12 @@
break; break;
case 40: case 40:
qa_db_upgrade_query('ALTER TABLE ^userpoints ADD COLUMN bonus '.$definitions['userpoints']['bonus'].' AFTER downvoteds'); qa_db_upgrade_query('ALTER TABLE ^userpoints ADD COLUMN bonus ' . $definitions['userpoints']['bonus'] . ' AFTER downvoteds');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
case 41: case 41:
qa_db_upgrade_query('ALTER TABLE ^pages ADD COLUMN permit '.$definitions['pages']['permit'].' AFTER flags'); qa_db_upgrade_query('ALTER TABLE ^pages ADD COLUMN permit ' . $definitions['pages']['permit'] . ' AFTER flags');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1225,7 +1236,7 @@ ...@@ -1225,7 +1236,7 @@
QA_FINAL_EXTERNAL_USERS ? null : 'CONSTRAINT ^usermetas_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE', QA_FINAL_EXTERNAL_USERS ? null : 'CONSTRAINT ^usermetas_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE',
))); )));
$locktablesquery.=', ^usermetas WRITE'; $locktablesquery .= ', ^usermetas WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1240,7 +1251,7 @@ ...@@ -1240,7 +1251,7 @@
'CONSTRAINT ^postmetas_ibfk_1 FOREIGN KEY (postid) REFERENCES ^posts(postid) ON DELETE CASCADE', 'CONSTRAINT ^postmetas_ibfk_1 FOREIGN KEY (postid) REFERENCES ^posts(postid) ON DELETE CASCADE',
))); )));
$locktablesquery.=', ^postmetas WRITE'; $locktablesquery .= ', ^postmetas WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1255,7 +1266,7 @@ ...@@ -1255,7 +1266,7 @@
'CONSTRAINT ^categorymetas_ibfk_1 FOREIGN KEY (categoryid) REFERENCES ^categories(categoryid) ON DELETE CASCADE', 'CONSTRAINT ^categorymetas_ibfk_1 FOREIGN KEY (categoryid) REFERENCES ^categories(categoryid) ON DELETE CASCADE',
))); )));
$locktablesquery.=', ^categorymetas WRITE'; $locktablesquery .= ', ^categorymetas WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1269,7 +1280,7 @@ ...@@ -1269,7 +1280,7 @@
'PRIMARY KEY (tag, title)', 'PRIMARY KEY (tag, title)',
))); )));
$locktablesquery.=', ^tagmetas WRITE'; $locktablesquery .= ', ^tagmetas WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1277,7 +1288,7 @@ ...@@ -1277,7 +1288,7 @@
qa_db_upgrade_query('ALTER TABLE ^posts DROP KEY selchildid, ADD KEY selchildid (selchildid, type, created), ADD COLUMN amaxvote SMALLINT UNSIGNED NOT NULL DEFAULT 0 AFTER acount, ADD KEY type_7 (type, amaxvote, created)'); qa_db_upgrade_query('ALTER TABLE ^posts DROP KEY selchildid, ADD KEY selchildid (selchildid, type, created), ADD COLUMN amaxvote SMALLINT UNSIGNED NOT NULL DEFAULT 0 AFTER acount, ADD KEY type_7 (type, amaxvote, created)');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
$keyrecalc['dorecountposts']=true; $keyrecalc['dorecountposts'] = true;
break; break;
case 47: case 47:
...@@ -1295,7 +1306,7 @@ ...@@ -1295,7 +1306,7 @@
QA_FINAL_EXTERNAL_USERS ? null : 'CONSTRAINT ^usernotices_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE', QA_FINAL_EXTERNAL_USERS ? null : 'CONSTRAINT ^usernotices_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE',
))); )));
$locktablesquery.=', ^usernotices WRITE'; $locktablesquery .= ', ^usernotices WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1303,14 +1314,14 @@ ...@@ -1303,14 +1314,14 @@
case 48: case 48:
if (!QA_FINAL_EXTERNAL_USERS) { if (!QA_FINAL_EXTERNAL_USERS) {
$keycolumns=qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^messages'))); $keycolumns = qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^messages')));
// might be using messages table shared with another installation, so check if we need to upgrade // might be using messages table shared with another installation, so check if we need to upgrade
if (isset($keycolumns['type'])) if (isset($keycolumns['type']))
qa_db_upgrade_progress('Skipping upgrading messages table since it was already upgraded by another Q2A site sharing it.'); qa_db_upgrade_progress('Skipping upgrading messages table since it was already upgraded by another Q2A site sharing it.');
else { else {
qa_db_upgrade_query('ALTER TABLE ^messages ADD COLUMN type '.$definitions['messages']['type'].' AFTER messageid, DROP KEY fromuserid, ADD key type (type, fromuserid, touserid, created), ADD KEY touserid (touserid, type, created)'); qa_db_upgrade_query('ALTER TABLE ^messages ADD COLUMN type ' . $definitions['messages']['type'] . ' AFTER messageid, DROP KEY fromuserid, ADD key type (type, fromuserid, touserid, created), ADD KEY touserid (touserid, type, created)');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
} }
} }
...@@ -1318,26 +1329,26 @@ ...@@ -1318,26 +1329,26 @@
case 49: case 49:
if (!QA_FINAL_EXTERNAL_USERS) { if (!QA_FINAL_EXTERNAL_USERS) {
qa_db_upgrade_query('ALTER TABLE ^users CHANGE COLUMN flags flags '.$definitions['users']['flags']); qa_db_upgrade_query('ALTER TABLE ^users CHANGE COLUMN flags flags ' . $definitions['users']['flags']);
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
} }
break; break;
case 50: case 50:
qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN name '.$definitions['posts']['name'].' AFTER tags'); qa_db_upgrade_query('ALTER TABLE ^posts ADD COLUMN name ' . $definitions['posts']['name'] . ' AFTER tags');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
case 51: case 51:
if (!QA_FINAL_EXTERNAL_USERS) { if (!QA_FINAL_EXTERNAL_USERS) {
$keycolumns=qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^userfields')));
// might be using userfields table shared with another installation, so check if we need to upgrade // might be using userfields table shared with another installation, so check if we need to upgrade
$keycolumns = qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^userfields')));
if (isset($keycolumns['permit'])) if (isset($keycolumns['permit']))
qa_db_upgrade_progress('Skipping upgrading userfields table since it was already upgraded by another Q2A site sharing it.'); qa_db_upgrade_progress('Skipping upgrading userfields table since it was already upgraded by another Q2A site sharing it.');
else { else {
qa_db_upgrade_query('ALTER TABLE ^userfields ADD COLUMN permit '.$definitions['userfields']['permit'].' AFTER flags'); qa_db_upgrade_query('ALTER TABLE ^userfields ADD COLUMN permit ' . $definitions['userfields']['permit'] . ' AFTER flags');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
} }
} }
...@@ -1345,7 +1356,7 @@ ...@@ -1345,7 +1356,7 @@
case 52: case 52:
if (!QA_FINAL_EXTERNAL_USERS) { if (!QA_FINAL_EXTERNAL_USERS) {
$keyindexes=qa_array_to_keys(qa_db_read_all_assoc(qa_db_query_sub('SHOW INDEX FROM ^users'), null, 'Key_name')); $keyindexes = qa_array_to_keys(qa_db_read_all_assoc(qa_db_query_sub('SHOW INDEX FROM ^users'), null, 'Key_name'));
if (isset($keyindexes['created'])) if (isset($keyindexes['created']))
qa_db_upgrade_progress('Skipping upgrading users table since it was already upgraded by another Q2A site sharing it.'); qa_db_upgrade_progress('Skipping upgrading users table since it was already upgraded by another Q2A site sharing it.');
...@@ -1358,7 +1369,7 @@ ...@@ -1358,7 +1369,7 @@
break; break;
case 53: case 53:
qa_db_upgrade_query('ALTER TABLE ^blobs CHANGE COLUMN content content '.$definitions['blobs']['content']); qa_db_upgrade_query('ALTER TABLE ^blobs CHANGE COLUMN content content ' . $definitions['blobs']['content']);
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1377,7 +1388,7 @@ ...@@ -1377,7 +1388,7 @@
QA_FINAL_EXTERNAL_USERS ? null : 'CONSTRAINT ^userlevels_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE', QA_FINAL_EXTERNAL_USERS ? null : 'CONSTRAINT ^userlevels_ibfk_1 FOREIGN KEY (userid) REFERENCES ^users(userid) ON DELETE CASCADE',
))); )));
$locktablesquery.=', ^userlevels WRITE'; $locktablesquery .= ', ^userlevels WRITE';
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
break; break;
...@@ -1385,14 +1396,14 @@ ...@@ -1385,14 +1396,14 @@
case 55: case 55:
if (!QA_FINAL_EXTERNAL_USERS) { if (!QA_FINAL_EXTERNAL_USERS) {
$keycolumns=qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^users')));
// might be using users table shared with another installation, so check if we need to upgrade // might be using users table shared with another installation, so check if we need to upgrade
$keycolumns = qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^users')));
if (isset($keycolumns['wallposts'])) if (isset($keycolumns['wallposts']))
qa_db_upgrade_progress('Skipping upgrading users table since it was already upgraded by another Q2A site sharing it.'); qa_db_upgrade_progress('Skipping upgrading users table since it was already upgraded by another Q2A site sharing it.');
else { else {
qa_db_upgrade_query('ALTER TABLE ^users ADD COLUMN wallposts '.$definitions['users']['wallposts'].' AFTER flags'); qa_db_upgrade_query('ALTER TABLE ^users ADD COLUMN wallposts ' . $definitions['users']['wallposts'] . ' AFTER flags');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
} }
} }
...@@ -1415,8 +1426,8 @@ ...@@ -1415,8 +1426,8 @@
if (isset($keycolumns['fromhidden'])) if (isset($keycolumns['fromhidden']))
qa_db_upgrade_progress('Skipping upgrading messages table since it was already upgraded by another Q2A site sharing it.'); qa_db_upgrade_progress('Skipping upgrading messages table since it was already upgraded by another Q2A site sharing it.');
else { else {
qa_db_upgrade_query('ALTER TABLE ^messages ADD COLUMN fromhidden '.$definitions['messages']['fromhidden'].' AFTER touserid'); qa_db_upgrade_query('ALTER TABLE ^messages ADD COLUMN fromhidden ' . $definitions['messages']['fromhidden'] . ' AFTER touserid');
qa_db_upgrade_query('ALTER TABLE ^messages ADD COLUMN tohidden '.$definitions['messages']['tohidden'].' AFTER fromhidden'); qa_db_upgrade_query('ALTER TABLE ^messages ADD COLUMN tohidden ' . $definitions['messages']['tohidden'] . ' AFTER fromhidden');
qa_db_upgrade_query('ALTER TABLE ^messages ADD KEY fromhidden (fromhidden), ADD KEY tohidden (tohidden)'); qa_db_upgrade_query('ALTER TABLE ^messages ADD KEY fromhidden (fromhidden), ADD KEY tohidden (tohidden)');
qa_db_upgrade_query($locktablesquery); qa_db_upgrade_query($locktablesquery);
...@@ -1458,15 +1469,15 @@ ...@@ -1458,15 +1469,15 @@
$oldlength = qa_db_read_one_value(qa_db_query_sub($query, QA_FINAL_MYSQL_DATABASE, $tablename)); $oldlength = qa_db_read_one_value(qa_db_query_sub($query, QA_FINAL_MYSQL_DATABASE, $tablename));
if ($oldlength < $newlength) { if ($oldlength < $newlength) {
qa_db_upgrade_query('ALTER TABLE ^posts MODIFY content '.$definitions['posts']['content']); qa_db_upgrade_query('ALTER TABLE ^posts MODIFY content ' . $definitions['posts']['content']);
} }
break; break;
case 62: case 62:
if (!QA_FINAL_EXTERNAL_USERS) { if (!QA_FINAL_EXTERNAL_USERS) {
$keycolumns=qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^users')));
// might be using users table shared with another installation, so check if we need to upgrade // might be using users table shared with another installation, so check if we need to upgrade
$keycolumns = qa_array_to_keys(qa_db_read_all_values(qa_db_query_sub('SHOW COLUMNS FROM ^users')));
if (isset($keycolumns['passhash'])) if (isset($keycolumns['passhash']))
qa_db_upgrade_progress(sprintf($skipMessage, 'users')); qa_db_upgrade_progress(sprintf($skipMessage, 'users'));
...@@ -1484,11 +1495,11 @@ ...@@ -1484,11 +1495,11 @@
if (strtolower($fieldDef['Type']) === 'varbinary(16)') if (strtolower($fieldDef['Type']) === 'varbinary(16)')
qa_db_upgrade_progress(sprintf($skipMessage, 'cookies')); qa_db_upgrade_progress(sprintf($skipMessage, 'cookies'));
else { else {
qa_db_upgrade_query('ALTER TABLE ^cookies MODIFY writeip '.$definitions['cookies']['writeip'].', MODIFY createip '.$definitions['cookies']['createip']); qa_db_upgrade_query('ALTER TABLE ^cookies MODIFY writeip ' . $definitions['cookies']['writeip'] . ', MODIFY createip ' . $definitions['cookies']['createip']);
qa_db_upgrade_query('UPDATE ^cookies SET writeip = UNHEX(HEX(CAST(writeip AS UNSIGNED))), createip = UNHEX(HEX(CAST(createip AS UNSIGNED)))'); qa_db_upgrade_query('UPDATE ^cookies SET writeip = UNHEX(HEX(CAST(writeip AS UNSIGNED))), createip = UNHEX(HEX(CAST(createip AS UNSIGNED)))');
} }
qa_db_upgrade_query('ALTER TABLE ^iplimits MODIFY ip '.$definitions['iplimits']['ip']); qa_db_upgrade_query('ALTER TABLE ^iplimits MODIFY ip ' . $definitions['iplimits']['ip']);
qa_db_upgrade_query('UPDATE ^iplimits SET ip = UNHEX(HEX(CAST(ip AS UNSIGNED)))'); qa_db_upgrade_query('UPDATE ^iplimits SET ip = UNHEX(HEX(CAST(ip AS UNSIGNED)))');
// check for shared blobs table // check for shared blobs table
...@@ -1496,11 +1507,11 @@ ...@@ -1496,11 +1507,11 @@
if (strtolower($fieldDef['Type']) === 'varbinary(16)') if (strtolower($fieldDef['Type']) === 'varbinary(16)')
qa_db_upgrade_progress(sprintf($skipMessage, 'blobs')); qa_db_upgrade_progress(sprintf($skipMessage, 'blobs'));
else { else {
qa_db_upgrade_query('ALTER TABLE ^blobs MODIFY createip '.$definitions['blobs']['createip']); qa_db_upgrade_query('ALTER TABLE ^blobs MODIFY createip ' . $definitions['blobs']['createip']);
qa_db_upgrade_query('UPDATE ^blobs SET createip = UNHEX(HEX(CAST(createip AS UNSIGNED)))'); qa_db_upgrade_query('UPDATE ^blobs SET createip = UNHEX(HEX(CAST(createip AS UNSIGNED)))');
} }
qa_db_upgrade_query('ALTER TABLE ^posts MODIFY lastviewip '.$definitions['posts']['lastviewip'].', MODIFY lastip '.$definitions['posts']['lastip'].', MODIFY createip '.$definitions['posts']['createip']); qa_db_upgrade_query('ALTER TABLE ^posts MODIFY lastviewip ' . $definitions['posts']['lastviewip'] . ', MODIFY lastip ' . $definitions['posts']['lastip'] . ', MODIFY createip ' . $definitions['posts']['createip']);
qa_db_upgrade_query('UPDATE ^posts SET lastviewip = UNHEX(HEX(CAST(lastviewip AS UNSIGNED))), lastip = UNHEX(HEX(CAST(lastip AS UNSIGNED))), createip = UNHEX(HEX(CAST(createip AS UNSIGNED)))'); qa_db_upgrade_query('UPDATE ^posts SET lastviewip = UNHEX(HEX(CAST(lastviewip AS UNSIGNED))), lastip = UNHEX(HEX(CAST(lastip AS UNSIGNED))), createip = UNHEX(HEX(CAST(createip AS UNSIGNED)))');
if (!QA_FINAL_EXTERNAL_USERS) { if (!QA_FINAL_EXTERNAL_USERS) {
...@@ -1509,7 +1520,7 @@ ...@@ -1509,7 +1520,7 @@
if (strtolower($fieldDef['Type']) === 'varbinary(16)') if (strtolower($fieldDef['Type']) === 'varbinary(16)')
qa_db_upgrade_progress(sprintf($skipMessage, 'users')); qa_db_upgrade_progress(sprintf($skipMessage, 'users'));
else { else {
qa_db_upgrade_query('ALTER TABLE ^users MODIFY createip '.$definitions['users']['createip'].', MODIFY loginip '.$definitions['users']['loginip'].', MODIFY writeip '.$definitions['users']['writeip']); qa_db_upgrade_query('ALTER TABLE ^users MODIFY createip ' . $definitions['users']['createip'] . ', MODIFY loginip ' . $definitions['users']['loginip'] . ', MODIFY writeip ' . $definitions['users']['writeip']);
qa_db_upgrade_query('UPDATE ^users SET createip = UNHEX(HEX(CAST(createip AS UNSIGNED))), loginip = UNHEX(HEX(CAST(loginip AS UNSIGNED))), writeip = UNHEX(HEX(CAST(writeip AS UNSIGNED)))'); qa_db_upgrade_query('UPDATE ^users SET createip = UNHEX(HEX(CAST(createip AS UNSIGNED))), loginip = UNHEX(HEX(CAST(loginip AS UNSIGNED))), writeip = UNHEX(HEX(CAST(writeip AS UNSIGNED)))');
} }
} }
...@@ -1529,7 +1540,7 @@ ...@@ -1529,7 +1540,7 @@
qa_db_set_db_version($newversion); qa_db_set_db_version($newversion);
if (qa_db_get_db_version()!=$newversion) if (qa_db_get_db_version() != $newversion)
qa_fatal_error('Could not increment database version'); qa_fatal_error('Could not increment database version');
} }
...@@ -1541,50 +1552,50 @@ ...@@ -1541,50 +1552,50 @@
while ($state) { while ($state) {
set_time_limit(60); set_time_limit(60);
$stoptime=time()+2; $stoptime = time() + 2;
while ( qa_recalc_perform_step($state) && (time()<$stoptime) ) while (qa_recalc_perform_step($state) && (time() < $stoptime))
; ;
qa_db_upgrade_progress(qa_recalc_get_message($state)); qa_db_upgrade_progress(qa_recalc_get_message($state));
} }
} }
function qa_db_upgrade_table_columns($definitions, $table, $columns) /**
/* * Reset the definitions of $columns in $table according to the $definitions array
Reset the definitions of $columns in $table according to the $definitions array * @param $definitions
*/ * @param $table
{ * @param $columns
$sqlchanges=array(); */
function qa_db_upgrade_table_columns($definitions, $table, $columns)
{
$sqlchanges = array();
foreach ($columns as $column) foreach ($columns as $column)
$sqlchanges[]='CHANGE COLUMN '.$column.' '.$column.' '.$definitions[$table][$column]; $sqlchanges[] = 'CHANGE COLUMN ' . $column . ' ' . $column . ' ' . $definitions[$table][$column];
qa_db_upgrade_query('ALTER TABLE ^'.$table.' '.implode(', ', $sqlchanges)); qa_db_upgrade_query('ALTER TABLE ^' . $table . ' ' . implode(', ', $sqlchanges));
} }
function qa_db_upgrade_query($query) /**
/* * Perform upgrade $query and output progress to the browser
Perform upgrade $query and output progress to the browser * @param $query
*/ */
{ function qa_db_upgrade_query($query)
qa_db_upgrade_progress('Running query: '.qa_db_apply_sub($query, array()).' ...'); {
qa_db_upgrade_progress('Running query: ' . qa_db_apply_sub($query, array()) . ' ...');
qa_db_query_sub($query); qa_db_query_sub($query);
} }
function qa_db_upgrade_progress($text) /**
/* * Output $text to the browser (after converting to HTML) and do all we can to get it displayed
Output $text to the browser (after converting to HTML) and do all we can to get it displayed * @param $text
*/ */
{ function qa_db_upgrade_progress($text)
echo qa_html($text).str_repeat(' ', 1024)."<br><br>\n"; {
echo qa_html($text) . str_repeat(' ', 1024) . "<br><br>\n";
flush(); flush();
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
...@@ -20,58 +20,66 @@ ...@@ -20,58 +20,66 @@
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
*/
function qa_db_pages_get_for_reindexing($startpageid, $count)
{
return qa_db_read_all_assoc(qa_db_query_sub( return qa_db_read_all_assoc(qa_db_query_sub(
'SELECT pageid, flags, tags, heading, content FROM ^pages WHERE pageid>=# ORDER BY pageid LIMIT #', 'SELECT pageid, flags, tags, heading, content FROM ^pages WHERE pageid>=# ORDER BY pageid LIMIT #',
$startpageid, $count $startpageid, $count
), 'pageid'); ), 'pageid');
} }
// For reindexing posts... // For reindexing posts...
function qa_db_posts_get_for_reindexing($startpostid, $count) /**
/* * 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 * @param $startpostid
*/ * @param $count
{ * @return array
*/
function qa_db_posts_get_for_reindexing($startpostid, $count)
{
return qa_db_read_all_assoc(qa_db_query_sub( return qa_db_read_all_assoc(qa_db_query_sub(
"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 #", "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 $startpostid, $count
), 'postid'); ), 'postid');
} }
function qa_db_prepare_for_reindexing($firstpostid, $lastpostid) /**
/* * Prepare posts $firstpostid to $lastpostid for reindexing in the database by removing their prior index entries
Prepare posts $firstpostid to $lastpostid for reindexing in the database by removing their prior index entries * @param $firstpostid
*/ * @param $lastpostid
{ */
function qa_db_prepare_for_reindexing($firstpostid, $lastpostid)
{
qa_db_query_sub( qa_db_query_sub(
'DELETE FROM ^titlewords WHERE postid>=# AND postid<=#', 'DELETE FROM ^titlewords WHERE postid>=# AND postid<=#',
$firstpostid, $lastpostid $firstpostid, $lastpostid
...@@ -91,14 +99,15 @@ ...@@ -91,14 +99,15 @@
'DELETE FROM ^posttags WHERE postid>=# AND postid<=#', 'DELETE FROM ^posttags WHERE postid>=# AND postid<=#',
$firstpostid, $lastpostid $firstpostid, $lastpostid
); );
} }
function qa_db_truncate_indexes($firstpostid) /**
/* * Remove any rows in the database word indexes with postid from $firstpostid upwards
Remove any rows in the database word indexes with postid from $firstpostid upwards * @param $firstpostid
*/ */
{ function qa_db_truncate_indexes($firstpostid)
{
qa_db_query_sub( qa_db_query_sub(
'DELETE FROM ^titlewords WHERE postid>=#', 'DELETE FROM ^titlewords WHERE postid>=#',
$firstpostid $firstpostid
...@@ -118,37 +127,42 @@ ...@@ -118,37 +127,42 @@
'DELETE FROM ^posttags WHERE postid>=#', 'DELETE FROM ^posttags WHERE postid>=#',
$firstpostid $firstpostid
); );
} }
function qa_db_count_words() /**
/* * Return the number of words currently referenced in the database
Return the number of words currently referenced in the database */
*/ function qa_db_count_words()
{ {
return qa_db_read_one_value(qa_db_query_sub( return qa_db_read_one_value(qa_db_query_sub(
'SELECT COUNT(*) FROM ^words' 'SELECT COUNT(*) FROM ^words'
)); ));
} }
function qa_db_words_prepare_for_recounting($startwordid, $count) /**
/* * Return the ids of up to $count words in the database starting from $startwordid
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( return qa_db_read_all_values(qa_db_query_sub(
'SELECT wordid FROM ^words WHERE wordid>=# ORDER BY wordid LIMIT #', 'SELECT wordid FROM ^words WHERE wordid>=# ORDER BY wordid LIMIT #',
$startwordid, $count $startwordid, $count
)); ));
} }
function qa_db_words_recount($firstwordid, $lastwordid) /**
/* * Recalculate the cached counts for words $firstwordid to $lastwordid in the database
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( 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', '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 $firstwordid, $lastwordid
...@@ -173,43 +187,50 @@ ...@@ -173,43 +187,50 @@
'DELETE FROM ^words WHERE wordid>=# AND wordid<=# AND titlecount=0 AND contentcount=0 AND tagwordcount=0 AND tagcount=0', 'DELETE FROM ^words WHERE wordid>=# AND wordid<=# AND titlecount=0 AND contentcount=0 AND tagwordcount=0 AND tagcount=0',
$firstwordid, $lastwordid $firstwordid, $lastwordid
); );
} }
// For recalculating numbers of votes and answers for questions... // 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 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( return qa_db_read_all_values(qa_db_query_sub(
'SELECT postid FROM ^posts WHERE postid>=# ORDER BY postid LIMIT #', 'SELECT postid FROM ^posts WHERE postid>=# ORDER BY postid LIMIT #',
$startpostid, $count $startpostid, $count
)); ));
} }
function qa_db_posts_votes_recount($firstpostid, $lastpostid) /**
/* * Recalculate the cached vote counts for posts $firstpostid to $lastpostid in the database
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( 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', '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 $firstpostid, $lastpostid
); );
qa_db_hotness_update($firstpostid, $lastpostid); qa_db_hotness_update($firstpostid, $lastpostid);
} }
function qa_db_posts_answers_recount($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
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
{ */
require_once QA_INCLUDE_DIR.'db/hotness.php'; function qa_db_posts_answers_recount($firstpostid, $lastpostid)
{
require_once QA_INCLUDE_DIR . 'db/hotness.php';
qa_db_query_sub( 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', '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',
...@@ -217,17 +238,20 @@ ...@@ -217,17 +238,20 @@
); );
qa_db_hotness_update($firstpostid, $lastpostid); qa_db_hotness_update($firstpostid, $lastpostid);
} }
// For recalculating user points... // For recalculating user points...
function qa_db_users_get_for_recalc_points($startuserid, $count) /**
/* * Return the ids of up to $count users in the database starting from $startuserid
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 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) 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 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 #', '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 #',
...@@ -238,29 +262,31 @@ ...@@ -238,29 +262,31 @@
'SELECT DISTINCT userid FROM ^users WHERE userid>=# ORDER BY userid LIMIT #', 'SELECT DISTINCT userid FROM ^users WHERE userid>=# ORDER BY userid LIMIT #',
$startuserid, $count $startuserid, $count
)); ));
} }
function qa_db_users_recalc_points($firstuserid, $lastuserid) /**
/* * Recalculate all userpoints columns for users $firstuserid to $lastuserid in the database
Recalculate all userpoints columns for users $firstuserid to $lastuserid in the database * @param $firstuserid
*/ * @param $lastuserid
{ */
require_once QA_INCLUDE_DIR.'db/points.php'; function qa_db_users_recalc_points($firstuserid, $lastuserid)
{
require_once QA_INCLUDE_DIR . 'db/points.php';
$qa_userpoints_calculations=qa_db_points_calculations(); $qa_userpoints_calculations = qa_db_points_calculations();
qa_db_query_sub( qa_db_query_sub(
'DELETE FROM ^userpoints WHERE userid>=# AND userid<=# AND bonus=0', // delete those with no bonus 'DELETE FROM ^userpoints WHERE userid>=# AND userid<=# AND bonus=0', // delete those with no bonus
$firstuserid, $lastuserid $firstuserid, $lastuserid
); );
$zeropoints='points=0'; $zeropoints = 'points=0';
foreach ($qa_userpoints_calculations as $field => $calculation) foreach ($qa_userpoints_calculations as $field => $calculation)
$zeropoints.=', '.$field.'=0'; $zeropoints .= ', ' . $field . '=0';
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^userpoints SET '.$zeropoints.' WHERE userid>=# AND userid<=#', // zero out the rest 'UPDATE ^userpoints SET ' . $zeropoints . ' WHERE userid>=# AND userid<=#', // zero out the rest
$firstuserid, $lastuserid $firstuserid, $lastuserid
); );
...@@ -275,150 +301,165 @@ ...@@ -275,150 +301,165 @@
$firstuserid, $lastuserid $firstuserid, $lastuserid
); );
$updatepoints=(int)qa_opt('points_base'); $updatepoints = (int)qa_opt('points_base');
foreach ($qa_userpoints_calculations as $field => $calculation) { foreach ($qa_userpoints_calculations as $field => $calculation) {
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^userpoints, (SELECT userid_src.userid, '.str_replace('~', ' BETWEEN # AND #', $calculation['formula']).' GROUP BY userid) AS results '. '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', 'SET ^userpoints.' . $field . '=results.' . $field . ' WHERE ^userpoints.userid=results.userid',
$firstuserid, $lastuserid $firstuserid, $lastuserid
); );
$updatepoints.='+('.((int)$calculation['multiple']).'*'.$field.')'; $updatepoints .= '+(' . ((int)$calculation['multiple']) . '*' . $field . ')';
} }
qa_db_query_sub( qa_db_query_sub(
'UPDATE ^userpoints SET points='.$updatepoints.'+bonus WHERE userid>=# AND userid<=#', 'UPDATE ^userpoints SET points=' . $updatepoints . '+bonus WHERE userid>=# AND userid<=#',
$firstuserid, $lastuserid $firstuserid, $lastuserid
); );
} }
function qa_db_truncate_userpoints($lastuserid) /**
/* * Remove any rows in the userpoints table where userid is greater than $lastuserid
Remove any rows in the userpoints table where userid is greater than $lastuserid * @param $lastuserid
*/ */
{ function qa_db_truncate_userpoints($lastuserid)
{
qa_db_query_sub( qa_db_query_sub(
'DELETE FROM ^userpoints WHERE userid>#', 'DELETE FROM ^userpoints WHERE userid>#',
$lastuserid $lastuserid
); );
} }
// For refilling event streams... // For refilling event streams...
function qa_db_qs_get_for_event_refilling($startpostid, $count) /**
/* * Return the ids of up to $count questions in the database starting from $startpostid
Return the ids of up to $count questions in the database starting from $startpostid * @param $startpostid
*/ * @param $count
{ * @return array
*/
function qa_db_qs_get_for_event_refilling($startpostid, $count)
{
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>=# AND LEFT(type, 1)='Q' ORDER BY postid LIMIT #", "SELECT postid FROM ^posts WHERE postid>=# AND LEFT(type, 1)='Q' ORDER BY postid LIMIT #",
$startpostid, $count $startpostid, $count
)); ));
} }
// For recalculating categories... // For recalculating categories...
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 the ids of up to $count posts (including queued/hidden) in the database starting from $startpostid * @param $startpostid
*/ * @param $count
{ * @return array
*/
function qa_db_posts_get_for_recategorizing($startpostid, $count)
{
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 postid FROM ^posts WHERE postid>=# ORDER BY postid LIMIT #",
$startpostid, $count $startpostid, $count
)); ));
} }
function qa_db_posts_recalc_categoryid($firstpostid, $lastpostid) /**
/* * Recalculate the (exact) categoryid for the posts (including queued/hidden) between $firstpostid and $lastpostid
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
in the database, where the category of comments and answers is set by the category of the antecedent question * @param $firstpostid
*/ * @param $lastpostid
{ */
function qa_db_posts_recalc_categoryid($firstpostid, $lastpostid)
{
qa_db_query_sub( 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", "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 $firstpostid, $lastpostid
); );
} }
function qa_db_categories_get_for_recalcs($startcategoryid, $count) /**
/* * Return the ids of up to $count categories in the database starting from $startcategoryid
Return the ids of up to $count categories in the database starting from $startcategoryid * @param $startcategoryid
*/ * @param $count
{ * @return array
*/
function qa_db_categories_get_for_recalcs($startcategoryid, $count)
{
return qa_db_read_all_values(qa_db_query_sub( return qa_db_read_all_values(qa_db_query_sub(
"SELECT categoryid FROM ^categories WHERE categoryid>=# ORDER BY categoryid LIMIT #", "SELECT categoryid FROM ^categories WHERE categoryid>=# ORDER BY categoryid LIMIT #",
$startcategoryid, $count $startcategoryid, $count
)); ));
} }
// For deleting hidden posts... // For deleting hidden posts...
function qa_db_posts_get_for_deleting($type, $startpostid=0, $limit=null) /**
/* * Return the ids of up to $limit posts of $type that can be deleted from the database (i.e. have no dependents)
Return the ids of up to $limit posts of $type that can be deleted from the database (i.e. have no dependents) * @param $type
*/ * @param int $startpostid
{ * @param $limit
$limitsql=isset($limit) ? (' ORDER BY ^posts.postid LIMIT '.(int)$limit) : ''; * @return array
*/
function qa_db_posts_get_for_deleting($type, $startpostid = 0, $limit = null)
{
$limitsql = isset($limit) ? (' ORDER BY ^posts.postid LIMIT ' . (int)$limit) : '';
return qa_db_read_all_values(qa_db_query_sub( 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, "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 $type . '_HIDDEN', $startpostid
)); ));
} }
// For moving blobs between database and disk... // For moving blobs between database and disk...
function qa_db_count_blobs_in_db() /**
/* * Return the number of blobs whose content is stored in the database, rather than on 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 qa_db_read_one_value(qa_db_query_sub('SELECT COUNT(*) FROM ^blobs WHERE content IS NOT NULL'));
} }
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 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( 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', 'SELECT blobid, content, format FROM ^blobs WHERE blobid>=# AND content IS NOT NULL LIMIT 1',
$startblobid $startblobid
), true); ), true);
} }
function qa_db_count_blobs_on_disk() /**
/* * Return the number of blobs whose content is stored on disk, rather than in the database
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 qa_db_read_one_value(qa_db_query_sub('SELECT COUNT(*) FROM ^blobs WHERE content IS NULL'));
} }
function qa_db_get_next_blob_on_disk($startblobid) /**
/* * Return the id and format of the first blob whose content is stored on disk starting from $startblobid
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( return qa_db_read_one_assoc(qa_db_query_sub(
'SELECT blobid, format FROM ^blobs WHERE blobid>=# AND content IS NULL LIMIT 1', 'SELECT blobid, format FROM ^blobs WHERE blobid>=# AND content IS NULL LIMIT 1',
$startblobid $startblobid
), true); ), true);
} }
/*
Omit PHP closing tag to help avoid accidental output
*/
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