PageRenderTime 57ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Doctrine/Doctrine/Query/Abstract.php

https://github.com/ostric/e-learning
PHP | 2162 lines | 1135 code | 208 blank | 819 comment | 133 complexity | cd09e94e643c03d2c5c34c46630c8d60 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*
  3. * $Id: Query.php 1393 2007-05-19 17:49:16Z zYne $
  4. *
  5. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  6. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  7. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  8. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  9. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  10. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  11. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  13. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  14. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  15. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. *
  17. * This software consists of voluntary contributions made by many individuals
  18. * and is licensed under the LGPL. For more information, see
  19. * <http://www.phpdoctrine.org>.
  20. */
  21. /**
  22. * Doctrine_Query_Abstract
  23. *
  24. * @package Doctrine
  25. * @subpackage Query
  26. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  27. * @link www.phpdoctrine.org
  28. * @since 1.0
  29. * @version $Revision: 1393 $
  30. * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
  31. * @todo See {@link Doctrine_Query}
  32. */
  33. abstract class Doctrine_Query_Abstract
  34. {
  35. /**
  36. * QUERY TYPE CONSTANTS
  37. */
  38. /**
  39. * constant for SELECT queries
  40. */
  41. const SELECT = 0;
  42. /**
  43. * constant for DELETE queries
  44. */
  45. const DELETE = 1;
  46. /**
  47. * constant for UPDATE queries
  48. */
  49. const UPDATE = 2;
  50. /**
  51. * constant for INSERT queries
  52. */
  53. const INSERT = 3;
  54. /**
  55. * constant for CREATE queries
  56. */
  57. const CREATE = 4;
  58. /** @todo document the query states (and the transitions between them). */
  59. /**
  60. * A query object is in CLEAN state when it has NO unparsed/unprocessed DQL parts.
  61. */
  62. const STATE_CLEAN = 1;
  63. /**
  64. * A query object is in state DIRTY when it has DQL parts that have not yet been
  65. * parsed/processed.
  66. */
  67. const STATE_DIRTY = 2;
  68. /**
  69. * A query is in DIRECT state when ... ?
  70. */
  71. const STATE_DIRECT = 3;
  72. /**
  73. * A query object is on LOCKED state when ... ?
  74. */
  75. const STATE_LOCKED = 4;
  76. /**
  77. * @var array Table alias map. Keys are SQL aliases and values DQL aliases.
  78. */
  79. protected $_tableAliasMap = array();
  80. /**
  81. * @var Doctrine_View The view object used by this query, if any.
  82. */
  83. protected $_view;
  84. /**
  85. * @var integer $_state The current state of this query.
  86. */
  87. protected $_state = Doctrine_Query::STATE_CLEAN;
  88. /**
  89. * @var array $params The parameters of this query.
  90. */
  91. protected $_params = array('join' => array(),
  92. 'where' => array(),
  93. 'set' => array(),
  94. 'having' => array());
  95. /* Caching properties */
  96. /**
  97. * @var Doctrine_Cache_Interface The cache driver used for caching result sets.
  98. */
  99. protected $_resultCache;
  100. /**
  101. * @var boolean $_expireResultCache A boolean value that indicates whether or not
  102. * expire the result cache.
  103. */
  104. protected $_expireResultCache = false;
  105. protected $_resultCacheTTL;
  106. /**
  107. * @var Doctrine_Cache_Interface The cache driver used for caching queries.
  108. */
  109. protected $_queryCache;
  110. protected $_expireQueryCache = false;
  111. protected $_queryCacheTTL;
  112. /**
  113. * @var Doctrine_Connection The connection used by this query object.
  114. */
  115. protected $_conn;
  116. /**
  117. * @var array $_sqlParts The SQL query string parts. Filled during the DQL parsing process.
  118. */
  119. protected $_sqlParts = array(
  120. 'select' => array(),
  121. 'distinct' => false,
  122. 'forUpdate' => false,
  123. 'from' => array(),
  124. 'set' => array(),
  125. 'join' => array(),
  126. 'where' => array(),
  127. 'groupby' => array(),
  128. 'having' => array(),
  129. 'orderby' => array(),
  130. 'limit' => false,
  131. 'offset' => false,
  132. );
  133. /**
  134. * @var array $_dqlParts an array containing all DQL query parts
  135. */
  136. protected $_dqlParts = array(
  137. 'from' => array(),
  138. 'select' => array(),
  139. 'forUpdate' => false,
  140. 'set' => array(),
  141. 'join' => array(),
  142. 'where' => array(),
  143. 'groupby' => array(),
  144. 'having' => array(),
  145. 'orderby' => array(),
  146. 'limit' => array(),
  147. 'offset' => array(),
  148. );
  149. /**
  150. * @var array $_queryComponents Two dimensional array containing the components of this query,
  151. * informations about their relations and other related information.
  152. * The components are constructed during query parsing.
  153. *
  154. * Keys are component aliases and values the following:
  155. *
  156. * table table object associated with given alias
  157. *
  158. * relation the relation object owned by the parent
  159. *
  160. * parent the alias of the parent
  161. *
  162. * agg the aggregates of this component
  163. *
  164. * map the name of the column / aggregate value this
  165. * component is mapped to a collection
  166. */
  167. protected $_queryComponents = array();
  168. /**
  169. * @var integer $type the query type
  170. *
  171. * @see Doctrine_Query::* constants
  172. */
  173. protected $_type = self::SELECT;
  174. /**
  175. * @var Doctrine_Hydrator The hydrator object used to hydrate query results.
  176. */
  177. protected $_hydrator;
  178. /**
  179. * @var Doctrine_Query_Tokenizer The tokenizer that is used during the query parsing process.
  180. */
  181. protected $_tokenizer;
  182. /**
  183. * @var Doctrine_Query_Parser The parser that is used for query parsing.
  184. */
  185. protected $_parser;
  186. /**
  187. * @var array $_tableAliasSeeds A simple array keys representing table aliases and values
  188. * table alias seeds. The seeds are used for generating short table
  189. * aliases.
  190. */
  191. protected $_tableAliasSeeds = array();
  192. /**
  193. * @var array $_options an array of options
  194. */
  195. protected $_options = array(
  196. 'hydrationMode' => Doctrine::HYDRATE_RECORD
  197. );
  198. /**
  199. * @var boolean
  200. */
  201. protected $_isLimitSubqueryUsed = false;
  202. /**
  203. * @var array components used in the DQL statement
  204. */
  205. protected $_components;
  206. /**
  207. * @var bool Boolean variable for whether or not the preQuery process has been executed
  208. */
  209. protected $_preQueried = false;
  210. /**
  211. * Constructor.
  212. *
  213. * @param Doctrine_Connection The connection object the query will use.
  214. * @param Doctrine_Hydrator_Abstract The hydrator that will be used for generating result sets.
  215. */
  216. public function __construct(Doctrine_Connection $connection = null,
  217. Doctrine_Hydrator_Abstract $hydrator = null)
  218. {
  219. if ($connection === null) {
  220. $connection = Doctrine_Manager::getInstance()->getCurrentConnection();
  221. }
  222. if ($hydrator === null) {
  223. $hydrator = new Doctrine_Hydrator();
  224. }
  225. $this->_conn = $connection;
  226. $this->_hydrator = $hydrator;
  227. $this->_tokenizer = new Doctrine_Query_Tokenizer();
  228. $this->_resultCacheTTL = $this->_conn->getAttribute(Doctrine::ATTR_RESULT_CACHE_LIFESPAN);
  229. $this->_queryCacheTTL = $this->_conn->getAttribute(Doctrine::ATTR_QUERY_CACHE_LIFESPAN);
  230. }
  231. /**
  232. * setOption
  233. *
  234. * @param string $name option name
  235. * @param string $value option value
  236. * @return Doctrine_Query this object
  237. */
  238. public function setOption($name, $value)
  239. {
  240. if ( ! isset($this->_options[$name])) {
  241. throw new Doctrine_Query_Exception('Unknown option ' . $name);
  242. }
  243. $this->_options[$name] = $value;
  244. }
  245. /**
  246. * hasTableAlias
  247. * whether or not this object has given tableAlias
  248. *
  249. * @param string $tableAlias the table alias to be checked
  250. * @return boolean true if this object has given alias, otherwise false
  251. * @deprecated
  252. */
  253. public function hasTableAlias($sqlTableAlias)
  254. {
  255. return $this->hasSqlTableAlias($sqlTableAlias);
  256. }
  257. /**
  258. * hasSqlTableAlias
  259. * whether or not this object has given tableAlias
  260. *
  261. * @param string $tableAlias the table alias to be checked
  262. * @return boolean true if this object has given alias, otherwise false
  263. */
  264. public function hasSqlTableAlias($sqlTableAlias)
  265. {
  266. return (isset($this->_tableAliasMap[$sqlTableAlias]));
  267. }
  268. /**
  269. * getTableAliases
  270. * returns all table aliases
  271. *
  272. * @return array table aliases as an array
  273. * @deprecated
  274. */
  275. public function getTableAliases()
  276. {
  277. return $this->getTableAliasMap();
  278. }
  279. /**
  280. * getTableAliasMap
  281. * returns all table aliases
  282. *
  283. * @return array table aliases as an array
  284. */
  285. public function getTableAliasMap()
  286. {
  287. return $this->_tableAliasMap;
  288. }
  289. /**
  290. * getDql
  291. * returns the DQL query that is represented by this query object.
  292. *
  293. * the query is built from $_dqlParts
  294. *
  295. * @return string the DQL query
  296. */
  297. public function getDql()
  298. {
  299. $q = '';
  300. if ($this->_type == self::SELECT) {
  301. $q .= ( ! empty($this->_dqlParts['select'])) ? 'SELECT ' . implode(', ', $this->_dqlParts['select']) : '';
  302. $q .= ( ! empty($this->_dqlParts['from'])) ? ' FROM ' . implode(' ', $this->_dqlParts['from']) : '';
  303. } else if ($this->_type == self::DELETE) {
  304. $q .= 'DELETE';
  305. $q .= ( ! empty($this->_dqlParts['from'])) ? ' FROM ' . implode(' ', $this->_dqlParts['from']) : '';
  306. } else if ($this->_type == self::UPDATE) {
  307. $q .= 'UPDATE ';
  308. $q .= ( ! empty($this->_dqlParts['from'])) ? implode(' ', $this->_dqlParts['from']) : '';
  309. $q .= ( ! empty($this->_dqlParts['set'])) ? ' SET ' . implode(' ', $this->_dqlParts['set']) : '';
  310. }
  311. $q .= ( ! empty($this->_dqlParts['where'])) ? ' WHERE ' . implode(' ', $this->_dqlParts['where']) : '';
  312. $q .= ( ! empty($this->_dqlParts['groupby'])) ? ' GROUP BY ' . implode(', ', $this->_dqlParts['groupby']) : '';
  313. $q .= ( ! empty($this->_dqlParts['having'])) ? ' HAVING ' . implode(' AND ', $this->_dqlParts['having']) : '';
  314. $q .= ( ! empty($this->_dqlParts['orderby'])) ? ' ORDER BY ' . implode(', ', $this->_dqlParts['orderby']) : '';
  315. $q .= ( ! empty($this->_dqlParts['limit'])) ? ' LIMIT ' . implode(' ', $this->_dqlParts['limit']) : '';
  316. $q .= ( ! empty($this->_dqlParts['offset'])) ? ' OFFSET ' . implode(' ', $this->_dqlParts['offset']) : '';
  317. return $q;
  318. }
  319. /**
  320. * getQueryPart
  321. * gets a query part from the query part array
  322. *
  323. * @param string $name the name of the query part to be set
  324. * @param string $part query part string
  325. * @throws Doctrine_Query_Exception if trying to set unknown query part
  326. * @return Doctrine_Query_Abstract this object
  327. * @deprecated
  328. */
  329. public function getQueryPart($part)
  330. {
  331. return $this->getSqlQueryPart($part);
  332. }
  333. /**
  334. * getSqlQueryPart
  335. * gets an SQL query part from the SQL query part array
  336. *
  337. * @param string $name the name of the query part to be set
  338. * @param string $part query part string
  339. * @throws Doctrine_Query_Exception if trying to set unknown query part
  340. * @return Doctrine_Hydrate this object
  341. */
  342. public function getSqlQueryPart($part)
  343. {
  344. if ( ! isset($this->_sqlParts[$part])) {
  345. throw new Doctrine_Query_Exception('Unknown SQL query part ' . $part);
  346. }
  347. return $this->_sqlParts[$part];
  348. }
  349. /**
  350. * setQueryPart
  351. * sets a query part in the query part array
  352. *
  353. * @param string $name the name of the query part to be set
  354. * @param string $part query part string
  355. * @throws Doctrine_Query_Exception if trying to set unknown query part
  356. * @return Doctrine_Hydrate this object
  357. * @deprecated
  358. */
  359. public function setQueryPart($name, $part)
  360. {
  361. return $this->setSqlQueryPart($name, $part);
  362. }
  363. /**
  364. * setSqlQueryPart
  365. * sets an SQL query part in the SQL query part array
  366. *
  367. * @param string $name the name of the query part to be set
  368. * @param string $part query part string
  369. * @throws Doctrine_Query_Exception if trying to set unknown query part
  370. * @return Doctrine_Hydrate this object
  371. */
  372. public function setSqlQueryPart($name, $part)
  373. {
  374. if ( ! isset($this->_sqlParts[$name])) {
  375. throw new Doctrine_Query_Exception('Unknown query part ' . $name);
  376. }
  377. if ($name !== 'limit' && $name !== 'offset') {
  378. if (is_array($part)) {
  379. $this->_sqlParts[$name] = $part;
  380. } else {
  381. $this->_sqlParts[$name] = array($part);
  382. }
  383. } else {
  384. $this->_sqlParts[$name] = $part;
  385. }
  386. return $this;
  387. }
  388. /**
  389. * addQueryPart
  390. * adds a query part in the query part array
  391. *
  392. * @param string $name the name of the query part to be added
  393. * @param string $part query part string
  394. * @throws Doctrine_Query_Exception if trying to add unknown query part
  395. * @return Doctrine_Hydrate this object
  396. * @deprecated
  397. */
  398. public function addQueryPart($name, $part)
  399. {
  400. return $this->addSqlQueryPart($name, $part);
  401. }
  402. /**
  403. * addSqlQueryPart
  404. * adds an SQL query part to the SQL query part array
  405. *
  406. * @param string $name the name of the query part to be added
  407. * @param string $part query part string
  408. * @throws Doctrine_Query_Exception if trying to add unknown query part
  409. * @return Doctrine_Hydrate this object
  410. */
  411. public function addSqlQueryPart($name, $part)
  412. {
  413. if ( ! isset($this->_sqlParts[$name])) {
  414. throw new Doctrine_Query_Exception('Unknown query part ' . $name);
  415. }
  416. if (is_array($part)) {
  417. $this->_sqlParts[$name] = array_merge($this->_sqlParts[$name], $part);
  418. } else {
  419. $this->_sqlParts[$name][] = $part;
  420. }
  421. return $this;
  422. }
  423. /**
  424. * removeQueryPart
  425. * removes a query part from the query part array
  426. *
  427. * @param string $name the name of the query part to be removed
  428. * @throws Doctrine_Query_Exception if trying to remove unknown query part
  429. * @return Doctrine_Hydrate this object
  430. * @deprecated
  431. */
  432. public function removeQueryPart($name)
  433. {
  434. return $this->removeSqlQueryPart($name);
  435. }
  436. /**
  437. * removeSqlQueryPart
  438. * removes a query part from the query part array
  439. *
  440. * @param string $name the name of the query part to be removed
  441. * @throws Doctrine_Query_Exception if trying to remove unknown query part
  442. * @return Doctrine_Hydrate this object
  443. */
  444. public function removeSqlQueryPart($name)
  445. {
  446. if ( ! isset($this->_sqlParts[$name])) {
  447. throw new Doctrine_Query_Exception('Unknown query part ' . $name);
  448. }
  449. if ($name == 'limit' || $name == 'offset') {
  450. $this->_sqlParts[$name] = false;
  451. } else {
  452. $this->_sqlParts[$name] = array();
  453. }
  454. return $this;
  455. }
  456. /**
  457. * removeDqlQueryPart
  458. * removes a dql query part from the dql query part array
  459. *
  460. * @param string $name the name of the query part to be removed
  461. * @throws Doctrine_Query_Exception if trying to remove unknown query part
  462. * @return Doctrine_Hydrate this object
  463. */
  464. public function removeDqlQueryPart($name)
  465. {
  466. if ( ! isset($this->_dqlParts[$name])) {
  467. throw new Doctrine_Query_Exception('Unknown query part ' . $name);
  468. }
  469. if ($name == 'limit' || $name == 'offset') {
  470. $this->_dqlParts[$name] = false;
  471. } else {
  472. $this->_dqlParts[$name] = array();
  473. }
  474. return $this;
  475. }
  476. /**
  477. * getParams
  478. *
  479. * @return array
  480. */
  481. public function getParams($params = array())
  482. {
  483. return array_merge((array) $params, $this->_params['join'], $this->_params['set'], $this->_params['where'], $this->_params['having']);
  484. }
  485. /**
  486. * Get the raw array of parameters
  487. *
  488. * @return array
  489. */
  490. public function getRawParams()
  491. {
  492. return $this->_params;
  493. }
  494. /**
  495. * setParams
  496. *
  497. * @param array $params
  498. */
  499. public function setParams(array $params = array())
  500. {
  501. $this->_params = $params;
  502. }
  503. /**
  504. * setView
  505. * sets a database view this query object uses
  506. * this method should only be called internally by doctrine
  507. *
  508. * @param Doctrine_View $view database view
  509. * @return void
  510. */
  511. public function setView(Doctrine_View $view)
  512. {
  513. $this->_view = $view;
  514. }
  515. /**
  516. * getView
  517. * returns the view associated with this query object (if any)
  518. *
  519. * @return Doctrine_View the view associated with this query object
  520. */
  521. public function getView()
  522. {
  523. return $this->_view;
  524. }
  525. /**
  526. * limitSubqueryUsed
  527. *
  528. * @return boolean
  529. */
  530. public function isLimitSubqueryUsed()
  531. {
  532. return $this->_isLimitSubqueryUsed;
  533. }
  534. /**
  535. * Returns the inheritance condition for the passed componentAlias
  536. * If no component alias is specified it defaults to the root component
  537. *
  538. * This function is used to append a SQL condition to models which have inheritance mapping
  539. * The condition is applied to the FROM component in the WHERE, but the condition is applied to
  540. * JOINS in the ON condition and not the WHERE
  541. *
  542. * @return string $str SQL condition string
  543. */
  544. public function getInheritanceCondition($componentAlias)
  545. {
  546. $map = $this->_queryComponents[$componentAlias]['table']->inheritanceMap;
  547. // No inheritance map so lets just return
  548. if (empty($map)) {
  549. return;
  550. }
  551. $tableAlias = $this->getSqlTableAlias($componentAlias);
  552. if ($this->_type !== Doctrine_Query::SELECT) {
  553. $tableAlias = '';
  554. } else {
  555. $tableAlias .= '.';
  556. }
  557. $field = key($map);
  558. $value = current($map);
  559. $identifier = $this->_conn->quoteIdentifier($tableAlias . $field);
  560. return $identifier . ' = ' . $this->_conn->quote($value);;
  561. }
  562. /**
  563. * getTableAlias
  564. * some database such as Oracle need the identifier lengths to be < ~30 chars
  565. * hence Doctrine creates as short identifier aliases as possible
  566. *
  567. * this method is used for the creation of short table aliases, its also
  568. * smart enough to check if an alias already exists for given component (componentAlias)
  569. *
  570. * @param string $componentAlias the alias for the query component to search table alias for
  571. * @param string $tableName the table name from which the table alias is being created
  572. * @return string the generated / fetched short alias
  573. * @deprecated
  574. */
  575. public function getTableAlias($componentAlias, $tableName = null)
  576. {
  577. return $this->getSqlTableAlias($componentAlias, $tableName);
  578. }
  579. /**
  580. * getSqlTableAlias
  581. * some database such as Oracle need the identifier lengths to be < ~30 chars
  582. * hence Doctrine creates as short identifier aliases as possible
  583. *
  584. * this method is used for the creation of short table aliases, its also
  585. * smart enough to check if an alias already exists for given component (componentAlias)
  586. *
  587. * @param string $componentAlias the alias for the query component to search table alias for
  588. * @param string $tableName the table name from which the table alias is being created
  589. * @return string the generated / fetched short alias
  590. */
  591. public function getSqlTableAlias($componentAlias, $tableName = null)
  592. {
  593. $alias = array_search($componentAlias, $this->_tableAliasMap);
  594. if ($alias !== false) {
  595. return $alias;
  596. }
  597. if ($tableName === null) {
  598. throw new Doctrine_Query_Exception("Couldn't get short alias for " . $componentAlias);
  599. }
  600. return $this->generateTableAlias($componentAlias, $tableName);
  601. }
  602. /**
  603. * generateNewTableAlias
  604. * generates a new alias from given table alias
  605. *
  606. * @param string $tableAlias table alias from which to generate the new alias from
  607. * @return string the created table alias
  608. * @deprecated
  609. */
  610. public function generateNewTableAlias($oldAlias)
  611. {
  612. return $this->generateNewSqlTableAlias($oldAlias);
  613. }
  614. /**
  615. * generateNewSqlTableAlias
  616. * generates a new alias from given table alias
  617. *
  618. * @param string $tableAlias table alias from which to generate the new alias from
  619. * @return string the created table alias
  620. */
  621. public function generateNewSqlTableAlias($oldAlias)
  622. {
  623. if (isset($this->_tableAliasMap[$oldAlias])) {
  624. // generate a new alias
  625. $name = substr($oldAlias, 0, 1);
  626. $i = ((int) substr($oldAlias, 1));
  627. // Fix #1530: It was reaching unexistent seeds index
  628. if ( ! isset($this->_tableAliasSeeds[$name])) {
  629. $this->_tableAliasSeeds[$name] = 1;
  630. }
  631. $newIndex = ($this->_tableAliasSeeds[$name] + (($i == 0) ? 1 : $i));
  632. return $name . $newIndex;
  633. }
  634. return $oldAlias;
  635. }
  636. /**
  637. * getTableAliasSeed
  638. * returns the alias seed for given table alias
  639. *
  640. * @param string $tableAlias table alias that identifies the alias seed
  641. * @return integer table alias seed
  642. * @deprecated
  643. */
  644. public function getTableAliasSeed($sqlTableAlias)
  645. {
  646. return $this->getSqlTableAliasSeed($sqlTableAlias);
  647. }
  648. /**
  649. * getSqlTableAliasSeed
  650. * returns the alias seed for given table alias
  651. *
  652. * @param string $tableAlias table alias that identifies the alias seed
  653. * @return integer table alias seed
  654. */
  655. public function getSqlTableAliasSeed($sqlTableAlias)
  656. {
  657. if ( ! isset($this->_tableAliasSeeds[$sqlTableAlias])) {
  658. return 0;
  659. }
  660. return $this->_tableAliasSeeds[$sqlTableAlias];
  661. }
  662. /**
  663. * hasAliasDeclaration
  664. * whether or not this object has a declaration for given component alias
  665. *
  666. * @param string $componentAlias the component alias the retrieve the declaration from
  667. * @return boolean
  668. */
  669. public function hasAliasDeclaration($componentAlias)
  670. {
  671. return isset($this->_queryComponents[$componentAlias]);
  672. }
  673. /**
  674. * getAliasDeclaration
  675. * get the declaration for given component alias
  676. *
  677. * @param string $componentAlias the component alias the retrieve the declaration from
  678. * @return array the alias declaration
  679. * @deprecated
  680. */
  681. public function getAliasDeclaration($componentAlias)
  682. {
  683. return $this->getQueryComponent($componentAlias);
  684. }
  685. /**
  686. * getQueryComponent
  687. * get the declaration for given component alias
  688. *
  689. * @param string $componentAlias the component alias the retrieve the declaration from
  690. * @return array the alias declaration
  691. */
  692. public function getQueryComponent($componentAlias)
  693. {
  694. if ( ! isset($this->_queryComponents[$componentAlias])) {
  695. throw new Doctrine_Query_Exception('Unknown component alias ' . $componentAlias);
  696. }
  697. return $this->_queryComponents[$componentAlias];
  698. }
  699. /**
  700. * copyAliases
  701. * copy aliases from another Hydrate object
  702. *
  703. * this method is needed by DQL subqueries which need the aliases
  704. * of the parent query
  705. *
  706. * @param Doctrine_Hydrate $query the query object from which the
  707. * aliases are copied from
  708. * @return Doctrine_Hydrate this object
  709. */
  710. public function copySubqueryInfo(Doctrine_Query_Abstract $query)
  711. {
  712. $this->_params =& $query->_params;
  713. $this->_tableAliasMap =& $query->_tableAliasMap;
  714. $this->_queryComponents =& $query->_queryComponents;
  715. $this->_tableAliasSeeds = $query->_tableAliasSeeds;
  716. return $this;
  717. }
  718. /**
  719. * getRootAlias
  720. * returns the alias of the the root component
  721. *
  722. * @return array
  723. */
  724. public function getRootAlias()
  725. {
  726. if ( ! $this->_queryComponents) {
  727. $this->getSql();
  728. }
  729. reset($this->_queryComponents);
  730. return key($this->_queryComponents);
  731. }
  732. /**
  733. * getRootDeclaration
  734. * returns the root declaration
  735. *
  736. * @return array
  737. */
  738. public function getRootDeclaration()
  739. {
  740. $map = reset($this->_queryComponents);
  741. return $map;
  742. }
  743. /**
  744. * getRoot
  745. * returns the root component for this object
  746. *
  747. * @return Doctrine_Table root components table
  748. */
  749. public function getRoot()
  750. {
  751. $map = reset($this->_queryComponents);
  752. if ( ! isset($map['table'])) {
  753. throw new Doctrine_Query_Exception('Root component not initialized.');
  754. }
  755. return $map['table'];
  756. }
  757. /**
  758. * generateTableAlias
  759. * generates a table alias from given table name and associates
  760. * it with given component alias
  761. *
  762. * @param string $componentAlias the component alias to be associated with generated table alias
  763. * @param string $tableName the table name from which to generate the table alias
  764. * @return string the generated table alias
  765. * @deprecated
  766. */
  767. public function generateTableAlias($componentAlias, $tableName)
  768. {
  769. return $this->generateSqlTableAlias($componentAlias, $tableName);
  770. }
  771. /**
  772. * generateSqlTableAlias
  773. * generates a table alias from given table name and associates
  774. * it with given component alias
  775. *
  776. * @param string $componentAlias the component alias to be associated with generated table alias
  777. * @param string $tableName the table name from which to generate the table alias
  778. * @return string the generated table alias
  779. */
  780. public function generateSqlTableAlias($componentAlias, $tableName)
  781. {
  782. preg_match('/([^_])/', $tableName, $matches);
  783. $char = strtolower($matches[0]);
  784. $alias = $char;
  785. if ( ! isset($this->_tableAliasSeeds[$alias])) {
  786. $this->_tableAliasSeeds[$alias] = 1;
  787. }
  788. while (isset($this->_tableAliasMap[$alias])) {
  789. if ( ! isset($this->_tableAliasSeeds[$alias])) {
  790. $this->_tableAliasSeeds[$alias] = 1;
  791. }
  792. $alias = $char . ++$this->_tableAliasSeeds[$alias];
  793. }
  794. $this->_tableAliasMap[$alias] = $componentAlias;
  795. return $alias;
  796. }
  797. /**
  798. * getComponentAlias
  799. * get component alias associated with given table alias
  800. *
  801. * @param string $sqlTableAlias the SQL table alias that identifies the component alias
  802. * @return string component alias
  803. */
  804. public function getComponentAlias($sqlTableAlias)
  805. {
  806. $sqlTableAlias = trim($sqlTableAlias, '[]`"');
  807. if ( ! isset($this->_tableAliasMap[$sqlTableAlias])) {
  808. throw new Doctrine_Query_Exception('Unknown table alias ' . $sqlTableAlias);
  809. }
  810. return $this->_tableAliasMap[$sqlTableAlias];
  811. }
  812. /**
  813. * calculateQueryCacheHash
  814. * calculate hash key for query cache
  815. *
  816. * @return string the hash
  817. */
  818. public function calculateQueryCacheHash()
  819. {
  820. $dql = $this->getDql();
  821. $hash = md5($dql . 'DOCTRINE_QUERY_CACHE_SALT');
  822. return $hash;
  823. }
  824. /**
  825. * calculateResultCacheHash
  826. * calculate hash key for result cache
  827. *
  828. * @param array $params
  829. * @return string the hash
  830. */
  831. public function calculateResultCacheHash($params = array())
  832. {
  833. $dql = $this->getDql();
  834. $params = $this->getParams($params);
  835. $conn = $this->getConnection();
  836. $hash = md5($conn->getName() . $conn->getOption('dsn') . $dql . var_export($params, true));
  837. return $hash;
  838. }
  839. /**
  840. * _execute
  841. *
  842. * @param array $params
  843. * @return PDOStatement The executed PDOStatement.
  844. */
  845. protected function _execute($params)
  846. {
  847. $params = $this->_conn->convertBooleans($params);
  848. if ( ! $this->_view) {
  849. if ($this->_queryCache !== false && ($this->_queryCache || $this->_conn->getAttribute(Doctrine::ATTR_QUERY_CACHE))) {
  850. $queryCacheDriver = $this->getQueryCacheDriver();
  851. $hash = $this->calculateQueryCacheHash();
  852. $cached = $queryCacheDriver->fetch($hash);
  853. if ($cached) {
  854. $query = $this->_constructQueryFromCache($cached);
  855. } else {
  856. $query = $this->getSqlQuery($params);
  857. // Check again because getSqlQuery() above could have flipped the _queryCache flag
  858. // if this query contains the limit sub query algorithm we don't need to cache it
  859. if ($this->_queryCache !== false && ($this->_queryCache || $this->_conn->getAttribute(Doctrine::ATTR_QUERY_CACHE))) {
  860. $serializedQuery = $this->getCachedForm($query);
  861. $queryCacheDriver->save($hash, $serializedQuery, $this->getQueryCacheLifeSpan());
  862. }
  863. }
  864. } else {
  865. $query = $this->getSqlQuery($params);
  866. }
  867. } else {
  868. $query = $this->_view->getSelectSql();
  869. }
  870. if ($this->isLimitSubqueryUsed() &&
  871. $this->_conn->getAttribute(Doctrine::ATTR_DRIVER_NAME) !== 'mysql') {
  872. $params = array_merge($params, $params);
  873. }
  874. if ($this->_type !== self::SELECT) {
  875. return $this->_conn->exec($query, $params);
  876. }
  877. $stmt = $this->_conn->execute($query, $params);
  878. return $stmt;
  879. }
  880. /**
  881. * execute
  882. * executes the query and populates the data set
  883. *
  884. * @param array $params
  885. * @return Doctrine_Collection the root collection
  886. */
  887. public function execute($params = array(), $hydrationMode = null)
  888. {
  889. if (empty($this->_dqlParts['from']) && empty($this->_sqlParts['from'])) {
  890. throw new Doctrine_Query_Exception('You must have at least one component specified in your from.');
  891. }
  892. $preQueryParams = $this->getParams($params);
  893. $this->_preQuery($preQueryParams);
  894. if ($hydrationMode !== null) {
  895. $this->_hydrator->setHydrationMode($hydrationMode);
  896. }
  897. $params = $this->getParams($params);
  898. if ($this->_resultCache && $this->_type == self::SELECT) {
  899. $cacheDriver = $this->getResultCacheDriver();
  900. $hash = $this->calculateResultCacheHash($params);
  901. $cached = ($this->_expireResultCache) ? false : $cacheDriver->fetch($hash);
  902. if ($cached === false) {
  903. // cache miss
  904. $stmt = $this->_execute($params);
  905. $this->_hydrator->setQueryComponents($this->_queryComponents);
  906. $result = $this->_hydrator->hydrateResultSet($stmt, $this->_tableAliasMap);
  907. $cached = $this->getCachedForm($result);
  908. $cacheDriver->save($hash, $cached, $this->getResultCacheLifeSpan());
  909. } else {
  910. $result = $this->_constructQueryFromCache($cached);
  911. }
  912. } else {
  913. $stmt = $this->_execute($params);
  914. if (is_integer($stmt)) {
  915. $result = $stmt;
  916. } else {
  917. $this->_hydrator->setQueryComponents($this->_queryComponents);
  918. $result = $this->_hydrator->hydrateResultSet($stmt, $this->_tableAliasMap);
  919. }
  920. }
  921. return $result;
  922. }
  923. /**
  924. * Get the dql call back for this query
  925. *
  926. * @return array $callback
  927. */
  928. protected function _getDqlCallback()
  929. {
  930. $callback = false;
  931. if ( ! empty($this->_dqlParts['from'])) {
  932. switch ($this->_type) {
  933. case self::DELETE:
  934. $callback = array(
  935. 'callback' => 'preDqlDelete',
  936. 'const' => Doctrine_Event::RECORD_DQL_DELETE
  937. );
  938. break;
  939. case self::UPDATE:
  940. $callback = array(
  941. 'callback' => 'preDqlUpdate',
  942. 'const' => Doctrine_Event::RECORD_DQL_UPDATE
  943. );
  944. break;
  945. case self::SELECT:
  946. $callback = array(
  947. 'callback' => 'preDqlSelect',
  948. 'const' => Doctrine_Event::RECORD_DQL_SELECT
  949. );
  950. break;
  951. }
  952. }
  953. return $callback;
  954. }
  955. /**
  956. * Pre query method which invokes the pre*Query() methods on the model instance or any attached
  957. * record listeners
  958. *
  959. * @return void
  960. */
  961. protected function _preQuery($params = array())
  962. {
  963. if ( ! $this->_preQueried && $this->getConnection()->getAttribute('use_dql_callbacks')) {
  964. $this->_preQueried = true;
  965. $callback = $this->_getDqlCallback();
  966. // if there is no callback for the query type, then we can return early
  967. if ( ! $callback) {
  968. return;
  969. }
  970. foreach ($this->_getDqlCallbackComponents($params) as $alias => $component) {
  971. $table = $component['table'];
  972. $record = $table->getRecordInstance();
  973. // Trigger preDql*() callback event
  974. $params = array('component' => $component, 'alias' => $alias);
  975. $event = new Doctrine_Event($record, $callback['const'], $this, $params);
  976. $record->$callback['callback']($event);
  977. $table->getRecordListener()->$callback['callback']($event);
  978. }
  979. }
  980. // Invoke preQuery() hook on Doctrine_Query for child classes which implement this hook
  981. $this->preQuery();
  982. }
  983. /**
  984. * Returns an array of components to execute the query callbacks for
  985. *
  986. * @param array $params
  987. * @return array $components
  988. */
  989. protected function _getDqlCallbackComponents($params = array())
  990. {
  991. $componentsBefore = array();
  992. if ($this->isSubquery()) {
  993. $componentsBefore = $this->getQueryComponents();
  994. }
  995. $copy = $this->copy();
  996. $copy->getSqlQuery($params);
  997. $componentsAfter = $copy->getQueryComponents();
  998. if ($componentsBefore !== $componentsAfter) {
  999. return array_diff($componentsAfter, $componentsBefore);
  1000. } else {
  1001. return $componentsAfter;
  1002. }
  1003. }
  1004. /**
  1005. * Blank hook methods which can be implemented in Doctrine_Query child classes
  1006. *
  1007. * @return void
  1008. */
  1009. public function preQuery()
  1010. {
  1011. }
  1012. /**
  1013. * Constructs the query from the cached form.
  1014. *
  1015. * @param string The cached query, in a serialized form.
  1016. * @return array The custom component that was cached together with the essential
  1017. * query data. This can be either a result set (result caching)
  1018. * or an SQL query string (query caching).
  1019. */
  1020. protected function _constructQueryFromCache($cached)
  1021. {
  1022. $cached = unserialize($cached);
  1023. $this->_tableAliasMap = $cached[2];
  1024. $customComponent = $cached[0];
  1025. $queryComponents = array();
  1026. $cachedComponents = $cached[1];
  1027. foreach ($cachedComponents as $alias => $components) {
  1028. $e = explode('.', $components[0]);
  1029. if (count($e) === 1) {
  1030. $queryComponents[$alias]['table'] = $this->_conn->getTable($e[0]);
  1031. } else {
  1032. $queryComponents[$alias]['parent'] = $e[0];
  1033. $queryComponents[$alias]['relation'] = $queryComponents[$e[0]]['table']->getRelation($e[1]);
  1034. $queryComponents[$alias]['table'] = $queryComponents[$alias]['relation']->getTable();
  1035. }
  1036. if (isset($components[1])) {
  1037. $queryComponents[$alias]['agg'] = $components[1];
  1038. }
  1039. if (isset($components[2])) {
  1040. $queryComponents[$alias]['map'] = $components[2];
  1041. }
  1042. }
  1043. $this->_queryComponents = $queryComponents;
  1044. return $customComponent;
  1045. }
  1046. /**
  1047. * getCachedForm
  1048. * returns the cached form of this query for given resultSet
  1049. *
  1050. * @param array $resultSet
  1051. * @return string serialized string representation of this query
  1052. */
  1053. public function getCachedForm($customComponent = null)
  1054. {
  1055. $componentInfo = array();
  1056. foreach ($this->getQueryComponents() as $alias => $components) {
  1057. if ( ! isset($components['parent'])) {
  1058. $componentInfo[$alias][] = $components['table']->getComponentName();
  1059. } else {
  1060. $componentInfo[$alias][] = $components['parent'] . '.' . $components['relation']->getAlias();
  1061. }
  1062. if (isset($components['agg'])) {
  1063. $componentInfo[$alias][] = $components['agg'];
  1064. }
  1065. if (isset($components['map'])) {
  1066. $componentInfo[$alias][] = $components['map'];
  1067. }
  1068. }
  1069. if ($customComponent instanceof Doctrine_Collection) {
  1070. foreach ($customComponent as $record) {
  1071. $record->serializeReferences(true);
  1072. }
  1073. }
  1074. return serialize(array($customComponent, $componentInfo, $this->getTableAliasMap()));
  1075. }
  1076. /**
  1077. * addSelect
  1078. * adds fields to the SELECT part of the query
  1079. *
  1080. * @param string $select Query SELECT part
  1081. * @return Doctrine_Query
  1082. */
  1083. public function addSelect($select)
  1084. {
  1085. return $this->_addDqlQueryPart('select', $select, true);
  1086. }
  1087. /**
  1088. * addTableAlias
  1089. * adds an alias for table and associates it with given component alias
  1090. *
  1091. * @param string $componentAlias the alias for the query component associated with given tableAlias
  1092. * @param string $tableAlias the table alias to be added
  1093. * @return Doctrine_Hydrate
  1094. * @deprecated
  1095. */
  1096. public function addTableAlias($tableAlias, $componentAlias)
  1097. {
  1098. return $this->addSqlTableAlias($tableAlias, $componentAlias);
  1099. }
  1100. /**
  1101. * addSqlTableAlias
  1102. * adds an SQL table alias and associates it a component alias
  1103. *
  1104. * @param string $componentAlias the alias for the query component associated with given tableAlias
  1105. * @param string $tableAlias the table alias to be added
  1106. * @return Doctrine_Query_Abstract
  1107. */
  1108. public function addSqlTableAlias($sqlTableAlias, $componentAlias)
  1109. {
  1110. $this->_tableAliasMap[$sqlTableAlias] = $componentAlias;
  1111. return $this;
  1112. }
  1113. /**
  1114. * addFrom
  1115. * adds fields to the FROM part of the query
  1116. *
  1117. * @param string $from Query FROM part
  1118. * @return Doctrine_Query
  1119. */
  1120. public function addFrom($from)
  1121. {
  1122. return $this->_addDqlQueryPart('from', $from, true);
  1123. }
  1124. /**
  1125. * addWhere
  1126. * adds conditions to the WHERE part of the query
  1127. *
  1128. * @param string $where Query WHERE part
  1129. * @param mixed $params an array of parameters or a simple scalar
  1130. * @return Doctrine_Query
  1131. */
  1132. public function addWhere($where, $params = array())
  1133. {
  1134. return $this->andWhere($where, $params);
  1135. }
  1136. /**
  1137. * Adds conditions to the WHERE part of the query
  1138. *
  1139. * @param string $where Query WHERE part
  1140. * @param mixed $params An array of parameters or a simple scalar
  1141. * @return Doctrine_Query
  1142. */
  1143. public function andWhere($where, $params = array())
  1144. {
  1145. if (is_array($params)) {
  1146. $this->_params['where'] = array_merge($this->_params['where'], $params);
  1147. } else {
  1148. $this->_params['where'][] = $params;
  1149. }
  1150. if ($this->_hasDqlQueryPart('where')) {
  1151. $this->_addDqlQueryPart('where', 'AND', true);
  1152. }
  1153. return $this->_addDqlQueryPart('where', $where, true);
  1154. }
  1155. /**
  1156. * Adds conditions to the WHERE part of the query
  1157. *
  1158. * @param string $where Query WHERE part
  1159. * @param mixed $params An array of parameters or a simple scalar
  1160. * @return Doctrine_Query
  1161. */
  1162. public function orWhere($where, $params = array())
  1163. {
  1164. if (is_array($params)) {
  1165. $this->_params['where'] = array_merge($this->_params['where'], $params);
  1166. } else {
  1167. $this->_params['where'][] = $params;
  1168. }
  1169. if ($this->_hasDqlQueryPart('where')) {
  1170. $this->_addDqlQueryPart('where', 'OR', true);
  1171. }
  1172. return $this->_addDqlQueryPart('where', $where, true);
  1173. }
  1174. /**
  1175. * whereIn
  1176. * adds IN condition to the query WHERE part
  1177. *
  1178. * @param string $expr the operand of the IN
  1179. * @param mixed $params an array of parameters or a simple scalar
  1180. * @param boolean $not whether or not to use NOT in front of IN
  1181. * @return Doctrine_Query
  1182. */
  1183. public function whereIn($expr, $params = array(), $not = false)
  1184. {
  1185. return $this->andWhereIn($expr, $params, $not);
  1186. }
  1187. /**
  1188. * Adds IN condition to the query WHERE part
  1189. *
  1190. * @param string $expr The operand of the IN
  1191. * @param mixed $params An array of parameters or a simple scalar
  1192. * @param boolean $not Whether or not to use NOT in front of IN
  1193. * @return Doctrine_Query
  1194. */
  1195. public function andWhereIn($expr, $params = array(), $not = false)
  1196. {
  1197. // if there's no params, return (else we'll get a WHERE IN (), invalid SQL)
  1198. if ( ! count($params)) {
  1199. return $this;
  1200. }
  1201. if ($this->_hasDqlQueryPart('where')) {
  1202. $this->_addDqlQueryPart('where', 'AND', true);
  1203. }
  1204. return $this->_addDqlQueryPart('where', $this->_processWhereIn($expr, $params, $not), true);
  1205. }
  1206. /**
  1207. * Adds IN condition to the query WHERE part
  1208. *
  1209. * @param string $expr The operand of the IN
  1210. * @param mixed $params An array of parameters or a simple scalar
  1211. * @param boolean $not Whether or not to use NOT in front of IN
  1212. * @return Doctrine_Query
  1213. */
  1214. public function orWhereIn($expr, $params = array(), $not = false)
  1215. {
  1216. // if there's no params, return (else we'll get a WHERE IN (), invalid SQL)
  1217. if ( ! count($params)) {
  1218. return $this;
  1219. }
  1220. if ($this->_hasDqlQueryPart('where')) {
  1221. $this->_addDqlQueryPart('where', 'OR', true);
  1222. }
  1223. return $this->_addDqlQueryPart('where', $this->_processWhereIn($expr, $params, $not), true);
  1224. }
  1225. /**
  1226. * @nodoc
  1227. */
  1228. protected function _processWhereIn($expr, $params = array(), $not = false)
  1229. {
  1230. $params = (array) $params;
  1231. // if there's no params, return (else we'll get a WHERE IN (), invalid SQL)
  1232. if ( ! count($params)) {
  1233. return $this;
  1234. }
  1235. $a = array();
  1236. foreach ($params as $k => $value) {
  1237. if ($value instanceof Doctrine_Expression) {
  1238. $value = $value->getSql();
  1239. unset($params[$k]);
  1240. } else {
  1241. $value = '?';
  1242. }
  1243. $a[] = $value;
  1244. }
  1245. $this->_params['where'] = array_merge($this->_params['where'], $params);
  1246. return $expr . ($not === true ? ' NOT ':'') . ' IN (' . implode(', ', $a) . ')';
  1247. }
  1248. /**
  1249. * whereNotIn
  1250. * adds NOT IN condition to the query WHERE part
  1251. *
  1252. * @param string $expr the operand of the NOT IN
  1253. * @param mixed $params an array of parameters or a simple scalar
  1254. * @return Doctrine_Query
  1255. */
  1256. public function whereNotIn($expr, $params = array())
  1257. {
  1258. return $this->whereIn($expr, $params, true);
  1259. }
  1260. /**
  1261. * Adds NOT IN condition to the query WHERE part
  1262. *
  1263. * @param string $expr The operand of the NOT IN
  1264. * @param mixed $params An array of parameters or a simple scalar
  1265. * @return Doctrine_Query
  1266. */
  1267. public function andWhereNotIn($expr, $params = array())
  1268. {
  1269. return $this->andWhereIn($expr, $params, true);
  1270. }
  1271. /**
  1272. * Adds NOT IN condition to the query WHERE part
  1273. *
  1274. * @param string $expr The operand of the NOT IN
  1275. * @param mixed $params An array of parameters or a simple scalar
  1276. * @return Doctrine_Query
  1277. */
  1278. public function orWhereNotIn($expr, $params = array())
  1279. {
  1280. return $this->orWhereIn($expr, $params, true);
  1281. }
  1282. /**
  1283. * addGroupBy
  1284. * adds fields to the GROUP BY part of the query
  1285. *
  1286. * @param string $groupby Query GROUP BY part
  1287. * @return Doctrine_Query
  1288. */
  1289. public function addGroupBy($groupby)
  1290. {
  1291. return $this->_addDqlQueryPart('groupby', $groupby, true);
  1292. }
  1293. /**
  1294. * addHaving
  1295. * adds conditions to the HAVING part of the query
  1296. *
  1297. * @param string $having Query HAVING part
  1298. * @param mixed $params an array of parameters or a simple scalar
  1299. * @return Doctrine_Query
  1300. */
  1301. public function addHaving($having, $params = array())
  1302. {
  1303. if (is_array($params)) {
  1304. $this->_params['having'] = array_merge($this->_params['having'], $params);
  1305. } else {
  1306. $this->_params['having'][] = $params;
  1307. }
  1308. return $this->_addDqlQueryPart('having', $having, true);
  1309. }
  1310. /**
  1311. * addOrderBy
  1312. * adds fields to the ORDER BY part of the query
  1313. *
  1314. * @param string $orderby Query ORDER BY part
  1315. * @return Doctrine_Query
  1316. */
  1317. public function addOrderBy($orderby)
  1318. {
  1319. return $this->_addDqlQueryPart('orderby', $orderby, true);
  1320. }
  1321. /**
  1322. * select
  1323. * sets the SELECT part of the query
  1324. *
  1325. * @param string $select Query SELECT part
  1326. * @return Doctrine_Query
  1327. */
  1328. public function select($select)
  1329. {
  1330. return $this->_addDqlQueryPart('select', $select);
  1331. }
  1332. /**
  1333. * distinct
  1334. * Makes the query SELECT DISTINCT.
  1335. *
  1336. * @param bool $flag Whether or not the SELECT is DISTINCT (default true).
  1337. * @return Doctrine_Query
  1338. */
  1339. public function distinct($flag = true)
  1340. {
  1341. $this->_sqlParts['distinct'] = (bool) $flag;
  1342. return $this;
  1343. }
  1344. /**
  1345. * forUpdate
  1346. * Makes the query SELECT FOR UPDATE.

Large files files are truncated, but you can click here to view the full file