From b7d460aaeb8e997473a3b0ac0cd42e550104a02c Mon Sep 17 00:00:00 2001 From: Roan Kattouw Date: Thu, 8 May 2008 12:33:20 +0000 Subject: [PATCH] API: * 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) --- includes/api/ApiQueryAllUsers.php | 16 +++++------ includes/api/ApiQueryAllpages.php | 8 +++--- includes/api/ApiQueryBacklinks.php | 8 +++--- includes/api/ApiQueryBase.php | 32 +++++++++++++++++++++ includes/api/ApiQueryLogEvents.php | 15 ++++++---- includes/api/ApiQueryRecentChanges.php | 15 ++++++---- includes/api/ApiQueryUserContributions.php | 6 ++-- includes/api/ApiQueryUsers.php | 33 ++++++++++++++++------ 8 files changed, 97 insertions(+), 36 deletions(-) diff --git a/includes/api/ApiQueryAllUsers.php b/includes/api/ApiQueryAllUsers.php index 4c6914bf56..71ea2886c5 100644 --- a/includes/api/ApiQueryAllUsers.php +++ b/includes/api/ApiQueryAllUsers.php @@ -54,7 +54,6 @@ class ApiQueryAllUsers extends ApiQueryBase { } $limit = $params['limit']; - $tables = $db->tableName('user'); if( !is_null( $params['from'] ) ) $this->addWhere( 'user_name >= ' . $db->addQuotes( self::keyToTitle( $params['from'] ) ) ); @@ -64,21 +63,23 @@ class ApiQueryAllUsers extends ApiQueryBase { 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; } @@ -86,7 +87,6 @@ class ApiQueryAllUsers extends ApiQueryBase { $this->addFields('user_registration'); $this->addOption('LIMIT', $sqlLimit); - $this->addTables($tables); $this->addFields('user_name'); $this->addFieldsIf('user_editcount', $fld_editcount); diff --git a/includes/api/ApiQueryAllpages.php b/includes/api/ApiQueryAllpages.php index 4758542e5e..efbca62d1e 100644 --- a/includes/api/ApiQueryAllpages.php +++ b/includes/api/ApiQueryAllpages.php @@ -97,11 +97,11 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase { } 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')); diff --git a/includes/api/ApiQueryBacklinks.php b/includes/api/ApiQueryBacklinks.php index e2cfcfb21b..3b504ecbbd 100644 --- a/includes/api/ApiQueryBacklinks.php +++ b/includes/api/ApiQueryBacklinks.php @@ -101,8 +101,8 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase { * 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 @@ -129,8 +129,8 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase { * 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 diff --git a/includes/api/ApiQueryBase.php b/includes/api/ApiQueryBase.php index d8a6051507..d9b9984fa1 100644 --- a/includes/api/ApiQueryBase.php +++ b/includes/api/ApiQueryBase.php @@ -37,6 +37,9 @@ if (!defined('MEDIAWIKI')) { 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); @@ -64,6 +67,35 @@ abstract class ApiQueryBase extends ApiBase { } } + 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); diff --git a/includes/api/ApiQueryLogEvents.php b/includes/api/ApiQueryLogEvents.php index df93e7c692..d5b84040df 100644 --- a/includes/api/ApiQueryLogEvents.php +++ b/includes/api/ApiQueryLogEvents.php @@ -57,11 +57,16 @@ class ApiQueryLogEvents extends ApiQueryBase { $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', diff --git a/includes/api/ApiQueryRecentChanges.php b/includes/api/ApiQueryRecentChanges.php index 16dd43b31a..4fd8298896 100644 --- a/includes/api/ApiQueryRecentChanges.php +++ b/includes/api/ApiQueryRecentChanges.php @@ -164,14 +164,19 @@ class ApiQueryRecentChanges extends ApiQueryBase { $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); diff --git a/includes/api/ApiQueryUserContributions.php b/includes/api/ApiQueryUserContributions.php index 21ceb27c46..11eff3cc31 100644 --- a/includes/api/ApiQueryUserContributions.php +++ b/includes/api/ApiQueryUserContributions.php @@ -131,8 +131,10 @@ class ApiQueryContributions extends ApiQueryBase { //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. diff --git a/includes/api/ApiQueryUsers.php b/includes/api/ApiQueryUsers.php index c0cae506d2..82908189fe 100644 --- a/includes/api/ApiQueryUsers.php +++ b/includes/api/ApiQueryUsers.php @@ -72,24 +72,41 @@ if (!defined('MEDIAWIKI')) { 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__); -- 2.20.1