blob: dd1b5677ae6e8f38498178b61749495031cd924c [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
21 * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. (http://ellislab.com/)
22 * @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;
84
85
Barry Mienydd671972010-10-04 16:33:58 +020086
Derek Allard2067d1a2008-11-13 22:59:24 +000087 /**
Derek Jones37f4b9c2011-07-01 17:56:50 -050088 * Constructor. Accepts one parameter containing the database
Derek Allard2067d1a2008-11-13 22:59:24 +000089 * connection settings.
90 *
91 * @param array
Barry Mienydd671972010-10-04 16:33:58 +020092 */
Timothy Warrena2097a02011-10-10 10:10:46 -040093 function __construct($params)
Derek Allard2067d1a2008-11-13 22:59:24 +000094 {
95 if (is_array($params))
96 {
97 foreach ($params as $key => $val)
98 {
99 $this->$key = $val;
100 }
101 }
102
103 log_message('debug', 'Database Driver Class Initialized');
104 }
Barry Mienydd671972010-10-04 16:33:58 +0200105
Derek Allard2067d1a2008-11-13 22:59:24 +0000106 // --------------------------------------------------------------------
107
108 /**
109 * Initialize Database Settings
110 *
111 * @access private Called by the constructor
112 * @param mixed
113 * @return void
Barry Mienydd671972010-10-04 16:33:58 +0200114 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000115 function initialize()
116 {
117 // If an existing connection resource is available
118 // there is no need to connect and select the database
119 if (is_resource($this->conn_id) OR is_object($this->conn_id))
120 {
121 return TRUE;
122 }
Barry Mienydd671972010-10-04 16:33:58 +0200123
Derek Allard2067d1a2008-11-13 22:59:24 +0000124 // ----------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200125
Derek Allard2067d1a2008-11-13 22:59:24 +0000126 // Connect to the database and set the connection ID
127 $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
128
Derek Jones37f4b9c2011-07-01 17:56:50 -0500129 // No connection resource? Throw an error
Derek Allard2067d1a2008-11-13 22:59:24 +0000130 if ( ! $this->conn_id)
131 {
132 log_message('error', 'Unable to connect to the database');
Barry Mienydd671972010-10-04 16:33:58 +0200133
Derek Allard2067d1a2008-11-13 22:59:24 +0000134 if ($this->db_debug)
135 {
136 $this->display_error('db_unable_to_connect');
137 }
138 return FALSE;
139 }
140
141 // ----------------------------------------------------------------
142
143 // Select the DB... assuming a database name is specified in the config file
144 if ($this->database != '')
145 {
146 if ( ! $this->db_select())
147 {
148 log_message('error', 'Unable to select database: '.$this->database);
Barry Mienydd671972010-10-04 16:33:58 +0200149
Derek Allard2067d1a2008-11-13 22:59:24 +0000150 if ($this->db_debug)
151 {
152 $this->display_error('db_unable_to_select', $this->database);
153 }
Barry Mienydd671972010-10-04 16:33:58 +0200154 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000155 }
156 else
157 {
158 // We've selected the DB. Now we set the character set
159 if ( ! $this->db_set_charset($this->char_set, $this->dbcollat))
160 {
161 return FALSE;
162 }
Barry Mienydd671972010-10-04 16:33:58 +0200163
Derek Allard2067d1a2008-11-13 22:59:24 +0000164 return TRUE;
165 }
166 }
167
168 return TRUE;
169 }
Barry Mienydd671972010-10-04 16:33:58 +0200170
Derek Allard2067d1a2008-11-13 22:59:24 +0000171 // --------------------------------------------------------------------
172
173 /**
174 * Set client character set
175 *
176 * @access public
177 * @param string
178 * @param string
179 * @return resource
180 */
181 function db_set_charset($charset, $collation)
182 {
183 if ( ! $this->_db_set_charset($this->char_set, $this->dbcollat))
184 {
185 log_message('error', 'Unable to set database connection charset: '.$this->char_set);
Barry Mienydd671972010-10-04 16:33:58 +0200186
Derek Allard2067d1a2008-11-13 22:59:24 +0000187 if ($this->db_debug)
188 {
189 $this->display_error('db_unable_to_set_charset', $this->char_set);
190 }
Barry Mienydd671972010-10-04 16:33:58 +0200191
Derek Allard2067d1a2008-11-13 22:59:24 +0000192 return FALSE;
193 }
Barry Mienydd671972010-10-04 16:33:58 +0200194
Derek Allard2067d1a2008-11-13 22:59:24 +0000195 return TRUE;
196 }
Barry Mienydd671972010-10-04 16:33:58 +0200197
Derek Allard2067d1a2008-11-13 22:59:24 +0000198 // --------------------------------------------------------------------
199
200 /**
201 * The name of the platform in use (mysql, mssql, etc...)
202 *
203 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200204 * @return string
205 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000206 function platform()
207 {
208 return $this->dbdriver;
209 }
210
211 // --------------------------------------------------------------------
212
213 /**
Derek Jones37f4b9c2011-07-01 17:56:50 -0500214 * Database Version Number. Returns a string containing the
Derek Allard2067d1a2008-11-13 22:59:24 +0000215 * version of the database being used
216 *
217 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200218 * @return string
219 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000220 function version()
221 {
222 if (FALSE === ($sql = $this->_version()))
223 {
224 if ($this->db_debug)
225 {
226 return $this->display_error('db_unsupported_function');
227 }
228 return FALSE;
229 }
Derek Allard3683f772009-12-16 17:32:33 +0000230
231 // Some DBs have functions that return the version, and don't run special
232 // SQL queries per se. In these instances, just return the result.
Timothy Warren36fb8de2011-08-24 08:29:05 -0400233 $driver_version_exceptions = array('oci8', 'sqlite', 'cubrid', 'pdo');
Derek Allard3683f772009-12-16 17:32:33 +0000234
235 if (in_array($this->dbdriver, $driver_version_exceptions))
Derek Allard2067d1a2008-11-13 22:59:24 +0000236 {
237 return $sql;
238 }
Derek Allard3683f772009-12-16 17:32:33 +0000239 else
240 {
241 $query = $this->query($sql);
242 return $query->row('ver');
243 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000244 }
Barry Mienydd671972010-10-04 16:33:58 +0200245
Derek Allard2067d1a2008-11-13 22:59:24 +0000246 // --------------------------------------------------------------------
247
248 /**
249 * Execute the query
250 *
251 * Accepts an SQL string as input and returns a result object upon
Derek Jones37f4b9c2011-07-01 17:56:50 -0500252 * successful execution of a "read" type query. Returns boolean TRUE
Derek Allard2067d1a2008-11-13 22:59:24 +0000253 * upon successful execution of a "write" type query. Returns boolean
254 * FALSE upon failure, and if the $db_debug variable is set to TRUE
255 * will raise an error.
256 *
257 * @access public
258 * @param string An SQL query string
259 * @param array An array of binding data
Barry Mienydd671972010-10-04 16:33:58 +0200260 * @return mixed
261 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000262 function query($sql, $binds = FALSE, $return_object = TRUE)
263 {
264 if ($sql == '')
265 {
Niklas Nilssond2018ee2011-08-30 13:39:42 +0200266 log_message('error', 'Invalid query: '.$sql);
267
Derek Allard2067d1a2008-11-13 22:59:24 +0000268 if ($this->db_debug)
269 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000270 return $this->display_error('db_invalid_query');
271 }
272 return FALSE;
273 }
274
275 // Verify table prefix and replace if necessary
276 if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) )
Derek Jonese7792202010-03-02 17:24:46 -0600277 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000278 $sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql);
279 }
Derek Jonese7792202010-03-02 17:24:46 -0600280
Derek Jones37f4b9c2011-07-01 17:56:50 -0500281 // Is query caching enabled? If the query is a "read type"
Derek Allard2067d1a2008-11-13 22:59:24 +0000282 // we will load the caching class and return the previously
283 // cached query if it exists
284 if ($this->cache_on == TRUE AND stristr($sql, 'SELECT'))
285 {
286 if ($this->_cache_init())
287 {
288 $this->load_rdriver();
289 if (FALSE !== ($cache = $this->CACHE->read($sql)))
290 {
291 return $cache;
292 }
293 }
294 }
Barry Mienydd671972010-10-04 16:33:58 +0200295
Derek Allard2067d1a2008-11-13 22:59:24 +0000296 // Compile binds if needed
297 if ($binds !== FALSE)
298 {
299 $sql = $this->compile_binds($sql, $binds);
300 }
301
Derek Jones37f4b9c2011-07-01 17:56:50 -0500302 // Save the query for debugging
Derek Allard2067d1a2008-11-13 22:59:24 +0000303 if ($this->save_queries == TRUE)
304 {
305 $this->queries[] = $sql;
306 }
Barry Mienydd671972010-10-04 16:33:58 +0200307
Derek Allard2067d1a2008-11-13 22:59:24 +0000308 // Start the Query Timer
309 $time_start = list($sm, $ss) = explode(' ', microtime());
Barry Mienydd671972010-10-04 16:33:58 +0200310
Derek Allard2067d1a2008-11-13 22:59:24 +0000311 // Run the Query
312 if (FALSE === ($this->result_id = $this->simple_query($sql)))
313 {
314 if ($this->save_queries == TRUE)
315 {
316 $this->query_times[] = 0;
317 }
Barry Mienydd671972010-10-04 16:33:58 +0200318
Derek Allard2067d1a2008-11-13 22:59:24 +0000319 // This will trigger a rollback if transactions are being used
320 $this->_trans_status = FALSE;
321
Niklas Nilssond2018ee2011-08-30 13:39:42 +0200322 // Grab the error number and message now, as we might run some
323 // additional queries before displaying the error
324 $error_no = $this->_error_number();
325 $error_msg = $this->_error_message();
326
327 // Log errors
328 log_message('error', 'Query error: '.$error_msg);
329
Derek Allard2067d1a2008-11-13 22:59:24 +0000330 if ($this->db_debug)
331 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000332 // We call this function in order to roll-back queries
Derek Jones37f4b9c2011-07-01 17:56:50 -0500333 // if transactions are enabled. If we don't call this here
Barry Mienydd671972010-10-04 16:33:58 +0200334 // the error message will trigger an exit, causing the
Derek Allard2067d1a2008-11-13 22:59:24 +0000335 // transactions to remain in limbo.
336 $this->trans_complete();
337
Niklas Nilssond2018ee2011-08-30 13:39:42 +0200338 // Display errors
Derek Allard2067d1a2008-11-13 22:59:24 +0000339 return $this->display_error(
340 array(
341 'Error Number: '.$error_no,
342 $error_msg,
343 $sql
344 )
345 );
346 }
Barry Mienydd671972010-10-04 16:33:58 +0200347
Derek Allard2067d1a2008-11-13 22:59:24 +0000348 return FALSE;
349 }
Barry Mienydd671972010-10-04 16:33:58 +0200350
Derek Allard2067d1a2008-11-13 22:59:24 +0000351 // Stop and aggregate the query time results
352 $time_end = list($em, $es) = explode(' ', microtime());
353 $this->benchmark += ($em + $es) - ($sm + $ss);
354
355 if ($this->save_queries == TRUE)
356 {
357 $this->query_times[] = ($em + $es) - ($sm + $ss);
358 }
Barry Mienydd671972010-10-04 16:33:58 +0200359
Derek Allard2067d1a2008-11-13 22:59:24 +0000360 // Increment the query counter
361 $this->query_count++;
Barry Mienydd671972010-10-04 16:33:58 +0200362
Derek Allard2067d1a2008-11-13 22:59:24 +0000363 // Was the query a "write" type?
364 // If so we'll simply return true
365 if ($this->is_write_type($sql) === TRUE)
366 {
367 // If caching is enabled we'll auto-cleanup any
368 // existing files related to this particular URI
369 if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init())
370 {
371 $this->CACHE->delete();
372 }
Barry Mienydd671972010-10-04 16:33:58 +0200373
Derek Allard2067d1a2008-11-13 22:59:24 +0000374 return TRUE;
375 }
Barry Mienydd671972010-10-04 16:33:58 +0200376
Derek Allard2067d1a2008-11-13 22:59:24 +0000377 // Return TRUE if we don't need to create a result object
378 // Currently only the Oracle driver uses this when stored
379 // procedures are used
380 if ($return_object !== TRUE)
381 {
382 return TRUE;
383 }
Barry Mienydd671972010-10-04 16:33:58 +0200384
385 // Load and instantiate the result driver
386
387 $driver = $this->load_rdriver();
388 $RES = new $driver();
Derek Allard2067d1a2008-11-13 22:59:24 +0000389 $RES->conn_id = $this->conn_id;
390 $RES->result_id = $this->result_id;
391
392 if ($this->dbdriver == 'oci8')
393 {
394 $RES->stmt_id = $this->stmt_id;
395 $RES->curs_id = NULL;
396 $RES->limit_used = $this->limit_used;
397 $this->stmt_id = FALSE;
398 }
Barry Mienydd671972010-10-04 16:33:58 +0200399
Derek Allard2067d1a2008-11-13 22:59:24 +0000400 // oci8 vars must be set before calling this
401 $RES->num_rows = $RES->num_rows();
Barry Mienydd671972010-10-04 16:33:58 +0200402
Derek Jones37f4b9c2011-07-01 17:56:50 -0500403 // Is query caching enabled? If so, we'll serialize the
Derek Allard2067d1a2008-11-13 22:59:24 +0000404 // result object and save it to a cache file.
405 if ($this->cache_on == TRUE AND $this->_cache_init())
406 {
407 // We'll create a new instance of the result object
408 // only without the platform specific driver since
409 // we can't use it with cached data (the query result
410 // resource ID won't be any good once we've cached the
411 // result object, so we'll have to compile the data
412 // and save it)
413 $CR = new CI_DB_result();
Barry Mienydd671972010-10-04 16:33:58 +0200414 $CR->num_rows = $RES->num_rows();
Derek Allard2067d1a2008-11-13 22:59:24 +0000415 $CR->result_object = $RES->result_object();
416 $CR->result_array = $RES->result_array();
Barry Mienydd671972010-10-04 16:33:58 +0200417
Derek Allard2067d1a2008-11-13 22:59:24 +0000418 // Reset these since cached objects can not utilize resource IDs.
419 $CR->conn_id = NULL;
420 $CR->result_id = NULL;
421
422 $this->CACHE->write($sql, $CR);
423 }
Barry Mienydd671972010-10-04 16:33:58 +0200424
Derek Allard2067d1a2008-11-13 22:59:24 +0000425 return $RES;
426 }
427
428 // --------------------------------------------------------------------
429
430 /**
431 * Load the result drivers
432 *
433 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200434 * @return string the name of the result class
435 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000436 function load_rdriver()
437 {
438 $driver = 'CI_DB_'.$this->dbdriver.'_result';
439
440 if ( ! class_exists($driver))
441 {
Greg Aker3a746652011-04-19 10:59:47 -0500442 include_once(BASEPATH.'database/DB_result.php');
443 include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result.php');
Derek Allard2067d1a2008-11-13 22:59:24 +0000444 }
Barry Mienydd671972010-10-04 16:33:58 +0200445
Derek Allard2067d1a2008-11-13 22:59:24 +0000446 return $driver;
447 }
Barry Mienydd671972010-10-04 16:33:58 +0200448
Derek Allard2067d1a2008-11-13 22:59:24 +0000449 // --------------------------------------------------------------------
450
451 /**
452 * Simple Query
Derek Jones37f4b9c2011-07-01 17:56:50 -0500453 * This is a simplified version of the query() function. Internally
Derek Allard2067d1a2008-11-13 22:59:24 +0000454 * we only use it when running transaction commands since they do
455 * not require all the features of the main query() function.
456 *
457 * @access public
458 * @param string the sql query
Barry Mienydd671972010-10-04 16:33:58 +0200459 * @return mixed
460 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000461 function simple_query($sql)
462 {
463 if ( ! $this->conn_id)
464 {
465 $this->initialize();
466 }
467
468 return $this->_execute($sql);
469 }
Barry Mienydd671972010-10-04 16:33:58 +0200470
Derek Allard2067d1a2008-11-13 22:59:24 +0000471 // --------------------------------------------------------------------
472
473 /**
474 * Disable Transactions
475 * This permits transactions to be disabled at run-time.
476 *
477 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200478 * @return void
479 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000480 function trans_off()
481 {
482 $this->trans_enabled = FALSE;
483 }
484
485 // --------------------------------------------------------------------
486
487 /**
488 * Enable/disable Transaction Strict Mode
489 * When strict mode is enabled, if you are running multiple groups of
490 * transactions, if one group fails all groups will be rolled back.
491 * If strict mode is disabled, each group is treated autonomously, meaning
492 * a failure of one group will not affect any others
493 *
494 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200495 * @return void
496 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000497 function trans_strict($mode = TRUE)
498 {
499 $this->trans_strict = is_bool($mode) ? $mode : TRUE;
500 }
Barry Mienydd671972010-10-04 16:33:58 +0200501
Derek Allard2067d1a2008-11-13 22:59:24 +0000502 // --------------------------------------------------------------------
503
504 /**
505 * Start Transaction
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_start($test_mode = FALSE)
Barry Mienydd671972010-10-04 16:33:58 +0200511 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000512 if ( ! $this->trans_enabled)
513 {
514 return FALSE;
515 }
516
517 // When transactions are nested we only begin/commit/rollback the outermost ones
518 if ($this->_trans_depth > 0)
519 {
520 $this->_trans_depth += 1;
521 return;
522 }
Barry Mienydd671972010-10-04 16:33:58 +0200523
Derek Allard2067d1a2008-11-13 22:59:24 +0000524 $this->trans_begin($test_mode);
525 }
526
527 // --------------------------------------------------------------------
528
529 /**
530 * Complete Transaction
531 *
532 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200533 * @return bool
534 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000535 function trans_complete()
536 {
537 if ( ! $this->trans_enabled)
538 {
539 return FALSE;
540 }
Barry Mienydd671972010-10-04 16:33:58 +0200541
Derek Allard2067d1a2008-11-13 22:59:24 +0000542 // When transactions are nested we only begin/commit/rollback the outermost ones
543 if ($this->_trans_depth > 1)
544 {
545 $this->_trans_depth -= 1;
546 return TRUE;
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 *
631 * @access public
632 * @param string An SQL query string
Barry Mienydd671972010-10-04 16:33:58 +0200633 * @return boolean
634 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000635 function is_write_type($sql)
636 {
Derek Allarde37ab382009-02-03 16:13:57 +0000637 if ( ! preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql))
Derek Allard2067d1a2008-11-13 22:59:24 +0000638 {
639 return FALSE;
640 }
641 return TRUE;
642 }
Barry Mienydd671972010-10-04 16:33:58 +0200643
Derek Allard2067d1a2008-11-13 22:59:24 +0000644 // --------------------------------------------------------------------
645
646 /**
647 * Calculate the aggregate query elapsed time
648 *
649 * @access public
650 * @param integer The number of decimal places
Barry Mienydd671972010-10-04 16:33:58 +0200651 * @return integer
652 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000653 function elapsed_time($decimals = 6)
654 {
655 return number_format($this->benchmark, $decimals);
656 }
Barry Mienydd671972010-10-04 16:33:58 +0200657
Derek Allard2067d1a2008-11-13 22:59:24 +0000658 // --------------------------------------------------------------------
659
660 /**
661 * Returns the total number of queries
662 *
663 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200664 * @return integer
665 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000666 function total_queries()
667 {
668 return $this->query_count;
669 }
Barry Mienydd671972010-10-04 16:33:58 +0200670
Derek Allard2067d1a2008-11-13 22:59:24 +0000671 // --------------------------------------------------------------------
672
673 /**
674 * Returns the last query that was executed
675 *
676 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200677 * @return void
678 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000679 function last_query()
680 {
681 return end($this->queries);
682 }
683
684 // --------------------------------------------------------------------
685
686 /**
687 * "Smart" Escape String
688 *
689 * Escapes data based on type
690 * Sets boolean and null types
691 *
692 * @access public
693 * @param string
Barry Mienydd671972010-10-04 16:33:58 +0200694 * @return mixed
695 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000696 function escape($str)
Barry Mienydd671972010-10-04 16:33:58 +0200697 {
Derek Jonesa377bdd2009-02-11 18:55:24 +0000698 if (is_string($str))
Derek Allard2067d1a2008-11-13 22:59:24 +0000699 {
Derek Jonesa377bdd2009-02-11 18:55:24 +0000700 $str = "'".$this->escape_str($str)."'";
701 }
702 elseif (is_bool($str))
703 {
704 $str = ($str === FALSE) ? 0 : 1;
705 }
706 elseif (is_null($str))
707 {
708 $str = 'NULL';
709 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000710
711 return $str;
712 }
713
714 // --------------------------------------------------------------------
Derek Jonese7792202010-03-02 17:24:46 -0600715
Derek Jonese4ed5832009-02-20 21:44:59 +0000716 /**
Derek Jonesbdc7fb92009-02-20 21:55:10 +0000717 * Escape LIKE String
Derek Jonese4ed5832009-02-20 21:44:59 +0000718 *
719 * Calls the individual driver for platform
720 * specific escaping for LIKE conditions
Barry Mienydd671972010-10-04 16:33:58 +0200721 *
Derek Jonese4ed5832009-02-20 21:44:59 +0000722 * @access public
723 * @param string
724 * @return mixed
725 */
Barry Mienydd671972010-10-04 16:33:58 +0200726 function escape_like_str($str)
727 {
728 return $this->escape_str($str, TRUE);
Derek Jonese4ed5832009-02-20 21:44:59 +0000729 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000730
Derek Jonese4ed5832009-02-20 21:44:59 +0000731 // --------------------------------------------------------------------
Derek Jonese7792202010-03-02 17:24:46 -0600732
Derek Allard2067d1a2008-11-13 22:59:24 +0000733 /**
734 * Primary
735 *
Derek Jones37f4b9c2011-07-01 17:56:50 -0500736 * Retrieves the primary key. It assumes that the row in the first
Derek Allard2067d1a2008-11-13 22:59:24 +0000737 * position is the primary key
738 *
739 * @access public
740 * @param string the table name
Barry Mienydd671972010-10-04 16:33:58 +0200741 * @return string
742 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000743 function primary($table = '')
Barry Mienydd671972010-10-04 16:33:58 +0200744 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000745 $fields = $this->list_fields($table);
Barry Mienydd671972010-10-04 16:33:58 +0200746
Derek Allard2067d1a2008-11-13 22:59:24 +0000747 if ( ! is_array($fields))
748 {
749 return FALSE;
750 }
751
752 return current($fields);
753 }
754
755 // --------------------------------------------------------------------
756
757 /**
758 * Returns an array of table names
759 *
760 * @access public
Barry Mienydd671972010-10-04 16:33:58 +0200761 * @return array
762 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000763 function list_tables($constrain_by_prefix = FALSE)
764 {
765 // Is there a cached result?
766 if (isset($this->data_cache['table_names']))
767 {
768 return $this->data_cache['table_names'];
769 }
Barry Mienydd671972010-10-04 16:33:58 +0200770
Derek Allard2067d1a2008-11-13 22:59:24 +0000771 if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
772 {
773 if ($this->db_debug)
774 {
775 return $this->display_error('db_unsupported_function');
776 }
777 return FALSE;
778 }
779
780 $retval = array();
781 $query = $this->query($sql);
Barry Mienydd671972010-10-04 16:33:58 +0200782
Derek Allard2067d1a2008-11-13 22:59:24 +0000783 if ($query->num_rows() > 0)
784 {
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500785 foreach ($query->result_array() as $row)
Derek Allard2067d1a2008-11-13 22:59:24 +0000786 {
787 if (isset($row['TABLE_NAME']))
788 {
789 $retval[] = $row['TABLE_NAME'];
790 }
791 else
792 {
793 $retval[] = array_shift($row);
794 }
795 }
796 }
797
798 $this->data_cache['table_names'] = $retval;
799 return $this->data_cache['table_names'];
800 }
Barry Mienydd671972010-10-04 16:33:58 +0200801
Derek Allard2067d1a2008-11-13 22:59:24 +0000802 // --------------------------------------------------------------------
803
804 /**
805 * Determine if a particular table exists
806 * @access public
807 * @return boolean
808 */
809 function table_exists($table_name)
Barry Mienydd671972010-10-04 16:33:58 +0200810 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000811 return ( ! in_array($this->_protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables())) ? FALSE : TRUE;
812 }
Barry Mienydd671972010-10-04 16:33:58 +0200813
Derek Allard2067d1a2008-11-13 22:59:24 +0000814 // --------------------------------------------------------------------
815
816 /**
817 * Fetch MySQL Field Names
818 *
819 * @access public
820 * @param string the table name
Barry Mienydd671972010-10-04 16:33:58 +0200821 * @return array
Derek Allard2067d1a2008-11-13 22:59:24 +0000822 */
823 function list_fields($table = '')
824 {
825 // Is there a cached result?
826 if (isset($this->data_cache['field_names'][$table]))
827 {
828 return $this->data_cache['field_names'][$table];
829 }
Barry Mienydd671972010-10-04 16:33:58 +0200830
Derek Allard2067d1a2008-11-13 22:59:24 +0000831 if ($table == '')
832 {
833 if ($this->db_debug)
834 {
835 return $this->display_error('db_field_param_missing');
836 }
837 return FALSE;
838 }
Barry Mienydd671972010-10-04 16:33:58 +0200839
Greg Aker1edde302010-01-26 00:17:01 +0000840 if (FALSE === ($sql = $this->_list_columns($table)))
Derek Allard2067d1a2008-11-13 22:59:24 +0000841 {
842 if ($this->db_debug)
843 {
844 return $this->display_error('db_unsupported_function');
845 }
846 return FALSE;
847 }
Barry Mienydd671972010-10-04 16:33:58 +0200848
Derek Allard2067d1a2008-11-13 22:59:24 +0000849 $query = $this->query($sql);
Barry Mienydd671972010-10-04 16:33:58 +0200850
Derek Allard2067d1a2008-11-13 22:59:24 +0000851 $retval = array();
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500852 foreach ($query->result_array() as $row)
Derek Allard2067d1a2008-11-13 22:59:24 +0000853 {
854 if (isset($row['COLUMN_NAME']))
855 {
856 $retval[] = $row['COLUMN_NAME'];
857 }
858 else
859 {
860 $retval[] = current($row);
Barry Mienydd671972010-10-04 16:33:58 +0200861 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000862 }
Barry Mienydd671972010-10-04 16:33:58 +0200863
Derek Allard2067d1a2008-11-13 22:59:24 +0000864 $this->data_cache['field_names'][$table] = $retval;
865 return $this->data_cache['field_names'][$table];
866 }
867
868 // --------------------------------------------------------------------
869
870 /**
871 * Determine if a particular field exists
872 * @access public
873 * @param string
874 * @param string
875 * @return boolean
876 */
877 function field_exists($field_name, $table_name)
Barry Mienydd671972010-10-04 16:33:58 +0200878 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000879 return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
880 }
Barry Mienydd671972010-10-04 16:33:58 +0200881
Derek Allard2067d1a2008-11-13 22:59:24 +0000882 // --------------------------------------------------------------------
883
884 /**
885 * Returns an object with field data
886 *
887 * @access public
888 * @param string the table name
Barry Mienydd671972010-10-04 16:33:58 +0200889 * @return object
890 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000891 function field_data($table = '')
892 {
893 if ($table == '')
894 {
895 if ($this->db_debug)
896 {
897 return $this->display_error('db_field_param_missing');
898 }
899 return FALSE;
900 }
Barry Mienydd671972010-10-04 16:33:58 +0200901
Derek Allard2067d1a2008-11-13 22:59:24 +0000902 $query = $this->query($this->_field_data($this->_protect_identifiers($table, TRUE, NULL, FALSE)));
903
904 return $query->field_data();
Barry Mienydd671972010-10-04 16:33:58 +0200905 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000906
907 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200908
Derek Allard2067d1a2008-11-13 22:59:24 +0000909 /**
910 * Generate an insert string
911 *
912 * @access public
913 * @param string the table upon which the query will be performed
914 * @param array an associative array data of key/values
Barry Mienydd671972010-10-04 16:33:58 +0200915 * @return string
916 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000917 function insert_string($table, $data)
918 {
919 $fields = array();
920 $values = array();
Barry Mienydd671972010-10-04 16:33:58 +0200921
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500922 foreach ($data as $key => $val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000923 {
924 $fields[] = $this->_escape_identifiers($key);
925 $values[] = $this->escape($val);
926 }
Barry Mienydd671972010-10-04 16:33:58 +0200927
Derek Allard2067d1a2008-11-13 22:59:24 +0000928 return $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values);
Barry Mienydd671972010-10-04 16:33:58 +0200929 }
930
Derek Allard2067d1a2008-11-13 22:59:24 +0000931 // --------------------------------------------------------------------
932
933 /**
934 * Generate an update string
935 *
936 * @access public
937 * @param string the table upon which the query will be performed
938 * @param array an associative array data of key/values
939 * @param mixed the "where" statement
Barry Mienydd671972010-10-04 16:33:58 +0200940 * @return string
941 */
Derek Allard2067d1a2008-11-13 22:59:24 +0000942 function update_string($table, $data, $where)
943 {
944 if ($where == '')
945 {
946 return false;
947 }
Barry Mienydd671972010-10-04 16:33:58 +0200948
Derek Allard2067d1a2008-11-13 22:59:24 +0000949 $fields = array();
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500950 foreach ($data as $key => $val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000951 {
952 $fields[$this->_protect_identifiers($key)] = $this->escape($val);
953 }
954
955 if ( ! is_array($where))
956 {
957 $dest = array($where);
958 }
959 else
960 {
961 $dest = array();
962 foreach ($where as $key => $val)
963 {
964 $prefix = (count($dest) == 0) ? '' : ' AND ';
Andrey Andreevdc46d992011-09-24 16:25:23 +0300965 $key = $this->_protect_identifiers($key);
Barry Mienydd671972010-10-04 16:33:58 +0200966
Derek Allard2067d1a2008-11-13 22:59:24 +0000967 if ($val !== '')
968 {
969 if ( ! $this->_has_operator($key))
970 {
971 $key .= ' =';
972 }
Barry Mienydd671972010-10-04 16:33:58 +0200973
Derek Allard2067d1a2008-11-13 22:59:24 +0000974 $val = ' '.$this->escape($val);
975 }
Barry Mienydd671972010-10-04 16:33:58 +0200976
Derek Allard2067d1a2008-11-13 22:59:24 +0000977 $dest[] = $prefix.$key.$val;
978 }
Barry Mienydd671972010-10-04 16:33:58 +0200979 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000980
981 return $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest);
Barry Mienydd671972010-10-04 16:33:58 +0200982 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000983
984 // --------------------------------------------------------------------
985
986 /**
987 * Tests whether the string has an SQL operator
988 *
989 * @access private
990 * @param string
991 * @return bool
992 */
993 function _has_operator($str)
994 {
995 $str = trim($str);
996 if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str))
997 {
998 return FALSE;
999 }
1000
1001 return TRUE;
1002 }
1003
1004 // --------------------------------------------------------------------
1005
1006 /**
1007 * Enables a native PHP function to be run, using a platform agnostic wrapper.
1008 *
1009 * @access public
1010 * @param string the function name
1011 * @param mixed any parameters needed by the function
Barry Mienydd671972010-10-04 16:33:58 +02001012 * @return mixed
1013 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001014 function call_function($function)
1015 {
1016 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
Barry Mienydd671972010-10-04 16:33:58 +02001017
Derek Allard2067d1a2008-11-13 22:59:24 +00001018 if (FALSE === strpos($driver, $function))
1019 {
1020 $function = $driver.$function;
1021 }
Barry Mienydd671972010-10-04 16:33:58 +02001022
Derek Allard2067d1a2008-11-13 22:59:24 +00001023 if ( ! function_exists($function))
1024 {
1025 if ($this->db_debug)
1026 {
1027 return $this->display_error('db_unsupported_function');
1028 }
1029 return FALSE;
1030 }
1031 else
1032 {
1033 $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
1034
1035 return call_user_func_array($function, $args);
1036 }
1037 }
1038
1039 // --------------------------------------------------------------------
1040
1041 /**
1042 * Set Cache Directory Path
1043 *
1044 * @access public
1045 * @param string the path to the cache directory
1046 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001047 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001048 function cache_set_path($path = '')
1049 {
1050 $this->cachedir = $path;
1051 }
1052
1053 // --------------------------------------------------------------------
1054
1055 /**
1056 * Enable Query Caching
1057 *
1058 * @access public
1059 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001060 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001061 function cache_on()
1062 {
1063 $this->cache_on = TRUE;
1064 return TRUE;
1065 }
1066
1067 // --------------------------------------------------------------------
1068
1069 /**
1070 * Disable Query Caching
1071 *
1072 * @access public
1073 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001074 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001075 function cache_off()
1076 {
1077 $this->cache_on = FALSE;
1078 return FALSE;
1079 }
Barry Mienydd671972010-10-04 16:33:58 +02001080
Derek Allard2067d1a2008-11-13 22:59:24 +00001081
1082 // --------------------------------------------------------------------
1083
1084 /**
1085 * Delete the cache files associated with a particular URI
1086 *
1087 * @access public
1088 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001089 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001090 function cache_delete($segment_one = '', $segment_two = '')
1091 {
1092 if ( ! $this->_cache_init())
1093 {
1094 return FALSE;
1095 }
1096 return $this->CACHE->delete($segment_one, $segment_two);
1097 }
1098
1099 // --------------------------------------------------------------------
1100
1101 /**
1102 * Delete All cache files
1103 *
1104 * @access public
1105 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001106 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001107 function cache_delete_all()
1108 {
1109 if ( ! $this->_cache_init())
1110 {
1111 return FALSE;
1112 }
1113
1114 return $this->CACHE->delete_all();
1115 }
1116
1117 // --------------------------------------------------------------------
1118
1119 /**
1120 * Initialize the Cache Class
1121 *
1122 * @access private
1123 * @return void
Barry Mienydd671972010-10-04 16:33:58 +02001124 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001125 function _cache_init()
1126 {
1127 if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
1128 {
1129 return TRUE;
1130 }
Derek Allarde37ab382009-02-03 16:13:57 +00001131
1132 if ( ! class_exists('CI_DB_Cache'))
Derek Allard2067d1a2008-11-13 22:59:24 +00001133 {
Greg Aker3a746652011-04-19 10:59:47 -05001134 if ( ! @include(BASEPATH.'database/DB_cache.php'))
Derek Allarde37ab382009-02-03 16:13:57 +00001135 {
1136 return $this->cache_off();
1137 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001138 }
Derek Allarde37ab382009-02-03 16:13:57 +00001139
Derek Allard2067d1a2008-11-13 22:59:24 +00001140 $this->CACHE = new CI_DB_Cache($this); // pass db object to support multiple db connections and returned db objects
1141 return TRUE;
1142 }
1143
1144 // --------------------------------------------------------------------
1145
1146 /**
1147 * Close DB Connection
1148 *
1149 * @access public
Barry Mienydd671972010-10-04 16:33:58 +02001150 * @return void
1151 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001152 function close()
1153 {
1154 if (is_resource($this->conn_id) OR is_object($this->conn_id))
1155 {
1156 $this->_close($this->conn_id);
1157 }
1158 $this->conn_id = FALSE;
1159 }
Barry Mienydd671972010-10-04 16:33:58 +02001160
Derek Allard2067d1a2008-11-13 22:59:24 +00001161 // --------------------------------------------------------------------
1162
1163 /**
1164 * Display an error message
1165 *
1166 * @access public
1167 * @param string the error message
1168 * @param string any "swap" values
1169 * @param boolean whether to localize the message
Barry Mienydd671972010-10-04 16:33:58 +02001170 * @return string sends the application/error_db.php template
1171 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001172 function display_error($error = '', $swap = '', $native = FALSE)
1173 {
Derek Jonese7792202010-03-02 17:24:46 -06001174 $LANG =& load_class('Lang', 'core');
Derek Allard2067d1a2008-11-13 22:59:24 +00001175 $LANG->load('db');
1176
1177 $heading = $LANG->line('db_error_heading');
1178
1179 if ($native == TRUE)
1180 {
Andrey Andreev85a99cc2011-09-24 17:17:37 +03001181 $message = (array) $error;
Derek Allard2067d1a2008-11-13 22:59:24 +00001182 }
1183 else
1184 {
1185 $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
1186 }
Barry Mienydd671972010-10-04 16:33:58 +02001187
Pascal Kriete60f8c392010-08-25 18:03:28 +02001188 // Find the most likely culprit of the error by going through
1189 // the backtrace until the source file is no longer in the
1190 // database folder.
Barry Mienydd671972010-10-04 16:33:58 +02001191
Pascal Kriete60f8c392010-08-25 18:03:28 +02001192 $trace = debug_backtrace();
1193
Pascal Krietec3a4a8d2011-02-14 13:40:08 -05001194 foreach ($trace as $call)
Pascal Kriete60f8c392010-08-25 18:03:28 +02001195 {
1196 if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE)
1197 {
1198 // Found it - use a relative path for safety
1199 $message[] = 'Filename: '.str_replace(array(BASEPATH, APPPATH), '', $call['file']);
1200 $message[] = 'Line Number: '.$call['line'];
Barry Mienydd671972010-10-04 16:33:58 +02001201
Pascal Kriete60f8c392010-08-25 18:03:28 +02001202 break;
1203 }
1204 }
Barry Mienydd671972010-10-04 16:33:58 +02001205
Derek Jonese7792202010-03-02 17:24:46 -06001206 $error =& load_class('Exceptions', 'core');
Derek Allard2067d1a2008-11-13 22:59:24 +00001207 echo $error->show_error($heading, $message, 'error_db');
1208 exit;
1209 }
1210
1211 // --------------------------------------------------------------------
1212
1213 /**
1214 * Protect Identifiers
1215 *
1216 * This function adds backticks if appropriate based on db type
1217 *
1218 * @access private
1219 * @param mixed the item to escape
1220 * @return mixed the item with backticks
1221 */
1222 function protect_identifiers($item, $prefix_single = FALSE)
1223 {
1224 return $this->_protect_identifiers($item, $prefix_single);
1225 }
1226
1227 // --------------------------------------------------------------------
1228
1229 /**
1230 * Protect Identifiers
1231 *
1232 * This function is used extensively by the Active Record class, and by
Barry Mienydd671972010-10-04 16:33:58 +02001233 * a couple functions in this class.
Derek Allard2067d1a2008-11-13 22:59:24 +00001234 * It takes a column or table name (optionally with an alias) and inserts
Derek Jones37f4b9c2011-07-01 17:56:50 -05001235 * the table prefix onto it. Some logic is necessary in order to deal with
1236 * column names that include the path. Consider a query like this:
Derek Allard2067d1a2008-11-13 22:59:24 +00001237 *
1238 * SELECT * FROM hostname.database.table.column AS c FROM hostname.database.table
1239 *
1240 * Or a query with aliasing:
1241 *
1242 * SELECT m.member_id, m.member_name FROM members AS m
1243 *
1244 * Since the column name can include up to four segments (host, DB, table, column)
1245 * or also have an alias prefix, we need to do a bit of work to figure this out and
1246 * insert the table prefix (if it exists) in the proper position, and escape only
1247 * the correct identifiers.
1248 *
1249 * @access private
1250 * @param string
1251 * @param bool
1252 * @param mixed
1253 * @param bool
1254 * @return string
Barry Mienydd671972010-10-04 16:33:58 +02001255 */
Derek Allard2067d1a2008-11-13 22:59:24 +00001256 function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE)
1257 {
1258 if ( ! is_bool($protect_identifiers))
1259 {
1260 $protect_identifiers = $this->_protect_identifiers;
1261 }
Derek Allarde37ab382009-02-03 16:13:57 +00001262
1263 if (is_array($item))
1264 {
1265 $escaped_array = array();
1266
Pascal Krietec3a4a8d2011-02-14 13:40:08 -05001267 foreach ($item as $k => $v)
Derek Allarde37ab382009-02-03 16:13:57 +00001268 {
1269 $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v);
1270 }
1271
1272 return $escaped_array;
1273 }
1274
Derek Allard2067d1a2008-11-13 22:59:24 +00001275 // Convert tabs or multiple spaces into single spaces
Derek Jones7b3b96c2009-02-10 21:01:47 +00001276 $item = preg_replace('/[\t ]+/', ' ', $item);
Barry Mienydd671972010-10-04 16:33:58 +02001277
Derek Allard2067d1a2008-11-13 22:59:24 +00001278 // If the item has an alias declaration we remove it and set it aside.
1279 // Basically we remove everything to the right of the first space
1280 $alias = '';
1281 if (strpos($item, ' ') !== FALSE)
Derek Allard911d3e02008-12-15 14:08:35 +00001282 {
Derek Allard2067d1a2008-11-13 22:59:24 +00001283 $alias = strstr($item, " ");
1284 $item = substr($item, 0, - strlen($alias));
1285 }
1286
Derek Allard911d3e02008-12-15 14:08:35 +00001287 // This is basically a bug fix for queries that use MAX, MIN, etc.
Barry Mienydd671972010-10-04 16:33:58 +02001288 // If a parenthesis is found we know that we do not need to
Derek Jones37f4b9c2011-07-01 17:56:50 -05001289 // escape the data or add a prefix. There's probably a more graceful
Derek Allard911d3e02008-12-15 14:08:35 +00001290 // way to deal with this, but I'm not thinking of it -- Rick
1291 if (strpos($item, '(') !== FALSE)
1292 {
1293 return $item.$alias;
1294 }
1295
Derek Allard2067d1a2008-11-13 22:59:24 +00001296 // Break the string apart if it contains periods, then insert the table prefix
1297 // in the correct location, assuming the period doesn't indicate that we're dealing
1298 // with an alias. While we're at it, we will escape the components
1299 if (strpos($item, '.') !== FALSE)
1300 {
1301 $parts = explode('.', $item);
Barry Mienydd671972010-10-04 16:33:58 +02001302
Derek Allard2067d1a2008-11-13 22:59:24 +00001303 // Does the first segment of the exploded item match
Derek Jones37f4b9c2011-07-01 17:56:50 -05001304 // one of the aliases previously identified? If so,
Derek Allard2067d1a2008-11-13 22:59:24 +00001305 // we have nothing more to do other than escape the item
1306 if (in_array($parts[0], $this->ar_aliased_tables))
Derek Allard911d3e02008-12-15 14:08:35 +00001307 {
Derek Allard2067d1a2008-11-13 22:59:24 +00001308 if ($protect_identifiers === TRUE)
1309 {
1310 foreach ($parts as $key => $val)
1311 {
1312 if ( ! in_array($val, $this->_reserved_identifiers))
1313 {
1314 $parts[$key] = $this->_escape_identifiers($val);
1315 }
1316 }
Barry Mienydd671972010-10-04 16:33:58 +02001317
Derek Allard2067d1a2008-11-13 22:59:24 +00001318 $item = implode('.', $parts);
Barry Mienydd671972010-10-04 16:33:58 +02001319 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001320 return $item.$alias;
1321 }
Barry Mienydd671972010-10-04 16:33:58 +02001322
Derek Jones37f4b9c2011-07-01 17:56:50 -05001323 // Is there a table prefix defined in the config file? If not, no need to do anything
Derek Allard2067d1a2008-11-13 22:59:24 +00001324 if ($this->dbprefix != '')
1325 {
1326 // We now add the table prefix based on some logic.
1327 // Do we have 4 segments (hostname.database.table.column)?
1328 // If so, we add the table prefix to the column name in the 3rd segment.
1329 if (isset($parts[3]))
1330 {
1331 $i = 2;
1332 }
1333 // Do we have 3 segments (database.table.column)?
1334 // If so, we add the table prefix to the column name in 2nd position
1335 elseif (isset($parts[2]))
1336 {
1337 $i = 1;
1338 }
1339 // Do we have 2 segments (table.column)?
1340 // If so, we add the table prefix to the column name in 1st segment
1341 else
1342 {
1343 $i = 0;
1344 }
Barry Mienydd671972010-10-04 16:33:58 +02001345
Derek Allard2067d1a2008-11-13 22:59:24 +00001346 // This flag is set when the supplied $item does not contain a field name.
1347 // This can happen when this function is being called from a JOIN.
1348 if ($field_exists == FALSE)
1349 {
1350 $i++;
1351 }
Barry Mienydd671972010-10-04 16:33:58 +02001352
Derek Jones55acc8b2009-07-11 03:38:13 +00001353 // Verify table prefix and replace if necessary
1354 if ($this->swap_pre != '' && strncmp($parts[$i], $this->swap_pre, strlen($this->swap_pre)) === 0)
1355 {
1356 $parts[$i] = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $parts[$i]);
1357 }
Barry Mienydd671972010-10-04 16:33:58 +02001358
Derek Allard2067d1a2008-11-13 22:59:24 +00001359 // We only add the table prefix if it does not already exist
1360 if (substr($parts[$i], 0, strlen($this->dbprefix)) != $this->dbprefix)
1361 {
1362 $parts[$i] = $this->dbprefix.$parts[$i];
1363 }
Barry Mienydd671972010-10-04 16:33:58 +02001364
Derek Allard2067d1a2008-11-13 22:59:24 +00001365 // Put the parts back together
1366 $item = implode('.', $parts);
1367 }
Barry Mienydd671972010-10-04 16:33:58 +02001368
Derek Allard2067d1a2008-11-13 22:59:24 +00001369 if ($protect_identifiers === TRUE)
1370 {
1371 $item = $this->_escape_identifiers($item);
1372 }
Barry Mienydd671972010-10-04 16:33:58 +02001373
Derek Allard2067d1a2008-11-13 22:59:24 +00001374 return $item.$alias;
1375 }
1376
Derek Jones37f4b9c2011-07-01 17:56:50 -05001377 // Is there a table prefix? If not, no need to insert it
Derek Allard2067d1a2008-11-13 22:59:24 +00001378 if ($this->dbprefix != '')
1379 {
Derek Jones55acc8b2009-07-11 03:38:13 +00001380 // Verify table prefix and replace if necessary
1381 if ($this->swap_pre != '' && strncmp($item, $this->swap_pre, strlen($this->swap_pre)) === 0)
1382 {
1383 $item = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $item);
1384 }
1385
Derek Allard2067d1a2008-11-13 22:59:24 +00001386 // Do we prefix an item with no segments?
1387 if ($prefix_single == TRUE AND substr($item, 0, strlen($this->dbprefix)) != $this->dbprefix)
1388 {
1389 $item = $this->dbprefix.$item;
Barry Mienydd671972010-10-04 16:33:58 +02001390 }
Derek Allard2067d1a2008-11-13 22:59:24 +00001391 }
1392
1393 if ($protect_identifiers === TRUE AND ! in_array($item, $this->_reserved_identifiers))
1394 {
1395 $item = $this->_escape_identifiers($item);
1396 }
Barry Mienydd671972010-10-04 16:33:58 +02001397
Derek Allard2067d1a2008-11-13 22:59:24 +00001398 return $item.$alias;
1399 }
1400
1401
1402}
1403
1404
1405/* End of file DB_driver.php */
Andrey Andreevdc46d992011-09-24 16:25:23 +03001406/* Location: ./system/database/DB_driver.php */