blob: a61450d4c63905e870c1ceb3007562aa5533418a [file] [log] [blame]
Derek Jones37f4b9c2011-07-01 17:56:50 -05001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
3 * CodeIgniter
4 *
Greg Aker741de1c2010-11-10 14:52:57 -06005 * An open source application development framework for PHP 5.1.6 or newer
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
8 *
9 * Licensed under the Open Software License version 3.0
10 *
11 * 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 *
Derek Allard2067d1a2008-11-13 22:59:24 +000019 * @package CodeIgniter
Derek Jonesf4a4bd82011-10-20 12:18:42 -050020 * @author EllisLab Dev Team
Greg Aker0defe5d2012-01-01 18:46:41 -060021 * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
Derek Jonesf4a4bd82011-10-20 12:18:42 -050022 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
Derek Allard2067d1a2008-11-13 22:59:24 +000023 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @filesource
26 */
27
28// ------------------------------------------------------------------------
29
30/**
31 * Database Driver Class
32 *
33 * This is the platform-independent base DB implementation class.
34 * This class will not be called directly. Rather, the adapter
35 * class for the specific database will extend and instantiate it.
36 *
37 * @package CodeIgniter
38 * @subpackage Drivers
39 * @category Database
Derek Jonesf4a4bd82011-10-20 12:18:42 -050040 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000041 * @link http://codeigniter.com/user_guide/database/
42 */
43class CI_DB_driver {
44
45 var $username;
46 var $password;
47 var $hostname;
48 var $database;
49 var $dbdriver = 'mysql';
50 var $dbprefix = '';
51 var $char_set = 'utf8';
52 var $dbcollat = 'utf8_general_ci';
53 var $autoinit = TRUE; // Whether to automatically initialize the DB
54 var $swap_pre = '';
55 var $port = '';
56 var $pconnect = FALSE;
57 var $conn_id = FALSE;
58 var $result_id = FALSE;
59 var $db_debug = FALSE;
60 var $benchmark = 0;
61 var $query_count = 0;
62 var $bind_marker = '?';
63 var $save_queries = TRUE;
64 var $queries = array();
65 var $query_times = array();
66 var $data_cache = array();
67 var $trans_enabled = TRUE;
68 var $trans_strict = TRUE;
69 var $_trans_depth = 0;
70 var $_trans_status = TRUE; // Used with transactions to determine if a rollback should occur
71 var $cache_on = FALSE;
72 var $cachedir = '';
73 var $cache_autodel = FALSE;
74 var $CACHE; // The cache class object
75
76 // Private variables
77 var $_protect_identifiers = TRUE;
78 var $_reserved_identifiers = array('*'); // Identifiers that should NOT be escaped
79
Derek Allard2067d1a2008-11-13 22:59:24 +000080 /**
Derek Jones37f4b9c2011-07-01 17:56:50 -050081 * Constructor. Accepts one parameter containing the database
Derek Allard2067d1a2008-11-13 22:59:24 +000082 * connection settings.
83 *
84 * @param array
Barry Mienydd671972010-10-04 16:33:58 +020085 */
Timothy Warrena2097a02011-10-10 10:10:46 -040086 function __construct($params)
Derek Allard2067d1a2008-11-13 22:59:24 +000087 {
88 if (is_array($params))
89 {
90 foreach ($params as $key => $val)
91 {
92 $this->$key = $val;
93 }
94 }
95
96 log_message('debug', 'Database Driver Class Initialized');
97 }
Barry Mienydd671972010-10-04 16:33:58 +020098
Derek Allard2067d1a2008-11-13 22:59:24 +000099 // --------------------------------------------------------------------
100
101 /**
102 * Initialize Database Settings
103 *
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200104 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200105 */
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200106 public function initialize()
Derek Allard2067d1a2008-11-13 22:59:24 +0000107 {
108 // If an existing connection resource is available
109 // there is no need to connect and select the database
110 if (is_resource($this->conn_id) OR is_object($this->conn_id))
111 {
112 return TRUE;
113 }
Barry Mienydd671972010-10-04 16:33:58 +0200114
Derek Allard2067d1a2008-11-13 22:59:24 +0000115 // ----------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200116
Derek Allard2067d1a2008-11-13 22:59:24 +0000117 // Connect to the database and set the connection ID
118 $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
119
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200120 // No connection resource? Check if there is a failover else throw an error
Derek Allard2067d1a2008-11-13 22:59:24 +0000121 if ( ! $this->conn_id)
122 {
Felix Balfoort5d581b62011-11-29 15:53:01 +0100123 // Check if there is a failover set
124 if ( ! empty($this->failover) && is_array($this->failover))
Derek Allard2067d1a2008-11-13 22:59:24 +0000125 {
Felix Balfoort5d581b62011-11-29 15:53:01 +0100126 // Go over all the failovers
127 foreach ($this->failover as $failover)
128 {
129 // Replace the current settings with those of the failover
130 foreach ($failover as $key => $val)
131 {
132 $this->$key = $val;
133 }
134
135 // Try to connect
136 $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
137
138 // If a connection is made break the foreach loop
139 if ($this->conn_id)
140 {
141 break;
142 }
143 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000144 }
Felix Balfoort5d581b62011-11-29 15:53:01 +0100145
146 // We still don't have a connection?
147 if ( ! $this->conn_id)
148 {
149 log_message('error', 'Unable to connect to the database');
150
151 if ($this->db_debug)
152 {
153 $this->display_error('db_unable_to_connect');
154 }
155 return FALSE;
156 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000157 }
158
159 // ----------------------------------------------------------------
160
161 // Select the DB... assuming a database name is specified in the config file
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200162 if ($this->database !== '' && ! $this->db_select())
Derek Allard2067d1a2008-11-13 22:59:24 +0000163 {
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200164 log_message('error', 'Unable to select database: '.$this->database);
Barry Mienydd671972010-10-04 16:33:58 +0200165
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200166 if ($this->db_debug)
Derek Allard2067d1a2008-11-13 22:59:24 +0000167 {
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200168 $this->display_error('db_unable_to_select', $this->database);
Derek Allard2067d1a2008-11-13 22:59:24 +0000169 }
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200170 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000171 }
172
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200173 // Now we set the character set and that's all
174 return $this->db_set_charset($this->char_set, $this->dbcollat);
Derek Allard2067d1a2008-11-13 22:59:24 +0000175 }
Barry Mienydd671972010-10-04 16:33:58 +0200176
Derek Allard2067d1a2008-11-13 22:59:24 +0000177 // --------------------------------------------------------------------
178
179 /**
180 * Set client character set
181 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000182 * @param string
183 * @param string
Andrey Andreev063f5962012-02-27 12:20:52 +0200184 * @return bool
Derek Allard2067d1a2008-11-13 22:59:24 +0000185 */
Andrey Andreev063f5962012-02-27 12:20:52 +0200186 public function db_set_charset($charset, $collation = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000187 {
Andrey Andreev063f5962012-02-27 12:20:52 +0200188 if (method_exists($this, '_db_set_charset') && ! $this->_db_set_charset($charset, $collation))
Derek Allard2067d1a2008-11-13 22:59:24 +0000189 {
Andrey Andreev063f5962012-02-27 12:20:52 +0200190 log_message('error', 'Unable to set database connection charset: '.$charset);
Barry Mienydd671972010-10-04 16:33:58 +0200191
Derek Allard2067d1a2008-11-13 22:59:24 +0000192 if ($this->db_debug)
193 {
Andrey Andreev063f5962012-02-27 12:20:52 +0200194 $this->display_error('db_unable_to_set_charset', $charset);
Derek Allard2067d1a2008-11-13 22:59:24 +0000195 }
Barry Mienydd671972010-10-04 16:33:58 +0200196
Derek Allard2067d1a2008-11-13 22:59:24 +0000197 return FALSE;
198 }
Barry Mienydd671972010-10-04 16:33:58 +0200199
Derek Allard2067d1a2008-11-13 22:59:24 +0000200 return TRUE;
201 }
Barry Mienydd671972010-10-04 16:33:58 +0200202
Derek Allard2067d1a2008-11-13 22:59:24 +0000203 // --------------------------------------------------------------------
204
205 /**
206 * The name of the platform in use (mysql, mssql, etc...)
207 *
208 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200209 * @return string
210 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000211 function platform()
212 {
213 return $this->dbdriver;
214 }
215
216 // --------------------------------------------------------------------
217
218 /**
Andrey Andreev08856b82012-03-03 03:19:28 +0200219 * Database version number
Derek Allard2067d1a2008-11-13 22:59:24 +0000220 *
Andrey Andreev08856b82012-03-03 03:19:28 +0200221 * Returns a string containing the version of the database being used.
222 * Most drivers will override this method.
223 *
Barry Mienydd671972010-10-04 16:33:58 +0200224 * @return string
225 */
Andrey Andreev08856b82012-03-03 03:19:28 +0200226 public function version()
Derek Allard2067d1a2008-11-13 22:59:24 +0000227 {
Andrey Andreev08856b82012-03-03 03:19:28 +0200228 if (isset($this->data_cache['version']))
229 {
230 return $this->data_cache['version'];
231 }
232
Derek Allard2067d1a2008-11-13 22:59:24 +0000233 if (FALSE === ($sql = $this->_version()))
234 {
Andrey Andreev08856b82012-03-03 03:19:28 +0200235 return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000236 }
Derek Allard3683f772009-12-16 17:32:33 +0000237
Andrey Andreev08856b82012-03-03 03:19:28 +0200238 $query = $this->query($sql);
239 $query = $query->row();
240 return $this->data_cache['version'] = $query->ver;
241 }
Derek Allard3683f772009-12-16 17:32:33 +0000242
Andrey Andreev08856b82012-03-03 03:19:28 +0200243 // --------------------------------------------------------------------
244
245 /**
246 * Version number query string
247 *
248 * @return string
249 */
250 protected function _version()
251 {
252 return 'SELECT VERSION() AS ver';
Derek Allard2067d1a2008-11-13 22:59:24 +0000253 }
Barry Mienydd671972010-10-04 16:33:58 +0200254
Derek Allard2067d1a2008-11-13 22:59:24 +0000255 // --------------------------------------------------------------------
256
257 /**
258 * Execute the query
259 *
260 * Accepts an SQL string as input and returns a result object upon
Derek Jones37f4b9c2011-07-01 17:56:50 -0500261 * successful execution of a "read" type query. Returns boolean TRUE
Derek Allard2067d1a2008-11-13 22:59:24 +0000262 * upon successful execution of a "write" type query. Returns boolean
263 * FALSE upon failure, and if the $db_debug variable is set to TRUE
264 * will raise an error.
265 *
266 * @access public
267 * @param string An SQL query string
268 * @param array An array of binding data
Barry Mienydd671972010-10-04 16:33:58 +0200269 * @return mixed
270 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000271 function query($sql, $binds = FALSE, $return_object = TRUE)
272 {
273 if ($sql == '')
274 {
Niklas Nilssond2018ee2011-08-30 13:39:42 +0200275 log_message('error', 'Invalid query: '.$sql);
276
Derek Allard2067d1a2008-11-13 22:59:24 +0000277 if ($this->db_debug)
278 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000279 return $this->display_error('db_invalid_query');
280 }
281 return FALSE;
282 }
283
284 // Verify table prefix and replace if necessary
285 if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) )
Derek Jonese7792202010-03-02 17:24:46 -0600286 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000287 $sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql);
288 }
Derek Jonese7792202010-03-02 17:24:46 -0600289
Ryan Dialef7474c2012-03-01 16:11:36 -0500290 // Compile binds if needed
291 if ($binds !== FALSE)
292 {
293 $sql = $this->compile_binds($sql, $binds);
294 }
295
Derek Jones37f4b9c2011-07-01 17:56:50 -0500296 // Is query caching enabled? If the query is a "read type"
Derek Allard2067d1a2008-11-13 22:59:24 +0000297 // we will load the caching class and return the previously
298 // cached query if it exists
299 if ($this->cache_on == TRUE AND stristr($sql, 'SELECT'))
300 {
301 if ($this->_cache_init())
302 {
303 $this->load_rdriver();
304 if (FALSE !== ($cache = $this->CACHE->read($sql)))
305 {
306 return $cache;
307 }
308 }
309 }
Barry Mienydd671972010-10-04 16:33:58 +0200310
Derek Jones37f4b9c2011-07-01 17:56:50 -0500311 // Save the query for debugging
Derek Allard2067d1a2008-11-13 22:59:24 +0000312 if ($this->save_queries == TRUE)
313 {
314 $this->queries[] = $sql;
315 }
Barry Mienydd671972010-10-04 16:33:58 +0200316
Derek Allard2067d1a2008-11-13 22:59:24 +0000317 // Start the Query Timer
318 $time_start = list($sm, $ss) = explode(' ', microtime());
Barry Mienydd671972010-10-04 16:33:58 +0200319
Derek Allard2067d1a2008-11-13 22:59:24 +0000320 // Run the Query
321 if (FALSE === ($this->result_id = $this->simple_query($sql)))
322 {
323 if ($this->save_queries == TRUE)
324 {
325 $this->query_times[] = 0;
326 }
Barry Mienydd671972010-10-04 16:33:58 +0200327
Derek Allard2067d1a2008-11-13 22:59:24 +0000328 // This will trigger a rollback if transactions are being used
329 $this->_trans_status = FALSE;
330
Andrey Andreev4be5de12012-03-02 15:45:41 +0200331 // Grab the error now, as we might run some additional queries before displaying the error
332 $error = $this->error();
Niklas Nilssond2018ee2011-08-30 13:39:42 +0200333
334 // Log errors
Andrey Andreev4be5de12012-03-02 15:45:41 +0200335 log_message('error', 'Query error: '.$error['message']);
Niklas Nilssond2018ee2011-08-30 13:39:42 +0200336
Derek Allard2067d1a2008-11-13 22:59:24 +0000337 if ($this->db_debug)
338 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000339 // We call this function in order to roll-back queries
Andrey Andreev4be5de12012-03-02 15:45:41 +0200340 // if transactions are enabled. If we don't call this here
Barry Mienydd671972010-10-04 16:33:58 +0200341 // the error message will trigger an exit, causing the
Derek Allard2067d1a2008-11-13 22:59:24 +0000342 // transactions to remain in limbo.
343 $this->trans_complete();
344
Niklas Nilssond2018ee2011-08-30 13:39:42 +0200345 // Display errors
Derek Allard2067d1a2008-11-13 22:59:24 +0000346 return $this->display_error(
Andrey Andreev4be5de12012-03-02 15:45:41 +0200347 array(
348 'Error Number: '.$error['code'],
349 $error['message'],
350 $sql
351 )
352 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000353 }
Barry Mienydd671972010-10-04 16:33:58 +0200354
Derek Allard2067d1a2008-11-13 22:59:24 +0000355 return FALSE;
356 }
Barry Mienydd671972010-10-04 16:33:58 +0200357
Derek Allard2067d1a2008-11-13 22:59:24 +0000358 // Stop and aggregate the query time results
359 $time_end = list($em, $es) = explode(' ', microtime());
360 $this->benchmark += ($em + $es) - ($sm + $ss);
361
362 if ($this->save_queries == TRUE)
363 {
364 $this->query_times[] = ($em + $es) - ($sm + $ss);
365 }
Barry Mienydd671972010-10-04 16:33:58 +0200366
Derek Allard2067d1a2008-11-13 22:59:24 +0000367 // Increment the query counter
368 $this->query_count++;
Barry Mienydd671972010-10-04 16:33:58 +0200369
Derek Allard2067d1a2008-11-13 22:59:24 +0000370 // Was the query a "write" type?
371 // If so we'll simply return true
372 if ($this->is_write_type($sql) === TRUE)
373 {
374 // If caching is enabled we'll auto-cleanup any
375 // existing files related to this particular URI
376 if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init())
377 {
378 $this->CACHE->delete();
379 }
Barry Mienydd671972010-10-04 16:33:58 +0200380
Derek Allard2067d1a2008-11-13 22:59:24 +0000381 return TRUE;
382 }
Barry Mienydd671972010-10-04 16:33:58 +0200383
Derek Allard2067d1a2008-11-13 22:59:24 +0000384 // Return TRUE if we don't need to create a result object
385 // Currently only the Oracle driver uses this when stored
386 // procedures are used
387 if ($return_object !== TRUE)
388 {
389 return TRUE;
390 }
Barry Mienydd671972010-10-04 16:33:58 +0200391
392 // Load and instantiate the result driver
Andrey Andreev57bdeb62012-03-05 15:59:16 +0200393 $driver = $this->load_rdriver();
394 $RES = new $driver($this);
Barry Mienydd671972010-10-04 16:33:58 +0200395
Derek Allard2067d1a2008-11-13 22:59:24 +0000396 $RES->num_rows = $RES->num_rows();
Barry Mienydd671972010-10-04 16:33:58 +0200397
Derek Jones37f4b9c2011-07-01 17:56:50 -0500398 // Is query caching enabled? If so, we'll serialize the
Derek Allard2067d1a2008-11-13 22:59:24 +0000399 // result object and save it to a cache file.
400 if ($this->cache_on == TRUE AND $this->_cache_init())
401 {
402 // We'll create a new instance of the result object
403 // only without the platform specific driver since
404 // we can't use it with cached data (the query result
405 // resource ID won't be any good once we've cached the
406 // result object, so we'll have to compile the data
407 // and save it)
408 $CR = new CI_DB_result();
Barry Mienydd671972010-10-04 16:33:58 +0200409 $CR->num_rows = $RES->num_rows();
Derek Allard2067d1a2008-11-13 22:59:24 +0000410 $CR->result_object = $RES->result_object();
411 $CR->result_array = $RES->result_array();
Barry Mienydd671972010-10-04 16:33:58 +0200412
Derek Allard2067d1a2008-11-13 22:59:24 +0000413 // Reset these since cached objects can not utilize resource IDs.
414 $CR->conn_id = NULL;
415 $CR->result_id = NULL;
416
417 $this->CACHE->write($sql, $CR);
418 }
Barry Mienydd671972010-10-04 16:33:58 +0200419
Derek Allard2067d1a2008-11-13 22:59:24 +0000420 return $RES;
421 }
422
423 // --------------------------------------------------------------------
424
425 /**
426 * Load the result drivers
427 *
428 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200429 * @return string the name of the result class
430 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000431 function load_rdriver()
432 {
433 $driver = 'CI_DB_'.$this->dbdriver.'_result';
434
435 if ( ! class_exists($driver))
436 {
Greg Aker3a746652011-04-19 10:59:47 -0500437 include_once(BASEPATH.'database/DB_result.php');
438 include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result.php');
Derek Allard2067d1a2008-11-13 22:59:24 +0000439 }
Barry Mienydd671972010-10-04 16:33:58 +0200440
Derek Allard2067d1a2008-11-13 22:59:24 +0000441 return $driver;
442 }
Barry Mienydd671972010-10-04 16:33:58 +0200443
Derek Allard2067d1a2008-11-13 22:59:24 +0000444 // --------------------------------------------------------------------
445
446 /**
447 * Simple Query
Derek Jones37f4b9c2011-07-01 17:56:50 -0500448 * This is a simplified version of the query() function. Internally
Derek Allard2067d1a2008-11-13 22:59:24 +0000449 * we only use it when running transaction commands since they do
450 * not require all the features of the main query() function.
451 *
452 * @access public
453 * @param string the sql query
Barry Mienydd671972010-10-04 16:33:58 +0200454 * @return mixed
455 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000456 function simple_query($sql)
457 {
458 if ( ! $this->conn_id)
459 {
460 $this->initialize();
461 }
462
463 return $this->_execute($sql);
464 }
Barry Mienydd671972010-10-04 16:33:58 +0200465
Derek Allard2067d1a2008-11-13 22:59:24 +0000466 // --------------------------------------------------------------------
467
468 /**
469 * Disable Transactions
470 * This permits transactions to be disabled at run-time.
471 *
472 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200473 * @return void
474 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000475 function trans_off()
476 {
477 $this->trans_enabled = FALSE;
478 }
479
480 // --------------------------------------------------------------------
481
482 /**
483 * Enable/disable Transaction Strict Mode
484 * When strict mode is enabled, if you are running multiple groups of
485 * transactions, if one group fails all groups will be rolled back.
486 * If strict mode is disabled, each group is treated autonomously, meaning
487 * a failure of one group will not affect any others
488 *
489 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200490 * @return void
491 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000492 function trans_strict($mode = TRUE)
493 {
494 $this->trans_strict = is_bool($mode) ? $mode : TRUE;
495 }
Barry Mienydd671972010-10-04 16:33:58 +0200496
Derek Allard2067d1a2008-11-13 22:59:24 +0000497 // --------------------------------------------------------------------
498
499 /**
500 * Start Transaction
501 *
502 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200503 * @return void
504 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000505 function trans_start($test_mode = FALSE)
Barry Mienydd671972010-10-04 16:33:58 +0200506 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000507 if ( ! $this->trans_enabled)
508 {
509 return FALSE;
510 }
511
512 // When transactions are nested we only begin/commit/rollback the outermost ones
513 if ($this->_trans_depth > 0)
514 {
515 $this->_trans_depth += 1;
516 return;
517 }
Barry Mienydd671972010-10-04 16:33:58 +0200518
Derek Allard2067d1a2008-11-13 22:59:24 +0000519 $this->trans_begin($test_mode);
Jacob Terry07fcedf2011-11-22 11:21:36 -0500520 $this->_trans_depth += 1;
Derek Allard2067d1a2008-11-13 22:59:24 +0000521 }
522
523 // --------------------------------------------------------------------
524
525 /**
526 * Complete Transaction
527 *
528 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200529 * @return bool
530 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000531 function trans_complete()
532 {
533 if ( ! $this->trans_enabled)
534 {
535 return FALSE;
536 }
Barry Mienydd671972010-10-04 16:33:58 +0200537
Derek Allard2067d1a2008-11-13 22:59:24 +0000538 // When transactions are nested we only begin/commit/rollback the outermost ones
539 if ($this->_trans_depth > 1)
540 {
541 $this->_trans_depth -= 1;
542 return TRUE;
543 }
Jacob Terry07fcedf2011-11-22 11:21:36 -0500544 else
545 {
546 $this->_trans_depth = 0;
547 }
Barry Mienydd671972010-10-04 16:33:58 +0200548
Derek Allard2067d1a2008-11-13 22:59:24 +0000549 // The query() function will set this flag to FALSE in the event that a query failed
550 if ($this->_trans_status === FALSE)
551 {
552 $this->trans_rollback();
Barry Mienydd671972010-10-04 16:33:58 +0200553
Derek Allard2067d1a2008-11-13 22:59:24 +0000554 // If we are NOT running in strict mode, we will reset
555 // the _trans_status flag so that subsequent groups of transactions
556 // will be permitted.
557 if ($this->trans_strict === FALSE)
558 {
559 $this->_trans_status = TRUE;
560 }
561
562 log_message('debug', 'DB Transaction Failure');
563 return FALSE;
564 }
Barry Mienydd671972010-10-04 16:33:58 +0200565
Derek Allard2067d1a2008-11-13 22:59:24 +0000566 $this->trans_commit();
567 return TRUE;
568 }
569
570 // --------------------------------------------------------------------
571
572 /**
573 * Lets you retrieve the transaction flag to determine if it has failed
574 *
575 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200576 * @return bool
577 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000578 function trans_status()
579 {
580 return $this->_trans_status;
581 }
582
583 // --------------------------------------------------------------------
584
585 /**
586 * Compile Bindings
587 *
588 * @access public
589 * @param string the sql statement
590 * @param array an array of bind data
Barry Mienydd671972010-10-04 16:33:58 +0200591 * @return string
592 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000593 function compile_binds($sql, $binds)
594 {
595 if (strpos($sql, $this->bind_marker) === FALSE)
596 {
597 return $sql;
598 }
Barry Mienydd671972010-10-04 16:33:58 +0200599
Derek Allard2067d1a2008-11-13 22:59:24 +0000600 if ( ! is_array($binds))
601 {
602 $binds = array($binds);
603 }
Barry Mienydd671972010-10-04 16:33:58 +0200604
Derek Allard2067d1a2008-11-13 22:59:24 +0000605 // Get the sql segments around the bind markers
606 $segments = explode($this->bind_marker, $sql);
607
608 // The count of bind should be 1 less then the count of segments
609 // If there are more bind arguments trim it down
610 if (count($binds) >= count($segments)) {
611 $binds = array_slice($binds, 0, count($segments)-1);
612 }
613
614 // Construct the binded query
615 $result = $segments[0];
616 $i = 0;
617 foreach ($binds as $bind)
618 {
619 $result .= $this->escape($bind);
620 $result .= $segments[++$i];
621 }
622
623 return $result;
624 }
Barry Mienydd671972010-10-04 16:33:58 +0200625
Derek Allard2067d1a2008-11-13 22:59:24 +0000626 // --------------------------------------------------------------------
627
628 /**
629 * Determines if a query is a "write" type.
630 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000631 * @param string An SQL query string
Andrey Andreev67f71a42012-03-01 16:18:42 +0200632 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200633 */
Andrey Andreev67f71a42012-03-01 16:18:42 +0200634 public function is_write_type($sql)
Derek Allard2067d1a2008-11-13 22:59:24 +0000635 {
Andrey Andreev5fa72982012-03-03 04:13:20 +0200636 return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|OPTIMIZE|REINDEX)\s+/i', $sql);
Derek Allard2067d1a2008-11-13 22:59:24 +0000637 }
Barry Mienydd671972010-10-04 16:33:58 +0200638
Derek Allard2067d1a2008-11-13 22:59:24 +0000639 // --------------------------------------------------------------------
640
641 /**
642 * Calculate the aggregate query elapsed time
643 *
644 * @access public
645 * @param integer The number of decimal places
Barry Mienydd671972010-10-04 16:33:58 +0200646 * @return integer
647 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000648 function elapsed_time($decimals = 6)
649 {
650 return number_format($this->benchmark, $decimals);
651 }
Barry Mienydd671972010-10-04 16:33:58 +0200652
Derek Allard2067d1a2008-11-13 22:59:24 +0000653 // --------------------------------------------------------------------
654
655 /**
656 * Returns the total number of queries
657 *
658 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200659 * @return integer
660 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000661 function total_queries()
662 {
663 return $this->query_count;
664 }
Barry Mienydd671972010-10-04 16:33:58 +0200665
Derek Allard2067d1a2008-11-13 22:59:24 +0000666 // --------------------------------------------------------------------
667
668 /**
669 * Returns the last query that was executed
670 *
671 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200672 * @return void
673 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000674 function last_query()
675 {
676 return end($this->queries);
677 }
678
679 // --------------------------------------------------------------------
680
681 /**
682 * "Smart" Escape String
683 *
684 * Escapes data based on type
685 * Sets boolean and null types
686 *
687 * @access public
688 * @param string
Barry Mienydd671972010-10-04 16:33:58 +0200689 * @return mixed
690 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000691 function escape($str)
Barry Mienydd671972010-10-04 16:33:58 +0200692 {
Derek Jonesa377bdd2009-02-11 18:55:24 +0000693 if (is_string($str))
Derek Allard2067d1a2008-11-13 22:59:24 +0000694 {
Derek Jonesa377bdd2009-02-11 18:55:24 +0000695 $str = "'".$this->escape_str($str)."'";
696 }
697 elseif (is_bool($str))
698 {
699 $str = ($str === FALSE) ? 0 : 1;
700 }
701 elseif (is_null($str))
702 {
703 $str = 'NULL';
704 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000705
706 return $str;
707 }
708
709 // --------------------------------------------------------------------
Derek Jonese7792202010-03-02 17:24:46 -0600710
Derek Jonese4ed5832009-02-20 21:44:59 +0000711 /**
Derek Jonesbdc7fb92009-02-20 21:55:10 +0000712 * Escape LIKE String
Derek Jonese4ed5832009-02-20 21:44:59 +0000713 *
714 * Calls the individual driver for platform
715 * specific escaping for LIKE conditions
Barry Mienydd671972010-10-04 16:33:58 +0200716 *
Derek Jonese4ed5832009-02-20 21:44:59 +0000717 * @access public
718 * @param string
719 * @return mixed
720 */
Barry Mienydd671972010-10-04 16:33:58 +0200721 function escape_like_str($str)
722 {
723 return $this->escape_str($str, TRUE);
Derek Jonese4ed5832009-02-20 21:44:59 +0000724 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000725
Derek Jonese4ed5832009-02-20 21:44:59 +0000726 // --------------------------------------------------------------------
Derek Jonese7792202010-03-02 17:24:46 -0600727
Derek Allard2067d1a2008-11-13 22:59:24 +0000728 /**
729 * Primary
730 *
Derek Jones37f4b9c2011-07-01 17:56:50 -0500731 * Retrieves the primary key. It assumes that the row in the first
Derek Allard2067d1a2008-11-13 22:59:24 +0000732 * position is the primary key
733 *
734 * @access public
735 * @param string the table name
Barry Mienydd671972010-10-04 16:33:58 +0200736 * @return string
737 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000738 function primary($table = '')
Barry Mienydd671972010-10-04 16:33:58 +0200739 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000740 $fields = $this->list_fields($table);
Barry Mienydd671972010-10-04 16:33:58 +0200741
Derek Allard2067d1a2008-11-13 22:59:24 +0000742 if ( ! is_array($fields))
743 {
744 return FALSE;
745 }
746
747 return current($fields);
748 }
749
750 // --------------------------------------------------------------------
751
752 /**
753 * Returns an array of table names
754 *
755 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200756 * @return array
757 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000758 function list_tables($constrain_by_prefix = FALSE)
759 {
760 // Is there a cached result?
761 if (isset($this->data_cache['table_names']))
762 {
763 return $this->data_cache['table_names'];
764 }
Barry Mienydd671972010-10-04 16:33:58 +0200765
Derek Allard2067d1a2008-11-13 22:59:24 +0000766 if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
767 {
768 if ($this->db_debug)
769 {
770 return $this->display_error('db_unsupported_function');
771 }
772 return FALSE;
773 }
774
775 $retval = array();
776 $query = $this->query($sql);
Barry Mienydd671972010-10-04 16:33:58 +0200777
Derek Allard2067d1a2008-11-13 22:59:24 +0000778 if ($query->num_rows() > 0)
779 {
Taufan Aditya18209332012-02-09 16:07:27 +0700780 $table = FALSE;
781 $rows = $query->result_array();
782 $key = (($row = current($rows)) && in_array('table_name', array_map('strtolower', array_keys($row))));
783
784 if ($key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000785 {
Taufan Aditya18209332012-02-09 16:07:27 +0700786 $table = array_key_exists('TABLE_NAME', $row) ? 'TABLE_NAME' : 'table_name';
787 }
788
789 foreach ($rows as $row)
790 {
791 $retval[] = ( ! $table) ? current($row) : $row[$table];
Derek Allard2067d1a2008-11-13 22:59:24 +0000792 }
793 }
794
795 $this->data_cache['table_names'] = $retval;
Taufan Aditya18209332012-02-09 16:07:27 +0700796
Derek Allard2067d1a2008-11-13 22:59:24 +0000797 return $this->data_cache['table_names'];
798 }
Barry Mienydd671972010-10-04 16:33:58 +0200799
Derek Allard2067d1a2008-11-13 22:59:24 +0000800 // --------------------------------------------------------------------
801
802 /**
803 * Determine if a particular table exists
804 * @access public
805 * @return boolean
806 */
807 function table_exists($table_name)
Barry Mienydd671972010-10-04 16:33:58 +0200808 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000809 return ( ! in_array($this->_protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables())) ? FALSE : TRUE;
810 }
Barry Mienydd671972010-10-04 16:33:58 +0200811
Derek Allard2067d1a2008-11-13 22:59:24 +0000812 // --------------------------------------------------------------------
813
814 /**
815 * Fetch MySQL Field Names
816 *
817 * @access public
818 * @param string the table name
Barry Mienydd671972010-10-04 16:33:58 +0200819 * @return array
Derek Allard2067d1a2008-11-13 22:59:24 +0000820 */
821 function list_fields($table = '')
822 {
823 // Is there a cached result?
824 if (isset($this->data_cache['field_names'][$table]))
825 {
826 return $this->data_cache['field_names'][$table];
827 }
Barry Mienydd671972010-10-04 16:33:58 +0200828
Derek Allard2067d1a2008-11-13 22:59:24 +0000829 if ($table == '')
830 {
831 if ($this->db_debug)
832 {
833 return $this->display_error('db_field_param_missing');
834 }
835 return FALSE;
836 }
Barry Mienydd671972010-10-04 16:33:58 +0200837
Greg Aker1edde302010-01-26 00:17:01 +0000838 if (FALSE === ($sql = $this->_list_columns($table)))
Derek Allard2067d1a2008-11-13 22:59:24 +0000839 {
840 if ($this->db_debug)
841 {
842 return $this->display_error('db_unsupported_function');
843 }
844 return FALSE;
845 }
Barry Mienydd671972010-10-04 16:33:58 +0200846
Derek Allard2067d1a2008-11-13 22:59:24 +0000847 $query = $this->query($sql);
Barry Mienydd671972010-10-04 16:33:58 +0200848
Derek Allard2067d1a2008-11-13 22:59:24 +0000849 $retval = array();
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500850 foreach ($query->result_array() as $row)
Derek Allard2067d1a2008-11-13 22:59:24 +0000851 {
852 if (isset($row['COLUMN_NAME']))
853 {
854 $retval[] = $row['COLUMN_NAME'];
855 }
856 else
857 {
858 $retval[] = current($row);
Barry Mienydd671972010-10-04 16:33:58 +0200859 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000860 }
Barry Mienydd671972010-10-04 16:33:58 +0200861
Derek Allard2067d1a2008-11-13 22:59:24 +0000862 $this->data_cache['field_names'][$table] = $retval;
863 return $this->data_cache['field_names'][$table];
864 }
865
866 // --------------------------------------------------------------------
867
868 /**
869 * Determine if a particular field exists
870 * @access public
871 * @param string
872 * @param string
873 * @return boolean
874 */
875 function field_exists($field_name, $table_name)
Barry Mienydd671972010-10-04 16:33:58 +0200876 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000877 return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
878 }
Barry Mienydd671972010-10-04 16:33:58 +0200879
Derek Allard2067d1a2008-11-13 22:59:24 +0000880 // --------------------------------------------------------------------
881
882 /**
883 * Returns an object with field data
884 *
885 * @access public
886 * @param string the table name
Barry Mienydd671972010-10-04 16:33:58 +0200887 * @return object
888 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000889 function field_data($table = '')
890 {
891 if ($table == '')
892 {
893 if ($this->db_debug)
894 {
895 return $this->display_error('db_field_param_missing');
896 }
897 return FALSE;
898 }
Barry Mienydd671972010-10-04 16:33:58 +0200899
Derek Allard2067d1a2008-11-13 22:59:24 +0000900 $query = $this->query($this->_field_data($this->_protect_identifiers($table, TRUE, NULL, FALSE)));
901
902 return $query->field_data();
Barry Mienydd671972010-10-04 16:33:58 +0200903 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000904
905 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200906
Derek Allard2067d1a2008-11-13 22:59:24 +0000907 /**
908 * Generate an insert string
909 *
910 * @access public
911 * @param string the table upon which the query will be performed
912 * @param array an associative array data of key/values
Barry Mienydd671972010-10-04 16:33:58 +0200913 * @return string
914 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000915 function insert_string($table, $data)
916 {
917 $fields = array();
918 $values = array();
Barry Mienydd671972010-10-04 16:33:58 +0200919
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500920 foreach ($data as $key => $val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000921 {
922 $fields[] = $this->_escape_identifiers($key);
923 $values[] = $this->escape($val);
924 }
Barry Mienydd671972010-10-04 16:33:58 +0200925
Derek Allard2067d1a2008-11-13 22:59:24 +0000926 return $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values);
Barry Mienydd671972010-10-04 16:33:58 +0200927 }
928
Derek Allard2067d1a2008-11-13 22:59:24 +0000929 // --------------------------------------------------------------------
930
931 /**
932 * Generate an update string
933 *
934 * @access public
935 * @param string the table upon which the query will be performed
936 * @param array an associative array data of key/values
937 * @param mixed the "where" statement
Barry Mienydd671972010-10-04 16:33:58 +0200938 * @return string
939 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000940 function update_string($table, $data, $where)
941 {
942 if ($where == '')
943 {
944 return false;
945 }
Barry Mienydd671972010-10-04 16:33:58 +0200946
Derek Allard2067d1a2008-11-13 22:59:24 +0000947 $fields = array();
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500948 foreach ($data as $key => $val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000949 {
950 $fields[$this->_protect_identifiers($key)] = $this->escape($val);
951 }
952
953 if ( ! is_array($where))
954 {
955 $dest = array($where);
956 }
957 else
958 {
959 $dest = array();
960 foreach ($where as $key => $val)
961 {
962 $prefix = (count($dest) == 0) ? '' : ' AND ';
Andrey Andreevdc46d992011-09-24 16:25:23 +0300963 $key = $this->_protect_identifiers($key);
Barry Mienydd671972010-10-04 16:33:58 +0200964
Derek Allard2067d1a2008-11-13 22:59:24 +0000965 if ($val !== '')
966 {
967 if ( ! $this->_has_operator($key))
968 {
969 $key .= ' =';
970 }
Barry Mienydd671972010-10-04 16:33:58 +0200971
Derek Allard2067d1a2008-11-13 22:59:24 +0000972 $val = ' '.$this->escape($val);
973 }
Barry Mienydd671972010-10-04 16:33:58 +0200974
Derek Allard2067d1a2008-11-13 22:59:24 +0000975 $dest[] = $prefix.$key.$val;
976 }
Barry Mienydd671972010-10-04 16:33:58 +0200977 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000978
979 return $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest);
Barry Mienydd671972010-10-04 16:33:58 +0200980 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000981
982 // --------------------------------------------------------------------
983
984 /**
985 * Tests whether the string has an SQL operator
986 *
987 * @access private
988 * @param string
989 * @return bool
990 */
991 function _has_operator($str)
992 {
993 $str = trim($str);
994 if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str))
995 {
996 return FALSE;
997 }
998
999 return TRUE;
1000 }
1001
1002 // --------------------------------------------------------------------
1003
1004 /**
1005 * Enables a native PHP function to be run, using a platform agnostic wrapper.
1006 *
1007 * @access public
1008 * @param string the function name
1009 * @param mixed any parameters needed by the function
Barry Mienydd671972010-10-04 16:33:58 +02001010 * @return mixed
1011 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001012 function call_function($function)
1013 {
1014 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
Barry Mienydd671972010-10-04 16:33:58 +02001015
Derek Allard2067d1a2008-11-13 22:59:24 +00001016 if (FALSE === strpos($driver, $function))
1017 {
1018 $function = $driver.$function;
1019 }
Barry Mienydd671972010-10-04 16:33:58 +02001020
Derek Allard2067d1a2008-11-13 22:59:24 +00001021 if ( ! function_exists($function))
1022 {
1023 if ($this->db_debug)
1024 {
1025 return $this->display_error('db_unsupported_function');
1026 }
1027 return FALSE;
1028 }
1029 else
1030 {
1031 $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
1032
Repox71b78092011-12-01 09:19:43 +01001033 if (is_null($args))
1034 {
1035 return call_user_func($function);
1036 }
1037 else
1038 {
1039 return call_user_func_array($function, $args);
1040 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001041 }
1042 }
1043
1044 // --------------------------------------------------------------------
1045
1046 /**
1047 * Set Cache Directory Path
1048 *
1049 * @access public
1050 * @param string the path to the cache directory
1051 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001052 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001053 function cache_set_path($path = '')
1054 {
1055 $this->cachedir = $path;
1056 }
1057
1058 // --------------------------------------------------------------------
1059
1060 /**
1061 * Enable Query Caching
1062 *
1063 * @access public
1064 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001065 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001066 function cache_on()
1067 {
1068 $this->cache_on = TRUE;
1069 return TRUE;
1070 }
1071
1072 // --------------------------------------------------------------------
1073
1074 /**
1075 * Disable Query Caching
1076 *
1077 * @access public
1078 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001079 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001080 function cache_off()
1081 {
1082 $this->cache_on = FALSE;
1083 return FALSE;
1084 }
Barry Mienydd671972010-10-04 16:33:58 +02001085
Derek Allard2067d1a2008-11-13 22:59:24 +00001086
1087 // --------------------------------------------------------------------
1088
1089 /**
1090 * Delete the cache files associated with a particular URI
1091 *
1092 * @access public
1093 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001094 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001095 function cache_delete($segment_one = '', $segment_two = '')
1096 {
1097 if ( ! $this->_cache_init())
1098 {
1099 return FALSE;
1100 }
1101 return $this->CACHE->delete($segment_one, $segment_two);
1102 }
1103
1104 // --------------------------------------------------------------------
1105
1106 /**
1107 * Delete All cache files
1108 *
1109 * @access public
1110 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001111 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001112 function cache_delete_all()
1113 {
1114 if ( ! $this->_cache_init())
1115 {
1116 return FALSE;
1117 }
1118
1119 return $this->CACHE->delete_all();
1120 }
1121
1122 // --------------------------------------------------------------------
1123
1124 /**
1125 * Initialize the Cache Class
1126 *
1127 * @access private
1128 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001129 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001130 function _cache_init()
1131 {
1132 if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
1133 {
1134 return TRUE;
1135 }
Derek Allarde37ab382009-02-03 16:13:57 +00001136
1137 if ( ! class_exists('CI_DB_Cache'))
Derek Allard2067d1a2008-11-13 22:59:24 +00001138 {
Greg Aker3a746652011-04-19 10:59:47 -05001139 if ( ! @include(BASEPATH.'database/DB_cache.php'))
Derek Allarde37ab382009-02-03 16:13:57 +00001140 {
1141 return $this->cache_off();
1142 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001143 }
Derek Allarde37ab382009-02-03 16:13:57 +00001144
Derek Allard2067d1a2008-11-13 22:59:24 +00001145 $this->CACHE = new CI_DB_Cache($this); // pass db object to support multiple db connections and returned db objects
1146 return TRUE;
1147 }
1148
1149 // --------------------------------------------------------------------
1150
1151 /**
1152 * Close DB Connection
1153 *
1154 * @access public
Barry Mienydd671972010-10-04 16:33:58 +02001155 * @return void
1156 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001157 function close()
1158 {
1159 if (is_resource($this->conn_id) OR is_object($this->conn_id))
1160 {
1161 $this->_close($this->conn_id);
1162 }
1163 $this->conn_id = FALSE;
1164 }
Barry Mienydd671972010-10-04 16:33:58 +02001165
Derek Allard2067d1a2008-11-13 22:59:24 +00001166 // --------------------------------------------------------------------
1167
1168 /**
1169 * Display an error message
1170 *
1171 * @access public
1172 * @param string the error message
1173 * @param string any "swap" values
1174 * @param boolean whether to localize the message
Barry Mienydd671972010-10-04 16:33:58 +02001175 * @return string sends the application/error_db.php template
1176 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001177 function display_error($error = '', $swap = '', $native = FALSE)
1178 {
Derek Jonese7792202010-03-02 17:24:46 -06001179 $LANG =& load_class('Lang', 'core');
Derek Allard2067d1a2008-11-13 22:59:24 +00001180 $LANG->load('db');
1181
1182 $heading = $LANG->line('db_error_heading');
1183
1184 if ($native == TRUE)
1185 {
Andrey Andreev85a99cc2011-09-24 17:17:37 +03001186 $message = (array) $error;
Derek Allard2067d1a2008-11-13 22:59:24 +00001187 }
1188 else
1189 {
1190 $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
1191 }
Barry Mienydd671972010-10-04 16:33:58 +02001192
Pascal Kriete60f8c392010-08-25 18:03:28 +02001193 // Find the most likely culprit of the error by going through
1194 // the backtrace until the source file is no longer in the
1195 // database folder.
Barry Mienydd671972010-10-04 16:33:58 +02001196
Pascal Kriete60f8c392010-08-25 18:03:28 +02001197 $trace = debug_backtrace();
1198
Pascal Krietec3a4a8d2011-02-14 13:40:08 -05001199 foreach ($trace as $call)
Pascal Kriete60f8c392010-08-25 18:03:28 +02001200 {
1201 if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE)
1202 {
1203 // Found it - use a relative path for safety
1204 $message[] = 'Filename: '.str_replace(array(BASEPATH, APPPATH), '', $call['file']);
1205 $message[] = 'Line Number: '.$call['line'];
Barry Mienydd671972010-10-04 16:33:58 +02001206
Pascal Kriete60f8c392010-08-25 18:03:28 +02001207 break;
1208 }
1209 }
Barry Mienydd671972010-10-04 16:33:58 +02001210
Derek Jonese7792202010-03-02 17:24:46 -06001211 $error =& load_class('Exceptions', 'core');
Derek Allard2067d1a2008-11-13 22:59:24 +00001212 echo $error->show_error($heading, $message, 'error_db');
1213 exit;
1214 }
1215
1216 // --------------------------------------------------------------------
1217
1218 /**
1219 * Protect Identifiers
1220 *
1221 * This function adds backticks if appropriate based on db type
1222 *
1223 * @access private
1224 * @param mixed the item to escape
1225 * @return mixed the item with backticks
1226 */
1227 function protect_identifiers($item, $prefix_single = FALSE)
1228 {
1229 return $this->_protect_identifiers($item, $prefix_single);
1230 }
1231
1232 // --------------------------------------------------------------------
1233
1234 /**
1235 * Protect Identifiers
1236 *
1237 * This function is used extensively by the Active Record class, and by
Barry Mienydd671972010-10-04 16:33:58 +02001238 * a couple functions in this class.
Derek Allard2067d1a2008-11-13 22:59:24 +00001239 * It takes a column or table name (optionally with an alias) and inserts
Derek Jones37f4b9c2011-07-01 17:56:50 -05001240 * the table prefix onto it. Some logic is necessary in order to deal with
1241 * column names that include the path. Consider a query like this:
Derek Allard2067d1a2008-11-13 22:59:24 +00001242 *
1243 * SELECT * FROM hostname.database.table.column AS c FROM hostname.database.table
1244 *
1245 * Or a query with aliasing:
1246 *
1247 * SELECT m.member_id, m.member_name FROM members AS m
1248 *
1249 * Since the column name can include up to four segments (host, DB, table, column)
1250 * or also have an alias prefix, we need to do a bit of work to figure this out and
1251 * insert the table prefix (if it exists) in the proper position, and escape only
1252 * the correct identifiers.
1253 *
1254 * @access private
1255 * @param string
1256 * @param bool
1257 * @param mixed
1258 * @param bool
1259 * @return string
Barry Mienydd671972010-10-04 16:33:58 +02001260 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001261 function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE)
1262 {
1263 if ( ! is_bool($protect_identifiers))
1264 {
1265 $protect_identifiers = $this->_protect_identifiers;
1266 }
Derek Allarde37ab382009-02-03 16:13:57 +00001267
1268 if (is_array($item))
1269 {
1270 $escaped_array = array();
1271
Pascal Krietec3a4a8d2011-02-14 13:40:08 -05001272 foreach ($item as $k => $v)
Derek Allarde37ab382009-02-03 16:13:57 +00001273 {
1274 $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v);
1275 }
1276
1277 return $escaped_array;
1278 }
1279
Derek Allard2067d1a2008-11-13 22:59:24 +00001280 // Convert tabs or multiple spaces into single spaces
Derek Jones7b3b96c2009-02-10 21:01:47 +00001281 $item = preg_replace('/[\t ]+/', ' ', $item);
Barry Mienydd671972010-10-04 16:33:58 +02001282
Derek Allard2067d1a2008-11-13 22:59:24 +00001283 // If the item has an alias declaration we remove it and set it aside.
1284 // Basically we remove everything to the right of the first space
1285 $alias = '';
1286 if (strpos($item, ' ') !== FALSE)
Derek Allard911d3e02008-12-15 14:08:35 +00001287 {
Derek Allard2067d1a2008-11-13 22:59:24 +00001288 $alias = strstr($item, " ");
1289 $item = substr($item, 0, - strlen($alias));
1290 }
1291
Derek Allard911d3e02008-12-15 14:08:35 +00001292 // This is basically a bug fix for queries that use MAX, MIN, etc.
Barry Mienydd671972010-10-04 16:33:58 +02001293 // If a parenthesis is found we know that we do not need to
Derek Jones37f4b9c2011-07-01 17:56:50 -05001294 // escape the data or add a prefix. There's probably a more graceful
Derek Allard911d3e02008-12-15 14:08:35 +00001295 // way to deal with this, but I'm not thinking of it -- Rick
1296 if (strpos($item, '(') !== FALSE)
1297 {
1298 return $item.$alias;
1299 }
1300
Derek Allard2067d1a2008-11-13 22:59:24 +00001301 // Break the string apart if it contains periods, then insert the table prefix
1302 // in the correct location, assuming the period doesn't indicate that we're dealing
1303 // with an alias. While we're at it, we will escape the components
1304 if (strpos($item, '.') !== FALSE)
1305 {
1306 $parts = explode('.', $item);
Barry Mienydd671972010-10-04 16:33:58 +02001307
Derek Allard2067d1a2008-11-13 22:59:24 +00001308 // Does the first segment of the exploded item match
Derek Jones37f4b9c2011-07-01 17:56:50 -05001309 // one of the aliases previously identified? If so,
Derek Allard2067d1a2008-11-13 22:59:24 +00001310 // we have nothing more to do other than escape the item
1311 if (in_array($parts[0], $this->ar_aliased_tables))
Derek Allard911d3e02008-12-15 14:08:35 +00001312 {
Derek Allard2067d1a2008-11-13 22:59:24 +00001313 if ($protect_identifiers === TRUE)
1314 {
1315 foreach ($parts as $key => $val)
1316 {
1317 if ( ! in_array($val, $this->_reserved_identifiers))
1318 {
1319 $parts[$key] = $this->_escape_identifiers($val);
1320 }
1321 }
Barry Mienydd671972010-10-04 16:33:58 +02001322
Derek Allard2067d1a2008-11-13 22:59:24 +00001323 $item = implode('.', $parts);
Barry Mienydd671972010-10-04 16:33:58 +02001324 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001325 return $item.$alias;
1326 }
Barry Mienydd671972010-10-04 16:33:58 +02001327
Derek Jones37f4b9c2011-07-01 17:56:50 -05001328 // Is there a table prefix defined in the config file? If not, no need to do anything
Derek Allard2067d1a2008-11-13 22:59:24 +00001329 if ($this->dbprefix != '')
1330 {
1331 // We now add the table prefix based on some logic.
1332 // Do we have 4 segments (hostname.database.table.column)?
1333 // If so, we add the table prefix to the column name in the 3rd segment.
1334 if (isset($parts[3]))
1335 {
1336 $i = 2;
1337 }
1338 // Do we have 3 segments (database.table.column)?
1339 // If so, we add the table prefix to the column name in 2nd position
1340 elseif (isset($parts[2]))
1341 {
1342 $i = 1;
1343 }
1344 // Do we have 2 segments (table.column)?
1345 // If so, we add the table prefix to the column name in 1st segment
1346 else
1347 {
1348 $i = 0;
1349 }
Barry Mienydd671972010-10-04 16:33:58 +02001350
Derek Allard2067d1a2008-11-13 22:59:24 +00001351 // This flag is set when the supplied $item does not contain a field name.
1352 // This can happen when this function is being called from a JOIN.
1353 if ($field_exists == FALSE)
1354 {
1355 $i++;
1356 }
Barry Mienydd671972010-10-04 16:33:58 +02001357
Derek Jones55acc8b2009-07-11 03:38:13 +00001358 // Verify table prefix and replace if necessary
1359 if ($this->swap_pre != '' && strncmp($parts[$i], $this->swap_pre, strlen($this->swap_pre)) === 0)
1360 {
1361 $parts[$i] = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $parts[$i]);
1362 }
Barry Mienydd671972010-10-04 16:33:58 +02001363
Derek Allard2067d1a2008-11-13 22:59:24 +00001364 // We only add the table prefix if it does not already exist
1365 if (substr($parts[$i], 0, strlen($this->dbprefix)) != $this->dbprefix)
1366 {
1367 $parts[$i] = $this->dbprefix.$parts[$i];
1368 }
Barry Mienydd671972010-10-04 16:33:58 +02001369
Derek Allard2067d1a2008-11-13 22:59:24 +00001370 // Put the parts back together
1371 $item = implode('.', $parts);
1372 }
Barry Mienydd671972010-10-04 16:33:58 +02001373
Derek Allard2067d1a2008-11-13 22:59:24 +00001374 if ($protect_identifiers === TRUE)
1375 {
1376 $item = $this->_escape_identifiers($item);
1377 }
Barry Mienydd671972010-10-04 16:33:58 +02001378
Derek Allard2067d1a2008-11-13 22:59:24 +00001379 return $item.$alias;
1380 }
1381
Derek Jones37f4b9c2011-07-01 17:56:50 -05001382 // Is there a table prefix? If not, no need to insert it
Derek Allard2067d1a2008-11-13 22:59:24 +00001383 if ($this->dbprefix != '')
1384 {
Derek Jones55acc8b2009-07-11 03:38:13 +00001385 // Verify table prefix and replace if necessary
1386 if ($this->swap_pre != '' && strncmp($item, $this->swap_pre, strlen($this->swap_pre)) === 0)
1387 {
1388 $item = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $item);
1389 }
1390
Derek Allard2067d1a2008-11-13 22:59:24 +00001391 // Do we prefix an item with no segments?
1392 if ($prefix_single == TRUE AND substr($item, 0, strlen($this->dbprefix)) != $this->dbprefix)
1393 {
1394 $item = $this->dbprefix.$item;
Barry Mienydd671972010-10-04 16:33:58 +02001395 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001396 }
1397
1398 if ($protect_identifiers === TRUE AND ! in_array($item, $this->_reserved_identifiers))
1399 {
1400 $item = $this->_escape_identifiers($item);
1401 }
Barry Mienydd671972010-10-04 16:33:58 +02001402
Derek Allard2067d1a2008-11-13 22:59:24 +00001403 return $item.$alias;
1404 }
Túbal Martín511f2252011-11-24 14:43:45 +01001405
1406 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +00001407
Túbal Martín511f2252011-11-24 14:43:45 +01001408 /**
1409 * Dummy method that allows Active Record class to be disabled
1410 *
1411 * This function is used extensively by every db driver.
1412 *
1413 * @access private
1414 * @return void
1415 */
1416 protected function _reset_select()
1417 {
1418
1419 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001420
1421}
1422
Derek Allard2067d1a2008-11-13 22:59:24 +00001423/* End of file DB_driver.php */
Timothy Warren6f531dc2011-10-10 10:10:46 -04001424/* Location: ./system/database/DB_driver.php */