blob: 257f1ee9bfe0198d24bd79798db65d835426bb3e [file] [log] [blame]
Derek Jones0b59f272008-05-13 04:22:33 +00001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allardd2df9bc2007-04-15 17:41:17 +00002/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
Derek Allard3d879d52008-01-18 19:41:32 +00008 * @author ExpressionEngine Dev Team
Rick Ellis37b3ecf2008-09-12 23:34:18 +00009 * @copyright Copyright (c) 2008, EllisLab, Inc.
Derek Jones7a9193a2008-01-21 18:39:20 +000010 * @license http://codeigniter.com/user_guide/license.html
11 * @link http://codeigniter.com
Derek Allardd2df9bc2007-04-15 17:41:17 +000012 * @since Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
17
18/**
19 * Database Driver Class
20 *
21 * This is the platform-independent base DB implementation class.
22 * This class will not be called directly. Rather, the adapter
23 * class for the specific database will extend and instantiate it.
24 *
25 * @package CodeIgniter
26 * @subpackage Drivers
27 * @category Database
Derek Allard3d879d52008-01-18 19:41:32 +000028 * @author ExpressionEngine Dev Team
Derek Jones7a9193a2008-01-21 18:39:20 +000029 * @link http://codeigniter.com/user_guide/database/
Derek Allardd2df9bc2007-04-15 17:41:17 +000030 */
31class CI_DB_driver {
32
33 var $username;
34 var $password;
35 var $hostname;
36 var $database;
37 var $dbdriver = 'mysql';
38 var $dbprefix = '';
Derek Jonescafd63e2008-05-14 15:08:17 +000039 var $char_set = 'utf8';
40 var $dbcollat = 'utf8_general_ci';
Derek Allard39b622d2008-01-16 21:10:09 +000041 var $autoinit = TRUE; // Whether to automatically initialize the DB
42 var $swap_pre = '';
Derek Allardd2df9bc2007-04-15 17:41:17 +000043 var $port = '';
44 var $pconnect = FALSE;
45 var $conn_id = FALSE;
46 var $result_id = FALSE;
47 var $db_debug = FALSE;
48 var $benchmark = 0;
49 var $query_count = 0;
50 var $bind_marker = '?';
Rick Ellis40990462007-07-17 21:40:44 +000051 var $save_queries = TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +000052 var $queries = array();
Derek Jones56e9fa52008-01-23 17:26:37 +000053 var $query_times = array();
Derek Allardd2df9bc2007-04-15 17:41:17 +000054 var $data_cache = array();
55 var $trans_enabled = TRUE;
Rick Ellis244b4c72008-05-12 18:21:33 +000056 var $trans_strict = TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +000057 var $_trans_depth = 0;
Rick Ellis28239ad2007-06-11 04:26:39 +000058 var $_trans_status = TRUE; // Used with transactions to determine if a rollback should occur
Derek Allardd2df9bc2007-04-15 17:41:17 +000059 var $cache_on = FALSE;
60 var $cachedir = '';
61 var $cache_autodel = FALSE;
62 var $CACHE; // The cache class object
63
64
65 // These are use with Oracle
66 var $stmt_id;
67 var $curs_id;
68 var $limit_used;
69
70
71
72 /**
73 * Constructor. Accepts one parameter containing the database
74 * connection settings.
75 *
Derek Jones7dd38382008-02-13 04:52:58 +000076 * @param array
Derek Allardd2df9bc2007-04-15 17:41:17 +000077 */
78 function CI_DB_driver($params)
79 {
Derek Allardd2df9bc2007-04-15 17:41:17 +000080 if (is_array($params))
81 {
Derek Allard39b622d2008-01-16 21:10:09 +000082 foreach ($params as $key => $val)
Derek Allardd2df9bc2007-04-15 17:41:17 +000083 {
Derek Allard39b622d2008-01-16 21:10:09 +000084 $this->$key = $val;
Derek Allardd2df9bc2007-04-15 17:41:17 +000085 }
86 }
Derek Allard39b622d2008-01-16 21:10:09 +000087
88 log_message('debug', 'Database Driver Class Initialized');
89 }
90
91 // --------------------------------------------------------------------
92
93 /**
94 * Initialize Database Settings
95 *
96 * @access private Called by the constructor
97 * @param mixed
98 * @return void
99 */
100 function initialize($create_db = FALSE)
101 {
Derek Allardd2df9bc2007-04-15 17:41:17 +0000102 // If an existing DB connection resource is supplied
103 // there is no need to connect and select the database
Derek Jones05097752008-05-07 19:58:23 +0000104 if (is_resource($this->conn_id) OR is_object($this->conn_id))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000105 {
106 return TRUE;
107 }
108
109 // Connect to the database
110 $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
111
112 // No connection? Throw an error
Rick Ellis244b4c72008-05-12 18:21:33 +0000113 if ( ! $this->conn_id)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000114 {
115 log_message('error', 'Unable to connect to the database');
116
117 if ($this->db_debug)
118 {
119 $this->display_error('db_unable_to_connect');
120 }
121 return FALSE;
122 }
123
124 // Select the database
125 if ($this->database != '')
126 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000127 if ( ! $this->db_select())
Derek Allardd2df9bc2007-04-15 17:41:17 +0000128 {
Derek Allard39b622d2008-01-16 21:10:09 +0000129 // Should we attempt to create the database?
130 if ($create_db == TRUE)
131 {
132 // Load the DB utility class
133 $CI =& get_instance();
134 $CI->load->dbutil();
135
136 // Create the DB
Rick Ellis244b4c72008-05-12 18:21:33 +0000137 if ( ! $CI->dbutil->create_database($this->database))
Derek Allard39b622d2008-01-16 21:10:09 +0000138 {
139 log_message('error', 'Unable to create database: '.$this->database);
140
141 if ($this->db_debug)
142 {
143 $this->display_error('db_unable_to_create', $this->database);
144 }
Derek Allard993925b2008-08-21 12:43:31 +0000145 return FALSE;
Derek Allard39b622d2008-01-16 21:10:09 +0000146 }
147 else
148 {
149 // In the event the DB was created we need to select it
150 if ($this->db_select())
151 {
Derek Jones0b59f272008-05-13 04:22:33 +0000152 if ( ! $this->db_set_charset($this->char_set, $this->dbcollat))
Derek Allard39b622d2008-01-16 21:10:09 +0000153 {
154 log_message('error', 'Unable to set database connection charset: '.$this->char_set);
155
156 if ($this->db_debug)
157 {
158 $this->display_error('db_unable_to_set_charset', $this->char_set);
159 }
160
161 return FALSE;
162 }
163
164 return TRUE;
165 }
166 }
167 }
168
Derek Allardd2df9bc2007-04-15 17:41:17 +0000169 log_message('error', 'Unable to select database: '.$this->database);
170
171 if ($this->db_debug)
172 {
173 $this->display_error('db_unable_to_select', $this->database);
174 }
175 return FALSE;
176 }
Derek Allard39b622d2008-01-16 21:10:09 +0000177
Derek Jones0b59f272008-05-13 04:22:33 +0000178 if ( ! $this->db_set_charset($this->char_set, $this->dbcollat))
Derek Allard39b622d2008-01-16 21:10:09 +0000179 {
180 log_message('error', 'Unable to set database connection charset: '.$this->char_set);
181
182 if ($this->db_debug)
183 {
184 $this->display_error('db_unable_to_set_charset', $this->char_set);
185 }
186
187 return FALSE;
188 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000189 }
190
191 return TRUE;
192 }
193
194 // --------------------------------------------------------------------
195
196 /**
197 * The name of the platform in use (mysql, mssql, etc...)
198 *
199 * @access public
200 * @return string
201 */
202 function platform()
203 {
204 return $this->dbdriver;
205 }
206
207 // --------------------------------------------------------------------
208
209 /**
210 * Database Version Number. Returns a string containing the
211 * version of the database being used
212 *
213 * @access public
214 * @return string
215 */
216 function version()
217 {
218 if (FALSE === ($sql = $this->_version()))
219 {
220 if ($this->db_debug)
221 {
222 return $this->display_error('db_unsupported_function');
223 }
Derek Allard993925b2008-08-21 12:43:31 +0000224 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000225 }
226
227 if ($this->dbdriver == 'oci8')
228 {
229 return $sql;
230 }
231
232 $query = $this->query($sql);
Derek Allard39b622d2008-01-16 21:10:09 +0000233 return $query->row('ver');
Derek Allardd2df9bc2007-04-15 17:41:17 +0000234 }
235
236 // --------------------------------------------------------------------
237
238 /**
239 * Execute the query
240 *
241 * Accepts an SQL string as input and returns a result object upon
242 * successful execution of a "read" type query. Returns boolean TRUE
243 * upon successful execution of a "write" type query. Returns boolean
244 * FALSE upon failure, and if the $db_debug variable is set to TRUE
245 * will raise an error.
246 *
247 * @access public
248 * @param string An SQL query string
249 * @param array An array of binding data
250 * @return mixed
251 */
252 function query($sql, $binds = FALSE, $return_object = TRUE)
253 {
254 if ($sql == '')
255 {
256 if ($this->db_debug)
257 {
258 log_message('error', 'Invalid query: '.$sql);
259 return $this->display_error('db_invalid_query');
260 }
Derek Allard993925b2008-08-21 12:43:31 +0000261 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000262 }
Derek Allard39b622d2008-01-16 21:10:09 +0000263
264 // Verify table prefix and replace if necessary
265 if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) )
266 {
267 $sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql);
268 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000269
270 // Is query caching enabled? If the query is a "read type"
271 // we will load the caching class and return the previously
272 // cached query if it exists
273 if ($this->cache_on == TRUE AND stristr($sql, 'SELECT'))
274 {
275 if ($this->_cache_init())
276 {
277 $this->load_rdriver();
278 if (FALSE !== ($cache = $this->CACHE->read($sql)))
279 {
280 return $cache;
281 }
282 }
283 }
284
285 // Compile binds if needed
286 if ($binds !== FALSE)
287 {
288 $sql = $this->compile_binds($sql, $binds);
289 }
290
291 // Save the query for debugging
Rick Ellis40990462007-07-17 21:40:44 +0000292 if ($this->save_queries == TRUE)
293 {
294 $this->queries[] = $sql;
295 }
Derek Allard39b622d2008-01-16 21:10:09 +0000296
Derek Allardd2df9bc2007-04-15 17:41:17 +0000297 // Start the Query Timer
298 $time_start = list($sm, $ss) = explode(' ', microtime());
299
300 // Run the Query
301 if (FALSE === ($this->result_id = $this->simple_query($sql)))
302 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000303 if ($this->save_queries == TRUE)
304 {
305 $this->query_times[] = 0;
306 }
307
Derek Allardd2df9bc2007-04-15 17:41:17 +0000308 // This will trigger a rollback if transactions are being used
Rick Ellis28239ad2007-06-11 04:26:39 +0000309 $this->_trans_status = FALSE;
Rick Ellis244b4c72008-05-12 18:21:33 +0000310
Derek Allardd2df9bc2007-04-15 17:41:17 +0000311 if ($this->db_debug)
312 {
Derek Jonesf38fe092008-05-13 20:28:11 +0000313 // grab the error number and message now, as we might run some
314 // additional queries before displaying the error
315 $error_no = $this->_error_number();
316 $error_msg = $this->_error_message();
317
Rick Ellis244b4c72008-05-12 18:21:33 +0000318 // We call this function in order to roll-back queries
319 // if transactions are enabled. If we don't call this here
320 // the error message will trigger an exit, causing the
321 // transactions to remain in limbo.
322 $this->trans_complete();
Derek Jonesf38fe092008-05-13 20:28:11 +0000323
Rick Ellis244b4c72008-05-12 18:21:33 +0000324 // Log and display errors
Derek Allardd2df9bc2007-04-15 17:41:17 +0000325 log_message('error', 'Query error: '.$this->_error_message());
326 return $this->display_error(
327 array(
Derek Jonesf38fe092008-05-13 20:28:11 +0000328 'Error Number: '.$error_no,
329 $error_msg,
Derek Allardd2df9bc2007-04-15 17:41:17 +0000330 $sql
331 )
332 );
333 }
334
Derek Allard39b622d2008-01-16 21:10:09 +0000335 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000336 }
337
338 // Stop and aggregate the query time results
339 $time_end = list($em, $es) = explode(' ', microtime());
340 $this->benchmark += ($em + $es) - ($sm + $ss);
341
Derek Jones56e9fa52008-01-23 17:26:37 +0000342 if ($this->save_queries == TRUE)
343 {
344 $this->query_times[] = ($em + $es) - ($sm + $ss);
345 }
346
Derek Allardd2df9bc2007-04-15 17:41:17 +0000347 // Increment the query counter
348 $this->query_count++;
349
350 // Was the query a "write" type?
351 // If so we'll simply return true
352 if ($this->is_write_type($sql) === TRUE)
353 {
354 // If caching is enabled we'll auto-cleanup any
355 // existing files related to this particular URI
356 if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init())
357 {
358 $this->CACHE->delete();
359 }
360
361 return TRUE;
362 }
363
364 // Return TRUE if we don't need to create a result object
365 // Currently only the Oracle driver uses this when stored
366 // procedures are used
367 if ($return_object !== TRUE)
368 {
369 return TRUE;
370 }
371
372 // Load and instantiate the result driver
373
374 $driver = $this->load_rdriver();
375 $RES = new $driver();
376 $RES->conn_id = $this->conn_id;
377 $RES->result_id = $this->result_id;
Derek Allard39b622d2008-01-16 21:10:09 +0000378 $RES->num_rows = $RES->num_rows();
Derek Allard060052d2007-07-14 14:26:13 +0000379
Derek Allardd2df9bc2007-04-15 17:41:17 +0000380 if ($this->dbdriver == 'oci8')
381 {
382 $RES->stmt_id = $this->stmt_id;
383 $RES->curs_id = NULL;
384 $RES->limit_used = $this->limit_used;
Rick Ellisa2a240a2008-10-07 00:55:41 +0000385 $this->stmt_id = FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000386 }
Derek Allard39b622d2008-01-16 21:10:09 +0000387
Derek Allardd2df9bc2007-04-15 17:41:17 +0000388 // Is query caching enabled? If so, we'll serialize the
389 // result object and save it to a cache file.
390 if ($this->cache_on == TRUE AND $this->_cache_init())
391 {
392 // We'll create a new instance of the result object
393 // only without the platform specific driver since
394 // we can't use it with cached data (the query result
395 // resource ID won't be any good once we've cached the
396 // result object, so we'll have to compile the data
397 // and save it)
398 $CR = new CI_DB_result();
399 $CR->num_rows = $RES->num_rows();
400 $CR->result_object = $RES->result_object();
401 $CR->result_array = $RES->result_array();
402
403 // Reset these since cached objects can not utilize resource IDs.
404 $CR->conn_id = NULL;
405 $CR->result_id = NULL;
406
407 $this->CACHE->write($sql, $CR);
408 }
409
410 return $RES;
411 }
412
413 // --------------------------------------------------------------------
414
415 /**
416 * Load the result drivers
417 *
418 * @access public
419 * @return string the name of the result class
420 */
421 function load_rdriver()
422 {
423 $driver = 'CI_DB_'.$this->dbdriver.'_result';
424
Rick Ellis244b4c72008-05-12 18:21:33 +0000425 if ( ! class_exists($driver))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000426 {
427 include_once(BASEPATH.'database/DB_result'.EXT);
428 include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result'.EXT);
429 }
430
431 return $driver;
432 }
433
434 // --------------------------------------------------------------------
435
436 /**
437 * Simple Query
438 * This is a simplified version of the query() function. Internally
439 * we only use it when running transaction commands since they do
440 * not require all the features of the main query() function.
441 *
442 * @access public
443 * @param string the sql query
444 * @return mixed
445 */
446 function simple_query($sql)
447 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000448 if ( ! $this->conn_id)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000449 {
450 $this->initialize();
451 }
452
453 return $this->_execute($sql);
454 }
455
456 // --------------------------------------------------------------------
457
458 /**
459 * Disable Transactions
460 * This permits transactions to be disabled at run-time.
461 *
462 * @access public
463 * @return void
464 */
465 function trans_off()
466 {
467 $this->trans_enabled = FALSE;
468 }
469
470 // --------------------------------------------------------------------
471
472 /**
Rick Ellis244b4c72008-05-12 18:21:33 +0000473 * Enable/disable Transaction Strict Mode
474 * When strict mode is enabled, if you are running multiple groups of
475 * transactions, if one group fails all groups will be rolled back.
476 * If strict mode is disabled, each group is treated autonomously, meaning
477 * a failure of one group will not affect any others
478 *
479 * @access public
480 * @return void
481 */
482 function trans_strict($mode = TRUE)
483 {
484 $this->trans_strict = is_bool($mode) ? $mode : TRUE;
485 }
486
487 // --------------------------------------------------------------------
488
489 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000490 * Start Transaction
491 *
492 * @access public
493 * @return void
494 */
495 function trans_start($test_mode = FALSE)
496 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000497 if ( ! $this->trans_enabled)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000498 {
499 return FALSE;
500 }
501
502 // When transactions are nested we only begin/commit/rollback the outermost ones
503 if ($this->_trans_depth > 0)
504 {
505 $this->_trans_depth += 1;
506 return;
507 }
508
509 $this->trans_begin($test_mode);
510 }
511
512 // --------------------------------------------------------------------
513
514 /**
515 * Complete Transaction
516 *
517 * @access public
518 * @return bool
519 */
520 function trans_complete()
521 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000522 if ( ! $this->trans_enabled)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000523 {
524 return FALSE;
525 }
526
527 // When transactions are nested we only begin/commit/rollback the outermost ones
528 if ($this->_trans_depth > 1)
529 {
530 $this->_trans_depth -= 1;
531 return TRUE;
532 }
533
Rick Ellis244b4c72008-05-12 18:21:33 +0000534 // The query() function will set this flag to FALSE in the event that a query failed
Rick Ellis28239ad2007-06-11 04:26:39 +0000535 if ($this->_trans_status === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000536 {
537 $this->trans_rollback();
538
Rick Ellis244b4c72008-05-12 18:21:33 +0000539 // If we are NOT running in strict mode, we will reset
540 // the _trans_status flag so that subsequent groups of transactions
541 // will be permitted.
542 if ($this->trans_strict === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000543 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000544 $this->_trans_status = TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000545 }
Rick Ellis244b4c72008-05-12 18:21:33 +0000546
Derek Allard993925b2008-08-21 12:43:31 +0000547 log_message('debug', 'DB Transaction Failure');
548 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000549 }
550
551 $this->trans_commit();
Derek Allard993925b2008-08-21 12:43:31 +0000552 return TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000553 }
554
555 // --------------------------------------------------------------------
556
557 /**
558 * Lets you retrieve the transaction flag to determine if it has failed
559 *
560 * @access public
561 * @return bool
562 */
563 function trans_status()
564 {
Rick Ellis28239ad2007-06-11 04:26:39 +0000565 return $this->_trans_status;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000566 }
567
568 // --------------------------------------------------------------------
569
570 /**
571 * Compile Bindings
572 *
573 * @access public
574 * @param string the sql statement
575 * @param array an array of bind data
576 * @return string
577 */
578 function compile_binds($sql, $binds)
Derek Allardc0743382008-02-11 05:54:44 +0000579 {
580 if (strpos($sql, $this->bind_marker) === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000581 {
582 return $sql;
583 }
584
Rick Ellis244b4c72008-05-12 18:21:33 +0000585 if ( ! is_array($binds))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000586 {
587 $binds = array($binds);
588 }
589
Derek Allardc0743382008-02-11 05:54:44 +0000590 // Get the sql segments around the bind markers
591 $segments = explode($this->bind_marker, $sql);
592
593 // The count of bind should be 1 less then the count of segments
594 // If there are more bind arguments trim it down
595 if (count($binds) >= count($segments)) {
596 $binds = array_slice($binds, 0, count($segments)-1);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000597 }
598
Derek Allardc0743382008-02-11 05:54:44 +0000599 // Construct the binded query
600 $result = $segments[0];
601 $i = 0;
602 foreach ($binds as $bind)
603 {
604 $result .= $this->escape($bind);
605 $result .= $segments[++$i];
606 }
607
608 return $result;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000609 }
610
611 // --------------------------------------------------------------------
612
613 /**
614 * Determines if a query is a "write" type.
615 *
616 * @access public
617 * @param string An SQL query string
618 * @return boolean
619 */
620 function is_write_type($sql)
621 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000622 if ( ! preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000623 {
624 return FALSE;
625 }
626 return TRUE;
627 }
628
629 // --------------------------------------------------------------------
630
631 /**
632 * Calculate the aggregate query elapsed time
633 *
634 * @access public
635 * @param integer The number of decimal places
636 * @return integer
637 */
638 function elapsed_time($decimals = 6)
639 {
640 return number_format($this->benchmark, $decimals);
641 }
642
643 // --------------------------------------------------------------------
644
645 /**
646 * Returns the total number of queries
647 *
648 * @access public
649 * @return integer
650 */
651 function total_queries()
652 {
653 return $this->query_count;
654 }
655
656 // --------------------------------------------------------------------
657
658 /**
659 * Returns the last query that was executed
660 *
661 * @access public
662 * @return void
663 */
664 function last_query()
665 {
666 return end($this->queries);
667 }
668
669 // --------------------------------------------------------------------
670
671 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000672 * Protect Identifiers
673 *
674 * This function adds backticks if appropriate based on db type
675 *
676 * @access private
677 * @param mixed the item to escape
678 * @param boolean only affect the first word
679 * @return mixed the item with backticks
680 */
681 function protect_identifiers($item, $first_word_only = FALSE)
682 {
Derek Allard1a704ce2008-01-27 15:03:06 +0000683 return $this->_protect_identifiers($item, $first_word_only);
Derek Allard39b622d2008-01-16 21:10:09 +0000684 }
685
686 // --------------------------------------------------------------------
687
688 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000689 * "Smart" Escape String
690 *
691 * Escapes data based on type
692 * Sets boolean and null types
693 *
694 * @access public
695 * @param string
696 * @return integer
697 */
698 function escape($str)
699 {
700 switch (gettype($str))
701 {
702 case 'string' : $str = "'".$this->escape_str($str)."'";
703 break;
704 case 'boolean' : $str = ($str === FALSE) ? 0 : 1;
705 break;
706 default : $str = ($str === NULL) ? 'NULL' : $str;
707 break;
708 }
709
710 return $str;
711 }
712
713 // --------------------------------------------------------------------
714
715 /**
716 * Primary
717 *
718 * Retrieves the primary key. It assumes that the row in the first
719 * position is the primary key
720 *
721 * @access public
722 * @param string the table name
723 * @return string
724 */
725 function primary($table = '')
726 {
727 $fields = $this->list_fields($table);
728
Rick Ellis244b4c72008-05-12 18:21:33 +0000729 if ( ! is_array($fields))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000730 {
731 return FALSE;
732 }
733
734 return current($fields);
735 }
736
737 // --------------------------------------------------------------------
738
739 /**
740 * Returns an array of table names
741 *
742 * @access public
743 * @return array
744 */
Derek Allard39b622d2008-01-16 21:10:09 +0000745 function list_tables($constrain_by_prefix = FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000746 {
747 // Is there a cached result?
748 if (isset($this->data_cache['table_names']))
749 {
750 return $this->data_cache['table_names'];
751 }
752
Derek Allard39b622d2008-01-16 21:10:09 +0000753 if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000754 {
755 if ($this->db_debug)
756 {
757 return $this->display_error('db_unsupported_function');
758 }
Derek Allard993925b2008-08-21 12:43:31 +0000759 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000760 }
761
762 $retval = array();
763 $query = $this->query($sql);
764
765 if ($query->num_rows() > 0)
766 {
767 foreach($query->result_array() as $row)
768 {
769 if (isset($row['TABLE_NAME']))
770 {
771 $retval[] = $row['TABLE_NAME'];
772 }
773 else
774 {
775 $retval[] = array_shift($row);
776 }
777 }
778 }
779
780 $this->data_cache['table_names'] = $retval;
781 return $this->data_cache['table_names'];
782 }
783
784 // --------------------------------------------------------------------
785
786 /**
787 * Determine if a particular table exists
788 * @access public
789 * @return boolean
790 */
791 function table_exists($table_name)
792 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000793 return ( ! in_array($this->prep_tablename($table_name), $this->list_tables())) ? FALSE : TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000794 }
795
796 // --------------------------------------------------------------------
797
798 /**
799 * Fetch MySQL Field Names
800 *
801 * @access public
802 * @param string the table name
803 * @return array
804 */
805 function list_fields($table = '')
806 {
807 // Is there a cached result?
808 if (isset($this->data_cache['field_names'][$table]))
809 {
810 return $this->data_cache['field_names'][$table];
811 }
812
813 if ($table == '')
814 {
815 if ($this->db_debug)
816 {
817 return $this->display_error('db_field_param_missing');
818 }
Derek Allard993925b2008-08-21 12:43:31 +0000819 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000820 }
821
Derek Allard39b622d2008-01-16 21:10:09 +0000822 if (FALSE === ($sql = $this->_list_columns($this->prep_tablename($table))))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000823 {
824 if ($this->db_debug)
825 {
826 return $this->display_error('db_unsupported_function');
827 }
Derek Allard993925b2008-08-21 12:43:31 +0000828 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000829 }
830
831 $query = $this->query($sql);
832
833 $retval = array();
834 foreach($query->result_array() as $row)
835 {
836 if (isset($row['COLUMN_NAME']))
837 {
838 $retval[] = $row['COLUMN_NAME'];
839 }
840 else
841 {
842 $retval[] = current($row);
843 }
844 }
845
846 $this->data_cache['field_names'][$table] = $retval;
847 return $this->data_cache['field_names'][$table];
848 }
849
850 // --------------------------------------------------------------------
851
852 /**
853 * Determine if a particular field exists
854 * @access public
855 * @param string
856 * @param string
857 * @return boolean
858 */
859 function field_exists($field_name, $table_name)
860 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000861 return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000862 }
863
864 // --------------------------------------------------------------------
865
866 /**
867 * DEPRECATED - use list_fields()
868 */
869 function field_names($table = '')
870 {
871 return $this->list_fields($table);
872 }
873
874 // --------------------------------------------------------------------
875
876 /**
877 * Returns an object with field data
878 *
879 * @access public
880 * @param string the table name
881 * @return object
882 */
883 function field_data($table = '')
884 {
885 if ($table == '')
886 {
887 if ($this->db_debug)
888 {
889 return $this->display_error('db_field_param_missing');
890 }
Derek Allard993925b2008-08-21 12:43:31 +0000891 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000892 }
893
Derek Allard39b622d2008-01-16 21:10:09 +0000894 $query = $this->query($this->_field_data($this->prep_tablename($table)));
Derek Allardd2df9bc2007-04-15 17:41:17 +0000895 return $query->field_data();
896 }
897
898 // --------------------------------------------------------------------
899
900 /**
901 * Generate an insert string
902 *
903 * @access public
904 * @param string the table upon which the query will be performed
905 * @param array an associative array data of key/values
906 * @return string
907 */
908 function insert_string($table, $data)
909 {
Derek Allard993925b2008-08-21 12:43:31 +0000910 $fields = array();
Derek Allardd2df9bc2007-04-15 17:41:17 +0000911 $values = array();
912
913 foreach($data as $key => $val)
914 {
Rick Ellis52dc8ca2008-09-30 19:53:52 +0000915 $fields[] = $this->_escape_column($key);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000916 $values[] = $this->escape($val);
917 }
Derek Allard39b622d2008-01-16 21:10:09 +0000918
Derek Allard39b622d2008-01-16 21:10:09 +0000919 return $this->_insert($this->prep_tablename($table), $fields, $values);
920 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000921
922 // --------------------------------------------------------------------
923
924 /**
925 * Generate an update string
926 *
927 * @access public
928 * @param string the table upon which the query will be performed
929 * @param array an associative array data of key/values
930 * @param mixed the "where" statement
931 * @return string
932 */
933 function update_string($table, $data, $where)
934 {
935 if ($where == '')
Derek Allard513ce072008-05-18 12:23:11 +0000936 {
Derek Allardd2df9bc2007-04-15 17:41:17 +0000937 return false;
Derek Allard513ce072008-05-18 12:23:11 +0000938 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000939
940 $fields = array();
941 foreach($data as $key => $val)
942 {
Rick Ellis52dc8ca2008-09-30 19:53:52 +0000943 $fields[$this->_escape_column($key)] = $this->escape($val);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000944 }
945
Rick Ellis244b4c72008-05-12 18:21:33 +0000946 if ( ! is_array($where))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000947 {
948 $dest = array($where);
949 }
950 else
951 {
952 $dest = array();
953 foreach ($where as $key => $val)
954 {
955 $prefix = (count($dest) == 0) ? '' : ' AND ';
956
Derek Allard39b622d2008-01-16 21:10:09 +0000957 if ($val !== '')
Derek Allardd2df9bc2007-04-15 17:41:17 +0000958 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000959 if ( ! $this->_has_operator($key))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000960 {
961 $key .= ' =';
962 }
963
964 $val = ' '.$this->escape($val);
965 }
966
967 $dest[] = $prefix.$key.$val;
968 }
969 }
970
Derek Allard39b622d2008-01-16 21:10:09 +0000971 return $this->_update($this->prep_tablename($table), $fields, $dest);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000972 }
973
974 // --------------------------------------------------------------------
975
976 /**
Derek Allard513ce072008-05-18 12:23:11 +0000977 * Tests whether the string has an SQL operator
978 *
979 * @access private
980 * @param string
981 * @return bool
982 */
983 function _has_operator($str)
984 {
985 $str = trim($str);
986 if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str))
987 {
988 return FALSE;
989 }
990
991 return TRUE;
992 }
993
994 // --------------------------------------------------------------------
995
996 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000997 * Prep the table name - simply adds the table prefix if needed
998 *
999 * @access public
1000 * @param string the table name
1001 * @return string
1002 */
1003 function prep_tablename($table = '')
1004 {
1005 // Do we need to add the table prefix?
1006 if ($this->dbprefix != '')
1007 {
1008 if (substr($table, 0, strlen($this->dbprefix)) != $this->dbprefix)
1009 {
1010 $table = $this->dbprefix.$table;
1011 }
1012 }
1013
1014 return $table;
1015 }
1016
1017 // --------------------------------------------------------------------
1018
1019 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +00001020 * Enables a native PHP function to be run, using a platform agnostic wrapper.
1021 *
1022 * @access public
1023 * @param string the function name
1024 * @param mixed any parameters needed by the function
1025 * @return mixed
1026 */
1027 function call_function($function)
1028 {
1029 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
1030
1031 if (FALSE === strpos($driver, $function))
1032 {
1033 $function = $driver.$function;
1034 }
1035
Rick Ellis244b4c72008-05-12 18:21:33 +00001036 if ( ! function_exists($function))
Derek Allardd2df9bc2007-04-15 17:41:17 +00001037 {
1038 if ($this->db_debug)
1039 {
1040 return $this->display_error('db_unsupported_function');
1041 }
Derek Allard993925b2008-08-21 12:43:31 +00001042 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +00001043 }
1044 else
1045 {
1046 $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
1047
1048 return call_user_func_array($function, $args);
1049 }
1050 }
1051
1052 // --------------------------------------------------------------------
1053
1054 /**
1055 * Set Cache Directory Path
1056 *
1057 * @access public
1058 * @param string the path to the cache directory
1059 * @return void
1060 */
1061 function cache_set_path($path = '')
1062 {
1063 $this->cachedir = $path;
1064 }
1065
1066 // --------------------------------------------------------------------
1067
1068 /**
1069 * Enable Query Caching
1070 *
1071 * @access public
1072 * @return void
1073 */
1074 function cache_on()
1075 {
1076 $this->cache_on = TRUE;
1077 return TRUE;
1078 }
1079
1080 // --------------------------------------------------------------------
1081
1082 /**
1083 * Disable Query Caching
1084 *
1085 * @access public
1086 * @return void
1087 */
1088 function cache_off()
1089 {
1090 $this->cache_on = FALSE;
1091 return FALSE;
1092 }
1093
1094
1095 // --------------------------------------------------------------------
1096
1097 /**
1098 * Delete the cache files associated with a particular URI
1099 *
1100 * @access public
1101 * @return void
1102 */
1103 function cache_delete($segment_one = '', $segment_two = '')
1104 {
Rick Ellis244b4c72008-05-12 18:21:33 +00001105 if ( ! $this->_cache_init())
Derek Allardd2df9bc2007-04-15 17:41:17 +00001106 {
1107 return FALSE;
1108 }
1109 return $this->CACHE->delete($segment_one, $segment_two);
1110 }
1111
1112 // --------------------------------------------------------------------
1113
1114 /**
1115 * Delete All cache files
1116 *
1117 * @access public
1118 * @return void
1119 */
1120 function cache_delete_all()
1121 {
Rick Ellis244b4c72008-05-12 18:21:33 +00001122 if ( ! $this->_cache_init())
Derek Allardd2df9bc2007-04-15 17:41:17 +00001123 {
1124 return FALSE;
1125 }
1126
1127 return $this->CACHE->delete_all();
1128 }
1129
1130 // --------------------------------------------------------------------
1131
1132 /**
1133 * Initialize the Cache Class
1134 *
1135 * @access private
1136 * @return void
1137 */
1138 function _cache_init()
1139 {
1140 if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
1141 {
1142 return TRUE;
1143 }
1144
Rick Ellis244b4c72008-05-12 18:21:33 +00001145 if ( ! @include(BASEPATH.'database/DB_cache'.EXT))
Derek Allardd2df9bc2007-04-15 17:41:17 +00001146 {
1147 return $this->cache_off();
1148 }
1149
Derek Jonesd36ade02008-05-12 15:17:41 +00001150 $this->CACHE = new CI_DB_Cache($this); // pass db object to support multiple db connections and returned db objects
Derek Allardd2df9bc2007-04-15 17:41:17 +00001151 return TRUE;
1152 }
1153
Derek Allardd2df9bc2007-04-15 17:41:17 +00001154 // --------------------------------------------------------------------
1155
1156 /**
1157 * Close DB Connection
1158 *
1159 * @access public
1160 * @return void
1161 */
1162 function close()
1163 {
Derek Jones05097752008-05-07 19:58:23 +00001164 if (is_resource($this->conn_id) OR is_object($this->conn_id))
Derek Allardd2df9bc2007-04-15 17:41:17 +00001165 {
1166 $this->_close($this->conn_id);
1167 }
1168 $this->conn_id = FALSE;
1169 }
1170
1171 // --------------------------------------------------------------------
1172
1173 /**
1174 * Display an error message
1175 *
1176 * @access public
1177 * @param string the error message
1178 * @param string any "swap" values
1179 * @param boolean whether to localize the message
1180 * @return string sends the application/error_db.php template
1181 */
1182 function display_error($error = '', $swap = '', $native = FALSE)
1183 {
Derek Jones7f88aa52008-05-12 00:03:51 +00001184 global $LANG;
Derek Allardd2df9bc2007-04-15 17:41:17 +00001185 $LANG->load('db');
1186
Derek Jones7f88aa52008-05-12 00:03:51 +00001187 $heading = $LANG->line('db_error_heading');
1188
Derek Allardd2df9bc2007-04-15 17:41:17 +00001189 if ($native == TRUE)
1190 {
1191 $message = $error;
1192 }
1193 else
1194 {
Derek Jones0b59f272008-05-13 04:22:33 +00001195 $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
Derek Allardd2df9bc2007-04-15 17:41:17 +00001196 }
Derek Allardd2df9bc2007-04-15 17:41:17 +00001197
Derek Jones7f88aa52008-05-12 00:03:51 +00001198 $error =& load_class('Exceptions');
1199 echo $error->show_error($heading, $message, 'error_db');
Derek Allardd2df9bc2007-04-15 17:41:17 +00001200 exit;
1201 }
1202
1203}
1204
Derek Jones7f88aa52008-05-12 00:03:51 +00001205
1206/* End of file DB_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +00001207/* Location: ./system/database/DB_driver.php */