PDO.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. <?php
  2. /**
  3. * PDO database connection.
  4. *
  5. * @package Kohana/Database
  6. * @category Drivers
  7. * @author Kohana Team
  8. * @copyright (c) Kohana Team
  9. * @license https://koseven.ga/LICENSE.md
  10. */
  11. class Kohana_Database_PDO extends Database {
  12. // PDO uses no quoting for identifiers
  13. protected $_identifier = '';
  14. public function __construct($name, array $config)
  15. {
  16. parent::__construct($name, $config);
  17. if (isset($this->_config['identifier']))
  18. {
  19. // Allow the identifier to be overloaded per-connection
  20. $this->_identifier = (string) $this->_config['identifier'];
  21. }
  22. }
  23. public function connect()
  24. {
  25. if ($this->_connection)
  26. return;
  27. // Extract the connection parameters, adding required variabels
  28. extract($this->_config['connection'] + [
  29. 'dsn' => '',
  30. 'username' => NULL,
  31. 'password' => NULL,
  32. 'persistent' => FALSE,
  33. ]);
  34. // Clear the connection parameters for security
  35. unset($this->_config['connection']);
  36. // Force PDO to use exceptions for all errors
  37. $options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
  38. if ( ! empty($persistent))
  39. {
  40. // Make the connection persistent
  41. $options[PDO::ATTR_PERSISTENT] = TRUE;
  42. }
  43. try
  44. {
  45. // Create a new PDO connection
  46. $this->_connection = new PDO($dsn, $username, $password, $options);
  47. }
  48. catch (PDOException $e)
  49. {
  50. throw new Database_Exception(':error',
  51. [':error' => $e->getMessage()],
  52. $e->getCode());
  53. }
  54. if ( ! empty($this->_config['charset']))
  55. {
  56. // Set the character set
  57. $this->set_charset($this->_config['charset']);
  58. }
  59. }
  60. /**
  61. * Create or redefine a SQL aggregate function.
  62. *
  63. * [!!] Works only with SQLite
  64. *
  65. * @link http://php.net/manual/function.pdo-sqlitecreateaggregate
  66. *
  67. * @param string $name Name of the SQL function to be created or redefined
  68. * @param callback $step Called for each row of a result set
  69. * @param callback $final Called after all rows of a result set have been processed
  70. * @param integer $arguments Number of arguments that the SQL function takes
  71. *
  72. * @return boolean
  73. */
  74. public function create_aggregate($name, $step, $final, $arguments = -1)
  75. {
  76. $this->_connection or $this->connect();
  77. return $this->_connection->sqliteCreateAggregate(
  78. $name, $step, $final, $arguments
  79. );
  80. }
  81. /**
  82. * Create or redefine a SQL function.
  83. *
  84. * [!!] Works only with SQLite
  85. *
  86. * @link http://php.net/manual/function.pdo-sqlitecreatefunction
  87. *
  88. * @param string $name Name of the SQL function to be created or redefined
  89. * @param callback $callback Callback which implements the SQL function
  90. * @param integer $arguments Number of arguments that the SQL function takes
  91. *
  92. * @return boolean
  93. */
  94. public function create_function($name, $callback, $arguments = -1)
  95. {
  96. $this->_connection or $this->connect();
  97. return $this->_connection->sqliteCreateFunction(
  98. $name, $callback, $arguments
  99. );
  100. }
  101. public function disconnect()
  102. {
  103. // Destroy the PDO object
  104. $this->_connection = NULL;
  105. return parent::disconnect();
  106. }
  107. public function set_charset($charset)
  108. {
  109. // Make sure the database is connected
  110. $this->_connection OR $this->connect();
  111. // This SQL-92 syntax is not supported by all drivers
  112. $this->_connection->exec('SET NAMES '.$this->quote($charset));
  113. }
  114. public function query($type, $sql, $as_object = FALSE, array $params = NULL)
  115. {
  116. // Make sure the database is connected
  117. $this->_connection or $this->connect();
  118. if (Kohana::$profiling)
  119. {
  120. // Benchmark this query for the current instance
  121. $benchmark = Profiler::start("Database ({$this->_instance})", $sql);
  122. }
  123. try
  124. {
  125. $result = $this->_connection->query($sql);
  126. }
  127. catch (Exception $e)
  128. {
  129. if (isset($benchmark))
  130. {
  131. // This benchmark is worthless
  132. Profiler::delete($benchmark);
  133. }
  134. // Convert the exception in a database exception
  135. throw new Database_Exception(':error [ :query ]',
  136. [
  137. ':error' => $e->getMessage(),
  138. ':query' => $sql
  139. ],
  140. $e->getCode());
  141. }
  142. if (isset($benchmark))
  143. {
  144. Profiler::stop($benchmark);
  145. }
  146. // Set the last query
  147. $this->last_query = $sql;
  148. if ($type === Database::SELECT)
  149. {
  150. // Convert the result into an array, as PDOStatement::rowCount is not reliable
  151. if ($as_object === FALSE)
  152. {
  153. $result->setFetchMode(PDO::FETCH_ASSOC);
  154. }
  155. elseif (is_string($as_object))
  156. {
  157. $result->setFetchMode(PDO::FETCH_CLASS, $as_object, $params);
  158. }
  159. else
  160. {
  161. $result->setFetchMode(PDO::FETCH_CLASS, 'stdClass');
  162. }
  163. $result = $result->fetchAll();
  164. // Return an iterator of results
  165. return new Database_Result_Cached($result, $sql, $as_object, $params);
  166. }
  167. elseif ($type === Database::INSERT)
  168. {
  169. // Return a list of insert id and rows created
  170. return [
  171. $this->_connection->lastInsertId(),
  172. $result->rowCount(),
  173. ];
  174. }
  175. else
  176. {
  177. // Return the number of rows affected
  178. return $result->rowCount();
  179. }
  180. }
  181. public function begin($mode = NULL)
  182. {
  183. // Make sure the database is connected
  184. $this->_connection or $this->connect();
  185. return $this->_connection->beginTransaction();
  186. }
  187. public function commit()
  188. {
  189. // Make sure the database is connected
  190. $this->_connection or $this->connect();
  191. return $this->_connection->commit();
  192. }
  193. public function rollback()
  194. {
  195. // Make sure the database is connected
  196. $this->_connection or $this->connect();
  197. return $this->_connection->rollBack();
  198. }
  199. public function list_tables($like = NULL)
  200. {
  201. throw new Kohana_Exception('Database method :method is not supported by :class',
  202. [':method' => __FUNCTION__, ':class' => __CLASS__]);
  203. }
  204. public function list_columns($table, $like = NULL, $add_prefix = TRUE)
  205. {
  206. throw new Kohana_Exception('Database method :method is not supported by :class',
  207. [':method' => __FUNCTION__, ':class' => __CLASS__]);
  208. }
  209. public function escape($value)
  210. {
  211. // Make sure the database is connected
  212. $this->_connection or $this->connect();
  213. return $this->_connection->quote($value);
  214. }
  215. } // End Database_PDO