You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
7.6 KiB

7 years ago
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2017, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 2.1.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * PDO Database Adapter Class
  41. *
  42. * Note: _DB is an extender class that the app controller
  43. * creates dynamically based on whether the query builder
  44. * class is being used or not.
  45. *
  46. * @package CodeIgniter
  47. * @subpackage Drivers
  48. * @category Database
  49. * @author EllisLab Dev Team
  50. * @link https://codeigniter.com/user_guide/database/
  51. */
  52. class CI_DB_pdo_driver extends CI_DB {
  53. /**
  54. * Database driver
  55. *
  56. * @var string
  57. */
  58. public $dbdriver = 'pdo';
  59. /**
  60. * PDO Options
  61. *
  62. * @var array
  63. */
  64. public $options = array();
  65. // --------------------------------------------------------------------
  66. /**
  67. * Class constructor
  68. *
  69. * Validates the DSN string and/or detects the subdriver.
  70. *
  71. * @param array $params
  72. * @return void
  73. */
  74. public function __construct($params)
  75. {
  76. parent::__construct($params);
  77. if (preg_match('/([^:]+):/', $this->dsn, $match) && count($match) === 2)
  78. {
  79. // If there is a minimum valid dsn string pattern found, we're done
  80. // This is for general PDO users, who tend to have a full DSN string.
  81. $this->subdriver = $match[1];
  82. return;
  83. }
  84. // Legacy support for DSN specified in the hostname field
  85. elseif (preg_match('/([^:]+):/', $this->hostname, $match) && count($match) === 2)
  86. {
  87. $this->dsn = $this->hostname;
  88. $this->hostname = NULL;
  89. $this->subdriver = $match[1];
  90. return;
  91. }
  92. elseif (in_array($this->subdriver, array('mssql', 'sybase'), TRUE))
  93. {
  94. $this->subdriver = 'dblib';
  95. }
  96. elseif ($this->subdriver === '4D')
  97. {
  98. $this->subdriver = '4d';
  99. }
  100. elseif ( ! in_array($this->subdriver, array('4d', 'cubrid', 'dblib', 'firebird', 'ibm', 'informix', 'mysql', 'oci', 'odbc', 'pgsql', 'sqlite', 'sqlsrv'), TRUE))
  101. {
  102. log_message('error', 'PDO: Invalid or non-existent subdriver');
  103. if ($this->db_debug)
  104. {
  105. show_error('Invalid or non-existent PDO subdriver');
  106. }
  107. }
  108. $this->dsn = NULL;
  109. }
  110. // --------------------------------------------------------------------
  111. /**
  112. * Database connection
  113. *
  114. * @param bool $persistent
  115. * @return object
  116. */
  117. public function db_connect($persistent = FALSE)
  118. {
  119. if ($persistent === TRUE)
  120. {
  121. $this->options[PDO::ATTR_PERSISTENT] = TRUE;
  122. }
  123. try
  124. {
  125. return new PDO($this->dsn, $this->username, $this->password, $this->options);
  126. }
  127. catch (PDOException $e)
  128. {
  129. if ($this->db_debug && empty($this->failover))
  130. {
  131. $this->display_error($e->getMessage(), '', TRUE);
  132. }
  133. return FALSE;
  134. }
  135. }
  136. // --------------------------------------------------------------------
  137. /**
  138. * Database version number
  139. *
  140. * @return string
  141. */
  142. public function version()
  143. {
  144. if (isset($this->data_cache['version']))
  145. {
  146. return $this->data_cache['version'];
  147. }
  148. // Not all subdrivers support the getAttribute() method
  149. try
  150. {
  151. return $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION);
  152. }
  153. catch (PDOException $e)
  154. {
  155. return parent::version();
  156. }
  157. }
  158. // --------------------------------------------------------------------
  159. /**
  160. * Execute the query
  161. *
  162. * @param string $sql SQL query
  163. * @return mixed
  164. */
  165. protected function _execute($sql)
  166. {
  167. return $this->conn_id->query($sql);
  168. }
  169. // --------------------------------------------------------------------
  170. /**
  171. * Begin Transaction
  172. *
  173. * @return bool
  174. */
  175. protected function _trans_begin()
  176. {
  177. return $this->conn_id->beginTransaction();
  178. }
  179. // --------------------------------------------------------------------
  180. /**
  181. * Commit Transaction
  182. *
  183. * @return bool
  184. */
  185. protected function _trans_commit()
  186. {
  187. return $this->conn_id->commit();
  188. }
  189. // --------------------------------------------------------------------
  190. /**
  191. * Rollback Transaction
  192. *
  193. * @return bool
  194. */
  195. protected function _trans_rollback()
  196. {
  197. return $this->conn_id->rollBack();
  198. }
  199. // --------------------------------------------------------------------
  200. /**
  201. * Platform-dependent string escape
  202. *
  203. * @param string
  204. * @return string
  205. */
  206. protected function _escape_str($str)
  207. {
  208. // Escape the string
  209. $str = $this->conn_id->quote($str);
  210. // If there are duplicated quotes, trim them away
  211. return ($str[0] === "'")
  212. ? substr($str, 1, -1)
  213. : $str;
  214. }
  215. // --------------------------------------------------------------------
  216. /**
  217. * Affected Rows
  218. *
  219. * @return int
  220. */
  221. public function affected_rows()
  222. {
  223. return is_object($this->result_id) ? $this->result_id->rowCount() : 0;
  224. }
  225. // --------------------------------------------------------------------
  226. /**
  227. * Insert ID
  228. *
  229. * @param string $name
  230. * @return int
  231. */
  232. public function insert_id($name = NULL)
  233. {
  234. return $this->conn_id->lastInsertId($name);
  235. }
  236. // --------------------------------------------------------------------
  237. /**
  238. * Field data query
  239. *
  240. * Generates a platform-specific query so that the column data can be retrieved
  241. *
  242. * @param string $table
  243. * @return string
  244. */
  245. protected function _field_data($table)
  246. {
  247. return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
  248. }
  249. // --------------------------------------------------------------------
  250. /**
  251. * Error
  252. *
  253. * Returns an array containing code and message of the last
  254. * database error that has occurred.
  255. *
  256. * @return array
  257. */
  258. public function error()
  259. {
  260. $error = array('code' => '00000', 'message' => '');
  261. $pdo_error = $this->conn_id->errorInfo();
  262. if (empty($pdo_error[0]))
  263. {
  264. return $error;
  265. }
  266. $error['code'] = isset($pdo_error[1]) ? $pdo_error[0].'/'.$pdo_error[1] : $pdo_error[0];
  267. if (isset($pdo_error[2]))
  268. {
  269. $error['message'] = $pdo_error[2];
  270. }
  271. return $error;
  272. }
  273. // --------------------------------------------------------------------
  274. /**
  275. * Truncate statement
  276. *
  277. * Generates a platform-specific truncate string from the supplied data
  278. *
  279. * If the database does not support the TRUNCATE statement,
  280. * then this method maps to 'DELETE FROM table'
  281. *
  282. * @param string $table
  283. * @return string
  284. */
  285. protected function _truncate($table)
  286. {
  287. return 'TRUNCATE TABLE '.$table;
  288. }
  289. }