r34565 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r34564‎ | r34565 | r34566 >
Date:10:49, 10 May 2008
Author:catrope
Status:old
Tags:
Comment:
* Re-applying r34449, r34500 and r34518 which Brion reverted by accident
* Adding ApiQueryBase::addJoinConds() as wrapper for Database::select()'s $join_conds parameter
* Migrating query modules to addJoinConds()
* Using implicit join rather than INNER JOIN in ApiQueryBacklinks
* Using FORCE INDEX (times) on logging table in ApiQueryLogEvents; although MySQL 4 seems to pick this index automatically (evidenced by the fact the WMF servers are still alive), MySQL 5 doesn't and filesorts
* Replacing LEFT JOIN with implicit (inner) join in ApiQueryContributions: revisions without a corresponding page table entry shouldn't be shown anyway
Modified paths:
  • /trunk/phase3/includes/api/ApiQueryAllUsers.php (modified) (history)
  • /trunk/phase3/includes/api/ApiQueryAllpages.php (modified) (history)
  • /trunk/phase3/includes/api/ApiQueryBacklinks.php (modified) (history)
  • /trunk/phase3/includes/api/ApiQueryBase.php (modified) (history)
  • /trunk/phase3/includes/api/ApiQueryLogEvents.php (modified) (history)
  • /trunk/phase3/includes/api/ApiQueryRecentChanges.php (modified) (history)
  • /trunk/phase3/includes/api/ApiQuerySiteinfo.php (modified) (history)
  • /trunk/phase3/includes/api/ApiQueryUserContributions.php (modified) (history)
  • /trunk/phase3/includes/api/ApiQueryUsers.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/api/ApiQueryRecentChanges.php
@@ -55,12 +55,13 @@
5656 extract($this->extractRequestParams());
5757
5858 /* Build our basic query. Namely, something along the lines of:
59 - * SELECT * from recentchanges WHERE rc_timestamp > $start
 59+ * SELECT * FROM recentchanges WHERE rc_timestamp > $start
6060 * AND rc_timestamp < $end AND rc_namespace = $namespace
6161 * AND rc_deleted = '0'
6262 */
6363 $db = $this->getDB();
64 - $rc = $db->tableName('recentchanges');
 64+ $this->addTables('recentchanges');
 65+ $this->addOption('USE INDEX', array('recentchanges' => 'rc_timestamp'));
6566 $this->addWhereRange('rc_timestamp', $dir, $start, $end);
6667 $this->addWhereFld('rc_namespace', $namespace);
6768 $this->addWhereFld('rc_deleted', 0);
@@ -164,14 +165,11 @@
165166 $this->addFieldsIf('rc_patrolled', $this->fld_patrolled);
166167 if($this->fld_redirect || isset($show['redirect']) || isset($show['!redirect']))
167168 {
168 - $page = $db->tableName('page');
169 - $tables = "$page RIGHT JOIN $rc FORCE INDEX(rc_timestamp) ON page_namespace=rc_namespace AND page_title=rc_title";
 169+ $this->addTables('page');
 170+ $this->addJoinConds(array('page' => array('RIGHT JOIN', array('page_namespace=rc_namespace', 'page_title=rc_title'))));
170171 $this->addFields('page_is_redirect');
171172 }
172173 }
173 - if(!isset($tables))
174 - $tables = "$rc FORCE INDEX(rc_timestamp)";
175 - $this->addTables($tables);
176174 /* Specify the limit for our query. It's $limit+1 because we (possibly) need to
177175 * generate a "continue" parameter, to allow paging. */
178176 $this->addOption('LIMIT', $limit +1);
Index: trunk/phase3/includes/api/ApiQuerySiteinfo.php
@@ -170,13 +170,16 @@
171171 $res = $this->select(__METHOD__);
172172
173173 $data = array();
 174+ $langNames = Language::getLanguageNames();
174175 while($row = $db->fetchObject($res))
175176 {
176177 $val = array();
177178 $val['prefix'] = $row->iw_prefix;
178 - if ($row->iw_local == '1')
 179+ if($row->iw_local == '1')
179180 $val['local'] = '';
180181 // $val['trans'] = intval($row->iw_trans); // should this be exposed?
 182+ if(isset($langNames[$row->iw_prefix]))
 183+ $val['language'] = $langNames[$row->iw_prefix];
181184 $val['url'] = $row->iw_url;
182185
183186 $data[] = $val;
Index: trunk/phase3/includes/api/ApiQueryAllpages.php
@@ -57,6 +57,7 @@
5858 $params = $this->extractRequestParams();
5959
6060 // Page filters
 61+ $this->addTables('page');
6162 if (!$this->addWhereIf('page_is_redirect = 1', $params['filterredir'] === 'redirects'))
6263 $this->addWhereIf('page_is_redirect = 0', $params['filterredir'] === 'nonredirects');
6364 $this->addWhereFld('page_namespace', $params['namespace']);
@@ -97,18 +98,14 @@
9899 }
99100
100101 if($params['filterlanglinks'] == 'withoutlanglinks') {
101 - $pageName = $this->getDB()->tableName('page');
102 - $llName = $this->getDB()->tableName('langlinks');
103 - $tables = "$pageName LEFT JOIN $llName ON page_id=ll_from";
 102+ $this->addTables('langlinks');
 103+ $this->addJoinConds(array('langlinks' => array('LEFT JOIN', 'page_id=ll_from')));
104104 $this->addWhere('ll_from IS NULL');
105 - $this->addTables($tables);
106105 $forceNameTitleIndex = false;
107106 } else if($params['filterlanglinks'] == 'withlanglinks') {
108 - $this->addTables(array('page', 'langlinks'));
 107+ $this->addTables('langlinks');
109108 $this->addWhere('page_id=ll_from');
110109 $forceNameTitleIndex = false;
111 - } else {
112 - $this->addTables('page');
113110 }
114111 if ($forceNameTitleIndex)
115112 $this->addOption('USE INDEX', 'name_title');
Index: trunk/phase3/includes/api/ApiQueryBacklinks.php
@@ -96,13 +96,13 @@
9797
9898 private function prepareFirstQuery($resultPageSet = null) {
9999 /* SELECT page_id, page_title, page_namespace, page_is_redirect
100 - * FROM pagelinks JOIN page ON pl_from=page_id
101 - * WHERE pl_title='Foo' AND pl_namespace=0
 100+ * FROM pagelinks, page WHERE pl_from=page_id
 101+ * AND pl_title='Foo' AND pl_namespace=0
102102 * LIMIT 11 ORDER BY pl_from
103103 */
104104 $db = $this->getDb();
105 - list($tblpage, $tbllinks) = $db->tableNamesN('page', $this->bl_table);
106 - $this->addTables("$tbllinks JOIN $tblpage ON {$this->bl_from}=page_id");
 105+ $this->addTables(array('page', $this->bl_table));
 106+ $this->addWhere("{$this->bl_from}=page_id");
107107 if(is_null($resultPageSet))
108108 $this->addFields(array('page_id', 'page_title', 'page_namespace'));
109109 else
@@ -124,13 +124,13 @@
125125
126126 private function prepareSecondQuery($resultPageSet = null) {
127127 /* SELECT page_id, page_title, page_namespace, page_is_redirect, pl_title, pl_namespace
128 - * FROM pagelinks JOIN page ON pl_from=page_id
129 - * WHERE (pl_title='Foo' AND pl_namespace=0) OR (pl_title='Bar' AND pl_namespace=1)
 128+ * FROM pagelinks, page WHERE pl_from=page_id
 129+ * AND (pl_title='Foo' AND pl_namespace=0) OR (pl_title='Bar' AND pl_namespace=1)
130130 * LIMIT 11 ORDER BY pl_namespace, pl_title, pl_from
131131 */
132132 $db = $this->getDb();
133 - list($tblpage, $tbllinks) = $db->tableNamesN('page', $this->bl_table);
134 - $this->addTables("$tbllinks JOIN $tblpage ON {$this->bl_from}=page_id");
 133+ $this->addTables(array('page', $this->bl_table));
 134+ $this->addWhere("{$this->bl_from}=page_id");
135135 if(is_null($resultPageSet))
136136 $this->addFields(array('page_id', 'page_title', 'page_namespace', 'page_is_redirect'));
137137 else
@@ -260,20 +260,14 @@
261261 }
262262
263263 protected function processContinue() {
264 - $pageSet = $this->getPageSet();
265 - $count = $pageSet->getTitleCount();
266 -
267264 if (!is_null($this->params['continue']))
268265 $this->parseContinueParam();
269266 else {
270267 $title = $this->params['title'];
271268 if (!is_null($title)) {
272269 $this->rootTitle = Title :: newFromText($title);
273 - } else { // This case is obsolete. Will support this for a while
274 - if ($count !== 1)
275 - $this->dieUsage("The {$this->getModuleName()} query requires one title to start", 'bad_title_count');
276 - $this->rootTitle = current($pageSet->getTitles()); // only one title there
277 - $this->setWarning('Using titles parameter is obsolete for this list. Use ' . $this->encodeParamName('title') . ' instead.');
 270+ } else {
 271+ $this->dieUsageMsg(array('missingparam', 'title'));
278272 }
279273 }
280274
Index: trunk/phase3/includes/api/ApiQueryBase.php
@@ -36,7 +36,7 @@
3737 */
3838 abstract class ApiQueryBase extends ApiBase {
3939
40 - private $mQueryModule, $mDb, $tables, $where, $fields, $options;
 40+ private $mQueryModule, $mDb, $tables, $where, $fields, $options, $join_conds;
4141
4242 public function __construct($query, $moduleName, $paramPrefix = '') {
4343 parent :: __construct($query->getMain(), $moduleName, $paramPrefix);
@@ -53,6 +53,7 @@
5454 $this->where = array ();
5555 $this->fields = array ();
5656 $this->options = array ();
 57+ $this->join_conds = array ();
5758 }
5859
5960 /**
@@ -67,10 +68,33 @@
6869 $this->tables = array_merge($this->tables, $tables);
6970 } else {
7071 if (!is_null($alias))
71 - $tables = $this->getDB()->tableName($tables) . ' ' . $alias;
 72+ $tables = $this->getAliasedName($tables, $alias);
7273 $this->tables[] = $tables;
7374 }
7475 }
 76+
 77+ /**
 78+ * Get the SQL for a table name with alias
 79+ * @param string $table Table name
 80+ * @param string $alias Alias
 81+ * @return string SQL
 82+ */
 83+ protected function getAliasedName($table, $alias) {
 84+ return $this->getDB()->tableName($table) . ' ' . $alias;
 85+ }
 86+
 87+ /**
 88+ * Add a set of JOIN conditions to the internal array
 89+ *
 90+ * JOIN conditions are formatted as array( tablename => array(jointype, conditions)
 91+ * e.g. array('page' => array('LEFT JOIN', 'page_id=rev_page'))
 92+ * @param array $join_conds JOIN conditions
 93+ */
 94+ protected function addJoinConds($join_conds) {
 95+ if(!is_array($join_conds))
 96+ ApiBase::dieDebug(__METHOD__, 'Join conditions have to be arrays');
 97+ $this->join_conds = array_merge($this->join_conds, $join_conds);
 98+ }
7599
76100 /**
77101 * Add a set of fields to select to the internal array
@@ -187,7 +211,7 @@
188212 $db = $this->getDB();
189213
190214 $this->profileDBIn();
191 - $res = $db->select($this->tables, $this->fields, $this->where, $method, $this->options);
 215+ $res = $db->select($this->tables, $this->fields, $this->where, $method, $this->options, $this->join_conds);
192216 $this->profileDBOut();
193217
194218 return $res;
Index: trunk/phase3/includes/api/ApiQueryAllUsers.php
@@ -46,26 +46,27 @@
4747 $prop = $params['prop'];
4848 if (!is_null($prop)) {
4949 $prop = array_flip($prop);
 50+ $fld_blockinfo = isset($prop['blockinfo']);
5051 $fld_editcount = isset($prop['editcount']);
5152 $fld_groups = isset($prop['groups']);
5253 $fld_registration = isset($prop['registration']);
53 - } else {
54 - $fld_editcount = $fld_groups = $fld_registration = false;
 54+ } else {
 55+ $fld_blockinfo = $fld_editcount = $fld_groups = $fld_registration = false;
5556 }
5657
5758 $limit = $params['limit'];
58 - $tables = $db->tableName('user');
 59+ $this->addTables('user', 'u1');
5960
6061 if( !is_null( $params['from'] ) )
61 - $this->addWhere( 'user_name >= ' . $db->addQuotes( self::keyToTitle( $params['from'] ) ) );
 62+ $this->addWhere( 'u1.user_name >= ' . $db->addQuotes( self::keyToTitle( $params['from'] ) ) );
6263
6364 if( isset( $params['prefix'] ) )
64 - $this->addWhere( 'user_name LIKE "' . $db->escapeLike( self::keyToTitle( $params['prefix'] ) ) . '%"' );
 65+ $this->addWhere( 'u1.user_name LIKE "' . $db->escapeLike( self::keyToTitle( $params['prefix'] ) ) . '%"' );
6566
6667 if (!is_null($params['group'])) {
6768 // Filter only users that belong to a given group
68 - $tblName = $db->tableName('user_groups');
69 - $tables = "$tables INNER JOIN $tblName ug1 ON ug1.ug_user=user_id";
 69+ $this->addTables('user_groups', 'ug1');
 70+ $this->addWhere('ug1.ug_user=u1.user_id');
7071 $this->addWhereFld('ug1.ug_group', $params['group']);
7172 }
7273
@@ -75,23 +76,30 @@
7677 $groupCount = count(User::getAllGroups());
7778 $sqlLimit = $limit+$groupCount+1;
7879
79 - $tblName = $db->tableName('user_groups');
80 - $tables = "$tables LEFT JOIN $tblName ug2 ON ug2.ug_user=user_id";
 80+ $this->addTables('user_groups', 'ug2');
 81+ $tname = $this->getAliasedName('user_groups', 'ug2');
 82+ $this->addJoinConds(array($tname => array('LEFT JOIN', 'ug2.ug_user=u1.user_id')));
8183 $this->addFields('ug2.ug_group ug_group2');
8284 } else {
8385 $sqlLimit = $limit+1;
8486 }
 87+ if ($fld_blockinfo) {
 88+ $this->addTables('ipblocks');
 89+ $this->addTables('user', 'u2');
 90+ $u2 = $this->getAliasedName('user', 'u2');
 91+ $this->addJoinConds(array(
 92+ 'ipblocks' => array('LEFT JOIN', 'ipb_user=u1.user_id'),
 93+ $u2 => array('LEFT JOIN', 'ipb_by=u2.user_id')));
 94+ $this->addFields(array('ipb_reason', 'u2.user_name blocker_name'));
 95+ }
8596
86 - if ($fld_registration)
87 - $this->addFields('user_registration');
88 -
8997 $this->addOption('LIMIT', $sqlLimit);
90 - $this->addTables($tables);
9198
92 - $this->addFields('user_name');
93 - $this->addFieldsIf('user_editcount', $fld_editcount);
 99+ $this->addFields('u1.user_name');
 100+ $this->addFieldsIf('u1.user_editcount', $fld_editcount);
 101+ $this->addFieldsIf('u1.user_registration', $fld_registration);
94102
95 - $this->addOption('ORDER BY', 'user_name');
 103+ $this->addOption('ORDER BY', 'u1.user_name');
96104
97105 $res = $this->select(__METHOD__);
98106
@@ -131,6 +139,10 @@
132140 // Record new user's data
133141 $lastUser = $row->user_name;
134142 $lastUserData = array( 'name' => $lastUser );
 143+ if ($fld_blockinfo) {
 144+ $lastUserData['blockedby'] = $row->blocker_name;
 145+ $lastUserData['blockreason'] = $row->ipb_reason;
 146+ }
135147 if ($fld_editcount)
136148 $lastUserData['editcount'] = intval($row->user_editcount);
137149 if ($fld_registration)
@@ -168,9 +180,10 @@
169181 'prop' => array (
170182 ApiBase :: PARAM_ISMULTI => true,
171183 ApiBase :: PARAM_TYPE => array (
 184+ 'blockinfo',
 185+ 'groups',
172186 'editcount',
173 - 'groups',
174 - 'registration',
 187+ 'registration'
175188 )
176189 ),
177190 'limit' => array (
Index: trunk/phase3/includes/api/ApiQueryUserContributions.php
@@ -59,7 +59,6 @@
6060 $this->selectNamedDB('contributions', DB_SLAVE, 'contributions');
6161 $db = $this->getDB();
6262
63 -
6463 if(isset($this->params['userprefix']))
6564 {
6665 $this->prefixMode = true;
@@ -131,8 +130,8 @@
132131
133132 //We're after the revision table, and the corresponding page row for
134133 //anything we retrieve.
135 - list ($tbl_page, $tbl_revision) = $this->getDB()->tableNamesN('page', 'revision');
136 - $this->addTables("$tbl_revision LEFT OUTER JOIN $tbl_page ON page_id=rev_page");
 134+ $this->addTables(array('revision', 'page'));
 135+ $this->addWhere('page_id=rev_page');
137136
138137 $this->addWhereFld('rev_deleted', 0);
139138 // We only want pages by the specified users.
Index: trunk/phase3/includes/api/ApiQueryUsers.php
@@ -72,24 +72,26 @@
7373 return $retval;
7474
7575 $db = $this->getDb();
76 - $userTable = $db->tableName('user');
77 - $tables = "$userTable AS u1";
 76+ $this->addTables('user', 'u1');
7877 $this->addFields('u1.user_name');
7978 $this->addWhereFld('u1.user_name', $goodNames);
8079 $this->addFieldsIf('u1.user_editcount', isset($this->prop['editcount']));
 80+ $this->addFieldsIf('u1.user_registration', isset($this->prop['registration']));
8181
8282 if(isset($this->prop['groups'])) {
83 - $ug = $db->tableName('user_groups');
84 - $tables = "$tables LEFT JOIN $ug ON ug_user=u1.user_id";
 83+ $this->addTables('user_groups');
 84+ $this->addJoinConds(array('user_groups' => array('LEFT JOIN', 'ug_user=u1.user_id')));
8585 $this->addFields('ug_group');
8686 }
8787 if(isset($this->prop['blockinfo'])) {
88 - $ipb = $db->tableName('ipblocks');
89 - $tables = "$tables LEFT JOIN $ipb ON ipb_user=u1.user_id";
90 - $tables = "$tables LEFT JOIN $userTable AS u2 ON ipb_by=u2.user_id";
91 - $this->addFields(array('ipb_reason', 'u2.user_name AS blocker_name'));
 88+ $this->addTables('ipblocks');
 89+ $this->addTables('user', 'u2');
 90+ $u2 = $this->getAliasedName('user', 'u2');
 91+ $this->addJoinConds(array(
 92+ 'ipblocks' => array('LEFT JOIN', 'ipb_user=u1.user_id'),
 93+ $u2 => array('LEFT JOIN', 'ipb_by=u2.user_id')));
 94+ $this->addFields(array('ipb_reason', 'u2.user_name blocker_name'));
9295 }
93 - $this->addTables($tables);
9496
9597 $data = array();
9698 $res = $this->select(__METHOD__);
@@ -97,6 +99,8 @@
98100 $data[$r->user_name]['name'] = $r->user_name;
99101 if(isset($this->prop['editcount']))
100102 $data[$r->user_name]['editcount'] = $r->user_editcount;
 103+ if(isset($this->prop['registration']))
 104+ $data[$r->user_name]['registration'] = wfTimestamp(TS_ISO_8601, $r->user_registration);
101105 if(isset($this->prop['groups']))
102106 // This row contains only one group, others will be added from other rows
103107 if(!is_null($r->ug_group))
@@ -129,7 +133,8 @@
130134 ApiBase :: PARAM_TYPE => array (
131135 'blockinfo',
132136 'groups',
133 - 'editcount'
 137+ 'editcount',
 138+ 'registration'
134139 )
135140 ),
136141 'users' => array(
Index: trunk/phase3/includes/api/ApiQueryLogEvents.php
@@ -58,10 +58,14 @@
5959 if($hideLogs !== false)
6060 $this->addWhere($hideLogs);
6161
62 - $this->addOption('STRAIGHT_JOIN');
63 - $this->addTables("$tbl_logging LEFT OUTER JOIN $tbl_page ON " .
64 - "log_namespace=page_namespace AND log_title=page_title " .
65 - "INNER JOIN $tbl_user ON user_id=log_user");
 62+ // Order is significant here
 63+ $this->addTables(array('user', 'page', 'logging'));
 64+ $this->addJoinConds(array(
 65+ 'page' => array('LEFT JOIN',
 66+ array( 'log_namespace=page_namespace',
 67+ 'log_title=page_title'))));
 68+ $this->addWhere('user_id=log_user');
 69+ $this->addOption('USE INDEX', array('logging' => 'times'));
6670
6771 $this->addFields(array (
6872 'log_type',
@@ -79,7 +83,6 @@
8084 $this->addFieldsIf('log_comment', $this->fld_comment);
8185 $this->addFieldsIf('log_params', $this->fld_details);
8286
83 -
8487 $this->addWhereFld('log_deleted', 0);
8588 $this->addWhereFld('log_type', $params['type']);
8689 $this->addWhereRange('log_timestamp', $params['dir'], $params['start'], $params['end']);

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r34449Localisation updates Cantonese, Chinese and Old/Late Time Chineseshinjiman17:20, 8 May 2008
r34500(bug 14022) Added usprop=registration and auprop=blockinfocatrope10:00, 9 May 2008
r34518(bug 14021) Removing titles= support from list=backlinks, has been obsolete f...catrope14:44, 9 May 2008

Status & tagging log