MediaWiki  master
BatchRowIterator.php
Go to the documentation of this file.
1 <?php
2 
4 
29 class BatchRowIterator implements RecursiveIterator {
30 
34  protected $db;
35 
39  protected $table;
40 
44  protected $primaryKey;
45 
49  protected $batchSize;
50 
55  protected $conditions = [];
56 
60  protected $joinConditions = [];
61 
66  protected $fetchColumns;
67 
71  protected $orderBy;
72 
76  private $current = [];
77 
81  private $key;
82 
86  protected $options = [];
87 
96  if ( $batchSize < 1 ) {
97  throw new InvalidArgumentException( 'Batch size must be at least 1 row.' );
98  }
99  $this->db = $db;
100  $this->table = $table;
101  $this->primaryKey = (array)$primaryKey;
102  $this->fetchColumns = $this->primaryKey;
103  $this->orderBy = implode( ' ASC,', $this->primaryKey ) . ' ASC';
104  $this->batchSize = $batchSize;
105  }
106 
111  public function addConditions( array $conditions ) {
112  $this->conditions = array_merge( $this->conditions, $conditions );
113  }
114 
119  public function addOptions( array $options ) {
120  $this->options = array_merge( $this->options, $options );
121  }
122 
127  public function addJoinConditions( array $conditions ) {
128  $this->joinConditions = array_merge( $this->joinConditions, $conditions );
129  }
130 
135  public function setFetchColumns( array $columns ) {
136  // If it's not the all column selector merge in the primary keys we need
137  if ( count( $columns ) === 1 && reset( $columns ) === '*' ) {
138  $this->fetchColumns = $columns;
139  } else {
140  $this->fetchColumns = array_unique( array_merge(
141  $this->primaryKey,
142  $columns
143  ) );
144  }
145  }
146 
153  public function extractPrimaryKeys( $row ) {
154  $pk = [];
155  foreach ( $this->primaryKey as $alias => $column ) {
156  $name = is_numeric( $alias ) ? $column : $alias;
157  $pk[$name] = $row->{$name};
158  }
159  return $pk;
160  }
161 
165  public function current() {
166  return $this->current;
167  }
168 
172  public function key() {
173  return $this->key;
174  }
175 
179  public function rewind() {
180  $this->key = -1; // self::next() will turn this into 0
181  $this->current = [];
182  $this->next();
183  }
184 
188  public function valid() {
189  return (bool)$this->current;
190  }
191 
195  public function hasChildren() {
196  return $this->current && count( $this->current );
197  }
198 
202  public function getChildren() {
203  return new NotRecursiveIterator( new ArrayIterator( $this->current ) );
204  }
205 
209  public function next() {
210  $res = $this->db->select(
211  $this->table,
212  $this->fetchColumns,
213  $this->buildConditions(),
214  __METHOD__,
215  [
216  'LIMIT' => $this->batchSize,
217  'ORDER BY' => $this->orderBy,
218  ] + $this->options,
219  $this->joinConditions
220  );
221 
222  // The iterator is converted to an array because in addition to
223  // returning it in self::current() we need to use the end value
224  // in self::buildConditions()
225  $this->current = iterator_to_array( $res );
226  $this->key++;
227  }
228 
241  protected function buildConditions() {
242  if ( !$this->current ) {
243  return $this->conditions;
244  }
245 
246  $maxRow = end( $this->current );
247  $maximumValues = [];
248  foreach ( $this->primaryKey as $alias => $column ) {
249  $name = is_numeric( $alias ) ? $column : $alias;
250  $maximumValues[$column] = $this->db->addQuotes( $maxRow->{$name} );
251  }
252 
253  $pkConditions = [];
254  // For example: If we have 3 primary keys
255  // first run through will generate
256  // col1 = 4 AND col2 = 7 AND col3 > 1
257  // second run through will generate
258  // col1 = 4 AND col2 > 7
259  // and the final run through will generate
260  // col1 > 4
261  while ( $maximumValues ) {
262  $pkConditions[] = $this->buildGreaterThanCondition( $maximumValues );
263  array_pop( $maximumValues );
264  }
265 
266  $conditions = $this->conditions;
267  $conditions[] = sprintf( '( %s )', implode( ' ) OR ( ', $pkConditions ) );
268 
269  return $conditions;
270  }
271 
284  protected function buildGreaterThanCondition( array $quotedMaximumValues ) {
285  $keys = array_keys( $quotedMaximumValues );
286  $lastColumn = end( $keys );
287  $lastValue = array_pop( $quotedMaximumValues );
288  $conditions = [];
289  foreach ( $quotedMaximumValues as $column => $value ) {
290  $conditions[] = "$column = $value";
291  }
292  $conditions[] = "$lastColumn > $lastValue";
293 
294  return implode( ' AND ', $conditions );
295  }
296 }
BatchRowIterator\$conditions
$conditions
Definition: BatchRowIterator.php:55
BatchRowIterator\$joinConditions
array $joinConditions
Definition: BatchRowIterator.php:60
BatchRowIterator\setFetchColumns
setFetchColumns(array $columns)
Definition: BatchRowIterator.php:135
BatchRowIterator\rewind
rewind()
Reset the iterator to the begining of the table.
Definition: BatchRowIterator.php:179
BatchRowIterator\valid
valid()
Definition: BatchRowIterator.php:188
BatchRowIterator\addConditions
addConditions(array $conditions)
Definition: BatchRowIterator.php:111
BatchRowIterator
Definition: BatchRowIterator.php:29
BatchRowIterator\buildGreaterThanCondition
buildGreaterThanCondition(array $quotedMaximumValues)
Given an array of column names and their maximum value generate an SQL condition where all keys excep...
Definition: BatchRowIterator.php:284
BatchRowIterator\extractPrimaryKeys
extractPrimaryKeys( $row)
Extracts the primary key(s) from a database row.
Definition: BatchRowIterator.php:153
$res
$res
Definition: testCompression.php:54
BatchRowIterator\$orderBy
$orderBy
Definition: BatchRowIterator.php:71
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
BatchRowIterator\hasChildren
hasChildren()
Definition: BatchRowIterator.php:195
BatchRowIterator\$table
$table
Definition: BatchRowIterator.php:39
BatchRowIterator\next
next()
Fetch the next set of rows from the database.
Definition: BatchRowIterator.php:209
BatchRowIterator\$current
$current
Definition: BatchRowIterator.php:76
BatchRowIterator\key
key()
Definition: BatchRowIterator.php:172
BatchRowIterator\buildConditions
buildConditions()
Uses the primary key list and the maximal result row from the previous iteration to build an SQL cond...
Definition: BatchRowIterator.php:241
BatchRowIterator\addOptions
addOptions(array $options)
Definition: BatchRowIterator.php:119
NotRecursiveIterator
Definition: NotRecursiveIterator.php:27
BatchRowIterator\__construct
__construct(IDatabase $db, $table, $primaryKey, $batchSize)
Definition: BatchRowIterator.php:95
BatchRowIterator\$batchSize
$batchSize
Definition: BatchRowIterator.php:49
BatchRowIterator\$db
$db
Definition: BatchRowIterator.php:34
BatchRowIterator\$primaryKey
$primaryKey
Definition: BatchRowIterator.php:44
BatchRowIterator\$key
int $key
key 0-indexed number of pages fetched since self::reset()
Definition: BatchRowIterator.php:81
BatchRowIterator\addJoinConditions
addJoinConditions(array $conditions)
Definition: BatchRowIterator.php:127
BatchRowIterator\$fetchColumns
$fetchColumns
Definition: BatchRowIterator.php:66
$keys
$keys
Definition: testCompression.php:69
BatchRowIterator\current
current()
Definition: BatchRowIterator.php:165
BatchRowIterator\getChildren
getChildren()
Definition: BatchRowIterator.php:202
BatchRowIterator\$options
array $options
Additional query options.
Definition: BatchRowIterator.php:86