blob: 1d4e626d4e3ed3d5677c8bd3523e1f625cac1adb [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 *
Timothy Warrend1a5ba22011-10-21 04:45:28 -04007 * NOTICE OF LICENSE
Andrey Andreevbd44d5a2012-03-20 22:59:29 +02008 *
Timothy Warrend1a5ba22011-10-21 04:45:28 -04009 * Licensed under the Open Software License version 3.0
Andrey Andreevbd44d5a2012-03-20 22:59:29 +020010 *
Timothy Warrend1a5ba22011-10-21 04:45:28 -040011 * This source file is subject to the Open Software License (OSL 3.0) that is
12 * bundled with this package in the files license.txt / license.rst. It is
13 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
Timothy Warren80ab8162011-08-22 18:26:12 -040019 * @package CodeIgniter
Timothy Warrend1a5ba22011-10-21 04:45:28 -040020 * @author EllisLab Dev Team
darwinel871754a2014-02-11 17:34:57 +010021 * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
Timothy Warrend1a5ba22011-10-21 04:45:28 -040022 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
Timothy Warren80ab8162011-08-22 18:26:12 -040023 * @link http://codeigniter.com
Timothy Warren018af7a2011-09-07 12:07:35 -040024 * @since Version 2.1.0
Timothy Warren80ab8162011-08-22 18:26:12 -040025 * @filesource
26 */
Andrey Andreevc5536aa2012-11-01 17:33:58 +020027defined('BASEPATH') OR exit('No direct script access allowed');
Timothy Warren80ab8162011-08-22 18:26:12 -040028
Timothy Warren80ab8162011-08-22 18:26:12 -040029/**
Timothy Warren02615962011-08-24 08:21:36 -040030 * PDO Database Adapter Class
Timothy Warren80ab8162011-08-22 18:26:12 -040031 *
32 * Note: _DB is an extender class that the app controller
Jamie Rumbelow7efad202012-02-19 12:37:00 +000033 * creates dynamically based on whether the query builder
Timothy Warren80ab8162011-08-22 18:26:12 -040034 * class is being used or not.
35 *
36 * @package CodeIgniter
37 * @subpackage Drivers
38 * @category Database
Timothy Warrend1a5ba22011-10-21 04:45:28 -040039 * @author EllisLab Dev Team
Timothy Warren80ab8162011-08-22 18:26:12 -040040 * @link http://codeigniter.com/user_guide/database/
41 */
42class CI_DB_pdo_driver extends CI_DB {
43
Andrey Andreeva24e52e2012-11-02 03:54:12 +020044 /**
45 * Database driver
46 *
47 * @var string
48 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +020049 public $dbdriver = 'pdo';
Timothy Warren80ab8162011-08-22 18:26:12 -040050
Andrey Andreeva24e52e2012-11-02 03:54:12 +020051 /**
Andrey Andreeva24e52e2012-11-02 03:54:12 +020052 * PDO Options
53 *
54 * @var array
55 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +020056 public $options = array();
Timothy Warren80ab8162011-08-22 18:26:12 -040057
Andrey Andreeva24e52e2012-11-02 03:54:12 +020058 // --------------------------------------------------------------------
59
Andrey Andreev50293052012-06-25 17:48:49 +030060 /**
Andrey Andreeva24e52e2012-11-02 03:54:12 +020061 * Class constructor
Andrey Andreev50293052012-06-25 17:48:49 +030062 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +020063 * Validates the DSN string and/or detects the subdriver.
Andrey Andreev50293052012-06-25 17:48:49 +030064 *
Andrey Andreev5fd3ae82012-10-24 14:55:35 +030065 * @param array $params
Andrey Andreev50293052012-06-25 17:48:49 +030066 * @return void
67 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +020068 public function __construct($params)
Timothy Warren80ab8162011-08-22 18:26:12 -040069 {
Timothy Warrenb5a43b02011-10-04 17:26:04 -040070 parent::__construct($params);
Taufan Aditya18209332012-02-09 16:07:27 +070071
Andrey Andreev42113442013-07-29 09:55:29 +030072 if (preg_match('/([^:]+):/', $this->dsn, $match) && count($match) === 2)
Taufan Aditya18209332012-02-09 16:07:27 +070073 {
74 // If there is a minimum valid dsn string pattern found, we're done
Taufan Adityafdd6ad02012-02-10 13:10:27 +070075 // This is for general PDO users, who tend to have a full DSN string.
Andrey Andreev7151e802012-06-25 00:47:41 +030076 $this->subdriver = $match[1];
Andrey Andreev50293052012-06-25 17:48:49 +030077 return;
Taufan Aditya18209332012-02-09 16:07:27 +070078 }
Andrey Andreev50293052012-06-25 17:48:49 +030079 // Legacy support for DSN specified in the hostname field
Andrey Andreev42113442013-07-29 09:55:29 +030080 elseif (preg_match('/([^:]+):/', $this->hostname, $match) && count($match) === 2)
Taufan Aditya18209332012-02-09 16:07:27 +070081 {
Andrey Andreev50293052012-06-25 17:48:49 +030082 $this->dsn = $this->hostname;
83 $this->hostname = NULL;
84 $this->subdriver = $match[1];
85 return;
Taufan Aditya18209332012-02-09 16:07:27 +070086 }
Andrey Andreev50293052012-06-25 17:48:49 +030087 elseif (in_array($this->subdriver, array('mssql', 'sybase'), TRUE))
Andrey Andreev7151e802012-06-25 00:47:41 +030088 {
89 $this->subdriver = 'dblib';
90 }
Andrey Andreev6b4bffa2012-06-25 02:29:20 +030091 elseif ($this->subdriver === '4D')
92 {
93 $this->subdriver = '4d';
94 }
Andrey Andreev279256f2014-01-30 13:50:00 +020095 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 -040096 {
Andrey Andreev50293052012-06-25 17:48:49 +030097 log_message('error', 'PDO: Invalid or non-existent subdriver');
Timothy Warren80ab8162011-08-22 18:26:12 -040098
Andrey Andreev50293052012-06-25 17:48:49 +030099 if ($this->db_debug)
Timothy Warren25dc7552012-02-13 14:12:35 -0500100 {
Andrey Andreev50293052012-06-25 17:48:49 +0300101 show_error('Invalid or non-existent PDO subdriver');
Taufan Aditya18209332012-02-09 16:07:27 +0700102 }
Andrey Andreevd42cc462012-06-24 23:52:40 +0300103 }
Andrey Andreev50293052012-06-25 17:48:49 +0300104
105 $this->dsn = NULL;
Taufan Aditya18209332012-02-09 16:07:27 +0700106 }
107
Andrey Andreev2387ed32012-04-07 00:11:14 +0300108 // --------------------------------------------------------------------
109
Taufan Aditya18209332012-02-09 16:07:27 +0700110 /**
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200111 * Database connection
Timothy Warren80ab8162011-08-22 18:26:12 -0400112 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200113 * @param bool $persistent
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200114 * @return object
Taufan Aditya18209332012-02-09 16:07:27 +0700115 */
Andrey Andreev3b0130d2012-06-24 21:41:42 +0300116 public function db_connect($persistent = FALSE)
Taufan Aditya18209332012-02-09 16:07:27 +0700117 {
Andrey Andreev3b0130d2012-06-24 21:41:42 +0300118 $this->options[PDO::ATTR_PERSISTENT] = $persistent;
Andrey Andreev2387ed32012-04-07 00:11:14 +0300119
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200120 try
Taufan Aditya18209332012-02-09 16:07:27 +0700121 {
Andrey Andreevf2818bd2014-02-25 15:26:20 +0200122 return new PDO($this->dsn, $this->username, $this->password, $this->options);
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200123 }
124 catch (PDOException $e)
Taufan Aditya18209332012-02-09 16:07:27 +0700125 {
126 if ($this->db_debug && empty($this->failover))
127 {
128 $this->display_error($e->getMessage(), '', TRUE);
129 }
130
131 return FALSE;
132 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400133 }
134
135 // --------------------------------------------------------------------
136
137 /**
Andrey Andreev08856b82012-03-03 03:19:28 +0200138 * Database version number
Timothy Warren80ab8162011-08-22 18:26:12 -0400139 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400140 * @return string
141 */
Andrey Andreev08856b82012-03-03 03:19:28 +0200142 public function version()
Timothy Warren80ab8162011-08-22 18:26:12 -0400143 {
Andrey Andreev9e3a83a2012-07-05 21:57:41 +0300144 if (isset($this->data_cache['version']))
145 {
146 return $this->data_cache['version'];
147 }
Andrey Andreev2b730372012-11-05 17:01:11 +0200148 elseif ( ! $this->conn_id)
149 {
150 $this->initialize();
151 }
Andrey Andreev9e3a83a2012-07-05 21:57:41 +0300152
153 // Not all subdrivers support the getAttribute() method
154 try
155 {
156 return $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION);
157 }
158 catch (PDOException $e)
159 {
160 return parent::version();
161 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400162 }
163
164 // --------------------------------------------------------------------
165
166 /**
167 * Execute the query
168 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200169 * @param string $sql SQL query
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200170 * @return mixed
Timothy Warren80ab8162011-08-22 18:26:12 -0400171 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200172 protected function _execute($sql)
Timothy Warren80ab8162011-08-22 18:26:12 -0400173 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300174 return $this->conn_id->query($sql);
Timothy Warren80ab8162011-08-22 18:26:12 -0400175 }
176
177 // --------------------------------------------------------------------
178
179 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400180 * Begin Transaction
181 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200182 * @param bool $test_mode
Timothy Warren80ab8162011-08-22 18:26:12 -0400183 * @return bool
184 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200185 public function trans_begin($test_mode = FALSE)
Timothy Warren80ab8162011-08-22 18:26:12 -0400186 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400187 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300188 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400189 {
190 return TRUE;
191 }
192
193 // Reset the transaction failure flag.
194 // If the $test_mode flag is set to TRUE transactions will be rolled back
195 // even if the queries produce a successful result.
Andrey Andreev2387ed32012-04-07 00:11:14 +0300196 $this->_trans_failure = ($test_mode === TRUE);
Timothy Warren80ab8162011-08-22 18:26:12 -0400197
Timothy Warrenab347582011-08-23 12:29:29 -0400198 return $this->conn_id->beginTransaction();
Timothy Warren80ab8162011-08-22 18:26:12 -0400199 }
200
201 // --------------------------------------------------------------------
202
203 /**
204 * Commit Transaction
205 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400206 * @return bool
207 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200208 public function trans_commit()
Timothy Warren80ab8162011-08-22 18:26:12 -0400209 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400210 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300211 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400212 {
213 return TRUE;
214 }
215
Andrey Andreev80144bf2012-04-06 22:19:26 +0300216 return $this->conn_id->commit();
Timothy Warren80ab8162011-08-22 18:26:12 -0400217 }
218
219 // --------------------------------------------------------------------
220
221 /**
222 * Rollback Transaction
223 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400224 * @return bool
225 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200226 public function trans_rollback()
Timothy Warren80ab8162011-08-22 18:26:12 -0400227 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400228 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300229 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400230 {
231 return TRUE;
232 }
233
Andrey Andreev80144bf2012-04-06 22:19:26 +0300234 return $this->conn_id->rollBack();
Timothy Warren80ab8162011-08-22 18:26:12 -0400235 }
236
237 // --------------------------------------------------------------------
238
239 /**
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200240 * Platform-dependant string escape
Timothy Warren80ab8162011-08-22 18:26:12 -0400241 *
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200242 * @param string
Timothy Warren80ab8162011-08-22 18:26:12 -0400243 * @return string
244 */
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200245 protected function _escape_str($str)
Timothy Warren80ab8162011-08-22 18:26:12 -0400246 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300247 // Escape the string
Timothy Warren47663972011-10-05 16:44:50 -0400248 $str = $this->conn_id->quote($str);
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200249
Andrey Andreev2387ed32012-04-07 00:11:14 +0300250 // If there are duplicated quotes, trim them away
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200251 return ($str[0] === "'")
252 ? substr($str, 1, -1)
253 : $str;
Timothy Warren80ab8162011-08-22 18:26:12 -0400254 }
255
256 // --------------------------------------------------------------------
257
258 /**
259 * Affected Rows
260 *
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200261 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400262 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200263 public function affected_rows()
Timothy Warren80ab8162011-08-22 18:26:12 -0400264 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300265 return is_object($this->result_id) ? $this->result_id->rowCount() : 0;
Timothy Warren80ab8162011-08-22 18:26:12 -0400266 }
267
268 // --------------------------------------------------------------------
269
270 /**
271 * Insert ID
Andrey Andreeva39d6992012-03-01 19:11:39 +0200272 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200273 * @param string $name
Andrey Andreeva39d6992012-03-01 19:11:39 +0200274 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400275 */
Andrey Andreeva39d6992012-03-01 19:11:39 +0200276 public function insert_id($name = NULL)
Timothy Warren80ab8162011-08-22 18:26:12 -0400277 {
Andrey Andreeva39d6992012-03-01 19:11:39 +0200278 return $this->conn_id->lastInsertId($name);
Timothy Warren80ab8162011-08-22 18:26:12 -0400279 }
280
281 // --------------------------------------------------------------------
282
283 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400284 * Field data query
285 *
286 * Generates a platform-specific query so that the column data can be retrieved
287 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200288 * @param string $table
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200289 * @return string
Timothy Warren80ab8162011-08-22 18:26:12 -0400290 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200291 protected function _field_data($table)
Timothy Warren80ab8162011-08-22 18:26:12 -0400292 {
Andrey Andreev50293052012-06-25 17:48:49 +0300293 return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
Timothy Warren80ab8162011-08-22 18:26:12 -0400294 }
295
296 // --------------------------------------------------------------------
297
298 /**
Andrey Andreev4be5de12012-03-02 15:45:41 +0200299 * Error
Timothy Warren80ab8162011-08-22 18:26:12 -0400300 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200301 * Returns an array containing code and message of the last
302 * database error that has occured.
Timothy Warren80ab8162011-08-22 18:26:12 -0400303 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200304 * @return array
Timothy Warren80ab8162011-08-22 18:26:12 -0400305 */
Andrey Andreev4be5de12012-03-02 15:45:41 +0200306 public function error()
Timothy Warren80ab8162011-08-22 18:26:12 -0400307 {
Andrey Andreev4be5de12012-03-02 15:45:41 +0200308 $error = array('code' => '00000', 'message' => '');
309 $pdo_error = $this->conn_id->errorInfo();
310
311 if (empty($pdo_error[0]))
312 {
313 return $error;
314 }
315
316 $error['code'] = isset($pdo_error[1]) ? $pdo_error[0].'/'.$pdo_error[1] : $pdo_error[0];
317 if (isset($pdo_error[2]))
318 {
319 $error['message'] = $pdo_error[2];
320 }
321
322 return $error;
Timothy Warren80ab8162011-08-22 18:26:12 -0400323 }
324
325 // --------------------------------------------------------------------
326
327 /**
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400328 * Update_Batch statement
329 *
330 * Generates a platform-specific batch update string from the supplied data
331 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200332 * @param string $table Table name
333 * @param array $values Update data
334 * @param string $index WHERE key
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400335 * @return string
336 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300337 protected function _update_batch($table, $values, $index)
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400338 {
Andrey Andreevdf8894f2012-06-25 16:18:50 +0300339 $ids = array();
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400340 foreach ($values as $key => $val)
341 {
342 $ids[] = $val[$index];
343
344 foreach (array_keys($val) as $field)
345 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100346 if ($field !== $index)
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400347 {
Andrey Andreev838a9d62012-12-03 14:37:47 +0200348 $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400349 }
350 }
351 }
352
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400353 $cases = '';
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400354 foreach ($final as $k => $v)
355 {
356 $cases .= $k.' = CASE '."\n";
Taufan Aditya18209332012-02-09 16:07:27 +0700357
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400358 foreach ($v as $row)
359 {
360 $cases .= $row."\n";
361 }
362
363 $cases .= 'ELSE '.$k.' END, ';
364 }
365
Andrey Andreevb0478652012-07-18 15:34:46 +0300366 $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400367
Andrey Andreevd40459d2012-07-18 16:46:39 +0300368 return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400369 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400370
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300371 // --------------------------------------------------------------------
372
373 /**
374 * Truncate statement
375 *
376 * Generates a platform-specific truncate string from the supplied data
377 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200378 * If the database does not support the TRUNCATE statement,
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300379 * then this method maps to 'DELETE FROM table'
380 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200381 * @param string $table
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300382 * @return string
383 */
384 protected function _truncate($table)
385 {
386 return 'TRUNCATE TABLE '.$table;
387 }
388
Timothy Warren80ab8162011-08-22 18:26:12 -0400389}
390
Timothy Warren80ab8162011-08-22 18:26:12 -0400391/* End of file pdo_driver.php */
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200392/* Location: ./system/database/drivers/pdo/pdo_driver.php */