blob: 3f4275f64c0dfc89e5f83e6b7fa0f2e42b6acee9 [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
Andrey Andreev80500af2013-01-01 08:16:53 +020021 * @copyright Copyright (c) 2008 - 2013, 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 Andreevf00b9f02012-07-02 14:40:49 +0300122 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 Andreev3b0130d2012-06-24 21:41:42 +0300138 * Persistent database connection
139 *
140 * @return object
141 */
142 public function db_pconnect()
143 {
144 return $this->db_connect(TRUE);
145 }
146
147 // --------------------------------------------------------------------
148
149 /**
Andrey Andreev08856b82012-03-03 03:19:28 +0200150 * Database version number
Timothy Warren80ab8162011-08-22 18:26:12 -0400151 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400152 * @return string
153 */
Andrey Andreev08856b82012-03-03 03:19:28 +0200154 public function version()
Timothy Warren80ab8162011-08-22 18:26:12 -0400155 {
Andrey Andreev9e3a83a2012-07-05 21:57:41 +0300156 if (isset($this->data_cache['version']))
157 {
158 return $this->data_cache['version'];
159 }
Andrey Andreev2b730372012-11-05 17:01:11 +0200160 elseif ( ! $this->conn_id)
161 {
162 $this->initialize();
163 }
Andrey Andreev9e3a83a2012-07-05 21:57:41 +0300164
165 // Not all subdrivers support the getAttribute() method
166 try
167 {
168 return $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION);
169 }
170 catch (PDOException $e)
171 {
172 return parent::version();
173 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400174 }
175
176 // --------------------------------------------------------------------
177
178 /**
179 * Execute the query
180 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200181 * @param string $sql SQL query
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200182 * @return mixed
Timothy Warren80ab8162011-08-22 18:26:12 -0400183 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200184 protected function _execute($sql)
Timothy Warren80ab8162011-08-22 18:26:12 -0400185 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300186 return $this->conn_id->query($sql);
Timothy Warren80ab8162011-08-22 18:26:12 -0400187 }
188
189 // --------------------------------------------------------------------
190
191 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400192 * Begin Transaction
193 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200194 * @param bool $test_mode
Timothy Warren80ab8162011-08-22 18:26:12 -0400195 * @return bool
196 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200197 public function trans_begin($test_mode = FALSE)
Timothy Warren80ab8162011-08-22 18:26:12 -0400198 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400199 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300200 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400201 {
202 return TRUE;
203 }
204
205 // Reset the transaction failure flag.
206 // If the $test_mode flag is set to TRUE transactions will be rolled back
207 // even if the queries produce a successful result.
Andrey Andreev2387ed32012-04-07 00:11:14 +0300208 $this->_trans_failure = ($test_mode === TRUE);
Timothy Warren80ab8162011-08-22 18:26:12 -0400209
Timothy Warrenab347582011-08-23 12:29:29 -0400210 return $this->conn_id->beginTransaction();
Timothy Warren80ab8162011-08-22 18:26:12 -0400211 }
212
213 // --------------------------------------------------------------------
214
215 /**
216 * Commit Transaction
217 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400218 * @return bool
219 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200220 public function trans_commit()
Timothy Warren80ab8162011-08-22 18:26:12 -0400221 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400222 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300223 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400224 {
225 return TRUE;
226 }
227
Andrey Andreev80144bf2012-04-06 22:19:26 +0300228 return $this->conn_id->commit();
Timothy Warren80ab8162011-08-22 18:26:12 -0400229 }
230
231 // --------------------------------------------------------------------
232
233 /**
234 * Rollback Transaction
235 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400236 * @return bool
237 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200238 public function trans_rollback()
Timothy Warren80ab8162011-08-22 18:26:12 -0400239 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400240 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300241 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400242 {
243 return TRUE;
244 }
245
Andrey Andreev80144bf2012-04-06 22:19:26 +0300246 return $this->conn_id->rollBack();
Timothy Warren80ab8162011-08-22 18:26:12 -0400247 }
248
249 // --------------------------------------------------------------------
250
251 /**
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200252 * Platform-dependant string escape
Timothy Warren80ab8162011-08-22 18:26:12 -0400253 *
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200254 * @param string
Timothy Warren80ab8162011-08-22 18:26:12 -0400255 * @return string
256 */
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200257 protected function _escape_str($str)
Timothy Warren80ab8162011-08-22 18:26:12 -0400258 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300259 // Escape the string
Timothy Warren47663972011-10-05 16:44:50 -0400260 $str = $this->conn_id->quote($str);
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200261
Andrey Andreev2387ed32012-04-07 00:11:14 +0300262 // If there are duplicated quotes, trim them away
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200263 return ($str[0] === "'")
264 ? substr($str, 1, -1)
265 : $str;
Timothy Warren80ab8162011-08-22 18:26:12 -0400266 }
267
268 // --------------------------------------------------------------------
269
270 /**
271 * Affected Rows
272 *
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200273 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400274 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200275 public function affected_rows()
Timothy Warren80ab8162011-08-22 18:26:12 -0400276 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300277 return is_object($this->result_id) ? $this->result_id->rowCount() : 0;
Timothy Warren80ab8162011-08-22 18:26:12 -0400278 }
279
280 // --------------------------------------------------------------------
281
282 /**
283 * Insert ID
Andrey Andreeva39d6992012-03-01 19:11:39 +0200284 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200285 * @param string $name
Andrey Andreeva39d6992012-03-01 19:11:39 +0200286 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400287 */
Andrey Andreeva39d6992012-03-01 19:11:39 +0200288 public function insert_id($name = NULL)
Timothy Warren80ab8162011-08-22 18:26:12 -0400289 {
Andrey Andreeva39d6992012-03-01 19:11:39 +0200290 return $this->conn_id->lastInsertId($name);
Timothy Warren80ab8162011-08-22 18:26:12 -0400291 }
292
293 // --------------------------------------------------------------------
294
295 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400296 * Field data query
297 *
298 * Generates a platform-specific query so that the column data can be retrieved
299 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200300 * @param string $table
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200301 * @return string
Timothy Warren80ab8162011-08-22 18:26:12 -0400302 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200303 protected function _field_data($table)
Timothy Warren80ab8162011-08-22 18:26:12 -0400304 {
Andrey Andreev50293052012-06-25 17:48:49 +0300305 return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
Timothy Warren80ab8162011-08-22 18:26:12 -0400306 }
307
308 // --------------------------------------------------------------------
309
310 /**
Andrey Andreev4be5de12012-03-02 15:45:41 +0200311 * Error
Timothy Warren80ab8162011-08-22 18:26:12 -0400312 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200313 * Returns an array containing code and message of the last
314 * database error that has occured.
Timothy Warren80ab8162011-08-22 18:26:12 -0400315 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200316 * @return array
Timothy Warren80ab8162011-08-22 18:26:12 -0400317 */
Andrey Andreev4be5de12012-03-02 15:45:41 +0200318 public function error()
Timothy Warren80ab8162011-08-22 18:26:12 -0400319 {
Andrey Andreev4be5de12012-03-02 15:45:41 +0200320 $error = array('code' => '00000', 'message' => '');
321 $pdo_error = $this->conn_id->errorInfo();
322
323 if (empty($pdo_error[0]))
324 {
325 return $error;
326 }
327
328 $error['code'] = isset($pdo_error[1]) ? $pdo_error[0].'/'.$pdo_error[1] : $pdo_error[0];
329 if (isset($pdo_error[2]))
330 {
331 $error['message'] = $pdo_error[2];
332 }
333
334 return $error;
Timothy Warren80ab8162011-08-22 18:26:12 -0400335 }
336
337 // --------------------------------------------------------------------
338
339 /**
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400340 * Update_Batch statement
341 *
342 * Generates a platform-specific batch update string from the supplied data
343 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200344 * @param string $table Table name
345 * @param array $values Update data
346 * @param string $index WHERE key
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400347 * @return string
348 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300349 protected function _update_batch($table, $values, $index)
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400350 {
Andrey Andreevdf8894f2012-06-25 16:18:50 +0300351 $ids = array();
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400352 foreach ($values as $key => $val)
353 {
354 $ids[] = $val[$index];
355
356 foreach (array_keys($val) as $field)
357 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100358 if ($field !== $index)
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400359 {
Andrey Andreev838a9d62012-12-03 14:37:47 +0200360 $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400361 }
362 }
363 }
364
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400365 $cases = '';
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400366 foreach ($final as $k => $v)
367 {
368 $cases .= $k.' = CASE '."\n";
Taufan Aditya18209332012-02-09 16:07:27 +0700369
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400370 foreach ($v as $row)
371 {
372 $cases .= $row."\n";
373 }
374
375 $cases .= 'ELSE '.$k.' END, ';
376 }
377
Andrey Andreevb0478652012-07-18 15:34:46 +0300378 $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400379
Andrey Andreevd40459d2012-07-18 16:46:39 +0300380 return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400381 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400382
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300383 // --------------------------------------------------------------------
384
385 /**
386 * Truncate statement
387 *
388 * Generates a platform-specific truncate string from the supplied data
389 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200390 * If the database does not support the TRUNCATE statement,
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300391 * then this method maps to 'DELETE FROM table'
392 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200393 * @param string $table
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300394 * @return string
395 */
396 protected function _truncate($table)
397 {
398 return 'TRUNCATE TABLE '.$table;
399 }
400
Timothy Warren80ab8162011-08-22 18:26:12 -0400401}
402
Timothy Warren80ab8162011-08-22 18:26:12 -0400403/* End of file pdo_driver.php */
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200404/* Location: ./system/database/drivers/pdo/pdo_driver.php */