"COALESCE(parent2.parentid, parent1.parentid, parent0.parentid, parent0.categoryid) AS catidpath1, ".
"IF (parent2.parentid IS NOT NULL, parent1.parentid, IF (parent1.parentid IS NOT NULL, parent0.parentid, IF (parent0.parentid IS NOT NULL, parent0.categoryid, NULL))) AS catidpath2, ".
"IF (parent2.parentid IS NOT NULL, parent0.parentid, IF (parent1.parentid IS NOT NULL, parent0.categoryid, NULL)) AS catidpath3 ".
"FROM ^posts LEFT JOIN ^categories AS parent0 ON ^posts.categoryid=parent0.categoryid LEFT JOIN ^categories AS parent1 ON parent0.parentid=parent1.categoryid LEFT JOIN ^categories AS parent2 ON parent1.parentid=parent2.categoryid WHERE ^posts.postid BETWEEN # AND #) AS a SET x.catidpath1=a.catidpath1, x.catidpath2=a.catidpath2, x.catidpath3=a.catidpath3 WHERE x.postid=a.postid",
$firstpostid,$lastpostid
);// requires QA_CATEGORY_DEPTH=4
}
/**
* Get the full category path (including categoryid) for $postid
* @param $postid
* @return array|null
*/
functionqa_db_post_get_category_path($postid)
{
returnqa_db_read_one_assoc(qa_db_query_sub(
'SELECT categoryid, catidpath1, catidpath2, catidpath3 FROM ^posts WHERE postid=#',
$postid
));// requires QA_CATEGORY_DEPTH=4
}
/**
* Update the cached number of answers for $questionid in the database, along with the highest netvotes of any of its answers
* @param $questionid
*/
functionqa_db_post_acount_update($questionid)
{
if(qa_should_update_counts()){
qa_db_query_sub(
qa_db_query_sub(
'INSERT INTO ^posts (categoryid, type, parentid, userid, cookieid, createip, title, content, format, tags, notify, name, created) '.
"UPDATE ^posts AS x, (SELECT COUNT(*) AS acount, COALESCE(GREATEST(MAX(netvotes), 0), 0) AS amaxvote FROM ^posts WHERE parentid=# AND type='A') AS a SET x.acount=a.acount, x.amaxvote=a.amaxvote WHERE x.postid=#",
// This seemed like the most sensible approach which avoids explicitly calculating the category's depth in the hierarchy
qa_db_query_sub(
qa_db_query_sub(
"UPDATE ^posts AS x, (SELECT ^posts.postid, ".
"UPDATE ^categories SET qcount=GREATEST( (SELECT COUNT(*) FROM ^posts WHERE categoryid=# AND type='Q'), (SELECT COUNT(*) FROM ^posts WHERE catidpath1=# AND type='Q'), (SELECT COUNT(*) FROM ^posts WHERE catidpath2=# AND type='Q'), (SELECT COUNT(*) FROM ^posts WHERE catidpath3=# AND type='Q') ) WHERE categoryid=#",
"COALESCE(parent2.parentid, parent1.parentid, parent0.parentid, parent0.categoryid) AS catidpath1, ".
"IF (parent2.parentid IS NOT NULL, parent1.parentid, IF (parent1.parentid IS NOT NULL, parent0.parentid, IF (parent0.parentid IS NOT NULL, parent0.categoryid, NULL))) AS catidpath2, ".
"IF (parent2.parentid IS NOT NULL, parent0.parentid, IF (parent1.parentid IS NOT NULL, parent0.categoryid, NULL)) AS catidpath3 ".
"FROM ^posts LEFT JOIN ^categories AS parent0 ON ^posts.categoryid=parent0.categoryid LEFT JOIN ^categories AS parent1 ON parent0.parentid=parent1.categoryid LEFT JOIN ^categories AS parent2 ON parent1.parentid=parent2.categoryid WHERE ^posts.postid BETWEEN # AND #) AS a SET x.catidpath1=a.catidpath1, x.catidpath2=a.catidpath2, x.catidpath3=a.catidpath3 WHERE x.postid=a.postid",
$firstpostid,$lastpostid
);// requires QA_CATEGORY_DEPTH=4
);// requires QA_CATEGORY_DEPTH=4
}
}
}
/**
* Add rows into the database title index, where $postid contains the words $wordids - this does the same sort
* of thing as qa_db_posttags_add_post_wordids() in a different way, for no particularly good reason.
'INSERT INTO ^titlewords (postid, wordid) VALUES #',
/*
$rowstoadd
Get the full category path (including categoryid) for $postid
);
*/
{
returnqa_db_read_one_assoc(qa_db_query_sub(
'SELECT categoryid, catidpath1, catidpath2, catidpath3 FROM ^posts WHERE postid=#',
$postid
));// requires QA_CATEGORY_DEPTH=4
}
functionqa_db_post_acount_update($questionid)
/*
Update the cached number of answers for $questionid in the database, along with the highest netvotes of any of its answers
*/
{
if(qa_should_update_counts())
qa_db_query_sub(
"UPDATE ^posts AS x, (SELECT COUNT(*) AS acount, COALESCE(GREATEST(MAX(netvotes), 0), 0) AS amaxvote FROM ^posts WHERE parentid=# AND type='A') AS a SET x.acount=a.acount, x.amaxvote=a.amaxvote WHERE x.postid=#",
$questionid,$questionid
);
}
}
}
/**
* Add rows into the database content index, where $postid (of $type, with the antecedent $questionid)
* has words as per the keys of $wordidcounts, and the corresponding number of those words in the values.
// This seemed like the most sensible approach which avoids explicitly calculating the category's depth in the hierarchy
{
if(count($wordids)){
qa_db_query_sub(
$rowstoadd=array();
"UPDATE ^categories SET qcount=GREATEST( (SELECT COUNT(*) FROM ^posts WHERE categoryid=# AND type='Q'), (SELECT COUNT(*) FROM ^posts WHERE catidpath1=# AND type='Q'), (SELECT COUNT(*) FROM ^posts WHERE catidpath2=# AND type='Q'), (SELECT COUNT(*) FROM ^posts WHERE catidpath3=# AND type='Q') ) WHERE categoryid=#",
Add rows into the database index of whole tags, where $postid contains the tags $wordids
*/
{
if(count($wordids))
qa_db_query_sub(
'INSERT INTO ^posttags (postid, wordid, postcreated) SELECT postid, wordid, created FROM ^words, ^posts WHERE postid=# AND wordid IN ($)',
$postid,$wordids
);
}
/**
* Return an array mapping each word in $words to its corresponding wordid in the database, adding any that are missing
* @param $words
* @return array
*/
functionqa_db_word_mapto_ids_add($words)
{
$wordtoid=qa_db_word_mapto_ids($words);
functionqa_db_word_mapto_ids($words)
$wordstoadd=array();
/*
foreach($wordsas$word){
Return an array mapping each word in $words to its corresponding wordid in the database
if(!isset($wordtoid[$word]))
*/
$wordstoadd[]=$word;
{
if(count($words))
returnqa_db_read_all_assoc(qa_db_query_sub(
'SELECT wordid, word FROM ^words WHERE word IN ($)',$words
),'word','wordid');
else
returnarray();
}
}
if(count($wordstoadd)){
qa_db_query_sub('LOCK TABLES ^words WRITE');// to prevent two requests adding the same word
functionqa_db_word_mapto_ids_add($words)
$wordtoid=qa_db_word_mapto_ids($words);// map it again in case table content changed before it was locked
/*
Return an array mapping each word in $words to its corresponding wordid in the database, adding any that are missing
*/
{
$wordtoid=qa_db_word_mapto_ids($words);
$wordstoadd=array();
$rowstoadd=array();
foreach($wordsas$word)
foreach($wordsas$word){
if(!isset($wordtoid[$word]))
if(!isset($wordtoid[$word]))
$wordstoadd[]=$word;
$rowstoadd[]=array($word);
}
if(count($wordstoadd)){
qa_db_query_sub('LOCK TABLES ^words WRITE');// to prevent two requests adding the same word
$wordtoid=qa_db_word_mapto_ids($words);// map it again in case table content changed before it was locked
$rowstoadd=array();
foreach($wordsas$word)
if(!isset($wordtoid[$word]))
$rowstoadd[]=array($word);
qa_db_query_sub('INSERT IGNORE INTO ^words (word) VALUES $',$rowstoadd);
qa_db_query_sub('UNLOCK TABLES');
qa_db_query_sub('INSERT IGNORE INTO ^words (word) VALUES $',$rowstoadd);
$wordtoid=qa_db_word_mapto_ids($words);// do it one last time
qa_db_query_sub('UNLOCK TABLES');
}
return$wordtoid;
$wordtoid=qa_db_word_mapto_ids($words);// do it one last time
}
}
return$wordtoid;
}
functionqa_db_word_titlecount_update($wordids)
/*
/**
Update the titlecount column in the database for the words in $wordids, based on how many posts they appear in the title of
* Update the titlecount column in the database for the words in $wordids, based on how many posts they appear in the title of
*/
* @param $wordids
{
*/
if(qa_should_update_counts()&&count($wordids))
functionqa_db_word_titlecount_update($wordids)
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 IN (#) GROUP BY wordid) AS a SET x.titlecount=a.titlecount WHERE x.wordid=a.wordid',
if(qa_should_update_counts()&&count($wordids)){
$wordids
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 IN (#) GROUP BY wordid) AS a SET x.titlecount=a.titlecount WHERE x.wordid=a.wordid',
$wordids
);
}
}
}
functionqa_db_word_contentcount_update($wordids)
/**
/*
* Update the contentcount column in the database for the words in $wordids, based on how many posts they appear in the content of
Update the contentcount column in the database for the words in $wordids, based on how many posts they appear in the content of
* @param $wordids
*/
*/
{
functionqa_db_word_contentcount_update($wordids)
if(qa_should_update_counts()&&count($wordids))
{
qa_db_query_sub(
if(qa_should_update_counts()&&count($wordids)){
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^contentwords.wordid) AS contentcount FROM ^words LEFT JOIN ^contentwords ON ^contentwords.wordid=^words.wordid WHERE ^words.wordid IN (#) GROUP BY wordid) AS a SET x.contentcount=a.contentcount WHERE x.wordid=a.wordid',
qa_db_query_sub(
$wordids
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^contentwords.wordid) AS contentcount FROM ^words LEFT JOIN ^contentwords ON ^contentwords.wordid=^words.wordid WHERE ^words.wordid IN (#) GROUP BY wordid) AS a SET x.contentcount=a.contentcount WHERE x.wordid=a.wordid',
);
$wordids
);
}
}
}
functionqa_db_word_tagwordcount_update($wordids)
/**
/*
* Update the tagwordcount column in the database for the individual tag words in $wordids, based on how many posts they appear in the tags of
Update the tagwordcount column in the database for the individual tag words in $wordids, based on how many posts they appear in the tags of
* @param $wordids
*/
*/
{
functionqa_db_word_tagwordcount_update($wordids)
if(qa_should_update_counts()&&count($wordids))
{
qa_db_query_sub(
if(qa_should_update_counts()&&count($wordids)){
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^tagwords.wordid) AS tagwordcount FROM ^words LEFT JOIN ^tagwords ON ^tagwords.wordid=^words.wordid WHERE ^words.wordid IN (#) GROUP BY wordid) AS a SET x.tagwordcount=a.tagwordcount WHERE x.wordid=a.wordid',
qa_db_query_sub(
$wordids
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^tagwords.wordid) AS tagwordcount FROM ^words LEFT JOIN ^tagwords ON ^tagwords.wordid=^words.wordid WHERE ^words.wordid IN (#) GROUP BY wordid) AS a SET x.tagwordcount=a.tagwordcount WHERE x.wordid=a.wordid',
);
$wordids
);
}
}
}
functionqa_db_word_tagcount_update($wordids)
/**
/*
* Update the tagcount column in the database for the whole tags in $wordids, based on how many posts they appear as tags of
Update the tagcount column in the database for the whole tags in $wordids, based on how many posts they appear as tags of
* @param $wordids
*/
*/
{
functionqa_db_word_tagcount_update($wordids)
if(qa_should_update_counts()&&count($wordids))
{
qa_db_query_sub(
if(qa_should_update_counts()&&count($wordids)){
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^posttags.wordid) AS tagcount FROM ^words LEFT JOIN ^posttags ON ^posttags.wordid=^words.wordid WHERE ^words.wordid IN (#) GROUP BY wordid) AS a SET x.tagcount=a.tagcount WHERE x.wordid=a.wordid',
qa_db_query_sub(
$wordids
'UPDATE ^words AS x, (SELECT ^words.wordid, COUNT(^posttags.wordid) AS tagcount FROM ^words LEFT JOIN ^posttags ON ^posttags.wordid=^words.wordid WHERE ^words.wordid IN (#) GROUP BY wordid) AS a SET x.tagcount=a.tagcount WHERE x.wordid=a.wordid',
);
$wordids
);
}
}
}
functionqa_db_qcount_update()
/**
/*
* Update the cached count in the database of the number of questions (excluding hidden/queued)
Update the cached count in the database of the number of questions (excluding hidden/queued)
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;
}
}
functionqa_db_uservote_set($postid,$userid,$vote)
/**
/*
* Set the vote for $userid on $postid to $vote in the database
Set the vote for $userid on $postid to $vote in the database
* @param $postid
*/
* @param $userid
{
* @param $vote
$vote=max(min(($vote),1),-1);
*/
functionqa_db_uservote_set($postid,$userid,$vote)
qa_db_query_sub(
{
'INSERT INTO ^uservotes (postid, userid, vote, flag) VALUES (#, #, #, 0) ON DUPLICATE KEY UPDATE vote=#',
$vote=max(min(($vote),1),-1);
$postid,$userid,$vote,$vote
);
qa_db_query_sub(
}
'INSERT INTO ^uservotes (postid, userid, vote, flag) VALUES (#, #, #, 0) ON DUPLICATE KEY UPDATE vote=#',
$postid,$userid,$vote,$vote
);
functionqa_db_uservote_get($postid,$userid)
}
/*
Get the vote for $userid on $postid from the database (or NULL if none)
*/
/**
{
* Get the vote for $userid on $postid from the database (or NULL if none)
returnqa_db_read_one_value(qa_db_query_sub(
* @param $postid
'SELECT vote FROM ^uservotes WHERE postid=# AND userid=#',
* @param $userid
$postid,$userid
* @return mixed|null
),true);
*/
}
functionqa_db_uservote_get($postid,$userid)
{
returnqa_db_read_one_value(qa_db_query_sub(
functionqa_db_userflag_set($postid,$userid,$flag)
'SELECT vote FROM ^uservotes WHERE postid=# AND userid=#',
/*
$postid,$userid
Set the flag for $userid on $postid to $flag (true or false) in the database
),true);
*/
}
{
$flag=$flag?1:0;
/**
* Set the flag for $userid on $postid to $flag (true or false) in the database
* @param $postid
* @param $userid
* @param $flag
*/
functionqa_db_userflag_set($postid,$userid,$flag)
{
$flag=$flag?1:0;
qa_db_query_sub(
'INSERT INTO ^uservotes (postid, userid, vote, flag) VALUES (#, #, 0, #) ON DUPLICATE KEY UPDATE flag=#',
$postid,$userid,$flag,$flag
);
}
/**
* Clear all flags for $postid in the database
* @param $postid
*/
functionqa_db_userflags_clear_all($postid)
{
qa_db_query_sub(
'UPDATE ^uservotes SET flag=0 WHERE postid=#',
$postid
);
}
/**
* Recalculate the cached count of upvotes, downvotes and netvotes for $postid in the database
* @param $postid
*/
functionqa_db_post_recount_votes($postid)
{
if(qa_should_update_counts())
qa_db_query_sub(
qa_db_query_sub(
'INSERT INTO ^uservotes (postid, userid, vote, flag) VALUES (#, #, 0, #) ON DUPLICATE KEY UPDATE flag=#',
'UPDATE ^posts AS x, (SELECT COALESCE(SUM(GREATEST(0,vote)),0) AS upvotes, -COALESCE(SUM(LEAST(0,vote)),0) AS downvotes FROM ^uservotes WHERE postid=#) AS a SET x.upvotes=a.upvotes, x.downvotes=a.downvotes, x.netvotes=a.upvotes-a.downvotes WHERE x.postid=#',
$postid,$userid,$flag,$flag
$postid,$postid
);
);
}
}
functionqa_db_userflags_clear_all($postid)
/**
/*
* Recalculate the cached count of flags for $postid in the database
Clear all flags for $postid in the database
* @param $postid
*/
*/
{
functionqa_db_post_recount_flags($postid)
{
if(qa_should_update_counts())
qa_db_query_sub(
qa_db_query_sub(
'UPDATE ^uservotes SET flag=0 WHERE postid=#',
'UPDATE ^posts AS x, (SELECT COALESCE(SUM(IF(flag, 1, 0)),0) AS flagcount FROM ^uservotes WHERE postid=#) AS a SET x.flagcount=a.flagcount WHERE x.postid=#',
$postid
$postid,$postid
);
);
}
}
functionqa_db_post_recount_votes($postid)
/**
/*
* Returns all non-zero votes on post $postid from the database as an array of [userid] => [vote]
Recalculate the cached count of upvotes, downvotes and netvotes for $postid in the database
* @param $postid
*/
* @return array
{
*/
if(qa_should_update_counts())
functionqa_db_uservote_post_get($postid)
qa_db_query_sub(
{
'UPDATE ^posts AS x, (SELECT COALESCE(SUM(GREATEST(0,vote)),0) AS upvotes, -COALESCE(SUM(LEAST(0,vote)),0) AS downvotes FROM ^uservotes WHERE postid=#) AS a SET x.upvotes=a.upvotes, x.downvotes=a.downvotes, x.netvotes=a.upvotes-a.downvotes WHERE x.postid=#',
returnqa_db_read_all_assoc(qa_db_query_sub(
$postid,$postid
'SELECT userid, vote FROM ^uservotes WHERE postid=# AND vote!=0',
);
$postid
}
),'userid','vote');
}
functionqa_db_post_recount_flags($postid)
/*
/**
Recalculate the cached count of flags for $postid in the database
* Returns all the postids from the database for posts that $userid has voted on or flagged
*/
* @param $userid
{
* @return array
if(qa_should_update_counts())
*/
qa_db_query_sub(
functionqa_db_uservoteflag_user_get($userid)
'UPDATE ^posts AS x, (SELECT COALESCE(SUM(IF(flag, 1, 0)),0) AS flagcount FROM ^uservotes WHERE postid=#) AS a SET x.flagcount=a.flagcount WHERE x.postid=#',
{
$postid,$postid
returnqa_db_read_all_values(qa_db_query_sub(
);
'SELECT postid FROM ^uservotes WHERE userid=# AND (vote!=0) OR (flag!=0)',
}
$userid
));
}
functionqa_db_uservote_post_get($postid)
/*
Returns all non-zero votes on post $postid from the database as an array of [userid] => [vote]
/**
*/
* Return information about all the non-zero votes and/or flags on the posts in postids, including user handles for internal user management
{
* @param $postids
* @return array
*/
functionqa_db_uservoteflag_posts_get($postids)
{
if(QA_FINAL_EXTERNAL_USERS){
returnqa_db_read_all_assoc(qa_db_query_sub(
returnqa_db_read_all_assoc(qa_db_query_sub(
'SELECT userid, vote FROM ^uservotes WHERE postid=# AND vote!=0',
'SELECT postid, userid, vote, flag FROM ^uservotes WHERE postid IN (#) AND ((vote!=0) OR (flag!=0))',
$postid
$postids
),'userid','vote');
));
}
}else{
returnqa_db_read_all_assoc(qa_db_query_sub(
'SELECT postid, handle, vote, flag FROM ^uservotes LEFT JOIN ^users ON ^uservotes.userid=^users.userid WHERE postid IN (#) AND ((vote!=0) OR (flag!=0))',
functionqa_db_uservoteflag_user_get($userid)
$postids
/*
Returns all the postids from the database for posts that $userid has voted on or flagged
*/
{
returnqa_db_read_all_values(qa_db_query_sub(
'SELECT postid FROM ^uservotes WHERE userid=# AND (vote!=0) OR (flag!=0)',
$userid
));
));
}
}
}
functionqa_db_uservoteflag_posts_get($postids)
/*
/**
Return information about all the non-zero votes and/or flags on the posts in postids, including user handles for internal user management
* Remove all votes assigned to a post that had been cast by the owner of the post.
*/
*
{
* @param int $postid The post ID from which the owner's votes will be removed.
if(QA_FINAL_EXTERNAL_USERS)
*/
returnqa_db_read_all_assoc(qa_db_query_sub(
functionqa_db_uservote_remove_own($postid)
'SELECT postid, userid, vote, flag FROM ^uservotes WHERE postid IN (#) AND ((vote!=0) OR (flag!=0))',
{
$postids
qa_db_query_sub(
));
'DELETE uv FROM ^uservotes uv JOIN ^posts p ON uv.postid=p.postid AND uv.userid=p.userid WHERE uv.postid=#',$postid
);
else
}
returnqa_db_read_all_assoc(qa_db_query_sub(
'SELECT postid, handle, vote, flag FROM ^uservotes LEFT JOIN ^users ON ^uservotes.userid=^users.userid WHERE postid IN (#) AND ((vote!=0) OR (flag!=0))',
$postids
));
}
/**
* Remove all votes assigned to a post that had been cast by the owner of the post.
*
* @param int $postid The post ID from which the owner's votes will be removed.
*/
functionqa_db_uservote_remove_own($postid)
{
qa_db_query_sub(
'DELETE uv FROM ^uservotes uv JOIN ^posts p ON uv.postid=p.postid AND uv.userid=p.userid WHERE uv.postid=#',$postid
);
}
/*
Omit PHP closing tag to help avoid accidental output