connection.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. /**
  3. * Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. namespace OC\DB;
  9. use Doctrine\DBAL\Driver;
  10. use Doctrine\DBAL\Configuration;
  11. use Doctrine\DBAL\Cache\QueryCacheProfile;
  12. use Doctrine\Common\EventManager;
  13. class Connection extends \Doctrine\DBAL\Connection {
  14. /**
  15. * @var string $tablePrefix
  16. */
  17. protected $tablePrefix;
  18. /**
  19. * @var \OC\DB\Adapter $adapter
  20. */
  21. protected $adapter;
  22. /**
  23. * @var \Doctrine\DBAL\Driver\Statement[] $preparedQueries
  24. */
  25. protected $preparedQueries = array();
  26. protected $cachingQueryStatementEnabled = true;
  27. /**
  28. * Initializes a new instance of the Connection class.
  29. *
  30. * @param array $params The connection parameters.
  31. * @param \Doctrine\DBAL\Driver $driver
  32. * @param \Doctrine\DBAL\Configuration $config
  33. * @param \Doctrine\Common\EventManager $eventManager
  34. * @throws \Exception
  35. */
  36. public function __construct(array $params, Driver $driver, Configuration $config = null,
  37. EventManager $eventManager = null)
  38. {
  39. if (!isset($params['adapter'])) {
  40. throw new \Exception('adapter not set');
  41. }
  42. if (!isset($params['tablePrefix'])) {
  43. throw new \Exception('tablePrefix not set');
  44. }
  45. parent::__construct($params, $driver, $config, $eventManager);
  46. $this->adapter = new $params['adapter']($this);
  47. $this->tablePrefix = $params['tablePrefix'];
  48. }
  49. /**
  50. * Prepares an SQL statement.
  51. *
  52. * @param string $statement The SQL statement to prepare.
  53. * @param int $limit
  54. * @param int $offset
  55. * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
  56. */
  57. public function prepare( $statement, $limit=null, $offset=null ) {
  58. if ($limit === -1) {
  59. $limit = null;
  60. }
  61. if (!is_null($limit)) {
  62. $platform = $this->getDatabasePlatform();
  63. $statement = $platform->modifyLimitQuery($statement, $limit, $offset);
  64. } else {
  65. if (isset($this->preparedQueries[$statement]) && $this->cachingQueryStatementEnabled) {
  66. return $this->preparedQueries[$statement];
  67. }
  68. $origStatement = $statement;
  69. }
  70. $statement = $this->replaceTablePrefix($statement);
  71. $statement = $this->adapter->fixupStatement($statement);
  72. if(\OC_Config::getValue( 'log_query', false)) {
  73. \OC_Log::write('core', 'DB prepare : '.$statement, \OC_Log::DEBUG);
  74. }
  75. $result = parent::prepare($statement);
  76. if (is_null($limit) && $this->cachingQueryStatementEnabled) {
  77. $this->preparedQueries[$origStatement] = $result;
  78. }
  79. return $result;
  80. }
  81. /**
  82. * Executes an, optionally parameterized, SQL query.
  83. *
  84. * If the query is parameterized, a prepared statement is used.
  85. * If an SQLLogger is configured, the execution is logged.
  86. *
  87. * @param string $query The SQL query to execute.
  88. * @param array $params The parameters to bind to the query, if any.
  89. * @param array $types The types the previous parameters are in.
  90. * @param QueryCacheProfile $qcp
  91. * @return \Doctrine\DBAL\Driver\Statement The executed statement.
  92. * @internal PERF: Directly prepares a driver statement, not a wrapper.
  93. */
  94. public function executeQuery($query, array $params = array(), $types = array(), QueryCacheProfile $qcp = null)
  95. {
  96. $query = $this->replaceTablePrefix($query);
  97. $query = $this->adapter->fixupStatement($query);
  98. return parent::executeQuery($query, $params, $types, $qcp);
  99. }
  100. /**
  101. * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
  102. * and returns the number of affected rows.
  103. *
  104. * This method supports PDO binding types as well as DBAL mapping types.
  105. *
  106. * @param string $query The SQL query.
  107. * @param array $params The query parameters.
  108. * @param array $types The parameter types.
  109. * @return integer The number of affected rows.
  110. * @internal PERF: Directly prepares a driver statement, not a wrapper.
  111. */
  112. public function executeUpdate($query, array $params = array(), array $types = array())
  113. {
  114. $query = $this->replaceTablePrefix($query);
  115. $query = $this->adapter->fixupStatement($query);
  116. return parent::executeUpdate($query, $params, $types);
  117. }
  118. /**
  119. * Returns the ID of the last inserted row, or the last value from a sequence object,
  120. * depending on the underlying driver.
  121. *
  122. * Note: This method may not return a meaningful or consistent result across different drivers,
  123. * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY
  124. * columns or sequences.
  125. *
  126. * @param string $seqName Name of the sequence object from which the ID should be returned.
  127. * @return string A string representation of the last inserted ID.
  128. */
  129. public function lastInsertId($seqName = null)
  130. {
  131. if ($seqName) {
  132. $seqName = $this->replaceTablePrefix($seqName);
  133. }
  134. return $this->adapter->lastInsertId($seqName);
  135. }
  136. // internal use
  137. public function realLastInsertId($seqName = null)
  138. {
  139. return parent::lastInsertId($seqName);
  140. }
  141. /**
  142. * @brief Insert a row if a matching row doesn't exists.
  143. * @param string $table. The table to insert into in the form '*PREFIX*tableName'
  144. * @param array $input. An array of fieldname/value pairs
  145. * @return bool The return value from execute()
  146. */
  147. public function insertIfNotExist($table, $input) {
  148. return $this->adapter->insertIfNotExist($table, $input);
  149. }
  150. /**
  151. * returns the error code and message as a string for logging
  152. * works with DoctrineException
  153. * @return string
  154. */
  155. public function getError() {
  156. $msg = $this->errorCode() . ': ';
  157. $errorInfo = $this->errorInfo();
  158. if (is_array($errorInfo)) {
  159. $msg .= 'SQLSTATE = '.$errorInfo[0] . ', ';
  160. $msg .= 'Driver Code = '.$errorInfo[1] . ', ';
  161. $msg .= 'Driver Message = '.$errorInfo[2];
  162. }
  163. return $msg;
  164. }
  165. // internal use
  166. /**
  167. * @param string $statement
  168. * @return string
  169. */
  170. protected function replaceTablePrefix($statement) {
  171. return str_replace( '*PREFIX*', $this->tablePrefix, $statement );
  172. }
  173. public function enableQueryStatementCaching() {
  174. $this->cachingQueryStatementEnabled = true;
  175. }
  176. public function disableQueryStatementCaching() {
  177. $this->cachingQueryStatementEnabled = false;
  178. $this->preparedQueries = array();
  179. }
  180. }