Index: trunk/phase3/includes/api/ApiQueryLinks.php |
— | — | @@ -84,7 +84,22 @@ |
85 | 85 | $this->addTables($this->table); |
86 | 86 | $this->addWhereFld($this->prefix . '_from', array_keys($this->getPageSet()->getGoodTitles())); |
87 | 87 | $this->addWhereFld($this->prefix . '_namespace', $params['namespace']); |
88 | | - |
| 88 | + |
| 89 | + if(!is_null($params['continue'])) { |
| 90 | + $cont = explode('|', $params['continue']); |
| 91 | + if(count($cont) != 3) |
| 92 | + $this->dieUsage("Invalid continue param. You should pass the " . |
| 93 | + "original value returned by the previous query", "_badcontinue"); |
| 94 | + $plfrom = intval($cont[0]); |
| 95 | + $plns = intval($cont[1]); |
| 96 | + $pltitle = $this->getDb()->strencode($cont[2]); |
| 97 | + $this->addWhere("{$this->prefix}_from > $plfrom OR ". |
| 98 | + "({$this->prefix}_from = $plfrom AND ". |
| 99 | + "({$this->prefix}_namespace > $plns OR ". |
| 100 | + "({$this->prefix}_namespace = $plns AND ". |
| 101 | + "{$this->prefix}_title >= '$pltitle')))"); |
| 102 | + } |
| 103 | + |
89 | 104 | # Here's some MySQL craziness going on: if you use WHERE foo='bar' |
90 | 105 | # and later ORDER BY foo MySQL doesn't notice the ORDER BY is pointless |
91 | 106 | # but instead goes and filesorts, because the index for foo was used |
— | — | @@ -93,11 +108,12 @@ |
94 | 109 | $order = array(); |
95 | 110 | if(count($this->getPageSet()->getGoodTitles()) != 1) |
96 | 111 | $order[] = "{$this->prefix}_from"; |
97 | | - if(!isset($params['namespace'])) |
| 112 | + if(count($params['namespace']) != 1) |
98 | 113 | $order[] = "{$this->prefix}_namespace"; |
99 | 114 | $order[] = "{$this->prefix}_title"; |
100 | 115 | $this->addOption('ORDER BY', implode(", ", $order)); |
101 | 116 | $this->addOption('USE INDEX', "{$this->prefix}_from"); |
| 117 | + $this->addOption('LIMIT', $params['limit'] + 1); |
102 | 118 | |
103 | 119 | $db = $this->getDB(); |
104 | 120 | $res = $this->select(__METHOD__); |
— | — | @@ -106,7 +122,15 @@ |
107 | 123 | |
108 | 124 | $data = array(); |
109 | 125 | $lastId = 0; // database has no ID 0 |
| 126 | + $count = 0; |
110 | 127 | while ($row = $db->fetchObject($res)) { |
| 128 | + if(++$count > $params['limit']) { |
| 129 | + // We've reached the one extra which shows that |
| 130 | + // there are additional pages to be had. Stop here... |
| 131 | + $this->setContinueEnumParameter('continue', |
| 132 | + "{$row->pl_from}|{$row->pl_namespace}|{$row->pl_title}"); |
| 133 | + break; |
| 134 | + } |
111 | 135 | if ($lastId != $row->pl_from) { |
112 | 136 | if($lastId != 0) { |
113 | 137 | $this->addPageSubItems($lastId, $data); |
— | — | @@ -127,7 +151,15 @@ |
128 | 152 | } else { |
129 | 153 | |
130 | 154 | $titles = array(); |
| 155 | + $count = 0; |
131 | 156 | while ($row = $db->fetchObject($res)) { |
| 157 | + if(++$count > $params['limit']) { |
| 158 | + // We've reached the one extra which shows that |
| 159 | + // there are additional pages to be had. Stop here... |
| 160 | + $this->setContinueEnumParameter('continue', |
| 161 | + "{$row->pl_from}|{$row->pl_namespace}|{$row->pl_title}"); |
| 162 | + break; |
| 163 | + } |
132 | 164 | $titles[] = Title :: makeTitle($row->pl_namespace, $row->pl_title); |
133 | 165 | } |
134 | 166 | $resultPageSet->populateFromTitles($titles); |
— | — | @@ -142,15 +174,25 @@ |
143 | 175 | 'namespace' => array( |
144 | 176 | ApiBase :: PARAM_TYPE => 'namespace', |
145 | 177 | ApiBase :: PARAM_ISMULTI => true |
146 | | - ) |
| 178 | + ), |
| 179 | + 'limit' => array( |
| 180 | + ApiBase :: PARAM_DFLT => 10, |
| 181 | + ApiBase :: PARAM_TYPE => 'limit', |
| 182 | + ApiBase :: PARAM_MIN => 1, |
| 183 | + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, |
| 184 | + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 |
| 185 | + ), |
| 186 | + 'continue' => null, |
147 | 187 | ); |
148 | 188 | } |
149 | 189 | |
150 | 190 | public function getParamDescription() |
151 | 191 | { |
152 | 192 | return array( |
153 | | - 'namespace' => "Show {$this->description}s in this namespace(s) only" |
154 | | - ); |
| 193 | + 'namespace' => "Show {$this->description}s in this namespace(s) only", |
| 194 | + 'limit' => 'How many links to return', |
| 195 | + 'continue' => 'When more results are available, use this to continue', |
| 196 | + ); |
155 | 197 | } |
156 | 198 | |
157 | 199 | public function getDescription() { |
Index: trunk/phase3/includes/api/ApiQueryLangLinks.php |
— | — | @@ -43,6 +43,7 @@ |
44 | 44 | if ( $this->getPageSet()->getGoodTitleCount() == 0 ) |
45 | 45 | return; |
46 | 46 | |
| 47 | + $params = $this->extractRequestParams(); |
47 | 48 | $this->addFields(array ( |
48 | 49 | 'll_from', |
49 | 50 | 'll_lang', |
— | — | @@ -51,14 +52,36 @@ |
52 | 53 | |
53 | 54 | $this->addTables('langlinks'); |
54 | 55 | $this->addWhereFld('ll_from', array_keys($this->getPageSet()->getGoodTitles())); |
55 | | - $this->addOption('ORDER BY', "ll_from, ll_lang"); |
| 56 | + if(!is_null($params['continue'])) { |
| 57 | + $cont = explode('|', $params['continue']); |
| 58 | + if(count($cont) != 2) |
| 59 | + $this->dieUsage("Invalid continue param. You should pass the " . |
| 60 | + "original value returned by the previous query", "_badcontinue"); |
| 61 | + $llfrom = intval($cont[0]); |
| 62 | + $lllang = $this->getDb()->strencode($cont[1]); |
| 63 | + $this->addWhere("ll_from > $llfrom OR ". |
| 64 | + "(ll_from = $llfrom AND ". |
| 65 | + "ll_lang >= '$lllang')"); |
| 66 | + } |
| 67 | + # Don't order by ll_from if it's constant in the WHERE clause |
| 68 | + if(count($this->getPageSet()->getGoodTitles()) == 1) |
| 69 | + $this->addOption('ORDER BY', 'll_lang'); |
| 70 | + else |
| 71 | + $this->addOption('ORDER BY', 'll_from, ll_lang'); |
| 72 | + $this->addOption('LIMIT', $params['limit'] + 1); |
56 | 73 | $res = $this->select(__METHOD__); |
57 | 74 | |
58 | 75 | $data = array(); |
59 | 76 | $lastId = 0; // database has no ID 0 |
| 77 | + $count = 0; |
60 | 78 | $db = $this->getDB(); |
61 | 79 | while ($row = $db->fetchObject($res)) { |
62 | | - |
| 80 | + if (++$count > $params['limit']) { |
| 81 | + // We've reached the one extra which shows that |
| 82 | + // there are additional pages to be had. Stop here... |
| 83 | + $this->setContinueEnumParameter('continue', "{$row->ll_from}|{$row->ll_lang}"); |
| 84 | + break; |
| 85 | + } |
63 | 86 | if ($lastId != $row->ll_from) { |
64 | 87 | if($lastId != 0) { |
65 | 88 | $this->addPageSubItems($lastId, $data); |
— | — | @@ -67,7 +90,7 @@ |
68 | 91 | $lastId = $row->ll_from; |
69 | 92 | } |
70 | 93 | |
71 | | - $entry = array('lang'=>$row->ll_lang); |
| 94 | + $entry = array('lang' => $row->ll_lang); |
72 | 95 | ApiResult :: setContent($entry, $row->ll_title); |
73 | 96 | $data[] = $entry; |
74 | 97 | } |
— | — | @@ -79,6 +102,26 @@ |
80 | 103 | $db->freeResult($res); |
81 | 104 | } |
82 | 105 | |
| 106 | + public function getAllowedParams() { |
| 107 | + return array( |
| 108 | + 'limit' => array( |
| 109 | + ApiBase :: PARAM_DFLT => 10, |
| 110 | + ApiBase :: PARAM_TYPE => 'limit', |
| 111 | + ApiBase :: PARAM_MIN => 1, |
| 112 | + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, |
| 113 | + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 |
| 114 | + ), |
| 115 | + 'continue' => null, |
| 116 | + ); |
| 117 | + } |
| 118 | + |
| 119 | + public function getParamDescription () { |
| 120 | + return array( |
| 121 | + 'limit' => 'How many langlinks to return', |
| 122 | + 'continue' => 'When more results are available, use this to continue', |
| 123 | + ); |
| 124 | + } |
| 125 | + |
83 | 126 | public function getDescription() { |
84 | 127 | return 'Returns all interlanguage links from the given page(s)'; |
85 | 128 | } |
Index: trunk/phase3/includes/api/ApiQueryExternalLinks.php |
— | — | @@ -43,6 +43,7 @@ |
44 | 44 | if ( $this->getPageSet()->getGoodTitleCount() == 0 ) |
45 | 45 | return; |
46 | 46 | |
| 47 | + $params = $this->extractRequestParams(); |
47 | 48 | $this->addFields(array ( |
48 | 49 | 'el_from', |
49 | 50 | 'el_to' |
— | — | @@ -50,13 +51,26 @@ |
51 | 52 | |
52 | 53 | $this->addTables('externallinks'); |
53 | 54 | $this->addWhereFld('el_from', array_keys($this->getPageSet()->getGoodTitles())); |
| 55 | + # Don't order by el_from if it's constant in the WHERE clause |
| 56 | + if(count($this->getPageSet()->getGoodTitles()) != 1) |
| 57 | + $this->addOption('ORDER BY', 'el_from'); |
| 58 | + $this->addOption('LIMIT', $params['limit'] + 1); |
| 59 | + if(!is_null($params['offset'])) |
| 60 | + $this->addOption('OFFSET', $params['offset']); |
54 | 61 | |
55 | 62 | $db = $this->getDB(); |
56 | 63 | $res = $this->select(__METHOD__); |
57 | 64 | |
58 | 65 | $data = array(); |
59 | 66 | $lastId = 0; // database has no ID 0 |
| 67 | + $count = 0; |
60 | 68 | while ($row = $db->fetchObject($res)) { |
| 69 | + if (++$count > $params['limit']) { |
| 70 | + // We've reached the one extra which shows that |
| 71 | + // there are additional pages to be had. Stop here... |
| 72 | + $this->setContinueEnumParameter('offset', @$params['offset'] + $params['limit']); |
| 73 | + break; |
| 74 | + } |
61 | 75 | if ($lastId != $row->el_from) { |
62 | 76 | if($lastId != 0) { |
63 | 77 | $this->addPageSubItems($lastId, $data); |
— | — | @@ -77,6 +91,26 @@ |
78 | 92 | $db->freeResult($res); |
79 | 93 | } |
80 | 94 | |
| 95 | + public function getAllowedParams() { |
| 96 | + return array( |
| 97 | + 'limit' => array( |
| 98 | + ApiBase :: PARAM_DFLT => 10, |
| 99 | + ApiBase :: PARAM_TYPE => 'limit', |
| 100 | + ApiBase :: PARAM_MIN => 1, |
| 101 | + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, |
| 102 | + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 |
| 103 | + ), |
| 104 | + 'offset' => null, |
| 105 | + ); |
| 106 | + } |
| 107 | + |
| 108 | + public function getParamDescription () { |
| 109 | + return array( |
| 110 | + 'limit' => 'How many links to return', |
| 111 | + 'offset' => 'When more results are available, use this to continue', |
| 112 | + ); |
| 113 | + } |
| 114 | + |
81 | 115 | public function getDescription() { |
82 | 116 | return 'Returns all external urls (not interwikies) from the given page(s)'; |
83 | 117 | } |
Index: trunk/phase3/includes/api/ApiQueryCategories.php |
— | — | @@ -80,7 +80,22 @@ |
81 | 81 | |
82 | 82 | $this->addTables('categorylinks'); |
83 | 83 | $this->addWhereFld('cl_from', array_keys($this->getPageSet()->getGoodTitles())); |
84 | | - $this->addOption('ORDER BY', "cl_from, cl_to"); |
| 84 | + if(!is_null($params['continue'])) { |
| 85 | + $cont = explode('|', $params['continue']); |
| 86 | + if(count($cont) != 2) |
| 87 | + $this->dieUsage("Invalid continue param. You should pass the " . |
| 88 | + "original value returned by the previous query", "_badcontinue"); |
| 89 | + $clfrom = intval($cont[0]); |
| 90 | + $clto = $this->getDb()->strencode($cont[1]); |
| 91 | + $this->addWhere("cl_from > $clfrom OR ". |
| 92 | + "(cl_from = $clfrom AND ". |
| 93 | + "cl_to >= '$clto')"); |
| 94 | + } |
| 95 | + # Don't order by cl_from if it's constant in the WHERE clause |
| 96 | + if(count($this->getPageSet()->getGoodTitles()) == 1) |
| 97 | + $this->addOption('ORDER BY', 'cl_to'); |
| 98 | + else |
| 99 | + $this->addOption('ORDER BY', "cl_from, cl_to"); |
85 | 100 | |
86 | 101 | $db = $this->getDB(); |
87 | 102 | $res = $this->select(__METHOD__); |
— | — | @@ -89,7 +104,14 @@ |
90 | 105 | |
91 | 106 | $data = array(); |
92 | 107 | $lastId = 0; // database has no ID 0 |
| 108 | + $count = 0; |
93 | 109 | while ($row = $db->fetchObject($res)) { |
| 110 | + if (++$count > $params['limit']) { |
| 111 | + // We've reached the one extra which shows that |
| 112 | + // there are additional pages to be had. Stop here... |
| 113 | + $this->setContinueEnumParameter('continue', "{$row->cl_from}|{$row->cl_to}"); |
| 114 | + break; |
| 115 | + } |
94 | 116 | if ($lastId != $row->cl_from) { |
95 | 117 | if($lastId != 0) { |
96 | 118 | $this->addPageSubItems($lastId, $data); |
— | — | @@ -118,6 +140,13 @@ |
119 | 141 | |
120 | 142 | $titles = array(); |
121 | 143 | while ($row = $db->fetchObject($res)) { |
| 144 | + if (++$count > $params['limit']) { |
| 145 | + // We've reached the one extra which shows that |
| 146 | + // there are additional pages to be had. Stop here... |
| 147 | + $this->setContinueEnumParameter('continue', "{$row->il_from}|{$row->il_to}"); |
| 148 | + break; |
| 149 | + } |
| 150 | + |
122 | 151 | $titles[] = Title :: makeTitle(NS_CATEGORY, $row->cl_to); |
123 | 152 | } |
124 | 153 | $resultPageSet->populateFromTitles($titles); |
— | — | @@ -134,13 +163,23 @@ |
135 | 164 | 'sortkey', |
136 | 165 | 'timestamp', |
137 | 166 | ) |
138 | | - ) |
| 167 | + ), |
| 168 | + 'limit' => array( |
| 169 | + ApiBase :: PARAM_DFLT => 10, |
| 170 | + ApiBase :: PARAM_TYPE => 'limit', |
| 171 | + ApiBase :: PARAM_MIN => 1, |
| 172 | + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, |
| 173 | + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 |
| 174 | + ), |
| 175 | + 'continue' => null, |
139 | 176 | ); |
140 | 177 | } |
141 | 178 | |
142 | 179 | public function getParamDescription() { |
143 | 180 | return array ( |
144 | 181 | 'prop' => 'Which additional properties to get for each category.', |
| 182 | + 'limit' => 'How many langlinks to return', |
| 183 | + 'continue' => 'When more results are available, use this to continue', |
145 | 184 | ); |
146 | 185 | } |
147 | 186 | |
Index: trunk/phase3/includes/api/ApiQueryImages.php |
— | — | @@ -29,7 +29,7 @@ |
30 | 30 | } |
31 | 31 | |
32 | 32 | /** |
33 | | - * This query adds <images> subelement to all pages with the list of images embedded into those pages. |
| 33 | + * This query adds an <images> subelement to all pages with the list of images embedded into those pages. |
34 | 34 | * |
35 | 35 | * @ingroup API |
36 | 36 | */ |
— | — | @@ -52,6 +52,7 @@ |
53 | 53 | if ($this->getPageSet()->getGoodTitleCount() == 0) |
54 | 54 | return; // nothing to do |
55 | 55 | |
| 56 | + $params = $this->extractRequestParams(); |
56 | 57 | $this->addFields(array ( |
57 | 58 | 'il_from', |
58 | 59 | 'il_to' |
— | — | @@ -59,7 +60,23 @@ |
60 | 61 | |
61 | 62 | $this->addTables('imagelinks'); |
62 | 63 | $this->addWhereFld('il_from', array_keys($this->getPageSet()->getGoodTitles())); |
63 | | - $this->addOption('ORDER BY', "il_from, il_to"); |
| 64 | + if(!is_null($params['continue'])) { |
| 65 | + $cont = explode('|', $params['continue']); |
| 66 | + if(count($cont) != 2) |
| 67 | + $this->dieUsage("Invalid continue param. You should pass the " . |
| 68 | + "original value returned by the previous query", "_badcontinue"); |
| 69 | + $ilfrom = intval($cont[0]); |
| 70 | + $ilto = $this->getDb()->strencode($cont[1]); |
| 71 | + $this->addWhere("il_from > $ilfrom OR ". |
| 72 | + "(il_from = $ilfrom AND ". |
| 73 | + "il_to >= '$ilto')"); |
| 74 | + } |
| 75 | + # Don't order by il_from if it's constant in the WHERE clause |
| 76 | + if(count($this->getPageSet()->getGoodTitles()) == 1) |
| 77 | + $this->addOption('ORDER BY', 'il_to'); |
| 78 | + else |
| 79 | + $this->addOption('ORDER BY', 'il_from, il_to'); |
| 80 | + $this->addOption('LIMIT', $params['limit'] + 1); |
64 | 81 | |
65 | 82 | $db = $this->getDB(); |
66 | 83 | $res = $this->select(__METHOD__); |
— | — | @@ -68,7 +85,14 @@ |
69 | 86 | |
70 | 87 | $data = array(); |
71 | 88 | $lastId = 0; // database has no ID 0 |
| 89 | + $count = 0; |
72 | 90 | while ($row = $db->fetchObject($res)) { |
| 91 | + if (++$count > $params['limit']) { |
| 92 | + // We've reached the one extra which shows that |
| 93 | + // there are additional pages to be had. Stop here... |
| 94 | + $this->setContinueEnumParameter('continue', "{$row->il_from}|{$row->il_to}"); |
| 95 | + break; |
| 96 | + } |
73 | 97 | if ($lastId != $row->il_from) { |
74 | 98 | if($lastId != 0) { |
75 | 99 | $this->addPageSubItems($lastId, $data); |
— | — | @@ -89,7 +113,14 @@ |
90 | 114 | } else { |
91 | 115 | |
92 | 116 | $titles = array(); |
| 117 | + $count = 0; |
93 | 118 | while ($row = $db->fetchObject($res)) { |
| 119 | + if (++$count > $params['limit']) { |
| 120 | + // We've reached the one extra which shows that |
| 121 | + // there are additional pages to be had. Stop here... |
| 122 | + $this->setContinueEnumParameter('continue', "{$row->il_from}|{$row->il_to}"); |
| 123 | + break; |
| 124 | + } |
94 | 125 | $titles[] = Title :: makeTitle(NS_IMAGE, $row->il_to); |
95 | 126 | } |
96 | 127 | $resultPageSet->populateFromTitles($titles); |
— | — | @@ -98,6 +129,26 @@ |
99 | 130 | $db->freeResult($res); |
100 | 131 | } |
101 | 132 | |
| 133 | + public function getAllowedParams() { |
| 134 | + return array( |
| 135 | + 'limit' => array( |
| 136 | + ApiBase :: PARAM_DFLT => 10, |
| 137 | + ApiBase :: PARAM_TYPE => 'limit', |
| 138 | + ApiBase :: PARAM_MIN => 1, |
| 139 | + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, |
| 140 | + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 |
| 141 | + ), |
| 142 | + 'continue' => null, |
| 143 | + ); |
| 144 | + } |
| 145 | + |
| 146 | + public function getParamDescription () { |
| 147 | + return array( |
| 148 | + 'limit' => 'How many images to return', |
| 149 | + 'continue' => 'When more results are available, use this to continue', |
| 150 | + ); |
| 151 | + } |
| 152 | + |
102 | 153 | public function getDescription() { |
103 | 154 | return 'Returns all images contained on the given page(s)'; |
104 | 155 | } |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -507,6 +507,8 @@ |
508 | 508 | * Added APIQueryInfoTokens and APIQueryRevisionsTokens hooks so extensions |
509 | 509 | can add their own tokens |
510 | 510 | * Added block and unblock tokens to prop=info as well |
| 511 | +* Added paging (limit and continue parameters) to |
| 512 | + prop={links,templatelinks,langlinks,extlinks,categories,images} |
511 | 513 | |
512 | 514 | === Languages updated in 1.13 === |
513 | 515 | |