blob: 1812f20bf68e2f53fe6446b6f2519da153cf3743 [file] [log] [blame]
Andrey Andreevc5536aa2012-11-01 17:33:58 +02001<?php
Timothy Warren80ab8162011-08-22 18:26:12 -04002/**
3 * CodeIgniter
4 *
Phil Sturgeon07c1ac82012-03-09 17:03:37 +00005 * An open source application development framework for PHP 5.2.4 or newer
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 Andreevbdb96ca2014-10-28 00:13:31 +02009 * Copyright (c) 2014, 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
darwinel871754a2014-02-11 17:34:57 +010031 * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020032 * @copyright Copyright (c) 2014, British Columbia Institute of Technology (http://bcit.ca/)
33 * @license http://opensource.org/licenses/MIT MIT License
34 * @link http://codeigniter.com
35 * @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
Timothy Warren80ab8162011-08-22 18:26:12 -040051 * @link http://codeigniter.com/user_guide/database/
52 */
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 Andreev3b0130d2012-06-24 21:41:42 +0300129 $this->options[PDO::ATTR_PERSISTENT] = $persistent;
Andrey Andreev2387ed32012-04-07 00:11:14 +0300130
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200131 try
Taufan Aditya18209332012-02-09 16:07:27 +0700132 {
Andrey Andreevf2818bd2014-02-25 15:26:20 +0200133 return new PDO($this->dsn, $this->username, $this->password, $this->options);
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200134 }
135 catch (PDOException $e)
Taufan Aditya18209332012-02-09 16:07:27 +0700136 {
137 if ($this->db_debug && empty($this->failover))
138 {
139 $this->display_error($e->getMessage(), '', TRUE);
140 }
141
142 return FALSE;
143 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400144 }
145
146 // --------------------------------------------------------------------
147
148 /**
Andrey Andreev08856b82012-03-03 03:19:28 +0200149 * Database version number
Timothy Warren80ab8162011-08-22 18:26:12 -0400150 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400151 * @return string
152 */
Andrey Andreev08856b82012-03-03 03:19:28 +0200153 public function version()
Timothy Warren80ab8162011-08-22 18:26:12 -0400154 {
Andrey Andreev9e3a83a2012-07-05 21:57:41 +0300155 if (isset($this->data_cache['version']))
156 {
157 return $this->data_cache['version'];
158 }
Andrey Andreev2b730372012-11-05 17:01:11 +0200159 elseif ( ! $this->conn_id)
160 {
161 $this->initialize();
162 }
Andrey Andreev9e3a83a2012-07-05 21:57:41 +0300163
164 // Not all subdrivers support the getAttribute() method
165 try
166 {
167 return $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION);
168 }
169 catch (PDOException $e)
170 {
171 return parent::version();
172 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400173 }
174
175 // --------------------------------------------------------------------
176
177 /**
178 * Execute the query
179 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200180 * @param string $sql SQL query
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200181 * @return mixed
Timothy Warren80ab8162011-08-22 18:26:12 -0400182 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200183 protected function _execute($sql)
Timothy Warren80ab8162011-08-22 18:26:12 -0400184 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300185 return $this->conn_id->query($sql);
Timothy Warren80ab8162011-08-22 18:26:12 -0400186 }
187
188 // --------------------------------------------------------------------
189
190 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400191 * Begin Transaction
192 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200193 * @param bool $test_mode
Timothy Warren80ab8162011-08-22 18:26:12 -0400194 * @return bool
195 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200196 public function trans_begin($test_mode = FALSE)
Timothy Warren80ab8162011-08-22 18:26:12 -0400197 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400198 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300199 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400200 {
201 return TRUE;
202 }
203
204 // Reset the transaction failure flag.
205 // If the $test_mode flag is set to TRUE transactions will be rolled back
206 // even if the queries produce a successful result.
Andrey Andreev2387ed32012-04-07 00:11:14 +0300207 $this->_trans_failure = ($test_mode === TRUE);
Timothy Warren80ab8162011-08-22 18:26:12 -0400208
Timothy Warrenab347582011-08-23 12:29:29 -0400209 return $this->conn_id->beginTransaction();
Timothy Warren80ab8162011-08-22 18:26:12 -0400210 }
211
212 // --------------------------------------------------------------------
213
214 /**
215 * Commit Transaction
216 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400217 * @return bool
218 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200219 public function trans_commit()
Timothy Warren80ab8162011-08-22 18:26:12 -0400220 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400221 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300222 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400223 {
224 return TRUE;
225 }
226
Andrey Andreev80144bf2012-04-06 22:19:26 +0300227 return $this->conn_id->commit();
Timothy Warren80ab8162011-08-22 18:26:12 -0400228 }
229
230 // --------------------------------------------------------------------
231
232 /**
233 * Rollback Transaction
234 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400235 * @return bool
236 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200237 public function trans_rollback()
Timothy Warren80ab8162011-08-22 18:26:12 -0400238 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400239 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300240 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400241 {
242 return TRUE;
243 }
244
Andrey Andreev80144bf2012-04-06 22:19:26 +0300245 return $this->conn_id->rollBack();
Timothy Warren80ab8162011-08-22 18:26:12 -0400246 }
247
248 // --------------------------------------------------------------------
249
250 /**
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200251 * Platform-dependant string escape
Timothy Warren80ab8162011-08-22 18:26:12 -0400252 *
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200253 * @param string
Timothy Warren80ab8162011-08-22 18:26:12 -0400254 * @return string
255 */
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200256 protected function _escape_str($str)
Timothy Warren80ab8162011-08-22 18:26:12 -0400257 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300258 // Escape the string
Timothy Warren47663972011-10-05 16:44:50 -0400259 $str = $this->conn_id->quote($str);
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200260
Andrey Andreev2387ed32012-04-07 00:11:14 +0300261 // If there are duplicated quotes, trim them away
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200262 return ($str[0] === "'")
263 ? substr($str, 1, -1)
264 : $str;
Timothy Warren80ab8162011-08-22 18:26:12 -0400265 }
266
267 // --------------------------------------------------------------------
268
269 /**
270 * Affected Rows
271 *
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200272 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400273 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200274 public function affected_rows()
Timothy Warren80ab8162011-08-22 18:26:12 -0400275 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300276 return is_object($this->result_id) ? $this->result_id->rowCount() : 0;
Timothy Warren80ab8162011-08-22 18:26:12 -0400277 }
278
279 // --------------------------------------------------------------------
280
281 /**
282 * Insert ID
Andrey Andreeva39d6992012-03-01 19:11:39 +0200283 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200284 * @param string $name
Andrey Andreeva39d6992012-03-01 19:11:39 +0200285 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400286 */
Andrey Andreeva39d6992012-03-01 19:11:39 +0200287 public function insert_id($name = NULL)
Timothy Warren80ab8162011-08-22 18:26:12 -0400288 {
Andrey Andreeva39d6992012-03-01 19:11:39 +0200289 return $this->conn_id->lastInsertId($name);
Timothy Warren80ab8162011-08-22 18:26:12 -0400290 }
291
292 // --------------------------------------------------------------------
293
294 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400295 * Field data query
296 *
297 * Generates a platform-specific query so that the column data can be retrieved
298 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200299 * @param string $table
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200300 * @return string
Timothy Warren80ab8162011-08-22 18:26:12 -0400301 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200302 protected function _field_data($table)
Timothy Warren80ab8162011-08-22 18:26:12 -0400303 {
Andrey Andreev50293052012-06-25 17:48:49 +0300304 return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
Timothy Warren80ab8162011-08-22 18:26:12 -0400305 }
306
307 // --------------------------------------------------------------------
308
309 /**
Andrey Andreev4be5de12012-03-02 15:45:41 +0200310 * Error
Timothy Warren80ab8162011-08-22 18:26:12 -0400311 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200312 * Returns an array containing code and message of the last
313 * database error that has occured.
Timothy Warren80ab8162011-08-22 18:26:12 -0400314 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200315 * @return array
Timothy Warren80ab8162011-08-22 18:26:12 -0400316 */
Andrey Andreev4be5de12012-03-02 15:45:41 +0200317 public function error()
Timothy Warren80ab8162011-08-22 18:26:12 -0400318 {
Andrey Andreev4be5de12012-03-02 15:45:41 +0200319 $error = array('code' => '00000', 'message' => '');
320 $pdo_error = $this->conn_id->errorInfo();
321
322 if (empty($pdo_error[0]))
323 {
324 return $error;
325 }
326
327 $error['code'] = isset($pdo_error[1]) ? $pdo_error[0].'/'.$pdo_error[1] : $pdo_error[0];
328 if (isset($pdo_error[2]))
329 {
330 $error['message'] = $pdo_error[2];
331 }
332
333 return $error;
Timothy Warren80ab8162011-08-22 18:26:12 -0400334 }
335
336 // --------------------------------------------------------------------
337
338 /**
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400339 * Update_Batch statement
340 *
341 * Generates a platform-specific batch update string from the supplied data
342 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200343 * @param string $table Table name
344 * @param array $values Update data
345 * @param string $index WHERE key
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400346 * @return string
347 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300348 protected function _update_batch($table, $values, $index)
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400349 {
Andrey Andreevdf8894f2012-06-25 16:18:50 +0300350 $ids = array();
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400351 foreach ($values as $key => $val)
352 {
353 $ids[] = $val[$index];
354
355 foreach (array_keys($val) as $field)
356 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100357 if ($field !== $index)
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400358 {
Andrey Andreev838a9d62012-12-03 14:37:47 +0200359 $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400360 }
361 }
362 }
363
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400364 $cases = '';
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400365 foreach ($final as $k => $v)
366 {
367 $cases .= $k.' = CASE '."\n";
Taufan Aditya18209332012-02-09 16:07:27 +0700368
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400369 foreach ($v as $row)
370 {
371 $cases .= $row."\n";
372 }
373
374 $cases .= 'ELSE '.$k.' END, ';
375 }
376
Andrey Andreevb0478652012-07-18 15:34:46 +0300377 $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400378
Andrey Andreevd40459d2012-07-18 16:46:39 +0300379 return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400380 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400381
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300382 // --------------------------------------------------------------------
383
384 /**
385 * Truncate statement
386 *
387 * Generates a platform-specific truncate string from the supplied data
388 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200389 * If the database does not support the TRUNCATE statement,
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300390 * then this method maps to 'DELETE FROM table'
391 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200392 * @param string $table
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300393 * @return string
394 */
395 protected function _truncate($table)
396 {
397 return 'TRUNCATE TABLE '.$table;
398 }
399
Timothy Warren80ab8162011-08-22 18:26:12 -0400400}
401
Timothy Warren80ab8162011-08-22 18:26:12 -0400402/* End of file pdo_driver.php */
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200403/* Location: ./system/database/drivers/pdo/pdo_driver.php */