MediaWiki master
UnionQueryBuilder.php
Go to the documentation of this file.
1<?php
2
3namespace Wikimedia\Rdbms;
4
6
18 public const SORT_ASC = 'ASC';
19
21 public const SORT_DESC = 'DESC';
22
26 private $sqbs = [];
27
28 private IDatabase $db;
29
32
34 private $options = [];
35
39 private $caller = __CLASS__;
40
44 public function __construct( IDatabase $db ) {
45 $this->db = $db;
46 }
47
53 public function add( SelectQueryBuilder $selectQueryBuilder ) {
54 $this->sqbs[] = $selectQueryBuilder;
55 return $this;
56 }
57
63 public function all() {
64 $this->all = $this->db::UNION_ALL;
65 return $this;
66 }
67
79 public function limit( $limit ) {
80 if ( !$this->db->unionSupportsOrderAndLimit() ) {
81 return $this;
82 }
83 $this->options['LIMIT'] = $limit;
84 return $this;
85 }
86
98 public function offset( $offset ) {
99 if ( !$this->db->unionSupportsOrderAndLimit() ) {
100 return $this;
101 }
102 $this->options['OFFSET'] = $offset;
103 return $this;
104 }
105
120 public function orderBy( $fields, $direction = null ) {
121 if ( !$this->db->unionSupportsOrderAndLimit() ) {
122 return $this;
123 }
124 if ( $direction === null ) {
125 $this->mergeOption( 'ORDER BY', $fields );
126 } elseif ( is_array( $fields ) ) {
127 $fieldsWithDirection = [];
128 foreach ( $fields as $field ) {
129 $fieldsWithDirection[] = "$field $direction";
130 }
131 $this->mergeOption( 'ORDER BY', $fieldsWithDirection );
132 } else {
133 $this->mergeOption( 'ORDER BY', "$fields $direction" );
134 }
135 return $this;
136 }
137
144 private function mergeOption( $name, $newArrayOrValue ) {
145 $value = isset( $this->options[$name] )
146 ? (array)$this->options[$name] : [];
147 if ( is_array( $newArrayOrValue ) ) {
148 $value = array_merge( $value, $newArrayOrValue );
149 } else {
150 $value[] = $newArrayOrValue;
151 }
152 $this->options[$name] = $value;
153 }
154
162 public function caller( $fname ) {
163 $this->caller = $fname;
164 return $this;
165 }
166
172 public function fetchResultSet() {
173 // @codeCoverageIgnoreStart
174 if ( defined( 'MW_PHPUNIT_TEST' ) && str_contains( $this->db->getSoftwareLink(), 'MySQL' ) ) {
175 // MySQL cannot open the same temporary table twice in the same query, and integration tests
176 // use temporary tables, so we need to emulate the UNION query (T412067).
177 $resultSets = array_map( static fn ( $qb ) => $qb->fetchResultSet(), $this->sqbs );
178 $res = [];
179 foreach ( $resultSets as $resultSet ) {
180 $res = array_merge( $res, iterator_to_array( $resultSet ) );
181 }
182 if ( $this->all === $this->db::UNION_DISTINCT ) {
183 $res = array_unique( $res );
184 }
185 return new FakeResultWrapper( $res );
186 }
187 // @codeCoverageIgnoreEnd
188 $query = new Query( $this->getSQL(), ISQLPlatform::QUERY_CHANGE_NONE, 'SELECT' );
189 return $this->db->query( $query, $this->caller );
190 }
191
202 public function fetchField() {
203 $this->limit( 1 );
204 foreach ( $this->fetchResultSet() as $row ) {
205 $row = (array)$row;
206 if ( count( $row ) !== 1 ) {
207 throw new \UnexpectedValueException(
208 __METHOD__ . ' expects the query to have only one field' );
209 }
210 return $row[ array_key_first( $row ) ];
211 }
212 return false;
213 }
214
224 public function fetchFieldValues() {
225 $values = [];
226 foreach ( $this->fetchResultSet() as $row ) {
227 $row = (array)$row;
228 if ( count( $row ) !== 1 ) {
229 throw new \UnexpectedValueException(
230 __METHOD__ . ' expects the query to have only one field' );
231 }
232 $values[] = $row[ array_key_first( $row ) ];
233 }
234 return $values;
235 }
236
245 public function fetchRow() {
246 $this->limit( 1 );
247 foreach ( $this->fetchResultSet() as $row ) {
248 return $row;
249 }
250 return false;
251 }
252
259 public function getSQL() {
260 $sqls = [];
261 foreach ( $this->sqbs as $sqb ) {
262 $sqls[] = $sqb->getSQL();
263 }
264 return $this->db->unionQueries( $sqls, $this->all, $this->options );
265 }
266
267}
Overloads the relevant methods of the real ResultWrapper so it doesn't go anywhere near an actual dat...
Holds information on Query to be executed.
Definition Query.php:17
Build SELECT queries with a fluent interface.
A query builder for UNION queries takes SelectQueryBuilder objects.
fetchFieldValues()
Run the constructed UNION query, and extract a single field from each result row, returning an array ...
orderBy( $fields, $direction=null)
Set the ORDER BY clause.
const SORT_DESC
sort the results in descending order
__construct(IDatabase $db)
To create a UnionQueryBuilder instance, use $db->newUnionQueryBuilder() instead.
fetchResultSet()
Run the constructed UNION query and return all results.
fetchField()
Run the constructed UNION query, and return a single field extracted from the first result row.
all()
Enable UNION_ALL option, the default is UNION_DISTINCT.
fetchRow()
Run the constructed UNION query, and return the first result row.
const SORT_ASC
sort the results in ascending order
caller( $fname)
Set the method name to be included in an SQL comment.
getSQL()
Get the SQL query string which would be used by fetchResultSet().
add(SelectQueryBuilder $selectQueryBuilder)
Add a select query builder object to the list of union.
limit( $limit)
Set the query limit.
Interface to a relational database.
Definition IDatabase.php:31
const UNION_DISTINCT
Parameter to unionQueries() for UNION DISTINCT.
Interface for query language.