Index: trunk/phase3/includes/api/ApiQueryRecentChanges.php |
— | — | @@ -55,12 +55,13 @@ |
56 | 56 | extract($this->extractRequestParams()); |
57 | 57 | |
58 | 58 | /* 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 |
60 | 60 | * AND rc_timestamp < $end AND rc_namespace = $namespace |
61 | 61 | * AND rc_deleted = '0' |
62 | 62 | */ |
63 | 63 | $db = $this->getDB(); |
64 | | - $rc = $db->tableName('recentchanges'); |
| 64 | + $this->addTables('recentchanges'); |
| 65 | + $this->addOption('USE INDEX', array('recentchanges' => 'rc_timestamp')); |
65 | 66 | $this->addWhereRange('rc_timestamp', $dir, $start, $end); |
66 | 67 | $this->addWhereFld('rc_namespace', $namespace); |
67 | 68 | $this->addWhereFld('rc_deleted', 0); |
— | — | @@ -164,14 +165,11 @@ |
165 | 166 | $this->addFieldsIf('rc_patrolled', $this->fld_patrolled); |
166 | 167 | if($this->fld_redirect || isset($show['redirect']) || isset($show['!redirect'])) |
167 | 168 | { |
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')))); |
170 | 171 | $this->addFields('page_is_redirect'); |
171 | 172 | } |
172 | 173 | } |
173 | | - if(!isset($tables)) |
174 | | - $tables = "$rc FORCE INDEX(rc_timestamp)"; |
175 | | - $this->addTables($tables); |
176 | 174 | /* Specify the limit for our query. It's $limit+1 because we (possibly) need to |
177 | 175 | * generate a "continue" parameter, to allow paging. */ |
178 | 176 | $this->addOption('LIMIT', $limit +1); |
Index: trunk/phase3/includes/api/ApiQuerySiteinfo.php |
— | — | @@ -170,13 +170,16 @@ |
171 | 171 | $res = $this->select(__METHOD__); |
172 | 172 | |
173 | 173 | $data = array(); |
| 174 | + $langNames = Language::getLanguageNames(); |
174 | 175 | while($row = $db->fetchObject($res)) |
175 | 176 | { |
176 | 177 | $val = array(); |
177 | 178 | $val['prefix'] = $row->iw_prefix; |
178 | | - if ($row->iw_local == '1') |
| 179 | + if($row->iw_local == '1') |
179 | 180 | $val['local'] = ''; |
180 | 181 | // $val['trans'] = intval($row->iw_trans); // should this be exposed? |
| 182 | + if(isset($langNames[$row->iw_prefix])) |
| 183 | + $val['language'] = $langNames[$row->iw_prefix]; |
181 | 184 | $val['url'] = $row->iw_url; |
182 | 185 | |
183 | 186 | $data[] = $val; |
Index: trunk/phase3/includes/api/ApiQueryAllpages.php |
— | — | @@ -57,6 +57,7 @@ |
58 | 58 | $params = $this->extractRequestParams(); |
59 | 59 | |
60 | 60 | // Page filters |
| 61 | + $this->addTables('page'); |
61 | 62 | if (!$this->addWhereIf('page_is_redirect = 1', $params['filterredir'] === 'redirects')) |
62 | 63 | $this->addWhereIf('page_is_redirect = 0', $params['filterredir'] === 'nonredirects'); |
63 | 64 | $this->addWhereFld('page_namespace', $params['namespace']); |
— | — | @@ -97,18 +98,14 @@ |
98 | 99 | } |
99 | 100 | |
100 | 101 | 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'))); |
104 | 104 | $this->addWhere('ll_from IS NULL'); |
105 | | - $this->addTables($tables); |
106 | 105 | $forceNameTitleIndex = false; |
107 | 106 | } else if($params['filterlanglinks'] == 'withlanglinks') { |
108 | | - $this->addTables(array('page', 'langlinks')); |
| 107 | + $this->addTables('langlinks'); |
109 | 108 | $this->addWhere('page_id=ll_from'); |
110 | 109 | $forceNameTitleIndex = false; |
111 | | - } else { |
112 | | - $this->addTables('page'); |
113 | 110 | } |
114 | 111 | if ($forceNameTitleIndex) |
115 | 112 | $this->addOption('USE INDEX', 'name_title'); |
Index: trunk/phase3/includes/api/ApiQueryBacklinks.php |
— | — | @@ -96,13 +96,13 @@ |
97 | 97 | |
98 | 98 | private function prepareFirstQuery($resultPageSet = null) { |
99 | 99 | /* 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 |
102 | 102 | * LIMIT 11 ORDER BY pl_from |
103 | 103 | */ |
104 | 104 | $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"); |
107 | 107 | if(is_null($resultPageSet)) |
108 | 108 | $this->addFields(array('page_id', 'page_title', 'page_namespace')); |
109 | 109 | else |
— | — | @@ -124,13 +124,13 @@ |
125 | 125 | |
126 | 126 | private function prepareSecondQuery($resultPageSet = null) { |
127 | 127 | /* 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) |
130 | 130 | * LIMIT 11 ORDER BY pl_namespace, pl_title, pl_from |
131 | 131 | */ |
132 | 132 | $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"); |
135 | 135 | if(is_null($resultPageSet)) |
136 | 136 | $this->addFields(array('page_id', 'page_title', 'page_namespace', 'page_is_redirect')); |
137 | 137 | else |
— | — | @@ -260,20 +260,14 @@ |
261 | 261 | } |
262 | 262 | |
263 | 263 | protected function processContinue() { |
264 | | - $pageSet = $this->getPageSet(); |
265 | | - $count = $pageSet->getTitleCount(); |
266 | | - |
267 | 264 | if (!is_null($this->params['continue'])) |
268 | 265 | $this->parseContinueParam(); |
269 | 266 | else { |
270 | 267 | $title = $this->params['title']; |
271 | 268 | if (!is_null($title)) { |
272 | 269 | $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')); |
278 | 272 | } |
279 | 273 | } |
280 | 274 | |
Index: trunk/phase3/includes/api/ApiQueryBase.php |
— | — | @@ -36,7 +36,7 @@ |
37 | 37 | */ |
38 | 38 | abstract class ApiQueryBase extends ApiBase { |
39 | 39 | |
40 | | - private $mQueryModule, $mDb, $tables, $where, $fields, $options; |
| 40 | + private $mQueryModule, $mDb, $tables, $where, $fields, $options, $join_conds; |
41 | 41 | |
42 | 42 | public function __construct($query, $moduleName, $paramPrefix = '') { |
43 | 43 | parent :: __construct($query->getMain(), $moduleName, $paramPrefix); |
— | — | @@ -53,6 +53,7 @@ |
54 | 54 | $this->where = array (); |
55 | 55 | $this->fields = array (); |
56 | 56 | $this->options = array (); |
| 57 | + $this->join_conds = array (); |
57 | 58 | } |
58 | 59 | |
59 | 60 | /** |
— | — | @@ -67,10 +68,33 @@ |
68 | 69 | $this->tables = array_merge($this->tables, $tables); |
69 | 70 | } else { |
70 | 71 | if (!is_null($alias)) |
71 | | - $tables = $this->getDB()->tableName($tables) . ' ' . $alias; |
| 72 | + $tables = $this->getAliasedName($tables, $alias); |
72 | 73 | $this->tables[] = $tables; |
73 | 74 | } |
74 | 75 | } |
| 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 | + } |
75 | 99 | |
76 | 100 | /** |
77 | 101 | * Add a set of fields to select to the internal array |
— | — | @@ -187,7 +211,7 @@ |
188 | 212 | $db = $this->getDB(); |
189 | 213 | |
190 | 214 | $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); |
192 | 216 | $this->profileDBOut(); |
193 | 217 | |
194 | 218 | return $res; |
Index: trunk/phase3/includes/api/ApiQueryAllUsers.php |
— | — | @@ -46,26 +46,27 @@ |
47 | 47 | $prop = $params['prop']; |
48 | 48 | if (!is_null($prop)) { |
49 | 49 | $prop = array_flip($prop); |
| 50 | + $fld_blockinfo = isset($prop['blockinfo']); |
50 | 51 | $fld_editcount = isset($prop['editcount']); |
51 | 52 | $fld_groups = isset($prop['groups']); |
52 | 53 | $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; |
55 | 56 | } |
56 | 57 | |
57 | 58 | $limit = $params['limit']; |
58 | | - $tables = $db->tableName('user'); |
| 59 | + $this->addTables('user', 'u1'); |
59 | 60 | |
60 | 61 | 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'] ) ) ); |
62 | 63 | |
63 | 64 | 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'] ) ) . '%"' ); |
65 | 66 | |
66 | 67 | if (!is_null($params['group'])) { |
67 | 68 | // 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'); |
70 | 71 | $this->addWhereFld('ug1.ug_group', $params['group']); |
71 | 72 | } |
72 | 73 | |
— | — | @@ -75,23 +76,30 @@ |
76 | 77 | $groupCount = count(User::getAllGroups()); |
77 | 78 | $sqlLimit = $limit+$groupCount+1; |
78 | 79 | |
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'))); |
81 | 83 | $this->addFields('ug2.ug_group ug_group2'); |
82 | 84 | } else { |
83 | 85 | $sqlLimit = $limit+1; |
84 | 86 | } |
| 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 | + } |
85 | 96 | |
86 | | - if ($fld_registration) |
87 | | - $this->addFields('user_registration'); |
88 | | - |
89 | 97 | $this->addOption('LIMIT', $sqlLimit); |
90 | | - $this->addTables($tables); |
91 | 98 | |
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); |
94 | 102 | |
95 | | - $this->addOption('ORDER BY', 'user_name'); |
| 103 | + $this->addOption('ORDER BY', 'u1.user_name'); |
96 | 104 | |
97 | 105 | $res = $this->select(__METHOD__); |
98 | 106 | |
— | — | @@ -131,6 +139,10 @@ |
132 | 140 | // Record new user's data |
133 | 141 | $lastUser = $row->user_name; |
134 | 142 | $lastUserData = array( 'name' => $lastUser ); |
| 143 | + if ($fld_blockinfo) { |
| 144 | + $lastUserData['blockedby'] = $row->blocker_name; |
| 145 | + $lastUserData['blockreason'] = $row->ipb_reason; |
| 146 | + } |
135 | 147 | if ($fld_editcount) |
136 | 148 | $lastUserData['editcount'] = intval($row->user_editcount); |
137 | 149 | if ($fld_registration) |
— | — | @@ -168,9 +180,10 @@ |
169 | 181 | 'prop' => array ( |
170 | 182 | ApiBase :: PARAM_ISMULTI => true, |
171 | 183 | ApiBase :: PARAM_TYPE => array ( |
| 184 | + 'blockinfo', |
| 185 | + 'groups', |
172 | 186 | 'editcount', |
173 | | - 'groups', |
174 | | - 'registration', |
| 187 | + 'registration' |
175 | 188 | ) |
176 | 189 | ), |
177 | 190 | 'limit' => array ( |
Index: trunk/phase3/includes/api/ApiQueryUserContributions.php |
— | — | @@ -59,7 +59,6 @@ |
60 | 60 | $this->selectNamedDB('contributions', DB_SLAVE, 'contributions'); |
61 | 61 | $db = $this->getDB(); |
62 | 62 | |
63 | | - |
64 | 63 | if(isset($this->params['userprefix'])) |
65 | 64 | { |
66 | 65 | $this->prefixMode = true; |
— | — | @@ -131,8 +130,8 @@ |
132 | 131 | |
133 | 132 | //We're after the revision table, and the corresponding page row for |
134 | 133 | //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'); |
137 | 136 | |
138 | 137 | $this->addWhereFld('rev_deleted', 0); |
139 | 138 | // We only want pages by the specified users. |
Index: trunk/phase3/includes/api/ApiQueryUsers.php |
— | — | @@ -72,24 +72,26 @@ |
73 | 73 | return $retval; |
74 | 74 | |
75 | 75 | $db = $this->getDb(); |
76 | | - $userTable = $db->tableName('user'); |
77 | | - $tables = "$userTable AS u1"; |
| 76 | + $this->addTables('user', 'u1'); |
78 | 77 | $this->addFields('u1.user_name'); |
79 | 78 | $this->addWhereFld('u1.user_name', $goodNames); |
80 | 79 | $this->addFieldsIf('u1.user_editcount', isset($this->prop['editcount'])); |
| 80 | + $this->addFieldsIf('u1.user_registration', isset($this->prop['registration'])); |
81 | 81 | |
82 | 82 | 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'))); |
85 | 85 | $this->addFields('ug_group'); |
86 | 86 | } |
87 | 87 | 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')); |
92 | 95 | } |
93 | | - $this->addTables($tables); |
94 | 96 | |
95 | 97 | $data = array(); |
96 | 98 | $res = $this->select(__METHOD__); |
— | — | @@ -97,6 +99,8 @@ |
98 | 100 | $data[$r->user_name]['name'] = $r->user_name; |
99 | 101 | if(isset($this->prop['editcount'])) |
100 | 102 | $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); |
101 | 105 | if(isset($this->prop['groups'])) |
102 | 106 | // This row contains only one group, others will be added from other rows |
103 | 107 | if(!is_null($r->ug_group)) |
— | — | @@ -129,7 +133,8 @@ |
130 | 134 | ApiBase :: PARAM_TYPE => array ( |
131 | 135 | 'blockinfo', |
132 | 136 | 'groups', |
133 | | - 'editcount' |
| 137 | + 'editcount', |
| 138 | + 'registration' |
134 | 139 | ) |
135 | 140 | ), |
136 | 141 | 'users' => array( |
Index: trunk/phase3/includes/api/ApiQueryLogEvents.php |
— | — | @@ -58,10 +58,14 @@ |
59 | 59 | if($hideLogs !== false) |
60 | 60 | $this->addWhere($hideLogs); |
61 | 61 | |
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')); |
66 | 70 | |
67 | 71 | $this->addFields(array ( |
68 | 72 | 'log_type', |
— | — | @@ -79,7 +83,6 @@ |
80 | 84 | $this->addFieldsIf('log_comment', $this->fld_comment); |
81 | 85 | $this->addFieldsIf('log_params', $this->fld_details); |
82 | 86 | |
83 | | - |
84 | 87 | $this->addWhereFld('log_deleted', 0); |
85 | 88 | $this->addWhereFld('log_type', $params['type']); |
86 | 89 | $this->addWhereRange('log_timestamp', $params['dir'], $params['start'], $params['end']); |