blob: 15195b20a0429896002fd43f764325d585a87839 [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
80 // These are use with Oracle
81 var $stmt_id;
82 var $curs_id;
83 var $limit_used;
Taufan Aditya18209332012-02-09 16:07:27 +070084
Barry Mienydd671972010-10-04 16:33:58 +020085
Derek Allard2067d1a2008-11-13 22:59:24 +000086 /**
Derek Jones37f4b9c2011-07-01 17:56:50 -050087 * Constructor. Accepts one parameter containing the database
Derek Allard2067d1a2008-11-13 22:59:24 +000088 * connection settings.
89 *
90 * @param array
Barry Mienydd671972010-10-04 16:33:58 +020091 */
Timothy Warrena2097a02011-10-10 10:10:46 -040092 function __construct($params)
Derek Allard2067d1a2008-11-13 22:59:24 +000093 {
94 if (is_array($params))
95 {
96 foreach ($params as $key => $val)
97 {
98 $this->$key = $val;
99 }
100 }
101
102 log_message('debug', 'Database Driver Class Initialized');
103 }
Barry Mienydd671972010-10-04 16:33:58 +0200104
Derek Allard2067d1a2008-11-13 22:59:24 +0000105 // --------------------------------------------------------------------
106
107 /**
108 * Initialize Database Settings
109 *
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200110 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200111 */
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200112 public function initialize()
Derek Allard2067d1a2008-11-13 22:59:24 +0000113 {
114 // If an existing connection resource is available
115 // there is no need to connect and select the database
116 if (is_resource($this->conn_id) OR is_object($this->conn_id))
117 {
118 return TRUE;
119 }
Barry Mienydd671972010-10-04 16:33:58 +0200120
Derek Allard2067d1a2008-11-13 22:59:24 +0000121 // ----------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200122
Derek Allard2067d1a2008-11-13 22:59:24 +0000123 // Connect to the database and set the connection ID
124 $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
125
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200126 // No connection resource? Check if there is a failover else throw an error
Derek Allard2067d1a2008-11-13 22:59:24 +0000127 if ( ! $this->conn_id)
128 {
Felix Balfoort5d581b62011-11-29 15:53:01 +0100129 // Check if there is a failover set
130 if ( ! empty($this->failover) && is_array($this->failover))
Derek Allard2067d1a2008-11-13 22:59:24 +0000131 {
Felix Balfoort5d581b62011-11-29 15:53:01 +0100132 // Go over all the failovers
133 foreach ($this->failover as $failover)
134 {
135 // Replace the current settings with those of the failover
136 foreach ($failover as $key => $val)
137 {
138 $this->$key = $val;
139 }
140
141 // Try to connect
142 $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
143
144 // If a connection is made break the foreach loop
145 if ($this->conn_id)
146 {
147 break;
148 }
149 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000150 }
Felix Balfoort5d581b62011-11-29 15:53:01 +0100151
152 // We still don't have a connection?
153 if ( ! $this->conn_id)
154 {
155 log_message('error', 'Unable to connect to the database');
156
157 if ($this->db_debug)
158 {
159 $this->display_error('db_unable_to_connect');
160 }
161 return FALSE;
162 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000163 }
164
165 // ----------------------------------------------------------------
166
167 // Select the DB... assuming a database name is specified in the config file
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200168 if ($this->database !== '' && ! $this->db_select())
Derek Allard2067d1a2008-11-13 22:59:24 +0000169 {
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200170 log_message('error', 'Unable to select database: '.$this->database);
Barry Mienydd671972010-10-04 16:33:58 +0200171
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200172 if ($this->db_debug)
Derek Allard2067d1a2008-11-13 22:59:24 +0000173 {
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200174 $this->display_error('db_unable_to_select', $this->database);
Derek Allard2067d1a2008-11-13 22:59:24 +0000175 }
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200176 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000177 }
178
Andrey Andreev82e8ac12012-02-22 19:35:34 +0200179 // Now we set the character set and that's all
180 return $this->db_set_charset($this->char_set, $this->dbcollat);
Derek Allard2067d1a2008-11-13 22:59:24 +0000181 }
Barry Mienydd671972010-10-04 16:33:58 +0200182
Derek Allard2067d1a2008-11-13 22:59:24 +0000183 // --------------------------------------------------------------------
184
185 /**
186 * Set client character set
187 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000188 * @param string
189 * @param string
Andrey Andreev063f5962012-02-27 12:20:52 +0200190 * @return bool
Derek Allard2067d1a2008-11-13 22:59:24 +0000191 */
Andrey Andreev063f5962012-02-27 12:20:52 +0200192 public function db_set_charset($charset, $collation = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000193 {
Andrey Andreev063f5962012-02-27 12:20:52 +0200194 if (method_exists($this, '_db_set_charset') && ! $this->_db_set_charset($charset, $collation))
Derek Allard2067d1a2008-11-13 22:59:24 +0000195 {
Andrey Andreev063f5962012-02-27 12:20:52 +0200196 log_message('error', 'Unable to set database connection charset: '.$charset);
Barry Mienydd671972010-10-04 16:33:58 +0200197
Derek Allard2067d1a2008-11-13 22:59:24 +0000198 if ($this->db_debug)
199 {
Andrey Andreev063f5962012-02-27 12:20:52 +0200200 $this->display_error('db_unable_to_set_charset', $charset);
Derek Allard2067d1a2008-11-13 22:59:24 +0000201 }
Barry Mienydd671972010-10-04 16:33:58 +0200202
Derek Allard2067d1a2008-11-13 22:59:24 +0000203 return FALSE;
204 }
Barry Mienydd671972010-10-04 16:33:58 +0200205
Derek Allard2067d1a2008-11-13 22:59:24 +0000206 return TRUE;
207 }
Barry Mienydd671972010-10-04 16:33:58 +0200208
Derek Allard2067d1a2008-11-13 22:59:24 +0000209 // --------------------------------------------------------------------
210
211 /**
212 * The name of the platform in use (mysql, mssql, etc...)
213 *
214 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200215 * @return string
216 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000217 function platform()
218 {
219 return $this->dbdriver;
220 }
221
222 // --------------------------------------------------------------------
223
224 /**
Andrey Andreev08856b82012-03-03 03:19:28 +0200225 * Database version number
Derek Allard2067d1a2008-11-13 22:59:24 +0000226 *
Andrey Andreev08856b82012-03-03 03:19:28 +0200227 * Returns a string containing the version of the database being used.
228 * Most drivers will override this method.
229 *
Barry Mienydd671972010-10-04 16:33:58 +0200230 * @return string
231 */
Andrey Andreev08856b82012-03-03 03:19:28 +0200232 public function version()
Derek Allard2067d1a2008-11-13 22:59:24 +0000233 {
Andrey Andreev08856b82012-03-03 03:19:28 +0200234 if (isset($this->data_cache['version']))
235 {
236 return $this->data_cache['version'];
237 }
238
Derek Allard2067d1a2008-11-13 22:59:24 +0000239 if (FALSE === ($sql = $this->_version()))
240 {
Andrey Andreev08856b82012-03-03 03:19:28 +0200241 return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000242 }
Derek Allard3683f772009-12-16 17:32:33 +0000243
Andrey Andreev08856b82012-03-03 03:19:28 +0200244 $query = $this->query($sql);
245 $query = $query->row();
246 return $this->data_cache['version'] = $query->ver;
247 }
Derek Allard3683f772009-12-16 17:32:33 +0000248
Andrey Andreev08856b82012-03-03 03:19:28 +0200249 // --------------------------------------------------------------------
250
251 /**
252 * Version number query string
253 *
254 * @return string
255 */
256 protected function _version()
257 {
258 return 'SELECT VERSION() AS ver';
Derek Allard2067d1a2008-11-13 22:59:24 +0000259 }
Barry Mienydd671972010-10-04 16:33:58 +0200260
Derek Allard2067d1a2008-11-13 22:59:24 +0000261 // --------------------------------------------------------------------
262
263 /**
264 * Execute the query
265 *
266 * Accepts an SQL string as input and returns a result object upon
Derek Jones37f4b9c2011-07-01 17:56:50 -0500267 * successful execution of a "read" type query. Returns boolean TRUE
Derek Allard2067d1a2008-11-13 22:59:24 +0000268 * upon successful execution of a "write" type query. Returns boolean
269 * FALSE upon failure, and if the $db_debug variable is set to TRUE
270 * will raise an error.
271 *
272 * @access public
273 * @param string An SQL query string
274 * @param array An array of binding data
Barry Mienydd671972010-10-04 16:33:58 +0200275 * @return mixed
276 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000277 function query($sql, $binds = FALSE, $return_object = TRUE)
278 {
279 if ($sql == '')
280 {
Niklas Nilssond2018ee2011-08-30 13:39:42 +0200281 log_message('error', 'Invalid query: '.$sql);
282
Derek Allard2067d1a2008-11-13 22:59:24 +0000283 if ($this->db_debug)
284 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000285 return $this->display_error('db_invalid_query');
286 }
287 return FALSE;
288 }
289
290 // Verify table prefix and replace if necessary
291 if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) )
Derek Jonese7792202010-03-02 17:24:46 -0600292 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000293 $sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql);
294 }
Derek Jonese7792202010-03-02 17:24:46 -0600295
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 Allard2067d1a2008-11-13 22:59:24 +0000311 // Compile binds if needed
312 if ($binds !== FALSE)
313 {
314 $sql = $this->compile_binds($sql, $binds);
315 }
316
Derek Jones37f4b9c2011-07-01 17:56:50 -0500317 // Save the query for debugging
Derek Allard2067d1a2008-11-13 22:59:24 +0000318 if ($this->save_queries == TRUE)
319 {
320 $this->queries[] = $sql;
321 }
Barry Mienydd671972010-10-04 16:33:58 +0200322
Derek Allard2067d1a2008-11-13 22:59:24 +0000323 // Start the Query Timer
324 $time_start = list($sm, $ss) = explode(' ', microtime());
Barry Mienydd671972010-10-04 16:33:58 +0200325
Derek Allard2067d1a2008-11-13 22:59:24 +0000326 // Run the Query
327 if (FALSE === ($this->result_id = $this->simple_query($sql)))
328 {
329 if ($this->save_queries == TRUE)
330 {
331 $this->query_times[] = 0;
332 }
Barry Mienydd671972010-10-04 16:33:58 +0200333
Derek Allard2067d1a2008-11-13 22:59:24 +0000334 // This will trigger a rollback if transactions are being used
335 $this->_trans_status = FALSE;
336
Andrey Andreev4be5de12012-03-02 15:45:41 +0200337 // Grab the error now, as we might run some additional queries before displaying the error
338 $error = $this->error();
Niklas Nilssond2018ee2011-08-30 13:39:42 +0200339
340 // Log errors
Andrey Andreev4be5de12012-03-02 15:45:41 +0200341 log_message('error', 'Query error: '.$error['message']);
Niklas Nilssond2018ee2011-08-30 13:39:42 +0200342
Derek Allard2067d1a2008-11-13 22:59:24 +0000343 if ($this->db_debug)
344 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000345 // We call this function in order to roll-back queries
Andrey Andreev4be5de12012-03-02 15:45:41 +0200346 // if transactions are enabled. If we don't call this here
Barry Mienydd671972010-10-04 16:33:58 +0200347 // the error message will trigger an exit, causing the
Derek Allard2067d1a2008-11-13 22:59:24 +0000348 // transactions to remain in limbo.
349 $this->trans_complete();
350
Niklas Nilssond2018ee2011-08-30 13:39:42 +0200351 // Display errors
Derek Allard2067d1a2008-11-13 22:59:24 +0000352 return $this->display_error(
Andrey Andreev4be5de12012-03-02 15:45:41 +0200353 array(
354 'Error Number: '.$error['code'],
355 $error['message'],
356 $sql
357 )
358 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000359 }
Barry Mienydd671972010-10-04 16:33:58 +0200360
Derek Allard2067d1a2008-11-13 22:59:24 +0000361 return FALSE;
362 }
Barry Mienydd671972010-10-04 16:33:58 +0200363
Derek Allard2067d1a2008-11-13 22:59:24 +0000364 // Stop and aggregate the query time results
365 $time_end = list($em, $es) = explode(' ', microtime());
366 $this->benchmark += ($em + $es) - ($sm + $ss);
367
368 if ($this->save_queries == TRUE)
369 {
370 $this->query_times[] = ($em + $es) - ($sm + $ss);
371 }
Barry Mienydd671972010-10-04 16:33:58 +0200372
Derek Allard2067d1a2008-11-13 22:59:24 +0000373 // Increment the query counter
374 $this->query_count++;
Barry Mienydd671972010-10-04 16:33:58 +0200375
Derek Allard2067d1a2008-11-13 22:59:24 +0000376 // Was the query a "write" type?
377 // If so we'll simply return true
378 if ($this->is_write_type($sql) === TRUE)
379 {
380 // If caching is enabled we'll auto-cleanup any
381 // existing files related to this particular URI
382 if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init())
383 {
384 $this->CACHE->delete();
385 }
Barry Mienydd671972010-10-04 16:33:58 +0200386
Derek Allard2067d1a2008-11-13 22:59:24 +0000387 return TRUE;
388 }
Barry Mienydd671972010-10-04 16:33:58 +0200389
Derek Allard2067d1a2008-11-13 22:59:24 +0000390 // Return TRUE if we don't need to create a result object
391 // Currently only the Oracle driver uses this when stored
392 // procedures are used
393 if ($return_object !== TRUE)
394 {
395 return TRUE;
396 }
Barry Mienydd671972010-10-04 16:33:58 +0200397
398 // Load and instantiate the result driver
399
400 $driver = $this->load_rdriver();
401 $RES = new $driver();
Derek Allard2067d1a2008-11-13 22:59:24 +0000402 $RES->conn_id = $this->conn_id;
403 $RES->result_id = $this->result_id;
404
405 if ($this->dbdriver == 'oci8')
406 {
407 $RES->stmt_id = $this->stmt_id;
408 $RES->curs_id = NULL;
409 $RES->limit_used = $this->limit_used;
410 $this->stmt_id = FALSE;
411 }
Barry Mienydd671972010-10-04 16:33:58 +0200412
Derek Allard2067d1a2008-11-13 22:59:24 +0000413 // oci8 vars must be set before calling this
414 $RES->num_rows = $RES->num_rows();
Barry Mienydd671972010-10-04 16:33:58 +0200415
Derek Jones37f4b9c2011-07-01 17:56:50 -0500416 // Is query caching enabled? If so, we'll serialize the
Derek Allard2067d1a2008-11-13 22:59:24 +0000417 // result object and save it to a cache file.
418 if ($this->cache_on == TRUE AND $this->_cache_init())
419 {
420 // We'll create a new instance of the result object
421 // only without the platform specific driver since
422 // we can't use it with cached data (the query result
423 // resource ID won't be any good once we've cached the
424 // result object, so we'll have to compile the data
425 // and save it)
426 $CR = new CI_DB_result();
Barry Mienydd671972010-10-04 16:33:58 +0200427 $CR->num_rows = $RES->num_rows();
Derek Allard2067d1a2008-11-13 22:59:24 +0000428 $CR->result_object = $RES->result_object();
429 $CR->result_array = $RES->result_array();
Barry Mienydd671972010-10-04 16:33:58 +0200430
Derek Allard2067d1a2008-11-13 22:59:24 +0000431 // Reset these since cached objects can not utilize resource IDs.
432 $CR->conn_id = NULL;
433 $CR->result_id = NULL;
434
435 $this->CACHE->write($sql, $CR);
436 }
Barry Mienydd671972010-10-04 16:33:58 +0200437
Derek Allard2067d1a2008-11-13 22:59:24 +0000438 return $RES;
439 }
440
441 // --------------------------------------------------------------------
442
443 /**
444 * Load the result drivers
445 *
446 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200447 * @return string the name of the result class
448 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000449 function load_rdriver()
450 {
451 $driver = 'CI_DB_'.$this->dbdriver.'_result';
452
453 if ( ! class_exists($driver))
454 {
Greg Aker3a746652011-04-19 10:59:47 -0500455 include_once(BASEPATH.'database/DB_result.php');
456 include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result.php');
Derek Allard2067d1a2008-11-13 22:59:24 +0000457 }
Barry Mienydd671972010-10-04 16:33:58 +0200458
Derek Allard2067d1a2008-11-13 22:59:24 +0000459 return $driver;
460 }
Barry Mienydd671972010-10-04 16:33:58 +0200461
Derek Allard2067d1a2008-11-13 22:59:24 +0000462 // --------------------------------------------------------------------
463
464 /**
465 * Simple Query
Derek Jones37f4b9c2011-07-01 17:56:50 -0500466 * This is a simplified version of the query() function. Internally
Derek Allard2067d1a2008-11-13 22:59:24 +0000467 * we only use it when running transaction commands since they do
468 * not require all the features of the main query() function.
469 *
470 * @access public
471 * @param string the sql query
Barry Mienydd671972010-10-04 16:33:58 +0200472 * @return mixed
473 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000474 function simple_query($sql)
475 {
476 if ( ! $this->conn_id)
477 {
478 $this->initialize();
479 }
480
481 return $this->_execute($sql);
482 }
Barry Mienydd671972010-10-04 16:33:58 +0200483
Derek Allard2067d1a2008-11-13 22:59:24 +0000484 // --------------------------------------------------------------------
485
486 /**
487 * Disable Transactions
488 * This permits transactions to be disabled at run-time.
489 *
490 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200491 * @return void
492 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000493 function trans_off()
494 {
495 $this->trans_enabled = FALSE;
496 }
497
498 // --------------------------------------------------------------------
499
500 /**
501 * Enable/disable Transaction Strict Mode
502 * When strict mode is enabled, if you are running multiple groups of
503 * transactions, if one group fails all groups will be rolled back.
504 * If strict mode is disabled, each group is treated autonomously, meaning
505 * a failure of one group will not affect any others
506 *
507 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200508 * @return void
509 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000510 function trans_strict($mode = TRUE)
511 {
512 $this->trans_strict = is_bool($mode) ? $mode : TRUE;
513 }
Barry Mienydd671972010-10-04 16:33:58 +0200514
Derek Allard2067d1a2008-11-13 22:59:24 +0000515 // --------------------------------------------------------------------
516
517 /**
518 * Start Transaction
519 *
520 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200521 * @return void
522 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000523 function trans_start($test_mode = FALSE)
Barry Mienydd671972010-10-04 16:33:58 +0200524 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000525 if ( ! $this->trans_enabled)
526 {
527 return FALSE;
528 }
529
530 // When transactions are nested we only begin/commit/rollback the outermost ones
531 if ($this->_trans_depth > 0)
532 {
533 $this->_trans_depth += 1;
534 return;
535 }
Barry Mienydd671972010-10-04 16:33:58 +0200536
Derek Allard2067d1a2008-11-13 22:59:24 +0000537 $this->trans_begin($test_mode);
Jacob Terry07fcedf2011-11-22 11:21:36 -0500538 $this->_trans_depth += 1;
Derek Allard2067d1a2008-11-13 22:59:24 +0000539 }
540
541 // --------------------------------------------------------------------
542
543 /**
544 * Complete Transaction
545 *
546 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200547 * @return bool
548 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000549 function trans_complete()
550 {
551 if ( ! $this->trans_enabled)
552 {
553 return FALSE;
554 }
Barry Mienydd671972010-10-04 16:33:58 +0200555
Derek Allard2067d1a2008-11-13 22:59:24 +0000556 // When transactions are nested we only begin/commit/rollback the outermost ones
557 if ($this->_trans_depth > 1)
558 {
559 $this->_trans_depth -= 1;
560 return TRUE;
561 }
Jacob Terry07fcedf2011-11-22 11:21:36 -0500562 else
563 {
564 $this->_trans_depth = 0;
565 }
Barry Mienydd671972010-10-04 16:33:58 +0200566
Derek Allard2067d1a2008-11-13 22:59:24 +0000567 // The query() function will set this flag to FALSE in the event that a query failed
568 if ($this->_trans_status === FALSE)
569 {
570 $this->trans_rollback();
Barry Mienydd671972010-10-04 16:33:58 +0200571
Derek Allard2067d1a2008-11-13 22:59:24 +0000572 // If we are NOT running in strict mode, we will reset
573 // the _trans_status flag so that subsequent groups of transactions
574 // will be permitted.
575 if ($this->trans_strict === FALSE)
576 {
577 $this->_trans_status = TRUE;
578 }
579
580 log_message('debug', 'DB Transaction Failure');
581 return FALSE;
582 }
Barry Mienydd671972010-10-04 16:33:58 +0200583
Derek Allard2067d1a2008-11-13 22:59:24 +0000584 $this->trans_commit();
585 return TRUE;
586 }
587
588 // --------------------------------------------------------------------
589
590 /**
591 * Lets you retrieve the transaction flag to determine if it has failed
592 *
593 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200594 * @return bool
595 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000596 function trans_status()
597 {
598 return $this->_trans_status;
599 }
600
601 // --------------------------------------------------------------------
602
603 /**
604 * Compile Bindings
605 *
606 * @access public
607 * @param string the sql statement
608 * @param array an array of bind data
Barry Mienydd671972010-10-04 16:33:58 +0200609 * @return string
610 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000611 function compile_binds($sql, $binds)
612 {
613 if (strpos($sql, $this->bind_marker) === FALSE)
614 {
615 return $sql;
616 }
Barry Mienydd671972010-10-04 16:33:58 +0200617
Derek Allard2067d1a2008-11-13 22:59:24 +0000618 if ( ! is_array($binds))
619 {
620 $binds = array($binds);
621 }
Barry Mienydd671972010-10-04 16:33:58 +0200622
Derek Allard2067d1a2008-11-13 22:59:24 +0000623 // Get the sql segments around the bind markers
624 $segments = explode($this->bind_marker, $sql);
625
626 // The count of bind should be 1 less then the count of segments
627 // If there are more bind arguments trim it down
628 if (count($binds) >= count($segments)) {
629 $binds = array_slice($binds, 0, count($segments)-1);
630 }
631
632 // Construct the binded query
633 $result = $segments[0];
634 $i = 0;
635 foreach ($binds as $bind)
636 {
637 $result .= $this->escape($bind);
638 $result .= $segments[++$i];
639 }
640
641 return $result;
642 }
Barry Mienydd671972010-10-04 16:33:58 +0200643
Derek Allard2067d1a2008-11-13 22:59:24 +0000644 // --------------------------------------------------------------------
645
646 /**
647 * Determines if a query is a "write" type.
648 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000649 * @param string An SQL query string
Andrey Andreev67f71a42012-03-01 16:18:42 +0200650 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200651 */
Andrey Andreev67f71a42012-03-01 16:18:42 +0200652 public function is_write_type($sql)
Derek Allard2067d1a2008-11-13 22:59:24 +0000653 {
Andrey Andreev5fa72982012-03-03 04:13:20 +0200654 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 +0000655 }
Barry Mienydd671972010-10-04 16:33:58 +0200656
Derek Allard2067d1a2008-11-13 22:59:24 +0000657 // --------------------------------------------------------------------
658
659 /**
660 * Calculate the aggregate query elapsed time
661 *
662 * @access public
663 * @param integer The number of decimal places
Barry Mienydd671972010-10-04 16:33:58 +0200664 * @return integer
665 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000666 function elapsed_time($decimals = 6)
667 {
668 return number_format($this->benchmark, $decimals);
669 }
Barry Mienydd671972010-10-04 16:33:58 +0200670
Derek Allard2067d1a2008-11-13 22:59:24 +0000671 // --------------------------------------------------------------------
672
673 /**
674 * Returns the total number of queries
675 *
676 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200677 * @return integer
678 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000679 function total_queries()
680 {
681 return $this->query_count;
682 }
Barry Mienydd671972010-10-04 16:33:58 +0200683
Derek Allard2067d1a2008-11-13 22:59:24 +0000684 // --------------------------------------------------------------------
685
686 /**
687 * Returns the last query that was executed
688 *
689 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200690 * @return void
691 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000692 function last_query()
693 {
694 return end($this->queries);
695 }
696
697 // --------------------------------------------------------------------
698
699 /**
700 * "Smart" Escape String
701 *
702 * Escapes data based on type
703 * Sets boolean and null types
704 *
705 * @access public
706 * @param string
Barry Mienydd671972010-10-04 16:33:58 +0200707 * @return mixed
708 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000709 function escape($str)
Barry Mienydd671972010-10-04 16:33:58 +0200710 {
Derek Jonesa377bdd2009-02-11 18:55:24 +0000711 if (is_string($str))
Derek Allard2067d1a2008-11-13 22:59:24 +0000712 {
Derek Jonesa377bdd2009-02-11 18:55:24 +0000713 $str = "'".$this->escape_str($str)."'";
714 }
715 elseif (is_bool($str))
716 {
717 $str = ($str === FALSE) ? 0 : 1;
718 }
719 elseif (is_null($str))
720 {
721 $str = 'NULL';
722 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000723
724 return $str;
725 }
726
727 // --------------------------------------------------------------------
Derek Jonese7792202010-03-02 17:24:46 -0600728
Derek Jonese4ed5832009-02-20 21:44:59 +0000729 /**
Derek Jonesbdc7fb92009-02-20 21:55:10 +0000730 * Escape LIKE String
Derek Jonese4ed5832009-02-20 21:44:59 +0000731 *
732 * Calls the individual driver for platform
733 * specific escaping for LIKE conditions
Barry Mienydd671972010-10-04 16:33:58 +0200734 *
Derek Jonese4ed5832009-02-20 21:44:59 +0000735 * @access public
736 * @param string
737 * @return mixed
738 */
Barry Mienydd671972010-10-04 16:33:58 +0200739 function escape_like_str($str)
740 {
741 return $this->escape_str($str, TRUE);
Derek Jonese4ed5832009-02-20 21:44:59 +0000742 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000743
Derek Jonese4ed5832009-02-20 21:44:59 +0000744 // --------------------------------------------------------------------
Derek Jonese7792202010-03-02 17:24:46 -0600745
Derek Allard2067d1a2008-11-13 22:59:24 +0000746 /**
747 * Primary
748 *
Derek Jones37f4b9c2011-07-01 17:56:50 -0500749 * Retrieves the primary key. It assumes that the row in the first
Derek Allard2067d1a2008-11-13 22:59:24 +0000750 * position is the primary key
751 *
752 * @access public
753 * @param string the table name
Barry Mienydd671972010-10-04 16:33:58 +0200754 * @return string
755 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000756 function primary($table = '')
Barry Mienydd671972010-10-04 16:33:58 +0200757 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000758 $fields = $this->list_fields($table);
Barry Mienydd671972010-10-04 16:33:58 +0200759
Derek Allard2067d1a2008-11-13 22:59:24 +0000760 if ( ! is_array($fields))
761 {
762 return FALSE;
763 }
764
765 return current($fields);
766 }
767
768 // --------------------------------------------------------------------
769
770 /**
771 * Returns an array of table names
772 *
773 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200774 * @return array
775 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000776 function list_tables($constrain_by_prefix = FALSE)
777 {
778 // Is there a cached result?
779 if (isset($this->data_cache['table_names']))
780 {
781 return $this->data_cache['table_names'];
782 }
Barry Mienydd671972010-10-04 16:33:58 +0200783
Derek Allard2067d1a2008-11-13 22:59:24 +0000784 if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
785 {
786 if ($this->db_debug)
787 {
788 return $this->display_error('db_unsupported_function');
789 }
790 return FALSE;
791 }
792
793 $retval = array();
794 $query = $this->query($sql);
Barry Mienydd671972010-10-04 16:33:58 +0200795
Derek Allard2067d1a2008-11-13 22:59:24 +0000796 if ($query->num_rows() > 0)
797 {
Taufan Aditya18209332012-02-09 16:07:27 +0700798 $table = FALSE;
799 $rows = $query->result_array();
800 $key = (($row = current($rows)) && in_array('table_name', array_map('strtolower', array_keys($row))));
801
802 if ($key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000803 {
Taufan Aditya18209332012-02-09 16:07:27 +0700804 $table = array_key_exists('TABLE_NAME', $row) ? 'TABLE_NAME' : 'table_name';
805 }
806
807 foreach ($rows as $row)
808 {
809 $retval[] = ( ! $table) ? current($row) : $row[$table];
Derek Allard2067d1a2008-11-13 22:59:24 +0000810 }
811 }
812
813 $this->data_cache['table_names'] = $retval;
Taufan Aditya18209332012-02-09 16:07:27 +0700814
Derek Allard2067d1a2008-11-13 22:59:24 +0000815 return $this->data_cache['table_names'];
816 }
Barry Mienydd671972010-10-04 16:33:58 +0200817
Derek Allard2067d1a2008-11-13 22:59:24 +0000818 // --------------------------------------------------------------------
819
820 /**
821 * Determine if a particular table exists
822 * @access public
823 * @return boolean
824 */
825 function table_exists($table_name)
Barry Mienydd671972010-10-04 16:33:58 +0200826 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000827 return ( ! in_array($this->_protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables())) ? FALSE : TRUE;
828 }
Barry Mienydd671972010-10-04 16:33:58 +0200829
Derek Allard2067d1a2008-11-13 22:59:24 +0000830 // --------------------------------------------------------------------
831
832 /**
833 * Fetch MySQL Field Names
834 *
835 * @access public
836 * @param string the table name
Barry Mienydd671972010-10-04 16:33:58 +0200837 * @return array
Derek Allard2067d1a2008-11-13 22:59:24 +0000838 */
839 function list_fields($table = '')
840 {
841 // Is there a cached result?
842 if (isset($this->data_cache['field_names'][$table]))
843 {
844 return $this->data_cache['field_names'][$table];
845 }
Barry Mienydd671972010-10-04 16:33:58 +0200846
Derek Allard2067d1a2008-11-13 22:59:24 +0000847 if ($table == '')
848 {
849 if ($this->db_debug)
850 {
851 return $this->display_error('db_field_param_missing');
852 }
853 return FALSE;
854 }
Barry Mienydd671972010-10-04 16:33:58 +0200855
Greg Aker1edde302010-01-26 00:17:01 +0000856 if (FALSE === ($sql = $this->_list_columns($table)))
Derek Allard2067d1a2008-11-13 22:59:24 +0000857 {
858 if ($this->db_debug)
859 {
860 return $this->display_error('db_unsupported_function');
861 }
862 return FALSE;
863 }
Barry Mienydd671972010-10-04 16:33:58 +0200864
Derek Allard2067d1a2008-11-13 22:59:24 +0000865 $query = $this->query($sql);
Barry Mienydd671972010-10-04 16:33:58 +0200866
Derek Allard2067d1a2008-11-13 22:59:24 +0000867 $retval = array();
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500868 foreach ($query->result_array() as $row)
Derek Allard2067d1a2008-11-13 22:59:24 +0000869 {
870 if (isset($row['COLUMN_NAME']))
871 {
872 $retval[] = $row['COLUMN_NAME'];
873 }
874 else
875 {
876 $retval[] = current($row);
Barry Mienydd671972010-10-04 16:33:58 +0200877 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000878 }
Barry Mienydd671972010-10-04 16:33:58 +0200879
Derek Allard2067d1a2008-11-13 22:59:24 +0000880 $this->data_cache['field_names'][$table] = $retval;
881 return $this->data_cache['field_names'][$table];
882 }
883
884 // --------------------------------------------------------------------
885
886 /**
887 * Determine if a particular field exists
888 * @access public
889 * @param string
890 * @param string
891 * @return boolean
892 */
893 function field_exists($field_name, $table_name)
Barry Mienydd671972010-10-04 16:33:58 +0200894 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000895 return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
896 }
Barry Mienydd671972010-10-04 16:33:58 +0200897
Derek Allard2067d1a2008-11-13 22:59:24 +0000898 // --------------------------------------------------------------------
899
900 /**
901 * Returns an object with field data
902 *
903 * @access public
904 * @param string the table name
Barry Mienydd671972010-10-04 16:33:58 +0200905 * @return object
906 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000907 function field_data($table = '')
908 {
909 if ($table == '')
910 {
911 if ($this->db_debug)
912 {
913 return $this->display_error('db_field_param_missing');
914 }
915 return FALSE;
916 }
Barry Mienydd671972010-10-04 16:33:58 +0200917
Derek Allard2067d1a2008-11-13 22:59:24 +0000918 $query = $this->query($this->_field_data($this->_protect_identifiers($table, TRUE, NULL, FALSE)));
919
920 return $query->field_data();
Barry Mienydd671972010-10-04 16:33:58 +0200921 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000922
923 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200924
Derek Allard2067d1a2008-11-13 22:59:24 +0000925 /**
926 * Generate an insert string
927 *
928 * @access public
929 * @param string the table upon which the query will be performed
930 * @param array an associative array data of key/values
Barry Mienydd671972010-10-04 16:33:58 +0200931 * @return string
932 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000933 function insert_string($table, $data)
934 {
935 $fields = array();
936 $values = array();
Barry Mienydd671972010-10-04 16:33:58 +0200937
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500938 foreach ($data as $key => $val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000939 {
940 $fields[] = $this->_escape_identifiers($key);
941 $values[] = $this->escape($val);
942 }
Barry Mienydd671972010-10-04 16:33:58 +0200943
Derek Allard2067d1a2008-11-13 22:59:24 +0000944 return $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values);
Barry Mienydd671972010-10-04 16:33:58 +0200945 }
946
Derek Allard2067d1a2008-11-13 22:59:24 +0000947 // --------------------------------------------------------------------
948
949 /**
950 * Generate an update string
951 *
952 * @access public
953 * @param string the table upon which the query will be performed
954 * @param array an associative array data of key/values
955 * @param mixed the "where" statement
Barry Mienydd671972010-10-04 16:33:58 +0200956 * @return string
957 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000958 function update_string($table, $data, $where)
959 {
960 if ($where == '')
961 {
962 return false;
963 }
Barry Mienydd671972010-10-04 16:33:58 +0200964
Derek Allard2067d1a2008-11-13 22:59:24 +0000965 $fields = array();
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500966 foreach ($data as $key => $val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000967 {
968 $fields[$this->_protect_identifiers($key)] = $this->escape($val);
969 }
970
971 if ( ! is_array($where))
972 {
973 $dest = array($where);
974 }
975 else
976 {
977 $dest = array();
978 foreach ($where as $key => $val)
979 {
980 $prefix = (count($dest) == 0) ? '' : ' AND ';
Andrey Andreevdc46d992011-09-24 16:25:23 +0300981 $key = $this->_protect_identifiers($key);
Barry Mienydd671972010-10-04 16:33:58 +0200982
Derek Allard2067d1a2008-11-13 22:59:24 +0000983 if ($val !== '')
984 {
985 if ( ! $this->_has_operator($key))
986 {
987 $key .= ' =';
988 }
Barry Mienydd671972010-10-04 16:33:58 +0200989
Derek Allard2067d1a2008-11-13 22:59:24 +0000990 $val = ' '.$this->escape($val);
991 }
Barry Mienydd671972010-10-04 16:33:58 +0200992
Derek Allard2067d1a2008-11-13 22:59:24 +0000993 $dest[] = $prefix.$key.$val;
994 }
Barry Mienydd671972010-10-04 16:33:58 +0200995 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000996
997 return $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest);
Barry Mienydd671972010-10-04 16:33:58 +0200998 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000999
1000 // --------------------------------------------------------------------
1001
1002 /**
1003 * Tests whether the string has an SQL operator
1004 *
1005 * @access private
1006 * @param string
1007 * @return bool
1008 */
1009 function _has_operator($str)
1010 {
1011 $str = trim($str);
1012 if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str))
1013 {
1014 return FALSE;
1015 }
1016
1017 return TRUE;
1018 }
1019
1020 // --------------------------------------------------------------------
1021
1022 /**
1023 * Enables a native PHP function to be run, using a platform agnostic wrapper.
1024 *
1025 * @access public
1026 * @param string the function name
1027 * @param mixed any parameters needed by the function
Barry Mienydd671972010-10-04 16:33:58 +02001028 * @return mixed
1029 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001030 function call_function($function)
1031 {
1032 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
Barry Mienydd671972010-10-04 16:33:58 +02001033
Derek Allard2067d1a2008-11-13 22:59:24 +00001034 if (FALSE === strpos($driver, $function))
1035 {
1036 $function = $driver.$function;
1037 }
Barry Mienydd671972010-10-04 16:33:58 +02001038
Derek Allard2067d1a2008-11-13 22:59:24 +00001039 if ( ! function_exists($function))
1040 {
1041 if ($this->db_debug)
1042 {
1043 return $this->display_error('db_unsupported_function');
1044 }
1045 return FALSE;
1046 }
1047 else
1048 {
1049 $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
1050
Repox71b78092011-12-01 09:19:43 +01001051 if (is_null($args))
1052 {
1053 return call_user_func($function);
1054 }
1055 else
1056 {
1057 return call_user_func_array($function, $args);
1058 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001059 }
1060 }
1061
1062 // --------------------------------------------------------------------
1063
1064 /**
1065 * Set Cache Directory Path
1066 *
1067 * @access public
1068 * @param string the path to the cache directory
1069 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001070 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001071 function cache_set_path($path = '')
1072 {
1073 $this->cachedir = $path;
1074 }
1075
1076 // --------------------------------------------------------------------
1077
1078 /**
1079 * Enable Query Caching
1080 *
1081 * @access public
1082 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001083 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001084 function cache_on()
1085 {
1086 $this->cache_on = TRUE;
1087 return TRUE;
1088 }
1089
1090 // --------------------------------------------------------------------
1091
1092 /**
1093 * Disable Query Caching
1094 *
1095 * @access public
1096 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001097 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001098 function cache_off()
1099 {
1100 $this->cache_on = FALSE;
1101 return FALSE;
1102 }
Barry Mienydd671972010-10-04 16:33:58 +02001103
Derek Allard2067d1a2008-11-13 22:59:24 +00001104
1105 // --------------------------------------------------------------------
1106
1107 /**
1108 * Delete the cache files associated with a particular URI
1109 *
1110 * @access public
1111 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001112 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001113 function cache_delete($segment_one = '', $segment_two = '')
1114 {
1115 if ( ! $this->_cache_init())
1116 {
1117 return FALSE;
1118 }
1119 return $this->CACHE->delete($segment_one, $segment_two);
1120 }
1121
1122 // --------------------------------------------------------------------
1123
1124 /**
1125 * Delete All cache files
1126 *
1127 * @access public
1128 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001129 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001130 function cache_delete_all()
1131 {
1132 if ( ! $this->_cache_init())
1133 {
1134 return FALSE;
1135 }
1136
1137 return $this->CACHE->delete_all();
1138 }
1139
1140 // --------------------------------------------------------------------
1141
1142 /**
1143 * Initialize the Cache Class
1144 *
1145 * @access private
1146 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001147 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001148 function _cache_init()
1149 {
1150 if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
1151 {
1152 return TRUE;
1153 }
Derek Allarde37ab382009-02-03 16:13:57 +00001154
1155 if ( ! class_exists('CI_DB_Cache'))
Derek Allard2067d1a2008-11-13 22:59:24 +00001156 {
Greg Aker3a746652011-04-19 10:59:47 -05001157 if ( ! @include(BASEPATH.'database/DB_cache.php'))
Derek Allarde37ab382009-02-03 16:13:57 +00001158 {
1159 return $this->cache_off();
1160 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001161 }
Derek Allarde37ab382009-02-03 16:13:57 +00001162
Derek Allard2067d1a2008-11-13 22:59:24 +00001163 $this->CACHE = new CI_DB_Cache($this); // pass db object to support multiple db connections and returned db objects
1164 return TRUE;
1165 }
1166
1167 // --------------------------------------------------------------------
1168
1169 /**
1170 * Close DB Connection
1171 *
1172 * @access public
Barry Mienydd671972010-10-04 16:33:58 +02001173 * @return void
1174 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001175 function close()
1176 {
1177 if (is_resource($this->conn_id) OR is_object($this->conn_id))
1178 {
1179 $this->_close($this->conn_id);
1180 }
1181 $this->conn_id = FALSE;
1182 }
Barry Mienydd671972010-10-04 16:33:58 +02001183
Derek Allard2067d1a2008-11-13 22:59:24 +00001184 // --------------------------------------------------------------------
1185
1186 /**
1187 * Display an error message
1188 *
1189 * @access public
1190 * @param string the error message
1191 * @param string any "swap" values
1192 * @param boolean whether to localize the message
Barry Mienydd671972010-10-04 16:33:58 +02001193 * @return string sends the application/error_db.php template
1194 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001195 function display_error($error = '', $swap = '', $native = FALSE)
1196 {
Derek Jonese7792202010-03-02 17:24:46 -06001197 $LANG =& load_class('Lang', 'core');
Derek Allard2067d1a2008-11-13 22:59:24 +00001198 $LANG->load('db');
1199
1200 $heading = $LANG->line('db_error_heading');
1201
1202 if ($native == TRUE)
1203 {
Andrey Andreev85a99cc2011-09-24 17:17:37 +03001204 $message = (array) $error;
Derek Allard2067d1a2008-11-13 22:59:24 +00001205 }
1206 else
1207 {
1208 $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
1209 }
Barry Mienydd671972010-10-04 16:33:58 +02001210
Pascal Kriete60f8c392010-08-25 18:03:28 +02001211 // Find the most likely culprit of the error by going through
1212 // the backtrace until the source file is no longer in the
1213 // database folder.
Barry Mienydd671972010-10-04 16:33:58 +02001214
Pascal Kriete60f8c392010-08-25 18:03:28 +02001215 $trace = debug_backtrace();
1216
Pascal Krietec3a4a8d2011-02-14 13:40:08 -05001217 foreach ($trace as $call)
Pascal Kriete60f8c392010-08-25 18:03:28 +02001218 {
1219 if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE)
1220 {
1221 // Found it - use a relative path for safety
1222 $message[] = 'Filename: '.str_replace(array(BASEPATH, APPPATH), '', $call['file']);
1223 $message[] = 'Line Number: '.$call['line'];
Barry Mienydd671972010-10-04 16:33:58 +02001224
Pascal Kriete60f8c392010-08-25 18:03:28 +02001225 break;
1226 }
1227 }
Barry Mienydd671972010-10-04 16:33:58 +02001228
Derek Jonese7792202010-03-02 17:24:46 -06001229 $error =& load_class('Exceptions', 'core');
Derek Allard2067d1a2008-11-13 22:59:24 +00001230 echo $error->show_error($heading, $message, 'error_db');
1231 exit;
1232 }
1233
1234 // --------------------------------------------------------------------
1235
1236 /**
1237 * Protect Identifiers
1238 *
1239 * This function adds backticks if appropriate based on db type
1240 *
1241 * @access private
1242 * @param mixed the item to escape
1243 * @return mixed the item with backticks
1244 */
1245 function protect_identifiers($item, $prefix_single = FALSE)
1246 {
1247 return $this->_protect_identifiers($item, $prefix_single);
1248 }
1249
1250 // --------------------------------------------------------------------
1251
1252 /**
1253 * Protect Identifiers
1254 *
1255 * This function is used extensively by the Active Record class, and by
Barry Mienydd671972010-10-04 16:33:58 +02001256 * a couple functions in this class.
Derek Allard2067d1a2008-11-13 22:59:24 +00001257 * It takes a column or table name (optionally with an alias) and inserts
Derek Jones37f4b9c2011-07-01 17:56:50 -05001258 * the table prefix onto it. Some logic is necessary in order to deal with
1259 * column names that include the path. Consider a query like this:
Derek Allard2067d1a2008-11-13 22:59:24 +00001260 *
1261 * SELECT * FROM hostname.database.table.column AS c FROM hostname.database.table
1262 *
1263 * Or a query with aliasing:
1264 *
1265 * SELECT m.member_id, m.member_name FROM members AS m
1266 *
1267 * Since the column name can include up to four segments (host, DB, table, column)
1268 * or also have an alias prefix, we need to do a bit of work to figure this out and
1269 * insert the table prefix (if it exists) in the proper position, and escape only
1270 * the correct identifiers.
1271 *
1272 * @access private
1273 * @param string
1274 * @param bool
1275 * @param mixed
1276 * @param bool
1277 * @return string
Barry Mienydd671972010-10-04 16:33:58 +02001278 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001279 function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE)
1280 {
1281 if ( ! is_bool($protect_identifiers))
1282 {
1283 $protect_identifiers = $this->_protect_identifiers;
1284 }
Derek Allarde37ab382009-02-03 16:13:57 +00001285
1286 if (is_array($item))
1287 {
1288 $escaped_array = array();
1289
Pascal Krietec3a4a8d2011-02-14 13:40:08 -05001290 foreach ($item as $k => $v)
Derek Allarde37ab382009-02-03 16:13:57 +00001291 {
1292 $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v);
1293 }
1294
1295 return $escaped_array;
1296 }
1297
Derek Allard2067d1a2008-11-13 22:59:24 +00001298 // Convert tabs or multiple spaces into single spaces
Derek Jones7b3b96c2009-02-10 21:01:47 +00001299 $item = preg_replace('/[\t ]+/', ' ', $item);
Barry Mienydd671972010-10-04 16:33:58 +02001300
Derek Allard2067d1a2008-11-13 22:59:24 +00001301 // If the item has an alias declaration we remove it and set it aside.
1302 // Basically we remove everything to the right of the first space
1303 $alias = '';
1304 if (strpos($item, ' ') !== FALSE)
Derek Allard911d3e02008-12-15 14:08:35 +00001305 {
Derek Allard2067d1a2008-11-13 22:59:24 +00001306 $alias = strstr($item, " ");
1307 $item = substr($item, 0, - strlen($alias));
1308 }
1309
Derek Allard911d3e02008-12-15 14:08:35 +00001310 // This is basically a bug fix for queries that use MAX, MIN, etc.
Barry Mienydd671972010-10-04 16:33:58 +02001311 // If a parenthesis is found we know that we do not need to
Derek Jones37f4b9c2011-07-01 17:56:50 -05001312 // escape the data or add a prefix. There's probably a more graceful
Derek Allard911d3e02008-12-15 14:08:35 +00001313 // way to deal with this, but I'm not thinking of it -- Rick
1314 if (strpos($item, '(') !== FALSE)
1315 {
1316 return $item.$alias;
1317 }
1318
Derek Allard2067d1a2008-11-13 22:59:24 +00001319 // Break the string apart if it contains periods, then insert the table prefix
1320 // in the correct location, assuming the period doesn't indicate that we're dealing
1321 // with an alias. While we're at it, we will escape the components
1322 if (strpos($item, '.') !== FALSE)
1323 {
1324 $parts = explode('.', $item);
Barry Mienydd671972010-10-04 16:33:58 +02001325
Derek Allard2067d1a2008-11-13 22:59:24 +00001326 // Does the first segment of the exploded item match
Derek Jones37f4b9c2011-07-01 17:56:50 -05001327 // one of the aliases previously identified? If so,
Derek Allard2067d1a2008-11-13 22:59:24 +00001328 // we have nothing more to do other than escape the item
1329 if (in_array($parts[0], $this->ar_aliased_tables))
Derek Allard911d3e02008-12-15 14:08:35 +00001330 {
Derek Allard2067d1a2008-11-13 22:59:24 +00001331 if ($protect_identifiers === TRUE)
1332 {
1333 foreach ($parts as $key => $val)
1334 {
1335 if ( ! in_array($val, $this->_reserved_identifiers))
1336 {
1337 $parts[$key] = $this->_escape_identifiers($val);
1338 }
1339 }
Barry Mienydd671972010-10-04 16:33:58 +02001340
Derek Allard2067d1a2008-11-13 22:59:24 +00001341 $item = implode('.', $parts);
Barry Mienydd671972010-10-04 16:33:58 +02001342 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001343 return $item.$alias;
1344 }
Barry Mienydd671972010-10-04 16:33:58 +02001345
Derek Jones37f4b9c2011-07-01 17:56:50 -05001346 // Is there a table prefix defined in the config file? If not, no need to do anything
Derek Allard2067d1a2008-11-13 22:59:24 +00001347 if ($this->dbprefix != '')
1348 {
1349 // We now add the table prefix based on some logic.
1350 // Do we have 4 segments (hostname.database.table.column)?
1351 // If so, we add the table prefix to the column name in the 3rd segment.
1352 if (isset($parts[3]))
1353 {
1354 $i = 2;
1355 }
1356 // Do we have 3 segments (database.table.column)?
1357 // If so, we add the table prefix to the column name in 2nd position
1358 elseif (isset($parts[2]))
1359 {
1360 $i = 1;
1361 }
1362 // Do we have 2 segments (table.column)?
1363 // If so, we add the table prefix to the column name in 1st segment
1364 else
1365 {
1366 $i = 0;
1367 }
Barry Mienydd671972010-10-04 16:33:58 +02001368
Derek Allard2067d1a2008-11-13 22:59:24 +00001369 // This flag is set when the supplied $item does not contain a field name.
1370 // This can happen when this function is being called from a JOIN.
1371 if ($field_exists == FALSE)
1372 {
1373 $i++;
1374 }
Barry Mienydd671972010-10-04 16:33:58 +02001375
Derek Jones55acc8b2009-07-11 03:38:13 +00001376 // Verify table prefix and replace if necessary
1377 if ($this->swap_pre != '' && strncmp($parts[$i], $this->swap_pre, strlen($this->swap_pre)) === 0)
1378 {
1379 $parts[$i] = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $parts[$i]);
1380 }
Barry Mienydd671972010-10-04 16:33:58 +02001381
Derek Allard2067d1a2008-11-13 22:59:24 +00001382 // We only add the table prefix if it does not already exist
1383 if (substr($parts[$i], 0, strlen($this->dbprefix)) != $this->dbprefix)
1384 {
1385 $parts[$i] = $this->dbprefix.$parts[$i];
1386 }
Barry Mienydd671972010-10-04 16:33:58 +02001387
Derek Allard2067d1a2008-11-13 22:59:24 +00001388 // Put the parts back together
1389 $item = implode('.', $parts);
1390 }
Barry Mienydd671972010-10-04 16:33:58 +02001391
Derek Allard2067d1a2008-11-13 22:59:24 +00001392 if ($protect_identifiers === TRUE)
1393 {
1394 $item = $this->_escape_identifiers($item);
1395 }
Barry Mienydd671972010-10-04 16:33:58 +02001396
Derek Allard2067d1a2008-11-13 22:59:24 +00001397 return $item.$alias;
1398 }
1399
Derek Jones37f4b9c2011-07-01 17:56:50 -05001400 // Is there a table prefix? If not, no need to insert it
Derek Allard2067d1a2008-11-13 22:59:24 +00001401 if ($this->dbprefix != '')
1402 {
Derek Jones55acc8b2009-07-11 03:38:13 +00001403 // Verify table prefix and replace if necessary
1404 if ($this->swap_pre != '' && strncmp($item, $this->swap_pre, strlen($this->swap_pre)) === 0)
1405 {
1406 $item = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $item);
1407 }
1408
Derek Allard2067d1a2008-11-13 22:59:24 +00001409 // Do we prefix an item with no segments?
1410 if ($prefix_single == TRUE AND substr($item, 0, strlen($this->dbprefix)) != $this->dbprefix)
1411 {
1412 $item = $this->dbprefix.$item;
Barry Mienydd671972010-10-04 16:33:58 +02001413 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001414 }
1415
1416 if ($protect_identifiers === TRUE AND ! in_array($item, $this->_reserved_identifiers))
1417 {
1418 $item = $this->_escape_identifiers($item);
1419 }
Barry Mienydd671972010-10-04 16:33:58 +02001420
Derek Allard2067d1a2008-11-13 22:59:24 +00001421 return $item.$alias;
1422 }
Túbal Martín511f2252011-11-24 14:43:45 +01001423
1424 // --------------------------------------------------------------------
Derek Allard2067d1a2008-11-13 22:59:24 +00001425
Túbal Martín511f2252011-11-24 14:43:45 +01001426 /**
1427 * Dummy method that allows Active Record class to be disabled
1428 *
1429 * This function is used extensively by every db driver.
1430 *
1431 * @access private
1432 * @return void
1433 */
1434 protected function _reset_select()
1435 {
1436
1437 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001438
1439}
1440
Derek Allard2067d1a2008-11-13 22:59:24 +00001441/* End of file DB_driver.php */
Andrey Andreevdc46d992011-09-24 16:25:23 +03001442/* Location: ./system/database/DB_driver.php */