1. 8.3.x core/lib/Drupal/Core/Database/Driver/pgsql/Select.php
  2. 8.3.x core/lib/Drupal/Core/Database/Driver/mysql/Select.php
  3. 8.3.x core/lib/Drupal/Core/Render/Element/Select.php
  4. 8.3.x core/lib/Drupal/Core/Database/Query/Select.php
  5. 8.3.x core/tests/Drupal/Tests/Core/Database/Stub/Select.php
  6. 8.3.x core/lib/Drupal/Core/Database/Driver/sqlite/Select.php
  7. 8.0.x core/lib/Drupal/Core/Database/Query/Select.php
  8. 8.0.x core/lib/Drupal/Core/Database/Driver/mysql/Select.php
  9. 8.0.x core/lib/Drupal/Core/Database/Driver/pgsql/Select.php
  10. 8.0.x core/lib/Drupal/Core/Render/Element/Select.php
  11. 8.0.x core/lib/Drupal/Core/Database/Driver/sqlite/Select.php
  12. 8.1.x core/lib/Drupal/Core/Database/Driver/mysql/Select.php
  13. 8.1.x core/tests/Drupal/Tests/Core/Database/Stub/Select.php
  14. 8.1.x core/lib/Drupal/Core/Database/Driver/sqlite/Select.php
  15. 8.1.x core/lib/Drupal/Core/Database/Driver/pgsql/Select.php
  16. 8.1.x core/lib/Drupal/Core/Render/Element/Select.php
  17. 8.1.x core/lib/Drupal/Core/Database/Query/Select.php
  18. 8.2.x core/lib/Drupal/Core/Render/Element/Select.php
  19. 8.2.x core/lib/Drupal/Core/Database/Driver/pgsql/Select.php
  20. 8.2.x core/lib/Drupal/Core/Database/Query/Select.php
  21. 8.2.x core/lib/Drupal/Core/Database/Driver/mysql/Select.php
  22. 8.2.x core/tests/Drupal/Tests/Core/Database/Stub/Select.php
  23. 8.2.x core/lib/Drupal/Core/Database/Driver/sqlite/Select.php
  24. 8.4.x core/lib/Drupal/Core/Database/Driver/sqlite/Select.php
  25. 8.4.x core/tests/Drupal/Tests/Core/Database/Stub/Select.php
  26. 8.4.x core/lib/Drupal/Core/Database/Driver/pgsql/Select.php
  27. 8.4.x core/lib/Drupal/Core/Render/Element/Select.php
  28. 8.4.x core/lib/Drupal/Core/Database/Query/Select.php
  29. 8.4.x core/lib/Drupal/Core/Database/Driver/mysql/Select.php

Namespace

Drupal\Core\Database\Query

File

core/lib/Drupal/Core/Database/Query/Select.php
View source
  1. <?php
  2. namespace Drupal\Core\Database\Query;
  3. use Drupal\Core\Database\Database;
  4. use Drupal\Core\Database\Connection;
  5. /**
  6. * Query builder for SELECT statements.
  7. *
  8. * @ingroup database
  9. */
  10. class Select extends Query implements SelectInterface {
  11. use QueryConditionTrait;
  12. /**
  13. * The fields to SELECT.
  14. *
  15. * @var array
  16. */
  17. protected $fields = array();
  18. /**
  19. * The expressions to SELECT as virtual fields.
  20. *
  21. * @var array
  22. */
  23. protected $expressions = array();
  24. /**
  25. * The tables against which to JOIN.
  26. *
  27. * This property is a nested array. Each entry is an array representing
  28. * a single table against which to join. The structure of each entry is:
  29. *
  30. * array(
  31. * 'type' => $join_type (one of INNER, LEFT OUTER, RIGHT OUTER),
  32. * 'table' => $table,
  33. * 'alias' => $alias_of_the_table,
  34. * 'condition' => $join_condition (string or Condition object),
  35. * 'arguments' => $array_of_arguments_for_placeholders_in_the condition.
  36. * 'all_fields' => TRUE to SELECT $alias.*, FALSE or NULL otherwise.
  37. * )
  38. *
  39. * If $table is a string, it is taken as the name of a table. If it is
  40. * a Select query object, it is taken as a subquery.
  41. *
  42. * If $join_condition is a Condition object, any arguments should be
  43. * incorporated into the object; a separate array of arguments does not
  44. * need to be provided.
  45. *
  46. * @var array
  47. */
  48. protected $tables = array();
  49. /**
  50. * The fields by which to order this query.
  51. *
  52. * This is an associative array. The keys are the fields to order, and the value
  53. * is the direction to order, either ASC or DESC.
  54. *
  55. * @var array
  56. */
  57. protected $order = array();
  58. /**
  59. * The fields by which to group.
  60. *
  61. * @var array
  62. */
  63. protected $group = array();
  64. /**
  65. * The conditional object for the HAVING clause.
  66. *
  67. * @var \Drupal\Core\Database\Query\Condition
  68. */
  69. protected $having;
  70. /**
  71. * Whether or not this query should be DISTINCT
  72. *
  73. * @var bool
  74. */
  75. protected $distinct = FALSE;
  76. /**
  77. * The range limiters for this query.
  78. *
  79. * @var array
  80. */
  81. protected $range;
  82. /**
  83. * An array whose elements specify a query to UNION, and the UNION type. The
  84. * 'type' key may be '', 'ALL', or 'DISTINCT' to represent a 'UNION',
  85. * 'UNION ALL', or 'UNION DISTINCT' statement, respectively.
  86. *
  87. * All entries in this array will be applied from front to back, with the
  88. * first query to union on the right of the original query, the second union
  89. * to the right of the first, etc.
  90. *
  91. * @var array
  92. */
  93. protected $union = array();
  94. /**
  95. * Indicates if preExecute() has already been called.
  96. * @var bool
  97. */
  98. protected $prepared = FALSE;
  99. /**
  100. * The FOR UPDATE status
  101. */
  102. protected $forUpdate = FALSE;
  103. /**
  104. * Constructs a Select object.
  105. *
  106. * @param string $table
  107. * The name of the table that is being queried.
  108. * @param string $alias
  109. * The alias for the table.
  110. * @param \Drupal\Core\Database\Connection $connection
  111. * Database connection object.
  112. * @param array $options
  113. * Array of query options.
  114. */
  115. public function __construct($table, $alias = NULL, Connection $connection, $options = array()) {
  116. $options['return'] = Database::RETURN_STATEMENT;
  117. parent::__construct($connection, $options);
  118. $conjunction = isset($options['conjunction']) ? $options['conjunction'] : 'AND';
  119. $this->condition = new Condition($conjunction);
  120. $this->having = new Condition($conjunction);
  121. $this->addJoin(NULL, $table, $alias);
  122. }
  123. /**
  124. * {@inheritdoc}
  125. */
  126. public function addTag($tag) {
  127. $this->alterTags[$tag] = 1;
  128. return $this;
  129. }
  130. /**
  131. * {@inheritdoc}
  132. */
  133. public function hasTag($tag) {
  134. return isset($this->alterTags[$tag]);
  135. }
  136. /**
  137. * {@inheritdoc}
  138. */
  139. public function hasAllTags() {
  140. return !(boolean)array_diff(func_get_args(), array_keys($this->alterTags));
  141. }
  142. /**
  143. * {@inheritdoc}
  144. */
  145. public function hasAnyTag() {
  146. return (boolean)array_intersect(func_get_args(), array_keys($this->alterTags));
  147. }
  148. /**
  149. * {@inheritdoc}
  150. */
  151. public function addMetaData($key, $object) {
  152. $this->alterMetaData[$key] = $object;
  153. return $this;
  154. }
  155. /**
  156. * {@inheritdoc}
  157. */
  158. public function getMetaData($key) {
  159. return isset($this->alterMetaData[$key]) ? $this->alterMetaData[$key] : NULL;
  160. }
  161. /**
  162. * {@inheritdoc}
  163. */
  164. public function arguments() {
  165. if (!$this->compiled()) {
  166. return NULL;
  167. }
  168. $args = $this->condition->arguments() + $this->having->arguments();
  169. foreach ($this->tables as $table) {
  170. if ($table['arguments']) {
  171. $args += $table['arguments'];
  172. }
  173. // If this table is a subquery, grab its arguments recursively.
  174. if ($table['table'] instanceof SelectInterface) {
  175. $args += $table['table']->arguments();
  176. }
  177. // If the join condition is an object, grab its arguments recursively.
  178. if (!empty($table['condition']) && $table['condition'] instanceof ConditionInterface) {
  179. $args += $table['condition']->arguments();
  180. }
  181. }
  182. foreach ($this->expressions as $expression) {
  183. if ($expression['arguments']) {
  184. $args += $expression['arguments'];
  185. }
  186. }
  187. // If there are any dependent queries to UNION,
  188. // incorporate their arguments recursively.
  189. foreach ($this->union as $union) {
  190. $args += $union['query']->arguments();
  191. }
  192. return $args;
  193. }
  194. /**
  195. * {@inheritdoc}
  196. */
  197. public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {
  198. $this->condition->compile($connection, $queryPlaceholder);
  199. $this->having->compile($connection, $queryPlaceholder);
  200. foreach ($this->tables as $table) {
  201. // If this table is a subquery, compile it recursively.
  202. if ($table['table'] instanceof SelectInterface) {
  203. $table['table']->compile($connection, $queryPlaceholder);
  204. }
  205. // Make sure join conditions are also compiled.
  206. if (!empty($table['condition']) && $table['condition'] instanceof ConditionInterface) {
  207. $table['condition']->compile($connection, $queryPlaceholder);
  208. }
  209. }
  210. // If there are any dependent queries to UNION, compile it recursively.
  211. foreach ($this->union as $union) {
  212. $union['query']->compile($connection, $queryPlaceholder);
  213. }
  214. }
  215. /**
  216. * {@inheritdoc}
  217. */
  218. public function compiled() {
  219. if (!$this->condition->compiled() || !$this->having->compiled()) {
  220. return FALSE;
  221. }
  222. foreach ($this->tables as $table) {
  223. // If this table is a subquery, check its status recursively.
  224. if ($table['table'] instanceof SelectInterface) {
  225. if (!$table['table']->compiled()) {
  226. return FALSE;
  227. }
  228. }
  229. if (!empty($table['condition']) && $table['condition'] instanceof ConditionInterface) {
  230. if (!$table['condition']->compiled()) {
  231. return FALSE;
  232. }
  233. }
  234. }
  235. foreach ($this->union as $union) {
  236. if (!$union['query']->compiled()) {
  237. return FALSE;
  238. }
  239. }
  240. return TRUE;
  241. }
  242. /**
  243. * {@inheritdoc}
  244. */
  245. public function havingCondition($field, $value = NULL, $operator = NULL) {
  246. $this->having->condition($field, $value, $operator);
  247. return $this;
  248. }
  249. /**
  250. * {@inheritdoc}
  251. */
  252. public function &havingConditions() {
  253. return $this->having->conditions();
  254. }
  255. /**
  256. * {@inheritdoc}
  257. */
  258. public function havingArguments() {
  259. return $this->having->arguments();
  260. }
  261. /**
  262. * {@inheritdoc}
  263. */
  264. public function having($snippet, $args = array()) {
  265. $this->having->where($snippet, $args);
  266. return $this;
  267. }
  268. /**
  269. * {@inheritdoc}
  270. */
  271. public function havingCompile(Connection $connection) {
  272. $this->having->compile($connection, $this);
  273. }
  274. /**
  275. * {@inheritdoc}
  276. */
  277. public function extend($extender_name) {
  278. $override_class = $extender_name . '_' . $this->connection->driver();
  279. if (class_exists($override_class)) {
  280. $extender_name = $override_class;
  281. }
  282. return new $extender_name($this, $this->connection);
  283. }
  284. /**
  285. * {@inheritdoc}
  286. */
  287. public function havingIsNull($field) {
  288. $this->having->isNull($field);
  289. return $this;
  290. }
  291. /**
  292. * {@inheritdoc}
  293. */
  294. public function havingIsNotNull($field) {
  295. $this->having->isNotNull($field);
  296. return $this;
  297. }
  298. /**
  299. * {@inheritdoc}
  300. */
  301. public function havingExists(SelectInterface $select) {
  302. $this->having->exists($select);
  303. return $this;
  304. }
  305. /**
  306. * {@inheritdoc}
  307. */
  308. public function havingNotExists(SelectInterface $select) {
  309. $this->having->notExists($select);
  310. return $this;
  311. }
  312. /**
  313. * {@inheritdoc}
  314. */
  315. public function forUpdate($set = TRUE) {
  316. if (isset($set)) {
  317. $this->forUpdate = $set;
  318. }
  319. return $this;
  320. }
  321. /**
  322. * {@inheritdoc}
  323. */
  324. public function &getFields() {
  325. return $this->fields;
  326. }
  327. /**
  328. * {@inheritdoc}
  329. */
  330. public function &getExpressions() {
  331. return $this->expressions;
  332. }
  333. /**
  334. * {@inheritdoc}
  335. */
  336. public function &getOrderBy() {
  337. return $this->order;
  338. }
  339. /**
  340. * {@inheritdoc}
  341. */
  342. public function &getGroupBy() {
  343. return $this->group;
  344. }
  345. /**
  346. * {@inheritdoc}
  347. */
  348. public function &getTables() {
  349. return $this->tables;
  350. }
  351. /**
  352. * {@inheritdoc}
  353. */
  354. public function &getUnion() {
  355. return $this->union;
  356. }
  357. /**
  358. * {@inheritdoc}
  359. */
  360. public function escapeLike($string) {
  361. return $this->connection->escapeLike($string);
  362. }
  363. /**
  364. * {@inheritdoc}
  365. */
  366. public function escapeField($string) {
  367. return $this->connection->escapeField($string);
  368. }
  369. /**
  370. * {@inheritdoc}
  371. */
  372. public function getArguments(PlaceholderInterface $queryPlaceholder = NULL) {
  373. if (!isset($queryPlaceholder)) {
  374. $queryPlaceholder = $this;
  375. }
  376. $this->compile($this->connection, $queryPlaceholder);
  377. return $this->arguments();
  378. }
  379. /**
  380. * {@inheritdoc}
  381. */
  382. public function isPrepared() {
  383. return $this->prepared;
  384. }
  385. /**
  386. * {@inheritdoc}
  387. */
  388. public function preExecute(SelectInterface $query = NULL) {
  389. // If no query object is passed in, use $this.
  390. if (!isset($query)) {
  391. $query = $this;
  392. }
  393. // Only execute this once.
  394. if ($query->isPrepared()) {
  395. return TRUE;
  396. }
  397. // Modules may alter all queries or only those having a particular tag.
  398. if (isset($this->alterTags)) {
  399. // Many contrib modules as well as Entity Reference in core assume that
  400. // query tags used for access-checking purposes follow the pattern
  401. // $entity_type . '_access'. But this is not the case for taxonomy terms,
  402. // since the core Taxonomy module used to add term_access instead of
  403. // taxonomy_term_access to its queries. Provide backwards compatibility
  404. // by adding both tags here instead of attempting to fix all contrib
  405. // modules in a coordinated effort.
  406. // TODO:
  407. // - Extract this mechanism into a hook as part of a public (non-security)
  408. // issue.
  409. // - Emit E_USER_DEPRECATED if term_access is used.
  410. // https://www.drupal.org/node/2575081
  411. $term_access_tags = array('term_access' => 1, 'taxonomy_term_access' => 1);
  412. if (array_intersect_key($this->alterTags, $term_access_tags)) {
  413. $this->alterTags += $term_access_tags;
  414. }
  415. $hooks = array('query');
  416. foreach ($this->alterTags as $tag => $value) {
  417. $hooks[] = 'query_' . $tag;
  418. }
  419. \Drupal::moduleHandler()->alter($hooks, $query);
  420. }
  421. $this->prepared = TRUE;
  422. // Now also prepare any sub-queries.
  423. foreach ($this->tables as $table) {
  424. if ($table['table'] instanceof SelectInterface) {
  425. $table['table']->preExecute();
  426. }
  427. }
  428. foreach ($this->union as $union) {
  429. $union['query']->preExecute();
  430. }
  431. return $this->prepared;
  432. }
  433. /**
  434. * {@inheritdoc}
  435. */
  436. public function execute() {
  437. // If validation fails, simply return NULL.
  438. // Note that validation routines in preExecute() may throw exceptions instead.
  439. if (!$this->preExecute()) {
  440. return NULL;
  441. }
  442. $args = $this->getArguments();
  443. return $this->connection->query((string) $this, $args, $this->queryOptions);
  444. }
  445. /**
  446. * {@inheritdoc}
  447. */
  448. public function distinct($distinct = TRUE) {
  449. $this->distinct = $distinct;
  450. return $this;
  451. }
  452. /**
  453. * {@inheritdoc}
  454. */
  455. public function addField($table_alias, $field, $alias = NULL) {
  456. // If no alias is specified, first try the field name itself.
  457. if (empty($alias)) {
  458. $alias = $field;
  459. }
  460. // If that's already in use, try the table name and field name.
  461. if (!empty($this->fields[$alias])) {
  462. $alias = $table_alias . '_' . $field;
  463. }
  464. // If that is already used, just add a counter until we find an unused alias.
  465. $alias_candidate = $alias;
  466. $count = 2;
  467. while (!empty($this->fields[$alias_candidate])) {
  468. $alias_candidate = $alias . '_' . $count++;
  469. }
  470. $alias = $alias_candidate;
  471. $this->fields[$alias] = array(
  472. 'field' => $field,
  473. 'table' => $table_alias,
  474. 'alias' => $alias,
  475. );
  476. return $alias;
  477. }
  478. /**
  479. * {@inheritdoc}
  480. */
  481. public function fields($table_alias, array $fields = array()) {
  482. if ($fields) {
  483. foreach ($fields as $field) {
  484. // We don't care what alias was assigned.
  485. $this->addField($table_alias, $field);
  486. }
  487. }
  488. else {
  489. // We want all fields from this table.
  490. $this->tables[$table_alias]['all_fields'] = TRUE;
  491. }
  492. return $this;
  493. }
  494. /**
  495. * {@inheritdoc}
  496. */
  497. public function addExpression($expression, $alias = NULL, $arguments = array()) {
  498. if (empty($alias)) {
  499. $alias = 'expression';
  500. }
  501. $alias_candidate = $alias;
  502. $count = 2;
  503. while (!empty($this->expressions[$alias_candidate])) {
  504. $alias_candidate = $alias . '_' . $count++;
  505. }
  506. $alias = $alias_candidate;
  507. $this->expressions[$alias] = array(
  508. 'expression' => $expression,
  509. 'alias' => $alias,
  510. 'arguments' => $arguments,
  511. );
  512. return $alias;
  513. }
  514. /**
  515. * {@inheritdoc}
  516. */
  517. public function join($table, $alias = NULL, $condition = NULL, $arguments = array()) {
  518. return $this->addJoin('INNER', $table, $alias, $condition, $arguments);
  519. }
  520. /**
  521. * {@inheritdoc}
  522. */
  523. public function innerJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
  524. return $this->addJoin('INNER', $table, $alias, $condition, $arguments);
  525. }
  526. /**
  527. * {@inheritdoc}
  528. */
  529. public function leftJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
  530. return $this->addJoin('LEFT OUTER', $table, $alias, $condition, $arguments);
  531. }
  532. /**
  533. * {@inheritdoc}
  534. */
  535. public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
  536. return $this->addJoin('RIGHT OUTER', $table, $alias, $condition, $arguments);
  537. }
  538. /**
  539. * {@inheritdoc}
  540. */
  541. public function addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = array()) {
  542. if (empty($alias)) {
  543. if ($table instanceof SelectInterface) {
  544. $alias = 'subquery';
  545. }
  546. else {
  547. $alias = $table;
  548. }
  549. }
  550. $alias_candidate = $alias;
  551. $count = 2;
  552. while (!empty($this->tables[$alias_candidate])) {
  553. $alias_candidate = $alias . '_' . $count++;
  554. }
  555. $alias = $alias_candidate;
  556. if (is_string($condition)) {
  557. $condition = str_replace('%alias', $alias, $condition);
  558. }
  559. $this->tables[$alias] = array(
  560. 'join type' => $type,
  561. 'table' => $table,
  562. 'alias' => $alias,
  563. 'condition' => $condition,
  564. 'arguments' => $arguments,
  565. );
  566. return $alias;
  567. }
  568. /**
  569. * {@inheritdoc}
  570. */
  571. public function orderBy($field, $direction = 'ASC') {
  572. // Only allow ASC and DESC, default to ASC.
  573. $direction = strtoupper($direction) == 'DESC' ? 'DESC' : 'ASC';
  574. $this->order[$field] = $direction;
  575. return $this;
  576. }
  577. /**
  578. * {@inheritdoc}
  579. */
  580. public function orderRandom() {
  581. $alias = $this->addExpression('RAND()', 'random_field');
  582. $this->orderBy($alias);
  583. return $this;
  584. }
  585. /**
  586. * {@inheritdoc}
  587. */
  588. public function range($start = NULL, $length = NULL) {
  589. $this->range = $start !== NULL ? array('start' => $start, 'length' => $length) : array();
  590. return $this;
  591. }
  592. /**
  593. * {@inheritdoc}
  594. */
  595. public function union(SelectInterface $query, $type = '') {
  596. // Handle UNION aliasing.
  597. switch ($type) {
  598. // Fold UNION DISTINCT to UNION for better cross database support.
  599. case 'DISTINCT':
  600. case '':
  601. $type = 'UNION';
  602. break;
  603. case 'ALL':
  604. $type = 'UNION ALL';
  605. default:
  606. }
  607. $this->union[] = array(
  608. 'type' => $type,
  609. 'query' => $query,
  610. );
  611. return $this;
  612. }
  613. /**
  614. * {@inheritdoc}
  615. */
  616. public function groupBy($field) {
  617. $this->group[$field] = $field;
  618. return $this;
  619. }
  620. /**
  621. * {@inheritdoc}
  622. */
  623. public function countQuery() {
  624. $count = $this->prepareCountQuery();
  625. $query = $this->connection->select($count, NULL, $this->queryOptions);
  626. $query->addExpression('COUNT(*)');
  627. return $query;
  628. }
  629. /**
  630. * Prepares a count query from the current query object.
  631. *
  632. * @return \Drupal\Core\Database\Query\Select
  633. * A new query object ready to have COUNT(*) performed on it.
  634. */
  635. protected function prepareCountQuery() {
  636. // Create our new query object that we will mutate into a count query.
  637. $count = clone($this);
  638. $group_by = $count->getGroupBy();
  639. $having = $count->havingConditions();
  640. if (!$count->distinct && !isset($having[0])) {
  641. // When not executing a distinct query, we can zero-out existing fields
  642. // and expressions that are not used by a GROUP BY or HAVING. Fields
  643. // listed in a GROUP BY or HAVING clause need to be present in the
  644. // query.
  645. $fields =& $count->getFields();
  646. foreach (array_keys($fields) as $field) {
  647. if (empty($group_by[$field])) {
  648. unset($fields[$field]);
  649. }
  650. }
  651. $expressions =& $count->getExpressions();
  652. foreach (array_keys($expressions) as $field) {
  653. if (empty($group_by[$field])) {
  654. unset($expressions[$field]);
  655. }
  656. }
  657. // Also remove 'all_fields' statements, which are expanded into tablename.*
  658. // when the query is executed.
  659. foreach ($count->tables as &$table) {
  660. unset($table['all_fields']);
  661. }
  662. }
  663. // If we've just removed all fields from the query, make sure there is at
  664. // least one so that the query still runs.
  665. $count->addExpression('1');
  666. // Ordering a count query is a waste of cycles, and breaks on some
  667. // databases anyway.
  668. $orders = &$count->getOrderBy();
  669. $orders = array();
  670. if ($count->distinct && !empty($group_by)) {
  671. // If the query is distinct and contains a GROUP BY, we need to remove the
  672. // distinct because SQL99 does not support counting on distinct multiple fields.
  673. $count->distinct = FALSE;
  674. }
  675. // If there are any dependent queries to UNION, prepare each of those for
  676. // the count query also.
  677. foreach ($count->union as &$union) {
  678. $union['query'] = $union['query']->prepareCountQuery();
  679. }
  680. return $count;
  681. }
  682. /**
  683. * {@inheritdoc}
  684. */
  685. public function __toString() {
  686. // For convenience, we compile the query ourselves if the caller forgot
  687. // to do it. This allows constructs like "(string) $query" to work. When
  688. // the query will be executed, it will be recompiled using the proper
  689. // placeholder generator anyway.
  690. if (!$this->compiled()) {
  691. $this->compile($this->connection, $this);
  692. }
  693. // Create a sanitized comment string to prepend to the query.
  694. $comments = $this->connection->makeComment($this->comments);
  695. // SELECT
  696. $query = $comments . 'SELECT ';
  697. if ($this->distinct) {
  698. $query .= 'DISTINCT ';
  699. }
  700. // FIELDS and EXPRESSIONS
  701. $fields = array();
  702. foreach ($this->tables as $alias => $table) {
  703. if (!empty($table['all_fields'])) {
  704. $fields[] = $this->connection->escapeTable($alias) . '.*';
  705. }
  706. }
  707. foreach ($this->fields as $field) {
  708. // Always use the AS keyword for field aliases, as some
  709. // databases require it (e.g., PostgreSQL).
  710. $fields[] = (isset($field['table']) ? $this->connection->escapeTable($field['table']) . '.' : '') . $this->connection->escapeField($field['field']) . ' AS ' . $this->connection->escapeAlias($field['alias']);
  711. }
  712. foreach ($this->expressions as $expression) {
  713. $fields[] = $expression['expression'] . ' AS ' . $this->connection->escapeAlias($expression['alias']);
  714. }
  715. $query .= implode(', ', $fields);
  716. // FROM - We presume all queries have a FROM, as any query that doesn't won't need the query builder anyway.
  717. $query .= "\nFROM ";
  718. foreach ($this->tables as $table) {
  719. $query .= "\n";
  720. if (isset($table['join type'])) {
  721. $query .= $table['join type'] . ' JOIN ';
  722. }
  723. // If the table is a subquery, compile it and integrate it into this query.
  724. if ($table['table'] instanceof SelectInterface) {
  725. // Run preparation steps on this sub-query before converting to string.
  726. $subquery = $table['table'];
  727. $subquery->preExecute();
  728. $table_string = '(' . (string) $subquery . ')';
  729. }
  730. else {
  731. $table_string = $this->connection->escapeTable($table['table']);
  732. // Do not attempt prefixing cross database / schema queries.
  733. if (strpos($table_string, '.') === FALSE) {
  734. $table_string = '{' . $table_string . '}';
  735. }
  736. }
  737. // Don't use the AS keyword for table aliases, as some
  738. // databases don't support it (e.g., Oracle).
  739. $query .= $table_string . ' ' . $this->connection->escapeTable($table['alias']);
  740. if (!empty($table['condition'])) {
  741. $query .= ' ON ' . (string) $table['condition'];
  742. }
  743. }
  744. // WHERE
  745. if (count($this->condition)) {
  746. // There is an implicit string cast on $this->condition.
  747. $query .= "\nWHERE " . $this->condition;
  748. }
  749. // GROUP BY
  750. if ($this->group) {
  751. $query .= "\nGROUP BY " . implode(', ', $this->group);
  752. }
  753. // HAVING
  754. if (count($this->having)) {
  755. // There is an implicit string cast on $this->having.
  756. $query .= "\nHAVING " . $this->having;
  757. }
  758. // UNION is a little odd, as the select queries to combine are passed into
  759. // this query, but syntactically they all end up on the same level.
  760. if ($this->union) {
  761. foreach ($this->union as $union) {
  762. $query .= ' ' . $union['type'] . ' ' . (string) $union['query'];
  763. }
  764. }
  765. // ORDER BY
  766. if ($this->order) {
  767. $query .= "\nORDER BY ";
  768. $fields = array();
  769. foreach ($this->order as $field => $direction) {
  770. $fields[] = $this->connection->escapeField($field) . ' ' . $direction;
  771. }
  772. $query .= implode(', ', $fields);
  773. }
  774. // RANGE
  775. // There is no universal SQL standard for handling range or limit clauses.
  776. // Fortunately, all core-supported databases use the same range syntax.
  777. // Databases that need a different syntax can override this method and
  778. // do whatever alternate logic they need to.
  779. if (!empty($this->range)) {
  780. $query .= "\nLIMIT " . (int) $this->range['length'] . " OFFSET " . (int) $this->range['start'];
  781. }
  782. if ($this->forUpdate) {
  783. $query .= ' FOR UPDATE';
  784. }
  785. return $query;
  786. }
  787. /**
  788. * {@inheritdoc}
  789. */
  790. public function __clone() {
  791. // On cloning, also clone the dependent objects. However, we do not
  792. // want to clone the database connection object as that would duplicate the
  793. // connection itself.
  794. $this->condition = clone($this->condition);
  795. $this->having = clone($this->having);
  796. foreach ($this->union as $key => $aggregate) {
  797. $this->union[$key]['query'] = clone($aggregate['query']);
  798. }
  799. }
  800. }

Classes

Namesort descending Description
Select Query builder for SELECT statements.