23 public const SORT_ASC =
'ASC';
26 public const SORT_DESC =
'DESC';
41 private $caller = __CLASS__;
51 private $nextAutoAlias = 1;
74 if ( $this->db->getType() !==
$db->
getType() ) {
75 throw new \InvalidArgumentException( __METHOD__ .
76 ' cannot switch to a database of a different type.' );
102 if ( isset( $info[
'tables'] ) ) {
105 if ( isset( $info[
'fields'] ) ) {
106 $this->
fields( $info[
'fields'] );
108 if ( isset( $info[
'conds'] ) ) {
109 $this->
where( $info[
'conds'] );
111 if ( isset( $info[
'options'] ) ) {
112 $this->
options( (array)$info[
'options'] );
114 if ( isset( $info[
'join_conds'] ) ) {
115 $this->
joinConds( (array)$info[
'join_conds'] );
117 if ( isset( $info[
'joins'] ) ) {
118 $this->
joinConds( (array)$info[
'joins'] );
138 } elseif ( is_string(
$tables ) ) {
141 throw new \InvalidArgumentException( __METHOD__ .
142 ': $tables must be a string or array' );
163 public function from( $table, $alias =
null ) {
164 return $this->
table( $table, $alias );
174 foreach (
$tables as $alias => $table ) {
175 if ( is_string( $alias ) ) {
176 $this->
table( $table, $alias );
178 $this->
table( $table );
195 if ( is_array( $fields ) ) {
198 $this->
fields[] = $fields;
210 return $this->
fields( $fields );
221 public function field( $field, $alias =
null ) {
222 if ( $alias ===
null ) {
225 $this->
fields[$alias] = $field;
267 if ( is_array( $conds ) ) {
268 foreach ( $conds as $key => $cond ) {
269 if ( is_int( $key ) ) {
270 $this->
conds[] = $cond;
271 } elseif ( isset( $this->
conds[$key] ) ) {
274 $this->
conds[] = $this->db->makeList(
277 $this->
conds[$key] = $cond;
281 $this->
conds[] = $conds;
293 return $this->
where( $conds );
303 return $this->
where( $conds );
325 return 'sqb' . ( $this->nextAutoAlias++ );
349 $this->
options[
'OFFSET'] = $offset;
364 $this->
options[
'LIMIT'] = $limit;
376 $this->
options[] =
'LOCK IN SHARE MODE';
388 $this->
options[] =
'FOR UPDATE';
409 $this->
options[
'MAX_EXECUTION_TIME'] = $time;
423 $this->mergeOption(
'GROUP BY', $group );
439 $this->mergeOption(
'HAVING', $having );
453 public function orderBy( $fields, $direction =
null ) {
454 if ( $direction ===
null ) {
455 $this->mergeOption(
'ORDER BY', $fields );
456 } elseif ( is_array( $fields ) ) {
457 $fieldsWithDirection = [];
458 foreach ( $fields as $field ) {
459 $fieldsWithDirection[] =
"$field $direction";
461 $this->mergeOption(
'ORDER BY', $fieldsWithDirection );
463 $this->mergeOption(
'ORDER BY',
"$fields $direction" );
474 private function mergeOption( $name, $newArrayOrValue ) {
475 $value = isset( $this->
options[$name] )
476 ? (array)$this->
options[$name] : [];
477 if ( is_array( $newArrayOrValue ) ) {
478 $value = array_merge( $value, $newArrayOrValue );
480 $value[] = $newArrayOrValue;
482 $this->
options[$name] = $value;
498 $this->setIndexHint(
'USE INDEX', $index );
515 $this->setIndexHint(
'IGNORE INDEX', $index );
525 private function setIndexHint(
$type, $value ) {
526 if ( !isset( $this->
options[$type] ) ) {
528 } elseif ( !is_array( $this->
options[$type] ) ) {
529 throw new \UnexpectedValueException(
530 __METHOD__ .
": The $type option cannot be appended to " .
531 'because it is not an array. This may have been caused by a prior ' .
532 'call to option() or options().' );
534 if ( is_array( $value ) ) {
536 } elseif ( $this->lastAlias ===
null ) {
537 throw new \UnexpectedValueException(
538 __METHOD__ .
': Cannot append index value since there is no' .
551 $this->
options[
'EXPLAIN'] =
true;
561 $this->
options[] =
'STRAIGHT_JOIN';
571 $this->
options[] =
'SQL_BIG_RESULT';
581 $this->
options[] =
'SQL_BUFFER_RESULT';
591 $this->
options[] =
'SQL_SMALL_RESULT';
601 $this->
options[] =
'SQL_CALC_FOUND_ROWS';
613 public function option( $name, $value =
null ) {
614 if ( $value ===
null ) {
617 $this->
options[$name] = $value;
663 if ( count( $this->
fields ) !== 1 ) {
664 throw new \UnexpectedValueException(
665 __METHOD__ .
' expects the query to have only one field' );
667 $field = reset( $this->
fields );
668 return $this->db->selectField( $this->
tables, $field, $this->
conds, $this->
caller,
680 if ( count( $this->
fields ) !== 1 ) {
681 throw new \UnexpectedValueException(
682 __METHOD__ .
' expects the query to have only one field' );
684 $field = reset( $this->
fields );
685 return $this->db->selectFieldValues( $this->
tables, $field, $this->
conds, $this->
caller,
708 return $this->db->selectRowCount( $this->
tables, $this->getRowCountVar(), $this->
conds,
723 return $this->db->estimateRowCount( $this->
tables, $this->getRowCountVar(), $this->
conds,
733 private function getRowCountVar() {
734 if ( count( $this->
fields ) === 0 ) {
736 } elseif ( count( $this->
fields ) === 1 ) {
737 return reset( $this->
fields );
739 throw new \UnexpectedValueException(
740 __METHOD__ .
' expects the query to have at most one field' );
768 if ( count( $this->
fields ) !== 1 ) {
769 throw new \UnexpectedValueException(
770 __METHOD__ .
' expects the query to have only one field' );
772 $field = reset( $this->
fields );
773 return $this->db->buildGroupConcatField( $delim, $this->
tables, $field,
804 'fields' => $this->fields,
805 'conds' => $this->conds,
827 if ( !array_intersect( $this->
options, [
'FOR UPDATE',
'LOCK IN SHARE MODE' ] ) ) {
828 throw new \UnexpectedValueException( __METHOD__ .
' can only be called ' .
829 'after forUpdate() or lockInShareMode()' );
831 $fields = $this->
fields ?:
'1';
if(!defined('MW_SETUP_CALLBACK'))