blob: 184a8df33944d8268fa8fa4cb51e69d180e9c8d2 [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 Andreev50293052012-06-25 17:48:49 +030095 elseif ( ! in_array($this->subdriver, array('4d', 'cubrid', 'dblib', 'firebird', 'ibm', 'informix', 'mysql', 'oci', 'odbc', '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
Taufan Aditya18209332012-02-09 16:07:27 +0700120 // Connecting...
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200121 try
Taufan Aditya18209332012-02-09 16:07:27 +0700122 {
Andrey Andreevf00b9f02012-07-02 14:40:49 +0300123 return @new PDO($this->dsn, $this->username, $this->password, $this->options);
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200124 }
125 catch (PDOException $e)
Taufan Aditya18209332012-02-09 16:07:27 +0700126 {
127 if ($this->db_debug && empty($this->failover))
128 {
129 $this->display_error($e->getMessage(), '', TRUE);
130 }
131
132 return FALSE;
133 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400134 }
135
136 // --------------------------------------------------------------------
137
138 /**
Andrey Andreev3b0130d2012-06-24 21:41:42 +0300139 * Persistent database connection
140 *
141 * @return object
142 */
143 public function db_pconnect()
144 {
145 return $this->db_connect(TRUE);
146 }
147
148 // --------------------------------------------------------------------
149
150 /**
Andrey Andreev08856b82012-03-03 03:19:28 +0200151 * Database version number
Timothy Warren80ab8162011-08-22 18:26:12 -0400152 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400153 * @return string
154 */
Andrey Andreev08856b82012-03-03 03:19:28 +0200155 public function version()
Timothy Warren80ab8162011-08-22 18:26:12 -0400156 {
Andrey Andreev9e3a83a2012-07-05 21:57:41 +0300157 if (isset($this->data_cache['version']))
158 {
159 return $this->data_cache['version'];
160 }
Andrey Andreev2b730372012-11-05 17:01:11 +0200161 elseif ( ! $this->conn_id)
162 {
163 $this->initialize();
164 }
Andrey Andreev9e3a83a2012-07-05 21:57:41 +0300165
166 // Not all subdrivers support the getAttribute() method
167 try
168 {
169 return $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION);
170 }
171 catch (PDOException $e)
172 {
173 return parent::version();
174 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400175 }
176
177 // --------------------------------------------------------------------
178
179 /**
180 * Execute the query
181 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200182 * @param string $sql SQL query
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200183 * @return mixed
Timothy Warren80ab8162011-08-22 18:26:12 -0400184 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200185 protected function _execute($sql)
Timothy Warren80ab8162011-08-22 18:26:12 -0400186 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300187 return $this->conn_id->query($sql);
Timothy Warren80ab8162011-08-22 18:26:12 -0400188 }
189
190 // --------------------------------------------------------------------
191
192 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400193 * Begin Transaction
194 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200195 * @param bool $test_mode
Timothy Warren80ab8162011-08-22 18:26:12 -0400196 * @return bool
197 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200198 public function trans_begin($test_mode = FALSE)
Timothy Warren80ab8162011-08-22 18:26:12 -0400199 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400200 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300201 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400202 {
203 return TRUE;
204 }
205
206 // Reset the transaction failure flag.
207 // If the $test_mode flag is set to TRUE transactions will be rolled back
208 // even if the queries produce a successful result.
Andrey Andreev2387ed32012-04-07 00:11:14 +0300209 $this->_trans_failure = ($test_mode === TRUE);
Timothy Warren80ab8162011-08-22 18:26:12 -0400210
Timothy Warrenab347582011-08-23 12:29:29 -0400211 return $this->conn_id->beginTransaction();
Timothy Warren80ab8162011-08-22 18:26:12 -0400212 }
213
214 // --------------------------------------------------------------------
215
216 /**
217 * Commit Transaction
218 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400219 * @return bool
220 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200221 public function trans_commit()
Timothy Warren80ab8162011-08-22 18:26:12 -0400222 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400223 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300224 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400225 {
226 return TRUE;
227 }
228
Andrey Andreev80144bf2012-04-06 22:19:26 +0300229 return $this->conn_id->commit();
Timothy Warren80ab8162011-08-22 18:26:12 -0400230 }
231
232 // --------------------------------------------------------------------
233
234 /**
235 * Rollback Transaction
236 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400237 * @return bool
238 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200239 public function trans_rollback()
Timothy Warren80ab8162011-08-22 18:26:12 -0400240 {
Timothy Warren80ab8162011-08-22 18:26:12 -0400241 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev80144bf2012-04-06 22:19:26 +0300242 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Timothy Warren80ab8162011-08-22 18:26:12 -0400243 {
244 return TRUE;
245 }
246
Andrey Andreev80144bf2012-04-06 22:19:26 +0300247 return $this->conn_id->rollBack();
Timothy Warren80ab8162011-08-22 18:26:12 -0400248 }
249
250 // --------------------------------------------------------------------
251
252 /**
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200253 * Platform-dependant string escape
Timothy Warren80ab8162011-08-22 18:26:12 -0400254 *
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200255 * @param string
Timothy Warren80ab8162011-08-22 18:26:12 -0400256 * @return string
257 */
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200258 protected function _escape_str($str)
Timothy Warren80ab8162011-08-22 18:26:12 -0400259 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300260 // Escape the string
Timothy Warren47663972011-10-05 16:44:50 -0400261 $str = $this->conn_id->quote($str);
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200262
Andrey Andreev2387ed32012-04-07 00:11:14 +0300263 // If there are duplicated quotes, trim them away
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200264 return ($str[0] === "'")
265 ? substr($str, 1, -1)
266 : $str;
Timothy Warren80ab8162011-08-22 18:26:12 -0400267 }
268
269 // --------------------------------------------------------------------
270
271 /**
272 * Affected Rows
273 *
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200274 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400275 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200276 public function affected_rows()
Timothy Warren80ab8162011-08-22 18:26:12 -0400277 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300278 return is_object($this->result_id) ? $this->result_id->rowCount() : 0;
Timothy Warren80ab8162011-08-22 18:26:12 -0400279 }
280
281 // --------------------------------------------------------------------
282
283 /**
284 * Insert ID
Andrey Andreeva39d6992012-03-01 19:11:39 +0200285 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200286 * @param string $name
Andrey Andreeva39d6992012-03-01 19:11:39 +0200287 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400288 */
Andrey Andreeva39d6992012-03-01 19:11:39 +0200289 public function insert_id($name = NULL)
Timothy Warren80ab8162011-08-22 18:26:12 -0400290 {
Andrey Andreeva39d6992012-03-01 19:11:39 +0200291 return $this->conn_id->lastInsertId($name);
Timothy Warren80ab8162011-08-22 18:26:12 -0400292 }
293
294 // --------------------------------------------------------------------
295
296 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400297 * Field data query
298 *
299 * Generates a platform-specific query so that the column data can be retrieved
300 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200301 * @param string $table
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200302 * @return string
Timothy Warren80ab8162011-08-22 18:26:12 -0400303 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200304 protected function _field_data($table)
Timothy Warren80ab8162011-08-22 18:26:12 -0400305 {
Andrey Andreev50293052012-06-25 17:48:49 +0300306 return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
Timothy Warren80ab8162011-08-22 18:26:12 -0400307 }
308
309 // --------------------------------------------------------------------
310
311 /**
Andrey Andreev4be5de12012-03-02 15:45:41 +0200312 * Error
Timothy Warren80ab8162011-08-22 18:26:12 -0400313 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200314 * Returns an array containing code and message of the last
315 * database error that has occured.
Timothy Warren80ab8162011-08-22 18:26:12 -0400316 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200317 * @return array
Timothy Warren80ab8162011-08-22 18:26:12 -0400318 */
Andrey Andreev4be5de12012-03-02 15:45:41 +0200319 public function error()
Timothy Warren80ab8162011-08-22 18:26:12 -0400320 {
Andrey Andreev4be5de12012-03-02 15:45:41 +0200321 $error = array('code' => '00000', 'message' => '');
322 $pdo_error = $this->conn_id->errorInfo();
323
324 if (empty($pdo_error[0]))
325 {
326 return $error;
327 }
328
329 $error['code'] = isset($pdo_error[1]) ? $pdo_error[0].'/'.$pdo_error[1] : $pdo_error[0];
330 if (isset($pdo_error[2]))
331 {
332 $error['message'] = $pdo_error[2];
333 }
334
335 return $error;
Timothy Warren80ab8162011-08-22 18:26:12 -0400336 }
337
338 // --------------------------------------------------------------------
339
340 /**
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400341 * Update_Batch statement
342 *
343 * Generates a platform-specific batch update string from the supplied data
344 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200345 * @param string $table Table name
346 * @param array $values Update data
347 * @param string $index WHERE key
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400348 * @return string
349 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300350 protected function _update_batch($table, $values, $index)
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400351 {
Andrey Andreevdf8894f2012-06-25 16:18:50 +0300352 $ids = array();
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400353 foreach ($values as $key => $val)
354 {
355 $ids[] = $val[$index];
356
357 foreach (array_keys($val) as $field)
358 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100359 if ($field !== $index)
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400360 {
Andrey Andreev838a9d62012-12-03 14:37:47 +0200361 $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400362 }
363 }
364 }
365
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400366 $cases = '';
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400367 foreach ($final as $k => $v)
368 {
369 $cases .= $k.' = CASE '."\n";
Taufan Aditya18209332012-02-09 16:07:27 +0700370
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400371 foreach ($v as $row)
372 {
373 $cases .= $row."\n";
374 }
375
376 $cases .= 'ELSE '.$k.' END, ';
377 }
378
Andrey Andreevb0478652012-07-18 15:34:46 +0300379 $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400380
Andrey Andreevd40459d2012-07-18 16:46:39 +0300381 return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400382 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400383
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300384 // --------------------------------------------------------------------
385
386 /**
387 * Truncate statement
388 *
389 * Generates a platform-specific truncate string from the supplied data
390 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200391 * If the database does not support the TRUNCATE statement,
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300392 * then this method maps to 'DELETE FROM table'
393 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200394 * @param string $table
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300395 * @return string
396 */
397 protected function _truncate($table)
398 {
399 return 'TRUNCATE TABLE '.$table;
400 }
401
Timothy Warren80ab8162011-08-22 18:26:12 -0400402}
403
Timothy Warren80ab8162011-08-22 18:26:12 -0400404/* End of file pdo_driver.php */
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200405/* Location: ./system/database/drivers/pdo/pdo_driver.php */