3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15 * This software consists of voluntary contributions made by many individuals
16 * and is licensed under the MIT license. For more information, see
17 * <http://www.doctrine-project.org>.
20 namespace Doctrine\DBAL;
22 use PDO, Closure, Exception,
23 Doctrine\DBAL\Types\Type,
24 Doctrine\DBAL\Driver\Connection as DriverConnection,
25 Doctrine\Common\EventManager,
26 Doctrine\DBAL\DBALException,
27 Doctrine\DBAL\Cache\ResultCacheStatement,
28 Doctrine\DBAL\Cache\QueryCacheProfile,
29 Doctrine\DBAL\Cache\ArrayStatement,
30 Doctrine\DBAL\Cache\CacheException;
33 * A wrapper around a Doctrine\DBAL\Driver\Connection that adds features like
34 * events, transaction isolation levels, configuration, emulated transaction nesting,
35 * lazy connecting and more.
38 * @link www.doctrine-project.org
40 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
41 * @author Jonathan Wage <jonwage@gmail.com>
42 * @author Roman Borschel <roman@code-factory.org>
43 * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
44 * @author Lukas Smith <smith@pooteeweet.org> (MDB2 library)
45 * @author Benjamin Eberlei <kontakt@beberlei.de>
47 class Connection implements DriverConnection
50 * Constant for transaction isolation level READ UNCOMMITTED.
52 const TRANSACTION_READ_UNCOMMITTED = 1;
55 * Constant for transaction isolation level READ COMMITTED.
57 const TRANSACTION_READ_COMMITTED = 2;
60 * Constant for transaction isolation level REPEATABLE READ.
62 const TRANSACTION_REPEATABLE_READ = 3;
65 * Constant for transaction isolation level SERIALIZABLE.
67 const TRANSACTION_SERIALIZABLE = 4;
70 * Represents an array of ints to be expanded by Doctrine SQL parsing.
74 const PARAM_INT_ARRAY = 101;
77 * Represents an array of strings to be expanded by Doctrine SQL parsing.
81 const PARAM_STR_ARRAY = 102;
84 * Offset by which PARAM_* constants are detected as arrays of the param type.
88 const ARRAY_PARAM_OFFSET = 100;
91 * The wrapped driver connection.
93 * @var \Doctrine\DBAL\Driver\Connection
98 * @var \Doctrine\DBAL\Configuration
103 * @var \Doctrine\Common\EventManager
105 protected $_eventManager;
108 * @var \Doctrine\DBAL\Query\Expression\ExpressionBuilder
113 * Whether or not a connection has been established.
117 private $_isConnected = false;
120 * The transaction nesting level.
124 private $_transactionNestingLevel = 0;
127 * The currently active transaction isolation level.
131 private $_transactionIsolationLevel;
134 * If nested transations should use savepoints
138 private $_nestTransactionsWithSavepoints;
141 * The parameters used during creation of the Connection instance.
145 private $_params = array();
148 * The DatabasePlatform object that provides information about the
149 * database platform used by the connection.
151 * @var \Doctrine\DBAL\Platforms\AbstractPlatform
153 protected $_platform;
156 * The schema manager.
158 * @var \Doctrine\DBAL\Schema\AbstractSchemaManager
160 protected $_schemaManager;
163 * The used DBAL driver.
165 * @var \Doctrine\DBAL\Driver
170 * Flag that indicates whether the current transaction is marked for rollback only.
174 private $_isRollbackOnly = false;
176 private $_defaultFetchMode = PDO::FETCH_ASSOC;
179 * Initializes a new instance of the Connection class.
181 * @param array $params The connection parameters.
182 * @param Driver $driver
183 * @param Configuration $config
184 * @param EventManager $eventManager
186 public function __construct(array $params, Driver $driver, Configuration $config = null,
187 EventManager $eventManager = null)
189 $this->_driver = $driver;
190 $this->_params = $params;
192 if (isset($params['pdo'])) {
193 $this->_conn = $params['pdo'];
194 $this->_isConnected = true;
197 // Create default config and event manager if none given
199 $config = new Configuration();
202 if ( ! $eventManager) {
203 $eventManager = new EventManager();
206 $this->_config = $config;
207 $this->_eventManager = $eventManager;
209 $this->_expr = new Query\Expression\ExpressionBuilder($this);
211 if ( ! isset($params['platform'])) {
212 $this->_platform = $driver->getDatabasePlatform();
213 } else if ($params['platform'] instanceof Platforms\AbstractPlatform) {
214 $this->_platform = $params['platform'];
216 throw DBALException::invalidPlatformSpecified();
219 $this->_platform->setEventManager($eventManager);
221 $this->_transactionIsolationLevel = $this->_platform->getDefaultTransactionIsolationLevel();
225 * Gets the parameters used during instantiation.
227 * @return array $params
229 public function getParams()
231 return $this->_params;
235 * Gets the name of the database this Connection is connected to.
237 * @return string $database
239 public function getDatabase()
241 return $this->_driver->getDatabase($this);
245 * Gets the hostname of the currently connected database.
249 public function getHost()
251 return isset($this->_params['host']) ? $this->_params['host'] : null;
255 * Gets the port of the currently connected database.
259 public function getPort()
261 return isset($this->_params['port']) ? $this->_params['port'] : null;
265 * Gets the username used by this connection.
269 public function getUsername()
271 return isset($this->_params['user']) ? $this->_params['user'] : null;
275 * Gets the password used by this connection.
279 public function getPassword()
281 return isset($this->_params['password']) ? $this->_params['password'] : null;
285 * Gets the DBAL driver instance.
287 * @return \Doctrine\DBAL\Driver
289 public function getDriver()
291 return $this->_driver;
295 * Gets the Configuration used by the Connection.
297 * @return \Doctrine\DBAL\Configuration
299 public function getConfiguration()
301 return $this->_config;
305 * Gets the EventManager used by the Connection.
307 * @return \Doctrine\Common\EventManager
309 public function getEventManager()
311 return $this->_eventManager;
315 * Gets the DatabasePlatform for the connection.
317 * @return \Doctrine\DBAL\Platforms\AbstractPlatform
319 public function getDatabasePlatform()
321 return $this->_platform;
325 * Gets the ExpressionBuilder for the connection.
327 * @return \Doctrine\DBAL\Query\Expression\ExpressionBuilder
329 public function getExpressionBuilder()
335 * Establishes the connection with the database.
337 * @return boolean TRUE if the connection was successfully established, FALSE if
338 * the connection is already open.
340 public function connect()
342 if ($this->_isConnected) return false;
344 $driverOptions = isset($this->_params['driverOptions']) ?
345 $this->_params['driverOptions'] : array();
346 $user = isset($this->_params['user']) ? $this->_params['user'] : null;
347 $password = isset($this->_params['password']) ?
348 $this->_params['password'] : null;
350 $this->_conn = $this->_driver->connect($this->_params, $user, $password, $driverOptions);
351 $this->_isConnected = true;
353 if ($this->_eventManager->hasListeners(Events::postConnect)) {
354 $eventArgs = new Event\ConnectionEventArgs($this);
355 $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
364 * @param integer $fetchMode
366 public function setFetchMode($fetchMode)
368 $this->_defaultFetchMode = $fetchMode;
372 * Prepares and executes an SQL query and returns the first row of the result
373 * as an associative array.
375 * @param string $statement The SQL query.
376 * @param array $params The query parameters.
379 public function fetchAssoc($statement, array $params = array())
381 return $this->executeQuery($statement, $params)->fetch(PDO::FETCH_ASSOC);
385 * Prepares and executes an SQL query and returns the first row of the result
386 * as a numerically indexed array.
388 * @param string $statement sql query to be executed
389 * @param array $params prepared statement params
392 public function fetchArray($statement, array $params = array())
394 return $this->executeQuery($statement, $params)->fetch(PDO::FETCH_NUM);
398 * Prepares and executes an SQL query and returns the value of a single column
399 * of the first row of the result.
401 * @param string $statement sql query to be executed
402 * @param array $params prepared statement params
403 * @param int $colnum 0-indexed column number to retrieve
406 public function fetchColumn($statement, array $params = array(), $colnum = 0)
408 return $this->executeQuery($statement, $params)->fetchColumn($colnum);
412 * Whether an actual connection to the database is established.
416 public function isConnected()
418 return $this->_isConnected;
422 * Checks whether a transaction is currently active.
424 * @return boolean TRUE if a transaction is currently active, FALSE otherwise.
426 public function isTransactionActive()
428 return $this->_transactionNestingLevel > 0;
432 * Executes an SQL DELETE statement on a table.
434 * @param string $tableName The name of the table on which to delete.
435 * @param array $identifier The deletion criteria. An associative array containing column-value pairs.
436 * @return integer The number of affected rows.
438 public function delete($tableName, array $identifier)
444 foreach (array_keys($identifier) as $columnName) {
445 $criteria[] = $columnName . ' = ?';
448 $query = 'DELETE FROM ' . $tableName . ' WHERE ' . implode(' AND ', $criteria);
450 return $this->executeUpdate($query, array_values($identifier));
454 * Closes the connection.
458 public function close()
462 $this->_isConnected = false;
466 * Sets the transaction isolation level.
468 * @param integer $level The level to set.
471 public function setTransactionIsolation($level)
473 $this->_transactionIsolationLevel = $level;
475 return $this->executeUpdate($this->_platform->getSetTransactionIsolationSQL($level));
479 * Gets the currently active transaction isolation level.
481 * @return integer The current transaction isolation level.
483 public function getTransactionIsolation()
485 return $this->_transactionIsolationLevel;
489 * Executes an SQL UPDATE statement on a table.
491 * @param string $tableName The name of the table to update.
493 * @param array $identifier The update criteria. An associative array containing column-value pairs.
494 * @param array $types Types of the merged $data and $identifier arrays in that order.
495 * @return integer The number of affected rows.
497 public function update($tableName, array $data, array $identifier, array $types = array())
501 foreach ($data as $columnName => $value) {
502 $set[] = $columnName . ' = ?';
505 $params = array_merge(array_values($data), array_values($identifier));
507 $sql = 'UPDATE ' . $tableName . ' SET ' . implode(', ', $set)
508 . ' WHERE ' . implode(' = ? AND ', array_keys($identifier))
511 return $this->executeUpdate($sql, $params, $types);
515 * Inserts a table row with specified data.
517 * @param string $tableName The name of the table to insert data into.
518 * @param array $data An associative array containing column-value pairs.
519 * @param array $types Types of the inserted data.
520 * @return integer The number of affected rows.
522 public function insert($tableName, array $data, array $types = array())
526 // column names are specified as array keys
528 $placeholders = array();
530 foreach ($data as $columnName => $value) {
531 $cols[] = $columnName;
532 $placeholders[] = '?';
535 $query = 'INSERT INTO ' . $tableName
536 . ' (' . implode(', ', $cols) . ')'
537 . ' VALUES (' . implode(', ', $placeholders) . ')';
539 return $this->executeUpdate($query, array_values($data), $types);
543 * Quote a string so it can be safely used as a table or column name, even if
544 * it is a reserved name.
546 * Delimiting style depends on the underlying database platform that is being used.
548 * NOTE: Just because you CAN use quoted identifiers does not mean
549 * you SHOULD use them. In general, they end up causing way more
550 * problems than they solve.
552 * @param string $str The name to be quoted.
553 * @return string The quoted name.
555 public function quoteIdentifier($str)
557 return $this->_platform->quoteIdentifier($str);
561 * Quotes a given input parameter.
563 * @param mixed $input Parameter to be quoted.
564 * @param string $type Type of the parameter.
565 * @return string The quoted parameter.
567 public function quote($input, $type = null)
571 list($value, $bindingType) = $this->getBindingInfo($input, $type);
572 return $this->_conn->quote($value, $bindingType);
576 * Prepares and executes an SQL query and returns the result as an associative array.
578 * @param string $sql The SQL query.
579 * @param array $params The query parameters.
582 public function fetchAll($sql, array $params = array())
584 return $this->executeQuery($sql, $params)->fetchAll();
588 * Prepares an SQL statement.
590 * @param string $statement The SQL statement to prepare.
591 * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
593 public function prepare($statement)
598 $stmt = new Statement($statement, $this);
599 } catch (\Exception $ex) {
600 throw DBALException::driverExceptionDuringQuery($ex, $statement);
603 $stmt->setFetchMode($this->_defaultFetchMode);
609 * Executes an, optionally parameterized, SQL query.
611 * If the query is parameterized, a prepared statement is used.
612 * If an SQLLogger is configured, the execution is logged.
614 * @param string $query The SQL query to execute.
615 * @param array $params The parameters to bind to the query, if any.
616 * @param array $types The types the previous parameters are in.
617 * @param QueryCacheProfile $qcp
618 * @return \Doctrine\DBAL\Driver\Statement The executed statement.
619 * @internal PERF: Directly prepares a driver statement, not a wrapper.
621 public function executeQuery($query, array $params = array(), $types = array(), QueryCacheProfile $qcp = null)
624 return $this->executeCacheQuery($query, $params, $types, $qcp);
629 $logger = $this->_config->getSQLLogger();
631 $logger->startQuery($query, $params, $types);
636 list($query, $params, $types) = SQLParserUtils::expandListParameters($query, $params, $types);
638 $stmt = $this->_conn->prepare($query);
640 $this->_bindTypedValues($stmt, $params, $types);
643 $stmt->execute($params);
646 $stmt = $this->_conn->query($query);
648 } catch (\Exception $ex) {
649 throw DBALException::driverExceptionDuringQuery($ex, $query, $this->resolveParams($params, $types));
652 $stmt->setFetchMode($this->_defaultFetchMode);
655 $logger->stopQuery();
662 * Execute a caching query and
664 * @param string $query
665 * @param array $params
666 * @param array $types
667 * @param QueryCacheProfile $qcp
668 * @return \Doctrine\DBAL\Driver\ResultStatement
670 public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qcp)
672 $resultCache = $qcp->getResultCacheDriver() ?: $this->_config->getResultCacheImpl();
673 if ( ! $resultCache) {
674 throw CacheException::noResultDriverConfigured();
677 list($cacheKey, $realKey) = $qcp->generateCacheKeys($query, $params, $types);
679 // fetch the row pointers entry
680 if ($data = $resultCache->fetch($cacheKey)) {
681 // is the real key part of this row pointers map or is the cache only pointing to other cache keys?
682 if (isset($data[$realKey])) {
683 $stmt = new ArrayStatement($data[$realKey]);
684 } else if (array_key_exists($realKey, $data)) {
685 $stmt = new ArrayStatement(array());
690 $stmt = new ResultCacheStatement($this->executeQuery($query, $params, $types), $resultCache, $cacheKey, $realKey, $qcp->getLifetime());
693 $stmt->setFetchMode($this->_defaultFetchMode);
699 * Executes an, optionally parameterized, SQL query and returns the result,
700 * applying a given projection/transformation function on each row of the result.
702 * @param string $query The SQL query to execute.
703 * @param array $params The parameters, if any.
704 * @param Closure $mapper The transformation function that is applied on each row.
705 * The function receives a single paramater, an array, that
706 * represents a row of the result set.
707 * @return mixed The projected result of the query.
709 public function project($query, array $params, Closure $function)
712 $stmt = $this->executeQuery($query, $params ?: array());
714 while ($row = $stmt->fetch()) {
715 $result[] = $function($row);
718 $stmt->closeCursor();
724 * Executes an SQL statement, returning a result set as a Statement object.
726 * @param string $statement
727 * @param integer $fetchType
728 * @return \Doctrine\DBAL\Driver\Statement
730 public function query()
734 $args = func_get_args();
736 $logger = $this->_config->getSQLLogger();
738 $logger->startQuery($args[0]);
742 $statement = call_user_func_array(array($this->_conn, 'query'), $args);
743 } catch (\Exception $ex) {
744 throw DBALException::driverExceptionDuringQuery($ex, func_get_arg(0));
747 $statement->setFetchMode($this->_defaultFetchMode);
750 $logger->stopQuery();
757 * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
758 * and returns the number of affected rows.
760 * This method supports PDO binding types as well as DBAL mapping types.
762 * @param string $query The SQL query.
763 * @param array $params The query parameters.
764 * @param array $types The parameter types.
765 * @return integer The number of affected rows.
766 * @internal PERF: Directly prepares a driver statement, not a wrapper.
768 public function executeUpdate($query, array $params = array(), array $types = array())
772 $logger = $this->_config->getSQLLogger();
774 $logger->startQuery($query, $params, $types);
779 list($query, $params, $types) = SQLParserUtils::expandListParameters($query, $params, $types);
781 $stmt = $this->_conn->prepare($query);
783 $this->_bindTypedValues($stmt, $params, $types);
786 $stmt->execute($params);
788 $result = $stmt->rowCount();
790 $result = $this->_conn->exec($query);
792 } catch (\Exception $ex) {
793 throw DBALException::driverExceptionDuringQuery($ex, $query, $this->resolveParams($params, $types));
797 $logger->stopQuery();
804 * Execute an SQL statement and return the number of affected rows.
806 * @param string $statement
807 * @return integer The number of affected rows.
809 public function exec($statement)
813 $logger = $this->_config->getSQLLogger();
815 $logger->startQuery($statement);
819 $result = $this->_conn->exec($statement);
820 } catch (\Exception $ex) {
821 throw DBALException::driverExceptionDuringQuery($ex, $statement);
825 $logger->stopQuery();
832 * Returns the current transaction nesting level.
834 * @return integer The nesting level. A value of 0 means there's no active transaction.
836 public function getTransactionNestingLevel()
838 return $this->_transactionNestingLevel;
842 * Fetch the SQLSTATE associated with the last database operation.
844 * @return integer The last error code.
846 public function errorCode()
849 return $this->_conn->errorCode();
853 * Fetch extended error information associated with the last database operation.
855 * @return array The last error information.
857 public function errorInfo()
860 return $this->_conn->errorInfo();
864 * Returns the ID of the last inserted row, or the last value from a sequence object,
865 * depending on the underlying driver.
867 * Note: This method may not return a meaningful or consistent result across different drivers,
868 * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY
869 * columns or sequences.
871 * @param string $seqName Name of the sequence object from which the ID should be returned.
872 * @return string A string representation of the last inserted ID.
874 public function lastInsertId($seqName = null)
877 return $this->_conn->lastInsertId($seqName);
881 * Executes a function in a transaction.
883 * The function gets passed this Connection instance as an (optional) parameter.
885 * If an exception occurs during execution of the function or transaction commit,
886 * the transaction is rolled back and the exception re-thrown.
888 * @param Closure $func The function to execute transactionally.
890 public function transactional(Closure $func)
892 $this->beginTransaction();
896 } catch (Exception $e) {
903 * Set if nested transactions should use savepoints
905 * @param boolean $nestTransactionsWithSavepoints
908 public function setNestTransactionsWithSavepoints($nestTransactionsWithSavepoints)
910 if ($this->_transactionNestingLevel > 0) {
911 throw ConnectionException::mayNotAlterNestedTransactionWithSavepointsInTransaction();
914 if ( ! $this->_platform->supportsSavepoints()) {
915 throw ConnectionException::savepointsNotSupported();
918 $this->_nestTransactionsWithSavepoints = $nestTransactionsWithSavepoints;
922 * Get if nested transactions should use savepoints
926 public function getNestTransactionsWithSavepoints()
928 return $this->_nestTransactionsWithSavepoints;
932 * Returns the savepoint name to use for nested transactions are false if they are not supported
933 * "savepointFormat" parameter is not set
935 * @return mixed a string with the savepoint name or false
937 protected function _getNestedTransactionSavePointName()
939 return 'DOCTRINE2_SAVEPOINT_'.$this->_transactionNestingLevel;
943 * Starts a transaction by suspending auto-commit mode.
947 public function beginTransaction()
951 ++$this->_transactionNestingLevel;
953 $logger = $this->_config->getSQLLogger();
955 if ($this->_transactionNestingLevel == 1) {
957 $logger->startQuery('"START TRANSACTION"');
959 $this->_conn->beginTransaction();
961 $logger->stopQuery();
963 } else if ($this->_nestTransactionsWithSavepoints) {
965 $logger->startQuery('"SAVEPOINT"');
967 $this->createSavepoint($this->_getNestedTransactionSavePointName());
969 $logger->stopQuery();
975 * Commits the current transaction.
978 * @throws ConnectionException If the commit failed due to no active transaction or
979 * because the transaction was marked for rollback only.
981 public function commit()
983 if ($this->_transactionNestingLevel == 0) {
984 throw ConnectionException::noActiveTransaction();
986 if ($this->_isRollbackOnly) {
987 throw ConnectionException::commitFailedRollbackOnly();
992 $logger = $this->_config->getSQLLogger();
994 if ($this->_transactionNestingLevel == 1) {
996 $logger->startQuery('"COMMIT"');
998 $this->_conn->commit();
1000 $logger->stopQuery();
1002 } else if ($this->_nestTransactionsWithSavepoints) {
1004 $logger->startQuery('"RELEASE SAVEPOINT"');
1006 $this->releaseSavepoint($this->_getNestedTransactionSavePointName());
1008 $logger->stopQuery();
1012 --$this->_transactionNestingLevel;
1016 * Cancel any database changes done during the current transaction.
1018 * this method can be listened with onPreTransactionRollback and onTransactionRollback
1019 * eventlistener methods
1021 * @throws ConnectionException If the rollback operation failed.
1023 public function rollBack()
1025 if ($this->_transactionNestingLevel == 0) {
1026 throw ConnectionException::noActiveTransaction();
1031 $logger = $this->_config->getSQLLogger();
1033 if ($this->_transactionNestingLevel == 1) {
1035 $logger->startQuery('"ROLLBACK"');
1037 $this->_transactionNestingLevel = 0;
1038 $this->_conn->rollback();
1039 $this->_isRollbackOnly = false;
1041 $logger->stopQuery();
1043 } else if ($this->_nestTransactionsWithSavepoints) {
1045 $logger->startQuery('"ROLLBACK TO SAVEPOINT"');
1047 $this->rollbackSavepoint($this->_getNestedTransactionSavePointName());
1048 --$this->_transactionNestingLevel;
1050 $logger->stopQuery();
1053 $this->_isRollbackOnly = true;
1054 --$this->_transactionNestingLevel;
1060 * creates a new savepoint
1062 * @param string $savepoint name of a savepoint to set
1065 public function createSavepoint($savepoint)
1067 if ( ! $this->_platform->supportsSavepoints()) {
1068 throw ConnectionException::savepointsNotSupported();
1071 $this->_conn->exec($this->_platform->createSavePoint($savepoint));
1076 * releases given savepoint
1078 * @param string $savepoint name of a savepoint to release
1081 public function releaseSavepoint($savepoint)
1083 if ( ! $this->_platform->supportsSavepoints()) {
1084 throw ConnectionException::savepointsNotSupported();
1087 if ($this->_platform->supportsReleaseSavepoints()) {
1088 $this->_conn->exec($this->_platform->releaseSavePoint($savepoint));
1094 * releases given savepoint
1096 * @param string $savepoint name of a savepoint to rollback to
1099 public function rollbackSavepoint($savepoint)
1101 if ( ! $this->_platform->supportsSavepoints()) {
1102 throw ConnectionException::savepointsNotSupported();
1105 $this->_conn->exec($this->_platform->rollbackSavePoint($savepoint));
1109 * Gets the wrapped driver connection.
1111 * @return \Doctrine\DBAL\Driver\Connection
1113 public function getWrappedConnection()
1117 return $this->_conn;
1121 * Gets the SchemaManager that can be used to inspect or change the
1122 * database schema through the connection.
1124 * @return \Doctrine\DBAL\Schema\AbstractSchemaManager
1126 public function getSchemaManager()
1128 if ( ! $this->_schemaManager) {
1129 $this->_schemaManager = $this->_driver->getSchemaManager($this);
1132 return $this->_schemaManager;
1136 * Marks the current transaction so that the only possible
1137 * outcome for the transaction to be rolled back.
1139 * @throws ConnectionException If no transaction is active.
1141 public function setRollbackOnly()
1143 if ($this->_transactionNestingLevel == 0) {
1144 throw ConnectionException::noActiveTransaction();
1146 $this->_isRollbackOnly = true;
1150 * Check whether the current transaction is marked for rollback only.
1153 * @throws ConnectionException If no transaction is active.
1155 public function isRollbackOnly()
1157 if ($this->_transactionNestingLevel == 0) {
1158 throw ConnectionException::noActiveTransaction();
1160 return $this->_isRollbackOnly;
1164 * Converts a given value to its database representation according to the conversion
1165 * rules of a specific DBAL mapping type.
1167 * @param mixed $value The value to convert.
1168 * @param string $type The name of the DBAL mapping type.
1169 * @return mixed The converted value.
1171 public function convertToDatabaseValue($value, $type)
1173 return Type::getType($type)->convertToDatabaseValue($value, $this->_platform);
1177 * Converts a given value to its PHP representation according to the conversion
1178 * rules of a specific DBAL mapping type.
1180 * @param mixed $value The value to convert.
1181 * @param string $type The name of the DBAL mapping type.
1182 * @return mixed The converted type.
1184 public function convertToPHPValue($value, $type)
1186 return Type::getType($type)->convertToPHPValue($value, $this->_platform);
1190 * Binds a set of parameters, some or all of which are typed with a PDO binding type
1191 * or DBAL mapping type, to a given statement.
1193 * @param string $stmt The statement to bind the values to.
1194 * @param array $params The map/list of named/positional parameters.
1195 * @param array $types The parameter types (PDO binding types or DBAL mapping types).
1196 * @internal Duck-typing used on the $stmt parameter to support driver statements as well as
1197 * raw PDOStatement instances.
1199 private function _bindTypedValues($stmt, array $params, array $types)
1201 // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO.
1202 if (is_int(key($params))) {
1203 // Positional parameters
1204 $typeOffset = array_key_exists(0, $types) ? -1 : 0;
1206 foreach ($params as $value) {
1207 $typeIndex = $bindIndex + $typeOffset;
1208 if (isset($types[$typeIndex])) {
1209 $type = $types[$typeIndex];
1210 list($value, $bindingType) = $this->getBindingInfo($value, $type);
1211 $stmt->bindValue($bindIndex, $value, $bindingType);
1213 $stmt->bindValue($bindIndex, $value);
1219 foreach ($params as $name => $value) {
1220 if (isset($types[$name])) {
1221 $type = $types[$name];
1222 list($value, $bindingType) = $this->getBindingInfo($value, $type);
1223 $stmt->bindValue($name, $value, $bindingType);
1225 $stmt->bindValue($name, $value);
1232 * Gets the binding type of a given type. The given type can be a PDO or DBAL mapping type.
1234 * @param mixed $value The value to bind
1235 * @param mixed $type The type to bind (PDO or DBAL)
1236 * @return array [0] => the (escaped) value, [1] => the binding type
1238 private function getBindingInfo($value, $type)
1240 if (is_string($type)) {
1241 $type = Type::getType($type);
1243 if ($type instanceof Type) {
1244 $value = $type->convertToDatabaseValue($value, $this->_platform);
1245 $bindingType = $type->getBindingType();
1247 $bindingType = $type; // PDO::PARAM_* constants
1249 return array($value, $bindingType);
1253 * Resolves the parameters to a format which can be displayed.
1255 * @internal This is a purely internal method. If you rely on this method, you are advised to
1256 * copy/paste the code as this method may change, or be removed without prior notice.
1258 * @param array $params
1259 * @param array $types
1263 public function resolveParams(array $params, array $types)
1265 $resolvedParams = array();
1267 // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO.
1268 if (is_int(key($params))) {
1269 // Positional parameters
1270 $typeOffset = array_key_exists(0, $types) ? -1 : 0;
1272 foreach ($params as $value) {
1273 $typeIndex = $bindIndex + $typeOffset;
1274 if (isset($types[$typeIndex])) {
1275 $type = $types[$typeIndex];
1276 list($value,) = $this->getBindingInfo($value, $type);
1277 $resolvedParams[$bindIndex] = $value;
1279 $resolvedParams[$bindIndex] = $value;
1285 foreach ($params as $name => $value) {
1286 if (isset($types[$name])) {
1287 $type = $types[$name];
1288 list($value,) = $this->getBindingInfo($value, $type);
1289 $resolvedParams[$name] = $value;
1291 $resolvedParams[$name] = $value;
1296 return $resolvedParams;
1300 * Create a new instance of a SQL query builder.
1302 * @return \Doctrine\DBAL\Query\QueryBuilder
1304 public function createQueryBuilder()
1306 return new Query\QueryBuilder($this);