Index: trunk/phase3/includes/api/ApiQueryCategoryMembers.php |
— | — | @@ -86,17 +86,15 @@ |
87 | 87 | $fld_type = isset( $prop['type'] ); |
88 | 88 | |
89 | 89 | if ( is_null( $resultPageSet ) ) { |
90 | | - $this->addFields( array( 'cl_from', 'page_namespace', 'page_title' ) ); |
| 90 | + $this->addFields( array( 'cl_from', 'cl_sortkey', 'cl_type', 'page_namespace', 'page_title' ) ); |
91 | 91 | $this->addFieldsIf( 'page_id', $fld_ids ); |
92 | 92 | $this->addFieldsIf( 'cl_sortkey_prefix', $fld_sortkeyprefix ); |
93 | | - $this->addFieldsIf( 'cl_sortkey', $fld_sortkey ); |
94 | 93 | } else { |
95 | 94 | $this->addFields( $resultPageSet->getPageTableFields() ); // will include page_ id, ns, title |
96 | | - $this->addFields( array( 'cl_from', 'cl_sortkey' ) ); |
| 95 | + $this->addFields( array( 'cl_from', 'cl_sortkey', 'cl_type' ) ); |
97 | 96 | } |
98 | 97 | |
99 | 98 | $this->addFieldsIf( 'cl_timestamp', $fld_timestamp || $params['sort'] == 'timestamp' ); |
100 | | - $this->addFieldsIf( 'cl_type', $fld_type ); |
101 | 99 | |
102 | 100 | $this->addTables( array( 'page', 'categorylinks' ) ); // must be in this order for 'USE INDEX' |
103 | 101 | |
— | — | @@ -123,18 +121,37 @@ |
124 | 122 | |
125 | 123 | $this->addOption( 'USE INDEX', 'cl_timestamp' ); |
126 | 124 | } else { |
127 | | - // The below produces ORDER BY cl_type, cl_sortkey, cl_from, possibly with DESC added to each of them |
128 | | - $this->addWhereRange( 'cl_type', $dir, null, null ); |
129 | | - $this->addWhereRange( 'cl_sortkey', |
130 | | - $dir, |
131 | | - $params['startsortkey'], |
132 | | - $params['endsortkey'] ); |
133 | | - $this->addWhereRange( 'cl_from', $dir, null, null ); |
| 125 | + if ( $params['continue'] ) { |
| 126 | + // type|from|sortkey |
| 127 | + $cont = explode( '|', $params['continue'], 3 ); |
| 128 | + if ( count( $cont ) != 3 ) { |
| 129 | + $this->dieUsage( 'Invalid continue param. You should pass the original value returned '. |
| 130 | + 'by the previous query', '_badcontinue' |
| 131 | + ); |
| 132 | + } |
| 133 | + $escType = $this->getDB()->addQuotes( $cont[0] ); |
| 134 | + $from = intval( $cont[1] ); |
| 135 | + $escSortkey = $this->getDB()->addQuotes( $cont[2] ); |
| 136 | + $op = $dir == 'newer' ? '>' : '<'; |
| 137 | + $this->addWhere( "cl_type $op $escType OR " . |
| 138 | + "(cl_type = $escType AND " . |
| 139 | + "(cl_sortkey $op $escSortkey OR " . |
| 140 | + "(cl_sortkey = $escSortkey AND " . |
| 141 | + "cl_from $op= $from)))" |
| 142 | + ); |
| 143 | + |
| 144 | + } else { |
| 145 | + // The below produces ORDER BY cl_type, cl_sortkey, cl_from, possibly with DESC added to each of them |
| 146 | + $this->addWhereRange( 'cl_type', $dir, null, null ); |
| 147 | + $this->addWhereRange( 'cl_sortkey', |
| 148 | + $dir, |
| 149 | + $params['startsortkey'], |
| 150 | + $params['endsortkey'] ); |
| 151 | + $this->addWhereRange( 'cl_from', $dir, null, null ); |
| 152 | + } |
134 | 153 | $this->addOption( 'USE INDEX', 'cl_sortkey' ); |
135 | 154 | } |
136 | 155 | |
137 | | - $this->setContinuation( $params['continue'], $params['dir'] ); |
138 | | - |
139 | 156 | $this->addWhere( 'cl_from=page_id' ); |
140 | 157 | |
141 | 158 | $limit = $params['limit']; |
— | — | @@ -149,7 +166,13 @@ |
150 | 167 | if ( $params['sort'] == 'timestamp' ) { |
151 | 168 | $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->cl_timestamp ) ); |
152 | 169 | } else { |
153 | | - $this->setContinueEnumParameter( 'continue', $row->cl_from ); |
| 170 | + // Continue format is type|from|sortkey |
| 171 | + // The order is a bit weird but it's convenient to put the sortkey at the end |
| 172 | + // because we don't have to worry about pipes in the sortkey that way |
| 173 | + // (and type and from can't contain pipes anyway) |
| 174 | + $this->setContinueEnumParameter( 'continue', |
| 175 | + "{$row->cl_type}|{$row->cl_from}|{$row->cl_sortkey}" |
| 176 | + ); |
154 | 177 | } |
155 | 178 | break; |
156 | 179 | } |
— | — | @@ -189,7 +212,9 @@ |
190 | 213 | if ( $params['sort'] == 'timestamp' ) { |
191 | 214 | $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->cl_timestamp ) ); |
192 | 215 | } else { |
193 | | - $this->setContinueEnumParameter( 'continue', $row->cl_from ); |
| 216 | + $this->setContinueEnumParameter( 'continue', |
| 217 | + "{$row->cl_type}|{$row->cl_from}|{$row->cl_sortkey}" |
| 218 | + ); |
194 | 219 | } |
195 | 220 | break; |
196 | 221 | } |
— | — | @@ -204,21 +229,6 @@ |
205 | 230 | } |
206 | 231 | } |
207 | 232 | |
208 | | - /** |
209 | | - * Add DB WHERE clause to continue previous query based on 'continue' parameter |
210 | | - */ |
211 | | - private function setContinuation( $continue, $dir ) { |
212 | | - if ( is_null( $continue ) ) { |
213 | | - return; // This is not a continuation request |
214 | | - } |
215 | | - |
216 | | - $encFrom = $this->getDB()->addQuotes( intval( $continue ) ); |
217 | | - |
218 | | - $op = ( $dir == 'desc' ? '<=' : '>=' ); |
219 | | - |
220 | | - $this->addWhere( "cl_from $op $encFrom" ); |
221 | | - } |
222 | | - |
223 | 233 | public function getAllowedParams() { |
224 | 234 | return array( |
225 | 235 | 'title' => array( |
— | — | @@ -316,7 +326,8 @@ |
317 | 327 | $desc['namespace'] = array( |
318 | 328 | $desc['namespace'], |
319 | 329 | 'NOTE: Due to $wgMiserMode, using this may result in fewer than "limit" results', |
320 | | - 'returned before continuing; in extreme cases, zero results may be returned', |
| 330 | + 'returned before continuing; in extreme cases, zero results may be returned.', |
| 331 | + 'Note that you can use cmtype=subcat or cmtype=file instead of cmnamespace=14 or 6.', |
321 | 332 | ); |
322 | 333 | } |
323 | 334 | return $desc; |