MediaWiki REL1_35
SelectQueryBuilder.php
Go to the documentation of this file.
1<?php
2
3namespace Wikimedia\Rdbms;
4
9 private $fields = [];
10
14 private $conds = [];
15
19 private $caller = __CLASS__;
20
24 private $options = [];
25
29 private $nextAutoAlias = 1;
30
32 private $db;
33
39 public function __construct( IDatabase $db ) {
40 $this->db = $db;
41 }
42
50 public function connection( IDatabase $db ) {
51 if ( $this->db->getType() !== $db->getType() ) {
52 throw new \InvalidArgumentException( __METHOD__ .
53 ' cannot switch to a database of a different type.' );
54 }
55 $this->db = $db;
56 return $this;
57 }
58
76 public function queryInfo( $info ) {
77 if ( isset( $info['tables'] ) ) {
78 $this->rawTables( $info['tables'] );
79 }
80 if ( isset( $info['fields'] ) ) {
81 $this->fields( $info['fields'] );
82 }
83 if ( isset( $info['conds'] ) ) {
84 $this->where( $info['conds'] );
85 }
86 if ( isset( $info['options'] ) ) {
87 $this->options( (array)$info['options'] );
88 }
89 if ( isset( $info['join_conds'] ) ) {
90 $this->joinConds( (array)$info['join_conds'] );
91 }
92 return $this;
93 }
94
107 public function rawTables( $tables ) {
108 if ( is_array( $tables ) ) {
109 $this->tables = array_merge( $this->tables, $tables );
110 } elseif ( is_string( $tables ) ) {
111 $this->tables[] = $tables;
112 } else {
113 throw new \InvalidArgumentException( __METHOD__ .
114 ': $tables must be a string or array' );
115 }
116 return $this;
117 }
118
124 public function newSubquery() {
125 return new self( $this->db );
126 }
127
135 public function from( $table, $alias = null ) {
136 return $this->table( $table, $alias );
137 }
138
145 public function tables( $tables ) {
146 foreach ( $tables as $alias => $table ) {
147 if ( is_string( $alias ) ) {
148 $this->table( $table, $alias );
149 } else {
150 $this->table( $table );
151 }
152 }
153 return $this;
154 }
155
166 public function fields( $fields ) {
167 if ( is_array( $fields ) ) {
168 $this->fields = array_merge( $this->fields, $fields );
169 } else {
170 $this->fields[] = $fields;
171 }
172 return $this;
173 }
174
181 public function select( $fields ) {
182 return $this->fields( $fields );
183 }
184
193 public function field( $field, $alias = null ) {
194 if ( $alias === null ) {
195 $this->fields[] = $field;
196 } else {
197 $this->fields[$alias] = $field;
198 }
199 return $this;
200 }
201
238 public function where( $conds ) {
239 if ( is_array( $conds ) ) {
240 $this->conds = array_merge( $this->conds, $conds );
241 } else {
242 $this->conds[] = $conds;
243 }
244 return $this;
245 }
246
253 public function andWhere( $conds ) {
254 return $this->where( $conds );
255 }
256
263 public function conds( $conds ) {
264 return $this->where( $conds );
265 }
266
275 public function joinConds( array $joinConds ) {
276 $this->joinConds = array_merge( $this->joinConds, $joinConds );
277 return $this;
278 }
279
285 protected function getAutoAlias() {
286 return 'sqb' . ( $this->nextAutoAlias++ );
287 }
288
295 public function newJoinGroup() {
296 return new JoinGroup( $this->getAutoAlias() );
297 }
298
309 public function offset( $offset ) {
310 $this->options['OFFSET'] = $offset;
311 return $this;
312 }
313
324 public function limit( $limit ) {
325 $this->options['LIMIT'] = $limit;
326 return $this;
327 }
328
336 public function lockInShareMode() {
337 $this->options[] = 'LOCK IN SHARE MODE';
338 return $this;
339 }
340
348 public function forUpdate() {
349 $this->options[] = 'FOR UPDATE';
350 return $this;
351 }
352
358 public function distinct() {
359 $this->options[] = 'DISTINCT';
360 return $this;
361 }
362
369 public function setMaxExecutionTime( int $time ) {
370 $this->options['MAX_EXECUTION_TIME'] = $time;
371 return $this;
372 }
373
383 public function groupBy( $group ) {
384 $this->mergeOption( 'GROUP BY', $group );
385 return $this;
386 }
387
399 public function having( $having ) {
400 $this->mergeOption( 'HAVING', $having );
401 return $this;
402 }
403
413 public function orderBy( $fields, $direction = null ) {
414 if ( $direction === null ) {
415 $this->mergeOption( 'ORDER BY', $fields );
416 } elseif ( is_array( $fields ) ) {
417 $fieldsWithDirection = [];
418 foreach ( $fields as $field ) {
419 $fieldsWithDirection[] = "$field $direction";
420 }
421 $this->mergeOption( 'ORDER BY', $fieldsWithDirection );
422 } else {
423 $this->mergeOption( 'ORDER BY', "$fields $direction" );
424 }
425 return $this;
426 }
427
434 private function mergeOption( $name, $newArrayOrValue ) {
435 $value = isset( $this->options[$name] )
436 ? (array)$this->options[$name] : [];
437 if ( is_array( $newArrayOrValue ) ) {
438 $value = array_merge( $value, $newArrayOrValue );
439 } else {
440 $value[] = $newArrayOrValue;
441 }
442 $this->options[$name] = $value;
443 }
444
457 public function useIndex( $index ) {
458 $this->setIndexHint( 'USE INDEX', $index );
459 return $this;
460 }
461
474 public function ignoreIndex( $index ) {
475 $this->setIndexHint( 'IGNORE INDEX', $index );
476 return $this;
477 }
478
485 private function setIndexHint( $type, $value ) {
486 if ( !isset( $this->options[$type] ) ) {
487 $this->options[$type] = [];
488 } elseif ( !is_array( $this->options[$type] ) ) {
489 throw new \UnexpectedValueException(
490 __METHOD__ . ": The $type option cannot be appended to " .
491 'because it is not an array. This may have been caused by a prior ' .
492 'call to option() or options().' );
493 }
494 if ( is_array( $value ) ) {
495 $this->options[$type] = array_merge( $this->options[$type], $value );
496 } elseif ( $this->lastAlias === null ) {
497 throw new \UnexpectedValueException(
498 __METHOD__ . ': Cannot append index value since there is no' .
499 'prior table' );
500 } else {
501 $this->options[$type][$this->lastAlias] = $value;
502 }
503 }
504
510 public function explain() {
511 $this->options['EXPLAIN'] = true;
512 return $this;
513 }
514
520 public function straightJoin() {
521 $this->options[] = 'STRAIGHT_JOIN';
522 return $this;
523 }
524
530 public function bigResult() {
531 $this->options[] = 'SQL_BIG_RESULT';
532 return $this;
533 }
534
540 public function bufferResult() {
541 $this->options[] = 'SQL_BUFFER_RESULT';
542 return $this;
543 }
544
550 public function smallResult() {
551 $this->options[] = 'SQL_SMALL_RESULT';
552 return $this;
553 }
554
560 public function calcFoundRows() {
561 $this->options[] = 'SQL_CALC_FOUND_ROWS';
562 return $this;
563 }
564
573 public function option( $name, $value = null ) {
574 if ( $value === null ) {
575 $this->options[] = $name;
576 } else {
577 $this->options[$name] = $value;
578 }
579 return $this;
580 }
581
589 public function options( array $options ) {
590 $this->options = array_merge( $this->options, $options );
591 return $this;
592 }
593
600 public function caller( $fname ) {
601 $this->caller = $fname;
602 return $this;
603 }
604
610 public function fetchResultSet() {
611 return $this->db->select( $this->tables, $this->fields, $this->conds, $this->caller,
612 $this->options, $this->joinConds );
613 }
614
622 public function fetchField() {
623 if ( count( $this->fields ) !== 1 ) {
624 throw new \UnexpectedValueException(
625 __METHOD__ . ' expects the query to have only one field' );
626 }
627 $field = reset( $this->fields );
628 return $this->db->selectField( $this->tables, $field, $this->conds, $this->caller,
629 $this->options, $this->joinConds );
630 }
631
639 public function fetchFieldValues() {
640 if ( count( $this->fields ) !== 1 ) {
641 throw new \UnexpectedValueException(
642 __METHOD__ . ' expects the query to have only one field' );
643 }
644 $field = reset( $this->fields );
645 return $this->db->selectFieldValues( $this->tables, $field, $this->conds, $this->caller,
646 $this->options, $this->joinConds );
647 }
648
655 public function fetchRow() {
656 return $this->db->selectRow( $this->tables, $this->fields, $this->conds, $this->caller,
657 $this->options, $this->joinConds );
658 }
659
667 public function fetchRowCount() {
668 return $this->db->selectRowCount( $this->tables, $this->getRowCountVar(), $this->conds,
669 $this->caller, $this->options, $this->joinConds );
670 }
671
682 public function estimateRowCount() {
683 return $this->db->estimateRowCount( $this->tables, $this->getRowCountVar(), $this->conds,
684 $this->caller, $this->options, $this->joinConds );
685 }
686
693 private function getRowCountVar() {
694 if ( count( $this->fields ) === 0 ) {
695 return '*';
696 } elseif ( count( $this->fields ) === 1 ) {
697 return reset( $this->fields );
698 } else {
699 throw new \UnexpectedValueException(
700 __METHOD__ . ' expects the query to have at most one field' );
701 }
702 }
703
709 public function lockForUpdate() {
710 return $this->db->lockForUpdate( $this->tables, $this->conds, $this->caller,
711 $this->options, $this->joinConds );
712 }
713
725 public function buildGroupConcatField( $delim ) {
726 if ( count( $this->fields ) !== 1 ) {
727 throw new \UnexpectedValueException(
728 __METHOD__ . ' expects the query to have only one field' );
729 }
730 $field = reset( $this->fields );
731 return $this->db->buildGroupConcatField( $delim, $this->tables, $field,
732 $this->conds, $this->joinConds );
733 }
734
740 public function getSQL() {
741 return $this->db->selectSQLText( $this->tables, $this->fields, $this->conds, $this->caller,
742 $this->options, $this->joinConds );
743 }
744
756 public function getQueryInfo() {
757 return [
758 'tables' => $this->tables,
759 'fields' => $this->fields,
760 'conds' => $this->conds,
761 'options' => $this->options,
762 'join_conds' => $this->joinConds
763 ];
764 }
765}
A class for code shared between SelectQueryBuilder and JoinGroup.
table( $table, $alias=null)
Add a single table or a single parenthesized group.
An object representing a parenthesized group of tables and their join types and conditions.
Definition JoinGroup.php:9
estimateRowCount()
Estimate the number of rows in dataset.
int $nextAutoAlias
An integer used to assign automatic aliases to tables and groups.
distinct()
Enable the DISTINCT option.
array $conds
The conditions to be passed to IDatabase::select()
groupBy( $group)
Add a GROUP BY clause.
newSubquery()
Get an empty SelectQueryBuilder which can be used to build a subquery of this query.
lockForUpdate()
Run the SELECT query with the FOR UPDATE option.
useIndex( $index)
Set a USE INDEX option.
connection(IDatabase $db)
Change the IDatabase object the query builder is bound to.
rawTables( $tables)
Given a table or table array as might be passed to Database::select(), append it to the existing tabl...
conds( $conds)
Add conditions to the query.
getQueryInfo()
Get an associative array describing the query in terms of its raw parameters to Database::select().
limit( $limit)
Set the query limit.
andWhere( $conds)
Add conditions to the query.
fetchField()
Run the constructed SELECT query, and return a single field extracted from the first result row.
setIndexHint( $type, $value)
Private helper for methods that set index hints.
array $options
The options to be passed to IDatabase::select()
straightJoin()
Enable the STRAIGHT_JOIN option.
fetchFieldValues()
Run the constructed SELECT query, and extract a single field from each result row,...
calcFoundRows()
Enable the SQL_CALC_FOUND_ROWS option.
newJoinGroup()
Create a parenthesized group of joins which can be added to the object like a table.
fetchResultSet()
Run the constructed SELECT query and return all results.
lockInShareMode()
Enable the LOCK IN SHARE MODE option.
bufferResult()
Enable the SQL_BUFFER_RESULT option.
queryInfo( $info)
Set the query parameters to the given values, appending to the values which were already set.
options(array $options)
Manually set multiple options in the $options array to be passed to IDatabase::select().
forUpdate()
Enable the FOR UPDATE option.
option( $name, $value=null)
Manually set an option in the $options array to be passed to IDatabase::select()
buildGroupConcatField( $delim)
Build a GROUP_CONCAT or equivalent statement for a query.
array $fields
The fields to be passed to IDatabase::select()
select( $fields)
Add a field or an array of fields to the query.
caller( $fname)
Set the method name to be included in an SQL comment.
tables( $tables)
Add multiple tables.
ignoreIndex( $index)
Set the IGNORE INDEX option.
string $caller
The caller (function name) to be passed to IDatabase::select()
having( $having)
Add a HAVING clause.
from( $table, $alias=null)
Add a single table to the SELECT query.
setMaxExecutionTime(int $time)
Set MAX_EXECUTION_TIME for queries.
field( $field, $alias=null)
Add a single field to the query, optionally with an alias.
orderBy( $fields, $direction=null)
Set the ORDER BY clause.
smallResult()
Enable the SQL_SMALL_RESULT option.
explain()
Make the query be an EXPLAIN SELECT query instead of a SELECT query.
bigResult()
Enable the SQL_BIG_RESULT option.
fetchRowCount()
Run the SELECT query, and return the number of results.
fetchRow()
Run the constructed SELECT query, and return the first result row.
joinConds(array $joinConds)
Manually append to the $join_conds array which will be passed to IDatabase::select().
mergeOption( $name, $newArrayOrValue)
Add a value to an option which may be not set or a string or array.
fields( $fields)
Add a field or an array of fields to the query.
getRowCountVar()
Private helper which extracts a field suitable for row counting from the fields array.
getAutoAlias()
Get a table alias which is unique to this SelectQueryBuilder.
where( $conds)
Add conditions to the query.
getSQL()
Get the SQL query string which would be used by fetchResultSet().
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:38
getType()
Get the type of the DBMS (e.g.