Property changes on: branches/querypage-work2/phase3/maintenance/cleanupTable.inc |
___________________________________________________________________ |
Name: svn:mergeinfo |
1 | 1 | - /branches/REL1_15/phase3/maintenance/cleanupTable.inc:51646 |
/branches/wmf-deployment/maintenance/cleanupTable.inc:56715 |
2 | 2 | + /branches/REL1_15/phase3/maintenance/cleanupTable.inc:51646 |
/branches/querypage-work/phase3/maintenance/cleanupTable.inc:49084 |
/branches/wmf-deployment/maintenance/cleanupTable.inc:56715 |
Property changes on: branches/querypage-work2/phase3/skins/common/jquery.js |
___________________________________________________________________ |
Name: svn:mergeinfo |
3 | 3 | - |
4 | 4 | + /branches/querypage-work/phase3/skins/common/jquery.js:49084 |
Property changes on: branches/querypage-work2/phase3/skins/common/jquery.min.js |
___________________________________________________________________ |
Name: svn:mergeinfo |
5 | 5 | - |
6 | 6 | + /branches/querypage-work/phase3/skins/common/jquery.min.js:49084 |
Property changes on: branches/querypage-work2/phase3/includes/OutputPage.php |
___________________________________________________________________ |
Name: svn:mergeinfo |
7 | 7 | - /branches/REL1_15/phase3/includes/OutputPage.php:51646 |
/branches/wmf-deployment/includes/OutputPage.php:53381,57468 |
8 | 8 | + /branches/REL1_15/phase3/includes/OutputPage.php:51646 |
/branches/querypage-work/phase3/includes/OutputPage.php:49084 |
/branches/wmf-deployment/includes/OutputPage.php:53381,57468 |
Property changes on: branches/querypage-work2/phase3/includes/api |
___________________________________________________________________ |
Name: svn:mergeinfo |
9 | 9 | - /branches/REL1_15/phase3/includes/api:51646 |
/branches/REL1_16/phase3/includes/api:63621-63636 |
/branches/sqlite/includes/api:58211-58321 |
/branches/wmf-deployment/includes/api:53381,59952 |
10 | 10 | + /branches/REL1_15/phase3/includes/api:51646 |
/branches/REL1_16/phase3/includes/api:63621-63636 |
/branches/querypage-work/phase3/includes/api:49084 |
/branches/sqlite/includes/api:58211-58321 |
/branches/wmf-deployment/includes/api:53381,59952 |
Property changes on: branches/querypage-work2/phase3/includes/ChangesList.php |
___________________________________________________________________ |
Name: svn:mergeinfo |
11 | 11 | - /branches/REL1_15/phase3/includes/ChangesList.php:51646 |
/branches/wmf-deployment/includes/ChangesList.php:53381,57589 |
12 | 12 | + /branches/REL1_15/phase3/includes/ChangesList.php:51646 |
/branches/querypage-work/phase3/includes/ChangesList.php:49084 |
/branches/wmf-deployment/includes/ChangesList.php:53381,57589 |
Property changes on: branches/querypage-work2/phase3/includes/ConfEditor.php |
___________________________________________________________________ |
Name: svn:mergeinfo |
13 | 13 | - |
14 | 14 | + /branches/querypage-work/phase3/includes/ConfEditor.php:49084 |
Index: branches/querypage-work2/phase3/includes/specials/SpecialBrokenRedirects.php |
— | — | @@ -39,9 +39,33 @@ |
40 | 40 | AND p2.page_namespace IS NULL"; |
41 | 41 | return $sql; |
42 | 42 | } |
| 43 | + |
| 44 | + function getQueryInfo() { |
| 45 | + return array( |
| 46 | + 'tables' => array( 'redirect', 'page AS p1', 'page AS p2' ), |
| 47 | + 'fields' => array( "'{$this->getName()}' AS type", |
| 48 | + 'p1.page_namespace AS namespace', |
| 49 | + 'p1.page_title AS title', |
| 50 | + 'rd_namespace', |
| 51 | + 'rd_title' |
| 52 | + ), |
| 53 | + 'conds' => array( 'rd_namespace >= 0', |
| 54 | + 'p2.page_namespace IS NULL' |
| 55 | + ), |
| 56 | + // TODO test this join |
| 57 | + 'join_conds' => array( 'page AS p1' => array( 'LEFT JOIN', array( |
| 58 | + 'rd_from=p1.page_id', |
| 59 | + ) ), |
| 60 | + 'page AS p2' => array( 'LEFT JOIN', array( |
| 61 | + 'rd_namespace=p2.page_namespace', |
| 62 | + 'rd_title=p2.page_title' |
| 63 | + ) ) |
| 64 | + ) |
| 65 | + ); |
| 66 | + } |
43 | 67 | |
44 | 68 | function getOrder() { |
45 | | - return ''; |
| 69 | + return array (); |
46 | 70 | } |
47 | 71 | |
48 | 72 | function formatResult( $skin, $result ) { |
Index: branches/querypage-work2/phase3/includes/specials/SpecialAncientpages.php |
— | — | @@ -20,38 +20,23 @@ |
21 | 21 | |
22 | 22 | function isSyndicated() { return false; } |
23 | 23 | |
24 | | - function getSQL() { |
| 24 | + function getQueryInfo() { |
| 25 | + // FIXME convert timestamps elsewhere |
| 26 | + // Possibly add bool returnsTimestamps() |
| 27 | + // FIXME standardize 'name' AS type ? |
25 | 28 | global $wgDBtype; |
26 | | - $db = wfGetDB( DB_SLAVE ); |
27 | | - $page = $db->tableName( 'page' ); |
28 | | - $revision = $db->tableName( 'revision' ); |
29 | | - |
30 | | - switch ($wgDBtype) { |
31 | | - case 'mysql': |
32 | | - $epoch = 'UNIX_TIMESTAMP(rev_timestamp)'; |
33 | | - break; |
34 | | - case 'ibm_db2': |
35 | | - // TODO implement proper conversion to a Unix epoch |
36 | | - $epoch = 'rev_timestamp'; |
37 | | - break; |
38 | | - case 'oracle': |
39 | | - $epoch = '((trunc(rev_timestamp) - to_date(\'19700101\',\'YYYYMMDD\')) * 86400)'; |
40 | | - break; |
41 | | - case 'sqlite': |
42 | | - $epoch = 'rev_timestamp'; |
43 | | - break; |
44 | | - default: |
45 | | - $epoch = 'EXTRACT(epoch FROM rev_timestamp)'; |
46 | | - } |
47 | | - |
48 | | - return |
49 | | - "SELECT 'Ancientpages' as type, |
50 | | - page_namespace as namespace, |
51 | | - page_title as title, |
52 | | - $epoch as value |
53 | | - FROM $page, $revision |
54 | | - WHERE page_namespace=".NS_MAIN." AND page_is_redirect=0 |
55 | | - AND page_latest=rev_id"; |
| 29 | + $epoch = $wgDBtype == 'mysql' ? 'UNIX_TIMESTAMP(rev_timestamp)' : |
| 30 | + 'EXTRACT(epoch FROM rev_timestamp)'; |
| 31 | + return array( |
| 32 | + 'tables' => array( 'page', 'revision' ), |
| 33 | + 'fields' => array( "'{$this->getName()}' AS type", |
| 34 | + 'page_namespace AS namespace', |
| 35 | + 'page_title AS title', |
| 36 | + "$epoch AS value" ), |
| 37 | + 'conds' => array( 'page_namespace' => NS_MAIN, |
| 38 | + 'page_is_redirect' => 0, |
| 39 | + 'page_latest=rev_id' ) |
| 40 | + ); |
56 | 41 | } |
57 | 42 | |
58 | 43 | function sortDescending() { |
Index: branches/querypage-work2/phase3/includes/specials/SpecialDeadendpages.php |
— | — | @@ -47,6 +47,24 @@ |
48 | 48 | "AND page_namespace = 0 " . |
49 | 49 | "AND page_is_redirect = 0"; |
50 | 50 | } |
| 51 | + |
| 52 | + function getQueryInfo() { |
| 53 | + return array( |
| 54 | + 'tables' => array( 'page', 'pagelinks' ), |
| 55 | + 'fields' => array( "'{$this->getName()} AS type", |
| 56 | + 'page_namespace AS namespace', |
| 57 | + 'page_title AS title', |
| 58 | + 'page_title AS value' |
| 59 | + ), |
| 60 | + 'conds' => array( 'pl_from IS NULL', |
| 61 | + 'page_namespace' => NS_MAIN, |
| 62 | + 'page_is_redirect' => 0 |
| 63 | + ), |
| 64 | + 'join_conds' => array( 'pagelinks' => array( 'LEFT JOIN', array( |
| 65 | + 'page_id=pl_from' |
| 66 | + ) ) ) |
| 67 | + ); |
| 68 | + } |
51 | 69 | } |
52 | 70 | |
53 | 71 | /** |
Property changes on: branches/querypage-work2/phase3/includes/specials |
___________________________________________________________________ |
Name: svn:mergeinfo |
54 | 72 | - /branches/REL1_15/phase3/includes/specials:51646 |
/branches/sqlite/includes/specials:58211-58321 |
/branches/wmf-deployment/includes/specials:53381,56967 |
55 | 73 | + /branches/REL1_15/phase3/includes/specials:51646 |
/branches/querypage-work/phase3/includes/specials:49084 |
/branches/sqlite/includes/specials:58211-58321 |
/branches/wmf-deployment/includes/specials:53381,56967 |
Index: branches/querypage-work2/phase3/includes/QueryPage.php |
— | — | @@ -60,7 +60,7 @@ |
61 | 61 | * subclasses derive from it. |
62 | 62 | * @ingroup SpecialPage |
63 | 63 | */ |
64 | | -class QueryPage { |
| 64 | +abstract class QueryPage { |
65 | 65 | /** |
66 | 66 | * Whether or not we want plain listoutput rather than an ordered list |
67 | 67 | * |
— | — | @@ -106,8 +106,14 @@ |
107 | 107 | } |
108 | 108 | |
109 | 109 | /** |
110 | | - * Subclasses return an SQL query here. |
111 | | - * |
| 110 | + * Subclasses return an SQL query here, formatted as an array with the |
| 111 | + * following keys: |
| 112 | + * tables => Table(s) for passing to Database::select() |
| 113 | + * fields => Field(s) for passing to Database::select(), may be * |
| 114 | + * conds => WHERE conditions |
| 115 | + * options => options |
| 116 | + * join_conds => JOIN conditions |
| 117 | + * |
112 | 118 | * Note that the query itself should return the following four columns: |
113 | 119 | * 'type' (your special page's name), 'namespace', 'title', and 'value' |
114 | 120 | * *in that order*. 'value' is used for sorting. |
— | — | @@ -118,10 +124,19 @@ |
119 | 125 | * an integer; non-numeric values are useful only for sorting the initial |
120 | 126 | * query. |
121 | 127 | * |
122 | | - * Don't include an ORDER or LIMIT clause, this will be added. |
| 128 | + * Don't include an ORDER or LIMIT clause, they will be added |
| 129 | + * @return array |
123 | 130 | */ |
124 | | - function getSQL() { |
125 | | - return "SELECT 'sample' as type, 0 as namespace, 'Sample result' as title, 42 as value"; |
| 131 | + abstract function getQueryInfo(); |
| 132 | + |
| 133 | + /** |
| 134 | + * Subclasses return an array of fields to order by here. Don't append |
| 135 | + * DESC to the field names, that'll be done automatically if |
| 136 | + * sortDescending() returns true |
| 137 | + * @return array |
| 138 | + */ |
| 139 | + function getOrderFields() { |
| 140 | + return array('value'); |
126 | 141 | } |
127 | 142 | |
128 | 143 | /** |
— | — | @@ -133,11 +148,6 @@ |
134 | 149 | return true; |
135 | 150 | } |
136 | 151 | |
137 | | - function getOrder() { |
138 | | - return ' ORDER BY value ' . |
139 | | - ($this->sortDescending() ? 'DESC' : ''); |
140 | | - } |
141 | | - |
142 | 152 | /** |
143 | 153 | * Is this query expensive (for some definition of expensive)? Then we |
144 | 154 | * don't let it run in miser mode. $wgDisableQueryPages causes all query |
— | — | @@ -151,7 +161,7 @@ |
152 | 162 | } |
153 | 163 | |
154 | 164 | /** |
155 | | - * Whether or not the output of the page in question is retrived from |
| 165 | + * Whether or not the output of the page in question is retrieved from |
156 | 166 | * the database cache. |
157 | 167 | * |
158 | 168 | * @return Boolean |
— | — | @@ -175,14 +185,15 @@ |
176 | 186 | * Formats the results of the query for display. The skin is the current |
177 | 187 | * skin; you can use it for making links. The result is a single row of |
178 | 188 | * result data. You should be able to grab SQL results off of it. |
179 | | - * If the function return "false", the line output will be skipped. |
| 189 | + * If the function returns false, the line output will be skipped. |
| 190 | + * @param $skin Skin |
| 191 | + * @param $result object Result row |
| 192 | + * @return mixed String or false to skip |
180 | 193 | * |
181 | 194 | * @param $skin Skin object |
182 | 195 | * @param $result Object: database row |
183 | 196 | */ |
184 | | - function formatResult( $skin, $result ) { |
185 | | - return ''; |
186 | | - } |
| 197 | + abstract function formatResult( $skin, $result ); |
187 | 198 | |
188 | 199 | /** |
189 | 200 | * The content returned by this function will be output before any result |
— | — | @@ -207,8 +218,9 @@ |
208 | 219 | /** |
209 | 220 | * Some special pages (for example SpecialListusers) might not return the |
210 | 221 | * current object formatted, but return the previous one instead. |
211 | | - * Setting this to return true, will call one more time wfFormatResult to |
212 | | - * be sure that the very last result is formatted and shown. |
| 222 | + * Setting this to return true will ensure formatResult() is called |
| 223 | + * one more time to make sure that the very last result is formatted |
| 224 | + * as well. |
213 | 225 | */ |
214 | 226 | function tryLastResult() { |
215 | 227 | return false; |
— | — | @@ -228,8 +240,6 @@ |
229 | 241 | return false; |
230 | 242 | } |
231 | 243 | |
232 | | - $querycache = $dbr->tableName( 'querycache' ); |
233 | | - |
234 | 244 | if ( $ignoreErrors ) { |
235 | 245 | $ignoreW = $dbw->ignoreErrors( true ); |
236 | 246 | $ignoreR = $dbr->ignoreErrors( true ); |
— | — | @@ -238,10 +248,7 @@ |
239 | 249 | # Clear out any old cached data |
240 | 250 | $dbw->delete( 'querycache', array( 'qc_type' => $this->getName() ), $fname ); |
241 | 251 | # Do query |
242 | | - $sql = $this->getSQL() . $this->getOrder(); |
243 | | - if ( $limit !== false ) |
244 | | - $sql = $dbr->limitResult( $sql, $limit, 0 ); |
245 | | - $res = $dbr->query( $sql, $fname ); |
| 252 | + $res = $this->reallyDoQuery( $limit, false ); |
246 | 253 | $num = false; |
247 | 254 | if ( $res ) { |
248 | 255 | $num = $dbr->numRows( $res ); |
— | — | @@ -265,7 +272,7 @@ |
266 | 273 | if ( !$dbw->insert( 'querycache', $vals, __METHOD__ ) ) { |
267 | 274 | // Set result to false to indicate error |
268 | 275 | $dbr->freeResult( $res ); |
269 | | - $res = false; |
| 276 | + $num = false; |
270 | 277 | } |
271 | 278 | } |
272 | 279 | if ( $res ) { |
— | — | @@ -283,6 +290,68 @@ |
284 | 291 | } |
285 | 292 | return $num; |
286 | 293 | } |
| 294 | + |
| 295 | + /** |
| 296 | + * Run the query and return the result |
| 297 | + * @param $limit mixed Numerical limit or false for no limit |
| 298 | + * @param $offset mixed Numerical offset or false for no offset |
| 299 | + * @return ResultWrapper |
| 300 | + */ |
| 301 | + function reallyDoQuery( $limit, $offset = false ) { |
| 302 | + $fname = get_class( $this ) . "::reallyDoQuery"; |
| 303 | + $query = $this->getQueryInfo(); |
| 304 | + $order = $this->getOrderFields(); |
| 305 | + if( $this->sortDescending() ) { |
| 306 | + foreach( $order as &$field ) { |
| 307 | + $field .= ' DESC'; |
| 308 | + } |
| 309 | + } |
| 310 | + if( !is_array( $query['options'] ) ) { |
| 311 | + $options = array (); |
| 312 | + } |
| 313 | + if( count( $order ) ) { |
| 314 | + $query['options']['ORDER BY'] = implode( ', ', $order ); |
| 315 | + } |
| 316 | + if( $limit !== false) { |
| 317 | + $query['options']['LIMIT'] = intval( $limit ); |
| 318 | + } |
| 319 | + if( $offset !== false) { |
| 320 | + $query['options']['OFFSET'] = intval( $offset ); |
| 321 | + } |
| 322 | + |
| 323 | + $dbr = wfGetDB( DB_SLAVE ); |
| 324 | + $res = $dbr->select( (array)$query['tables'], |
| 325 | + (array)$query['fields'], |
| 326 | + (array)$query['conds'], $fname, |
| 327 | + $query['options'], (array)$query['join_conds'] |
| 328 | + ); |
| 329 | + return $dbr->resultObject( $res ); |
| 330 | + } |
| 331 | + |
| 332 | + /** |
| 333 | + * Fetch the query results from the query cache |
| 334 | + * @param $limit mixed Numerical limit or false for no limit |
| 335 | + * @param $offset mixed Numerical offset or false for no offset |
| 336 | + * @return ResultWrapper |
| 337 | + */ |
| 338 | + function fetchFromCache( $limit, $offset = false ) { |
| 339 | + $dbr = wfGetDB( DB_SLAVE ); |
| 340 | + $options = array (); |
| 341 | + if( $limit !== false ) { |
| 342 | + $options['LIMIT'] = intval( $limit ); |
| 343 | + } |
| 344 | + if( $offset !== false) { |
| 345 | + $options['OFFSET'] = intval( $offset ); |
| 346 | + } |
| 347 | + $res = $dbr->select( 'querycache', array( 'qc_type', |
| 348 | + 'qc_namespace AS namespace', |
| 349 | + 'qc_title AS title', |
| 350 | + 'qc_value AS value' ), |
| 351 | + array( 'qc_type' => $this->getName() ), |
| 352 | + __METHOD__, $options |
| 353 | + ); |
| 354 | + return $dbr->resultObject( $res ); |
| 355 | + } |
287 | 356 | |
288 | 357 | /** |
289 | 358 | * This is the actual workhorse. It does everything needed to make a |
— | — | @@ -304,16 +373,12 @@ |
305 | 374 | |
306 | 375 | $wgOut->setSyndicated( $this->isSyndicated() ); |
307 | 376 | |
| 377 | + //$res = null; |
308 | 378 | if ( !$this->isCached() ) { |
309 | | - $sql = $this->getSQL(); |
| 379 | + $res = $this->reallyDoQuery( $limit, $offset ); |
310 | 380 | } else { |
311 | 381 | # Get the cached result |
312 | | - $querycache = $dbr->tableName( 'querycache' ); |
313 | | - $type = $dbr->strencode( $sname ); |
314 | | - $sql = |
315 | | - "SELECT qc_type as type, qc_namespace as namespace,qc_title as title, qc_value as value |
316 | | - FROM $querycache WHERE qc_type='$type'"; |
317 | | - |
| 382 | + $res = $this->fetchFromCache( $limit, $offset ); |
318 | 383 | if( !$this->listoutput ) { |
319 | 384 | |
320 | 385 | # Fetch the timestamp of this update |
— | — | @@ -342,9 +407,6 @@ |
343 | 408 | |
344 | 409 | } |
345 | 410 | |
346 | | - $sql .= $this->getOrder(); |
347 | | - $sql = $dbr->limitResult($sql, $limit, $offset); |
348 | | - $res = $dbr->query( $sql ); |
349 | 411 | $num = $dbr->numRows($res); |
350 | 412 | |
351 | 413 | $this->preprocessResults( $dbr, $res ); |
— | — | @@ -485,9 +547,7 @@ |
486 | 548 | $feed->outHeader(); |
487 | 549 | |
488 | 550 | $dbr = wfGetDB( DB_SLAVE ); |
489 | | - $sql = $this->getSQL() . $this->getOrder(); |
490 | | - $sql = $dbr->limitResult( $sql, $limit, 0 ); |
491 | | - $res = $dbr->query( $sql, 'QueryPage::doFeed' ); |
| 551 | + $res = $this->reallyDoQuery( $limit, 0 ); |
492 | 552 | while( $obj = $dbr->fetchObject( $res ) ) { |
493 | 553 | $item = $this->feedResult( $obj ); |
494 | 554 | if( $item ) $feed->outItem( $item ); |
Property changes on: branches/querypage-work2/phase3/includes |
___________________________________________________________________ |
Name: svn:mergeinfo |
495 | 555 | - /branches/REL1_15/phase3/includes:51646 |
/branches/sqlite/includes:58211-58321 |
/branches/wmf-deployment/includes:53381 |
496 | 556 | + /branches/REL1_15/phase3/includes:51646 |
/branches/querypage-work/phase3/includes:49084 |
/branches/sqlite/includes:58211-58321 |
/branches/wmf-deployment/includes:53381 |
Property changes on: branches/querypage-work2/phase3 |
___________________________________________________________________ |
Name: svn:mergeinfo |
497 | 557 | - /branches/REL1_15/phase3:51646 |
/branches/sqlite:58211-58321 |
498 | 558 | + /branches/REL1_15/phase3:51646 |
/branches/querypage-work/phase3:49084 |
/branches/sqlite:58211-58321 |
Property changes on: branches/querypage-work2 |
___________________________________________________________________ |
Name: svn:mergeinfo |
499 | 559 | + /branches/querypage-work:49084 |