16 public const SORT_ASC =
'ASC';
19 public const SORT_DESC =
'DESC';
34 private $caller = __CLASS__;
44 private $nextAutoAlias = 1;
66 if ( $this->db->getType() !==
$db->
getType() ) {
67 throw new \InvalidArgumentException( __METHOD__ .
68 ' cannot switch to a database of a different type.' );
94 if ( isset( $info[
'tables'] ) ) {
97 if ( isset( $info[
'fields'] ) ) {
98 $this->
fields( $info[
'fields'] );
100 if ( isset( $info[
'conds'] ) ) {
101 $this->
where( $info[
'conds'] );
103 if ( isset( $info[
'options'] ) ) {
104 $this->
options( (array)$info[
'options'] );
106 if ( isset( $info[
'join_conds'] ) ) {
107 $this->
joinConds( (array)$info[
'join_conds'] );
109 if ( isset( $info[
'joins'] ) ) {
110 $this->
joinConds( (array)$info[
'joins'] );
130 } elseif ( is_string(
$tables ) ) {
133 throw new \InvalidArgumentException( __METHOD__ .
134 ': $tables must be a string or array' );
155 public function from( $table, $alias =
null ) {
156 return $this->
table( $table, $alias );
166 foreach (
$tables as $alias => $table ) {
167 if ( is_string( $alias ) ) {
168 $this->
table( $table, $alias );
170 $this->
table( $table );
187 if ( is_array( $fields ) ) {
190 $this->
fields[] = $fields;
202 return $this->
fields( $fields );
213 public function field( $field, $alias =
null ) {
214 if ( $alias ===
null ) {
217 $this->
fields[$alias] = $field;
259 if ( is_array( $conds ) ) {
260 foreach ( $conds as $key => $cond ) {
261 if ( is_int( $key ) ) {
262 $this->
conds[] = $cond;
263 } elseif ( isset( $this->
conds[$key] ) ) {
266 $this->
conds[] = $this->db->makeList(
267 [ $key => $cond ], IDatabase::LIST_AND );
269 $this->
conds[$key] = $cond;
273 $this->
conds[] = $conds;
285 return $this->
where( $conds );
295 return $this->
where( $conds );
317 return 'sqb' . ( $this->nextAutoAlias++ );
341 $this->
options[
'OFFSET'] = $offset;
356 $this->
options[
'LIMIT'] = $limit;
368 $this->
options[] =
'LOCK IN SHARE MODE';
380 $this->
options[] =
'FOR UPDATE';
401 $this->
options[
'MAX_EXECUTION_TIME'] = $time;
415 $this->mergeOption(
'GROUP BY', $group );
431 $this->mergeOption(
'HAVING', $having );
445 public function orderBy( $fields, $direction =
null ) {
446 if ( $direction ===
null ) {
447 $this->mergeOption(
'ORDER BY', $fields );
448 } elseif ( is_array( $fields ) ) {
449 $fieldsWithDirection = [];
450 foreach ( $fields as $field ) {
451 $fieldsWithDirection[] =
"$field $direction";
453 $this->mergeOption(
'ORDER BY', $fieldsWithDirection );
455 $this->mergeOption(
'ORDER BY',
"$fields $direction" );
466 private function mergeOption( $name, $newArrayOrValue ) {
467 $value = isset( $this->
options[$name] )
468 ? (array)$this->
options[$name] : [];
469 if ( is_array( $newArrayOrValue ) ) {
470 $value = array_merge( $value, $newArrayOrValue );
472 $value[] = $newArrayOrValue;
474 $this->
options[$name] = $value;
490 $this->setIndexHint(
'USE INDEX', $index );
507 $this->setIndexHint(
'IGNORE INDEX', $index );
517 private function setIndexHint(
$type, $value ) {
518 if ( !isset( $this->
options[$type] ) ) {
520 } elseif ( !is_array( $this->
options[$type] ) ) {
521 throw new \UnexpectedValueException(
522 __METHOD__ .
": The $type option cannot be appended to " .
523 'because it is not an array. This may have been caused by a prior ' .
524 'call to option() or options().' );
526 if ( is_array( $value ) ) {
528 } elseif ( $this->lastAlias ===
null ) {
529 throw new \UnexpectedValueException(
530 __METHOD__ .
': Cannot append index value since there is no' .
543 $this->
options[
'EXPLAIN'] =
true;
553 $this->
options[] =
'STRAIGHT_JOIN';
563 $this->
options[] =
'SQL_BIG_RESULT';
573 $this->
options[] =
'SQL_BUFFER_RESULT';
583 $this->
options[] =
'SQL_SMALL_RESULT';
593 $this->
options[] =
'SQL_CALC_FOUND_ROWS';
605 public function option( $name, $value =
null ) {
606 if ( $value ===
null ) {
609 $this->
options[$name] = $value;
655 if ( count( $this->
fields ) !== 1 ) {
656 throw new \UnexpectedValueException(
657 __METHOD__ .
' expects the query to have only one field' );
659 $field = reset( $this->
fields );
660 return $this->db->selectField( $this->
tables, $field, $this->
conds, $this->
caller,
672 if ( count( $this->
fields ) !== 1 ) {
673 throw new \UnexpectedValueException(
674 __METHOD__ .
' expects the query to have only one field' );
676 $field = reset( $this->
fields );
677 return $this->db->selectFieldValues( $this->
tables, $field, $this->
conds, $this->
caller,
700 return $this->db->selectRowCount( $this->
tables, $this->getRowCountVar(), $this->
conds,
715 return $this->db->estimateRowCount( $this->
tables, $this->getRowCountVar(), $this->
conds,
725 private function getRowCountVar() {
726 if ( count( $this->
fields ) === 0 ) {
728 } elseif ( count( $this->
fields ) === 1 ) {
729 return reset( $this->
fields );
731 throw new \UnexpectedValueException(
732 __METHOD__ .
' expects the query to have at most one field' );
758 if ( count( $this->
fields ) !== 1 ) {
759 throw new \UnexpectedValueException(
760 __METHOD__ .
' expects the query to have only one field' );
762 $field = reset( $this->
fields );
763 return $this->db->buildGroupConcatField( $delim, $this->
tables, $field,
794 'fields' => $this->fields,
795 'conds' => $this->conds,