blob: c99bb06031870e0ff8e89f9d19498f9de30a1fd0 [file] [log] [blame]
Andrey Andreevc5536aa2012-11-01 17:33:58 +02001<?php
Timothy Warren80ab8162011-08-22 18:26:12 -04002/**
3 * CodeIgniter
4 *
Andrey Andreevfe9309d2015-01-09 17:48:58 +02005 * An open source application development framework for PHP
Timothy Warren80ab8162011-08-22 18:26:12 -04006 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +02007 * This content is released under the MIT License (MIT)
Andrey Andreevbd44d5a2012-03-20 22:59:29 +02008 *
Andrey Andreevcce6bd12018-01-09 11:32:02 +02009 * Copyright (c) 2014 - 2018, British Columbia Institute of Technology
Andrey Andreevbd44d5a2012-03-20 22:59:29 +020010 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020011 * 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:
Timothy Warrend1a5ba22011-10-21 04:45:28 -040017 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020018 * 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
Andrey Andreev1924e872016-01-11 12:55:34 +020031 * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
Andrey Andreevcce6bd12018-01-09 11:32:02 +020032 * @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020033 * @license http://opensource.org/licenses/MIT MIT License
Andrey Andreevbd202c92016-01-11 12:50:18 +020034 * @link https://codeigniter.com
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020035 * @since Version 2.1.0
Timothy Warren80ab8162011-08-22 18:26:12 -040036 * @filesource
37 */
Andrey Andreevc5536aa2012-11-01 17:33:58 +020038defined('BASEPATH') OR exit('No direct script access allowed');
Timothy Warren80ab8162011-08-22 18:26:12 -040039
Timothy Warren80ab8162011-08-22 18:26:12 -040040/**
Timothy Warren02615962011-08-24 08:21:36 -040041 * PDO Database Adapter Class
Timothy Warren80ab8162011-08-22 18:26:12 -040042 *
43 * Note: _DB is an extender class that the app controller
Jamie Rumbelow7efad202012-02-19 12:37:00 +000044 * creates dynamically based on whether the query builder
Timothy Warren80ab8162011-08-22 18:26:12 -040045 * class is being used or not.
46 *
47 * @package CodeIgniter
48 * @subpackage Drivers
49 * @category Database
Timothy Warrend1a5ba22011-10-21 04:45:28 -040050 * @author EllisLab Dev Team
Andrey Andreevbd202c92016-01-11 12:50:18 +020051 * @link https://codeigniter.com/user_guide/database/
Timothy Warren80ab8162011-08-22 18:26:12 -040052 */
53class CI_DB_pdo_driver extends CI_DB {
54
Andrey Andreeva24e52e2012-11-02 03:54:12 +020055 /**
56 * Database driver
57 *
58 * @var string
59 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +020060 public $dbdriver = 'pdo';
Timothy Warren80ab8162011-08-22 18:26:12 -040061
Andrey Andreeva24e52e2012-11-02 03:54:12 +020062 /**
Andrey Andreeva24e52e2012-11-02 03:54:12 +020063 * PDO Options
64 *
65 * @var array
66 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +020067 public $options = array();
Timothy Warren80ab8162011-08-22 18:26:12 -040068
Andrey Andreeva24e52e2012-11-02 03:54:12 +020069 // --------------------------------------------------------------------
70
Andrey Andreev50293052012-06-25 17:48:49 +030071 /**
Andrey Andreeva24e52e2012-11-02 03:54:12 +020072 * Class constructor
Andrey Andreev50293052012-06-25 17:48:49 +030073 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +020074 * Validates the DSN string and/or detects the subdriver.
Andrey Andreev50293052012-06-25 17:48:49 +030075 *
Andrey Andreev5fd3ae82012-10-24 14:55:35 +030076 * @param array $params
Andrey Andreev50293052012-06-25 17:48:49 +030077 * @return void
78 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +020079 public function __construct($params)
Timothy Warren80ab8162011-08-22 18:26:12 -040080 {
Timothy Warrenb5a43b02011-10-04 17:26:04 -040081 parent::__construct($params);
Taufan Aditya18209332012-02-09 16:07:27 +070082
Andrey Andreev42113442013-07-29 09:55:29 +030083 if (preg_match('/([^:]+):/', $this->dsn, $match) && count($match) === 2)
Taufan Aditya18209332012-02-09 16:07:27 +070084 {
85 // If there is a minimum valid dsn string pattern found, we're done
Taufan Adityafdd6ad02012-02-10 13:10:27 +070086 // This is for general PDO users, who tend to have a full DSN string.
Andrey Andreev7151e802012-06-25 00:47:41 +030087 $this->subdriver = $match[1];
Andrey Andreev50293052012-06-25 17:48:49 +030088 return;
Taufan Aditya18209332012-02-09 16:07:27 +070089 }
Andrey Andreev50293052012-06-25 17:48:49 +030090 // Legacy support for DSN specified in the hostname field
Andrey Andreev42113442013-07-29 09:55:29 +030091 elseif (preg_match('/([^:]+):/', $this->hostname, $match) && count($match) === 2)
Taufan Aditya18209332012-02-09 16:07:27 +070092 {
Andrey Andreev50293052012-06-25 17:48:49 +030093 $this->dsn = $this->hostname;
94 $this->hostname = NULL;
95 $this->subdriver = $match[1];
96 return;
Taufan Aditya18209332012-02-09 16:07:27 +070097 }
Andrey Andreev50293052012-06-25 17:48:49 +030098 elseif (in_array($this->subdriver, array('mssql', 'sybase'), TRUE))
Andrey Andreev7151e802012-06-25 00:47:41 +030099 {
100 $this->subdriver = 'dblib';
101 }
Andrey Andreev6b4bffa2012-06-25 02:29:20 +0300102 elseif ($this->subdriver === '4D')
103 {
104 $this->subdriver = '4d';
105 }
Andrey Andreev279256f2014-01-30 13:50:00 +0200106 elseif ( ! in_array($this->subdriver, array('4d', 'cubrid', 'dblib', 'firebird', 'ibm', 'informix', 'mysql', 'oci', 'odbc', 'pgsql', 'sqlite', 'sqlsrv'), TRUE))
Timothy Warrenc7ba6642011-09-14 12:25:14 -0400107 {
Andrey Andreev50293052012-06-25 17:48:49 +0300108 log_message('error', 'PDO: Invalid or non-existent subdriver');
Timothy Warren80ab8162011-08-22 18:26:12 -0400109
Andrey Andreev50293052012-06-25 17:48:49 +0300110 if ($this->db_debug)
Timothy Warren25dc7552012-02-13 14:12:35 -0500111 {
Andrey Andreev50293052012-06-25 17:48:49 +0300112 show_error('Invalid or non-existent PDO subdriver');
Taufan Aditya18209332012-02-09 16:07:27 +0700113 }
Andrey Andreevd42cc462012-06-24 23:52:40 +0300114 }
Andrey Andreev50293052012-06-25 17:48:49 +0300115
116 $this->dsn = NULL;
Taufan Aditya18209332012-02-09 16:07:27 +0700117 }
118
Andrey Andreev2387ed32012-04-07 00:11:14 +0300119 // --------------------------------------------------------------------
120
Taufan Aditya18209332012-02-09 16:07:27 +0700121 /**
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200122 * Database connection
Timothy Warren80ab8162011-08-22 18:26:12 -0400123 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200124 * @param bool $persistent
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200125 * @return object
Taufan Aditya18209332012-02-09 16:07:27 +0700126 */
Andrey Andreev3b0130d2012-06-24 21:41:42 +0300127 public function db_connect($persistent = FALSE)
Taufan Aditya18209332012-02-09 16:07:27 +0700128 {
Andrey Andreevac718622016-06-22 13:01:51 +0300129 if ($persistent === TRUE)
130 {
131 $this->options[PDO::ATTR_PERSISTENT] = TRUE;
132 }
Andrey Andreev2387ed32012-04-07 00:11:14 +0300133
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200134 try
Taufan Aditya18209332012-02-09 16:07:27 +0700135 {
Andrey Andreevf2818bd2014-02-25 15:26:20 +0200136 return new PDO($this->dsn, $this->username, $this->password, $this->options);
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200137 }
138 catch (PDOException $e)
Taufan Aditya18209332012-02-09 16:07:27 +0700139 {
140 if ($this->db_debug && empty($this->failover))
141 {
142 $this->display_error($e->getMessage(), '', TRUE);
143 }
144
145 return FALSE;
146 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400147 }
148
149 // --------------------------------------------------------------------
150
151 /**
Andrey Andreev08856b82012-03-03 03:19:28 +0200152 * Database version number
Timothy Warren80ab8162011-08-22 18:26:12 -0400153 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400154 * @return string
155 */
Andrey Andreev08856b82012-03-03 03:19:28 +0200156 public function version()
Timothy Warren80ab8162011-08-22 18:26:12 -0400157 {
Andrey Andreev9e3a83a2012-07-05 21:57:41 +0300158 if (isset($this->data_cache['version']))
159 {
160 return $this->data_cache['version'];
161 }
162
163 // Not all subdrivers support the getAttribute() method
164 try
165 {
166 return $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION);
167 }
168 catch (PDOException $e)
169 {
170 return parent::version();
171 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400172 }
173
174 // --------------------------------------------------------------------
175
176 /**
177 * Execute the query
178 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200179 * @param string $sql SQL query
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200180 * @return mixed
Timothy Warren80ab8162011-08-22 18:26:12 -0400181 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200182 protected function _execute($sql)
Timothy Warren80ab8162011-08-22 18:26:12 -0400183 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300184 return $this->conn_id->query($sql);
Timothy Warren80ab8162011-08-22 18:26:12 -0400185 }
186
187 // --------------------------------------------------------------------
188
189 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400190 * Begin Transaction
191 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400192 * @return bool
193 */
Andrey Andreeva7d4aba2015-10-19 14:39:44 +0300194 protected function _trans_begin()
Timothy Warren80ab8162011-08-22 18:26:12 -0400195 {
Timothy Warrenab347582011-08-23 12:29:29 -0400196 return $this->conn_id->beginTransaction();
Timothy Warren80ab8162011-08-22 18:26:12 -0400197 }
198
199 // --------------------------------------------------------------------
200
201 /**
202 * Commit Transaction
203 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400204 * @return bool
205 */
Andrey Andreeva7d4aba2015-10-19 14:39:44 +0300206 protected function _trans_commit()
Timothy Warren80ab8162011-08-22 18:26:12 -0400207 {
Andrey Andreev80144bf2012-04-06 22:19:26 +0300208 return $this->conn_id->commit();
Timothy Warren80ab8162011-08-22 18:26:12 -0400209 }
210
211 // --------------------------------------------------------------------
212
213 /**
214 * Rollback Transaction
215 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400216 * @return bool
217 */
Andrey Andreeva7d4aba2015-10-19 14:39:44 +0300218 protected function _trans_rollback()
Timothy Warren80ab8162011-08-22 18:26:12 -0400219 {
Andrey Andreev80144bf2012-04-06 22:19:26 +0300220 return $this->conn_id->rollBack();
Timothy Warren80ab8162011-08-22 18:26:12 -0400221 }
222
223 // --------------------------------------------------------------------
224
225 /**
Andrey Andreev71d8f722017-01-17 12:01:00 +0200226 * Platform-dependent string escape
Timothy Warren80ab8162011-08-22 18:26:12 -0400227 *
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200228 * @param string
Timothy Warren80ab8162011-08-22 18:26:12 -0400229 * @return string
230 */
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200231 protected function _escape_str($str)
Timothy Warren80ab8162011-08-22 18:26:12 -0400232 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300233 // Escape the string
Timothy Warren47663972011-10-05 16:44:50 -0400234 $str = $this->conn_id->quote($str);
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200235
Andrey Andreev2387ed32012-04-07 00:11:14 +0300236 // If there are duplicated quotes, trim them away
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200237 return ($str[0] === "'")
238 ? substr($str, 1, -1)
239 : $str;
Timothy Warren80ab8162011-08-22 18:26:12 -0400240 }
241
242 // --------------------------------------------------------------------
243
244 /**
245 * Affected Rows
246 *
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200247 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400248 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200249 public function affected_rows()
Timothy Warren80ab8162011-08-22 18:26:12 -0400250 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300251 return is_object($this->result_id) ? $this->result_id->rowCount() : 0;
Timothy Warren80ab8162011-08-22 18:26:12 -0400252 }
253
254 // --------------------------------------------------------------------
255
256 /**
257 * Insert ID
Andrey Andreeva39d6992012-03-01 19:11:39 +0200258 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200259 * @param string $name
Andrey Andreeva39d6992012-03-01 19:11:39 +0200260 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400261 */
Andrey Andreeva39d6992012-03-01 19:11:39 +0200262 public function insert_id($name = NULL)
Timothy Warren80ab8162011-08-22 18:26:12 -0400263 {
Andrey Andreeva39d6992012-03-01 19:11:39 +0200264 return $this->conn_id->lastInsertId($name);
Timothy Warren80ab8162011-08-22 18:26:12 -0400265 }
266
267 // --------------------------------------------------------------------
268
269 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400270 * Field data query
271 *
272 * Generates a platform-specific query so that the column data can be retrieved
273 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200274 * @param string $table
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200275 * @return string
Timothy Warren80ab8162011-08-22 18:26:12 -0400276 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200277 protected function _field_data($table)
Timothy Warren80ab8162011-08-22 18:26:12 -0400278 {
Andrey Andreev50293052012-06-25 17:48:49 +0300279 return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
Timothy Warren80ab8162011-08-22 18:26:12 -0400280 }
281
282 // --------------------------------------------------------------------
283
284 /**
Andrey Andreev4be5de12012-03-02 15:45:41 +0200285 * Error
Timothy Warren80ab8162011-08-22 18:26:12 -0400286 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200287 * Returns an array containing code and message of the last
Andrey Andreev71d8f722017-01-17 12:01:00 +0200288 * database error that has occurred.
Timothy Warren80ab8162011-08-22 18:26:12 -0400289 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200290 * @return array
Timothy Warren80ab8162011-08-22 18:26:12 -0400291 */
Andrey Andreev4be5de12012-03-02 15:45:41 +0200292 public function error()
Timothy Warren80ab8162011-08-22 18:26:12 -0400293 {
Andrey Andreev4be5de12012-03-02 15:45:41 +0200294 $error = array('code' => '00000', 'message' => '');
295 $pdo_error = $this->conn_id->errorInfo();
296
297 if (empty($pdo_error[0]))
298 {
299 return $error;
300 }
301
302 $error['code'] = isset($pdo_error[1]) ? $pdo_error[0].'/'.$pdo_error[1] : $pdo_error[0];
303 if (isset($pdo_error[2]))
304 {
305 $error['message'] = $pdo_error[2];
306 }
307
308 return $error;
Timothy Warren80ab8162011-08-22 18:26:12 -0400309 }
310
311 // --------------------------------------------------------------------
312
313 /**
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300314 * Truncate statement
315 *
316 * Generates a platform-specific truncate string from the supplied data
317 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200318 * If the database does not support the TRUNCATE statement,
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300319 * then this method maps to 'DELETE FROM table'
320 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200321 * @param string $table
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300322 * @return string
323 */
324 protected function _truncate($table)
325 {
326 return 'TRUNCATE TABLE '.$table;
327 }
328
Timothy Warren80ab8162011-08-22 18:26:12 -0400329}