blob: c6f84e0f937a95a187011e32dc1fdfe0fb59b325 [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 Andreev125ef472016-01-11 12:33:00 +02009 * Copyright (c) 2014 - 2016, 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 Andreev125ef472016-01-11 12:33:00 +020032 * @copyright Copyright (c) 2014 - 2016, 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 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 }
159
160 // Not all subdrivers support the getAttribute() method
161 try
162 {
163 return $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION);
164 }
165 catch (PDOException $e)
166 {
167 return parent::version();
168 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400169 }
170
171 // --------------------------------------------------------------------
172
173 /**
174 * Execute the query
175 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200176 * @param string $sql SQL query
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200177 * @return mixed
Timothy Warren80ab8162011-08-22 18:26:12 -0400178 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200179 protected function _execute($sql)
Timothy Warren80ab8162011-08-22 18:26:12 -0400180 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300181 return $this->conn_id->query($sql);
Timothy Warren80ab8162011-08-22 18:26:12 -0400182 }
183
184 // --------------------------------------------------------------------
185
186 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400187 * Begin Transaction
188 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400189 * @return bool
190 */
Andrey Andreeva7d4aba2015-10-19 14:39:44 +0300191 protected function _trans_begin()
Timothy Warren80ab8162011-08-22 18:26:12 -0400192 {
Timothy Warrenab347582011-08-23 12:29:29 -0400193 return $this->conn_id->beginTransaction();
Timothy Warren80ab8162011-08-22 18:26:12 -0400194 }
195
196 // --------------------------------------------------------------------
197
198 /**
199 * Commit Transaction
200 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400201 * @return bool
202 */
Andrey Andreeva7d4aba2015-10-19 14:39:44 +0300203 protected function _trans_commit()
Timothy Warren80ab8162011-08-22 18:26:12 -0400204 {
Andrey Andreev80144bf2012-04-06 22:19:26 +0300205 return $this->conn_id->commit();
Timothy Warren80ab8162011-08-22 18:26:12 -0400206 }
207
208 // --------------------------------------------------------------------
209
210 /**
211 * Rollback Transaction
212 *
Timothy Warren80ab8162011-08-22 18:26:12 -0400213 * @return bool
214 */
Andrey Andreeva7d4aba2015-10-19 14:39:44 +0300215 protected function _trans_rollback()
Timothy Warren80ab8162011-08-22 18:26:12 -0400216 {
Andrey Andreev80144bf2012-04-06 22:19:26 +0300217 return $this->conn_id->rollBack();
Timothy Warren80ab8162011-08-22 18:26:12 -0400218 }
219
220 // --------------------------------------------------------------------
221
222 /**
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200223 * Platform-dependant string escape
Timothy Warren80ab8162011-08-22 18:26:12 -0400224 *
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200225 * @param string
Timothy Warren80ab8162011-08-22 18:26:12 -0400226 * @return string
227 */
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200228 protected function _escape_str($str)
Timothy Warren80ab8162011-08-22 18:26:12 -0400229 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300230 // Escape the string
Timothy Warren47663972011-10-05 16:44:50 -0400231 $str = $this->conn_id->quote($str);
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200232
Andrey Andreev2387ed32012-04-07 00:11:14 +0300233 // If there are duplicated quotes, trim them away
Andrey Andreev0b6a4922013-01-10 16:53:44 +0200234 return ($str[0] === "'")
235 ? substr($str, 1, -1)
236 : $str;
Timothy Warren80ab8162011-08-22 18:26:12 -0400237 }
238
239 // --------------------------------------------------------------------
240
241 /**
242 * Affected Rows
243 *
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200244 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400245 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200246 public function affected_rows()
Timothy Warren80ab8162011-08-22 18:26:12 -0400247 {
Andrey Andreev2387ed32012-04-07 00:11:14 +0300248 return is_object($this->result_id) ? $this->result_id->rowCount() : 0;
Timothy Warren80ab8162011-08-22 18:26:12 -0400249 }
250
251 // --------------------------------------------------------------------
252
253 /**
254 * Insert ID
Andrey Andreeva39d6992012-03-01 19:11:39 +0200255 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200256 * @param string $name
Andrey Andreeva39d6992012-03-01 19:11:39 +0200257 * @return int
Timothy Warren80ab8162011-08-22 18:26:12 -0400258 */
Andrey Andreeva39d6992012-03-01 19:11:39 +0200259 public function insert_id($name = NULL)
Timothy Warren80ab8162011-08-22 18:26:12 -0400260 {
Andrey Andreeva39d6992012-03-01 19:11:39 +0200261 return $this->conn_id->lastInsertId($name);
Timothy Warren80ab8162011-08-22 18:26:12 -0400262 }
263
264 // --------------------------------------------------------------------
265
266 /**
Timothy Warren80ab8162011-08-22 18:26:12 -0400267 * Field data query
268 *
269 * Generates a platform-specific query so that the column data can be retrieved
270 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200271 * @param string $table
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200272 * @return string
Timothy Warren80ab8162011-08-22 18:26:12 -0400273 */
Andrey Andreevbd44d5a2012-03-20 22:59:29 +0200274 protected function _field_data($table)
Timothy Warren80ab8162011-08-22 18:26:12 -0400275 {
Andrey Andreev50293052012-06-25 17:48:49 +0300276 return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
Timothy Warren80ab8162011-08-22 18:26:12 -0400277 }
278
279 // --------------------------------------------------------------------
280
281 /**
Andrey Andreev4be5de12012-03-02 15:45:41 +0200282 * Error
Timothy Warren80ab8162011-08-22 18:26:12 -0400283 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200284 * Returns an array containing code and message of the last
285 * database error that has occured.
Timothy Warren80ab8162011-08-22 18:26:12 -0400286 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200287 * @return array
Timothy Warren80ab8162011-08-22 18:26:12 -0400288 */
Andrey Andreev4be5de12012-03-02 15:45:41 +0200289 public function error()
Timothy Warren80ab8162011-08-22 18:26:12 -0400290 {
Andrey Andreev4be5de12012-03-02 15:45:41 +0200291 $error = array('code' => '00000', 'message' => '');
292 $pdo_error = $this->conn_id->errorInfo();
293
294 if (empty($pdo_error[0]))
295 {
296 return $error;
297 }
298
299 $error['code'] = isset($pdo_error[1]) ? $pdo_error[0].'/'.$pdo_error[1] : $pdo_error[0];
300 if (isset($pdo_error[2]))
301 {
302 $error['message'] = $pdo_error[2];
303 }
304
305 return $error;
Timothy Warren80ab8162011-08-22 18:26:12 -0400306 }
307
308 // --------------------------------------------------------------------
309
310 /**
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400311 * Update_Batch statement
312 *
313 * Generates a platform-specific batch update string from the supplied data
314 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200315 * @param string $table Table name
316 * @param array $values Update data
317 * @param string $index WHERE key
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400318 * @return string
319 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300320 protected function _update_batch($table, $values, $index)
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400321 {
Andrey Andreevdf8894f2012-06-25 16:18:50 +0300322 $ids = array();
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400323 foreach ($values as $key => $val)
324 {
325 $ids[] = $val[$index];
326
327 foreach (array_keys($val) as $field)
328 {
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100329 if ($field !== $index)
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400330 {
Andrey Andreev838a9d62012-12-03 14:37:47 +0200331 $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field];
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400332 }
333 }
334 }
335
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400336 $cases = '';
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400337 foreach ($final as $k => $v)
338 {
339 $cases .= $k.' = CASE '."\n";
Taufan Aditya18209332012-02-09 16:07:27 +0700340
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400341 foreach ($v as $row)
342 {
343 $cases .= $row."\n";
344 }
345
346 $cases .= 'ELSE '.$k.' END, ';
347 }
348
Andrey Andreevb0478652012-07-18 15:34:46 +0300349 $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400350
Andrey Andreevd40459d2012-07-18 16:46:39 +0300351 return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
Timothy Warrenb5a43b02011-10-04 17:26:04 -0400352 }
Timothy Warren80ab8162011-08-22 18:26:12 -0400353
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300354 // --------------------------------------------------------------------
355
356 /**
357 * Truncate statement
358 *
359 * Generates a platform-specific truncate string from the supplied data
360 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200361 * If the database does not support the TRUNCATE statement,
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300362 * then this method maps to 'DELETE FROM table'
363 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200364 * @param string $table
Andrey Andreeve61b19f2012-06-25 18:11:39 +0300365 * @return string
366 */
367 protected function _truncate($table)
368 {
369 return 'TRUNCATE TABLE '.$table;
370 }
371
Timothy Warren80ab8162011-08-22 18:26:12 -0400372}