* Added ApiQueryBase::addJoin() which provides a cleaner interface to construct JOIN queries. Behind the scenes this still uses the old, ugly way, but it'll be easy to rewrite when/if the Database class gets its own function for JOINs
* Used addJoin() in query modules where necessary
* Removed FORCE INDEX (rc_timestamp) from ApiQueryRecentchanges: it's nigh impossible to integrate with addJoin() and it doesn't seem to be necessary anyway (my MySQL instance automatically chooses rc_timestamp)
}
$limit = $params['limit'];
- $tables = $db->tableName('user');
if( !is_null( $params['from'] ) )
$this->addWhere( 'user_name >= ' . $db->addQuotes( self::keyToTitle( $params['from'] ) ) );
if (!is_null($params['group'])) {
// Filter only users that belong to a given group
- $tblName = $db->tableName('user_groups');
- $tables = "$tables INNER JOIN $tblName ug1 ON ug1.ug_user=user_id";
+ $this->addTables('user_groups', 'ug1');
+ $this->addWhere('ug1.ug_user=user_id');
$this->addWhereFld('ug1.ug_group', $params['group']);
}
-
if ($fld_groups) {
// Show the groups the given users belong to
// request more than needed to avoid not getting all rows that belong to one user
$groupCount = count(User::getAllGroups());
$sqlLimit = $limit+$groupCount+1;
-
- $tblName = $db->tableName('user_groups');
- $tables = "$tables LEFT JOIN $tblName ug2 ON ug2.ug_user=user_id";
+ $this->addJoin(
+ array('user', 'user_groups'),
+ array(ApiQueryBase::LEFT_JOIN),
+ array('ug2.ug_user=user_id'),
+ array(null, 'ug2'));
$this->addFields('ug2.ug_group ug_group2');
} else {
+ $this->addTables('user');
$sqlLimit = $limit+1;
}
$this->addFields('user_registration');
$this->addOption('LIMIT', $sqlLimit);
- $this->addTables($tables);
$this->addFields('user_name');
$this->addFieldsIf('user_editcount', $fld_editcount);
}
if($params['filterlanglinks'] == 'withoutlanglinks') {
- $pageName = $this->getDB()->tableName('page');
- $llName = $this->getDB()->tableName('langlinks');
- $tables = "$pageName LEFT JOIN $llName ON page_id=ll_from";
+ $this->addJoin(
+ array('page', 'langlinks'),
+ array(ApiQueryBase::LEFT_JOIN),
+ array('page_id=ll_from'));
$this->addWhere('ll_from IS NULL');
- $this->addTables($tables);
$forceNameTitleIndex = false;
} else if($params['filterlanglinks'] == 'withlanglinks') {
$this->addTables(array('page', 'langlinks'));
* LIMIT 11 ORDER BY pl_from
*/
$db = $this->getDb();
- list($tblpage, $tbllinks) = $db->tableNamesN('page', $this->bl_table);
- $this->addTables("$tbllinks JOIN $tblpage ON {$this->bl_from}=page_id");
+ $this->addTables(array($this->bl_table, 'page'));
+ $this->addWhere("{$this->bl_from}=page_id");
if(is_null($resultPageSet))
$this->addFields(array('page_id', 'page_title', 'page_namespace'));
else
* LIMIT 11 ORDER BY pl_namespace, pl_title, pl_from
*/
$db = $this->getDb();
- list($tblpage, $tbllinks) = $db->tableNamesN('page', $this->bl_table);
- $this->addTables("$tbllinks JOIN $tblpage ON {$this->bl_from}=page_id");
+ $this->addTables(array($this->bl_table, 'page'));
+ $this->addWhere("{$this->bl_from}=page_id");
if(is_null($resultPageSet))
$this->addFields(array('page_id', 'page_title', 'page_namespace', 'page_is_redirect'));
else
abstract class ApiQueryBase extends ApiBase {
private $mQueryModule, $mDb, $tables, $where, $fields, $options;
+
+ const LEFT_JOIN = 1;
+ const RIGHT_JOIN = 2;
public function __construct($query, $moduleName, $paramPrefix = '') {
parent :: __construct($query->getMain(), $moduleName, $paramPrefix);
}
}
+ protected function addJoin($tables, $types, $onClauses, $aliases = null) {
+ if(is_null($aliases))
+ foreach($tables as $unused)
+ $aliases[] = null;
+ if(!is_array($tables) || !is_array($types) || !is_array($onClauses) || !is_array($aliases))
+ ApiBase::dieDebug(__METHOD__, 'This function only takes arrays as parameters');
+ $sql = $this->getDB()->tableName($tables[0]) . (is_null($aliases[0]) ? "" : " {$aliases[0]}");
+ for($i = 0; $i < count($tables) - 1; $i++)
+ {
+ if($types[$i] == self::LEFT_JOIN)
+ $join = "LEFT JOIN";
+ else if($types[$i] == self::RIGHT_JOIN)
+ $join = "RIGHT JOIN";
+ else
+ ApiBase::dieDebug(__METHOD__, "Invalid join type {$types[$i]}");
+
+ if(is_array($onClauses[$i]))
+ $on = $this->getDB()->makeList($onClauses[$i], LIST_AND);
+ else
+ $on = $onClauses[$i];
+ $alias = $aliases[$i+1];
+ $tblname = $this->getDB()->tableName($tables[$i+1]) . (is_null($alias) ? "" : " $alias");
+ $sql = "$sql $join $tblname ON $on";
+ }
+ $this->addTables($sql);
+ }
+
+
+
protected function addFields($value) {
if (is_array($value))
$this->fields = array_merge($this->fields, $value);
$hideLogs = LogEventsList::getExcludeClause($db);
if($hideLogs !== false)
$this->addWhere($hideLogs);
-
- $this->addOption('STRAIGHT_JOIN');
- $this->addTables("$tbl_logging LEFT OUTER JOIN $tbl_page ON " .
- "log_namespace=page_namespace AND log_title=page_title " .
- "INNER JOIN $tbl_user ON user_id=log_user");
+
+ $this->addTables('user');
+ $this->addWhere('user_id=log_user');
+ $this->addJoin(
+ array('logging', 'page'),
+ array(ApiQueryBase::LEFT_JOIN),
+ array(
+ array( 'log_title=page_title',
+ 'log_namespace=page_namespace'
+ )));
$this->addFields(array (
'log_type',
$this->addFieldsIf('rc_patrolled', $this->fld_patrolled);
if($this->fld_redirect || isset($show['redirect']) || isset($show['!redirect']))
{
- $page = $db->tableName('page');
- $tables = "$page RIGHT JOIN $rc FORCE INDEX(rc_timestamp) ON page_namespace=rc_namespace AND page_title=rc_title";
+ $this->addJoin(
+ array('page', 'recentchanges'),
+ array(ApiQueryBase::RIGHT_JOIN),
+ array(array(
+ 'page_namespace=rc_namespace',
+ 'page_title=rc_title')));
$this->addFields('page_is_redirect');
+ } else {
+ $this->addTables('recentchanges');
}
+ } else {
+ $this->addTables('recentchanges');
}
- if(!isset($tables))
- $tables = "$rc FORCE INDEX(rc_timestamp)";
- $this->addTables($tables);
/* Specify the limit for our query. It's $limit+1 because we (possibly) need to
* generate a "continue" parameter, to allow paging. */
$this->addOption('LIMIT', $limit +1);
//We're after the revision table, and the corresponding page row for
//anything we retrieve.
- list ($tbl_page, $tbl_revision) = $this->getDB()->tableNamesN('page', 'revision');
- $this->addTables("$tbl_revision LEFT OUTER JOIN $tbl_page ON page_id=rev_page");
+ $this->addJoin(
+ array('revision', 'page'),
+ array(ApiQueryBase::LEFT_JOIN),
+ array('page_id=rev_page'));
$this->addWhereFld('rev_deleted', 0);
// We only want pages by the specified users.
return $retval;
$db = $this->getDb();
- $userTable = $db->tableName('user');
- $tables = "$userTable AS u1";
$this->addFields('u1.user_name');
$this->addWhereFld('u1.user_name', $goodNames);
$this->addFieldsIf('u1.user_editcount', isset($this->prop['editcount']));
+ $join = false;
+ $tables = array('user');
+ $types = array();
+ $conds = array();
+ $aliases = array('u1');
if(isset($this->prop['groups'])) {
- $ug = $db->tableName('user_groups');
- $tables = "$tables LEFT JOIN $ug ON ug_user=u1.user_id";
+ $join = true;
+ $tables[] = 'user_groups';
+ $types[] = ApiQueryBase::LEFT_JOIN;
+ $conds[] = 'ug_user=u1.user_id';
+ $aliases[] = null;
$this->addFields('ug_group');
}
if(isset($this->prop['blockinfo'])) {
- $ipb = $db->tableName('ipblocks');
- $tables = "$tables LEFT JOIN $ipb ON ipb_user=u1.user_id";
- $tables = "$tables LEFT JOIN $userTable AS u2 ON ipb_by=u2.user_id";
+ $join = true;
+ $tables[] = 'ipblocks';
+ $types[] = ApiQueryBase::LEFT_JOIN;
+ $conds[] = 'ipb_user=u1.user_id';
+ $aliases[] = null;
+
+ $tables[] = 'user';
+ $types[] = ApiQueryBase::LEFT_JOIN;
+ $conds[] = 'ipb_by=u2.user_id';
+ $aliases[] = 'u2';
$this->addFields(array('ipb_reason', 'u2.user_name AS blocker_name'));
}
- $this->addTables($tables);
+
+ if($join)
+ $this->addJoin($tables, $types, $conds, $aliases);
+ else
+ $this->addTables('user', 'u1');
$data = array();
$res = $this->select(__METHOD__);