blob: a0833d0ce6556f41d842e8f89a3b850d354222fe [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
Derek Allardd2df9bc2007-04-15 17:41:17 +00009 * @copyright Copyright (c) 2006, 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 Allard39b622d2008-01-16 21:10:09 +000039 var $autoinit = TRUE; // Whether to automatically initialize the DB
40 var $swap_pre = '';
Derek Allardd2df9bc2007-04-15 17:41:17 +000041 var $port = '';
42 var $pconnect = FALSE;
43 var $conn_id = FALSE;
44 var $result_id = FALSE;
45 var $db_debug = FALSE;
46 var $benchmark = 0;
47 var $query_count = 0;
48 var $bind_marker = '?';
Rick Ellis40990462007-07-17 21:40:44 +000049 var $save_queries = TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +000050 var $queries = array();
Derek Jones56e9fa52008-01-23 17:26:37 +000051 var $query_times = array();
Derek Allardd2df9bc2007-04-15 17:41:17 +000052 var $data_cache = array();
53 var $trans_enabled = TRUE;
Rick Ellis244b4c72008-05-12 18:21:33 +000054 var $trans_strict = TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +000055 var $_trans_depth = 0;
Rick Ellis28239ad2007-06-11 04:26:39 +000056 var $_trans_status = TRUE; // Used with transactions to determine if a rollback should occur
Derek Allardd2df9bc2007-04-15 17:41:17 +000057 var $cache_on = FALSE;
58 var $cachedir = '';
59 var $cache_autodel = FALSE;
60 var $CACHE; // The cache class object
61
62
63 // These are use with Oracle
64 var $stmt_id;
65 var $curs_id;
66 var $limit_used;
67
68
69
70 /**
71 * Constructor. Accepts one parameter containing the database
72 * connection settings.
73 *
Derek Jones7dd38382008-02-13 04:52:58 +000074 * @param array
Derek Allardd2df9bc2007-04-15 17:41:17 +000075 */
76 function CI_DB_driver($params)
77 {
Derek Allardd2df9bc2007-04-15 17:41:17 +000078 if (is_array($params))
79 {
Derek Allard39b622d2008-01-16 21:10:09 +000080 foreach ($params as $key => $val)
Derek Allardd2df9bc2007-04-15 17:41:17 +000081 {
Derek Allard39b622d2008-01-16 21:10:09 +000082 $this->$key = $val;
Derek Allardd2df9bc2007-04-15 17:41:17 +000083 }
84 }
Derek Allard39b622d2008-01-16 21:10:09 +000085
86 log_message('debug', 'Database Driver Class Initialized');
87 }
88
89 // --------------------------------------------------------------------
90
91 /**
92 * Initialize Database Settings
93 *
94 * @access private Called by the constructor
95 * @param mixed
96 * @return void
97 */
98 function initialize($create_db = FALSE)
99 {
Derek Allardd2df9bc2007-04-15 17:41:17 +0000100 // If an existing DB connection resource is supplied
101 // there is no need to connect and select the database
Derek Jones05097752008-05-07 19:58:23 +0000102 if (is_resource($this->conn_id) OR is_object($this->conn_id))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000103 {
104 return TRUE;
105 }
106
107 // Connect to the database
108 $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
109
110 // No connection? Throw an error
Rick Ellis244b4c72008-05-12 18:21:33 +0000111 if ( ! $this->conn_id)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000112 {
113 log_message('error', 'Unable to connect to the database');
114
115 if ($this->db_debug)
116 {
117 $this->display_error('db_unable_to_connect');
118 }
119 return FALSE;
120 }
121
122 // Select the database
123 if ($this->database != '')
124 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000125 if ( ! $this->db_select())
Derek Allardd2df9bc2007-04-15 17:41:17 +0000126 {
Derek Allard39b622d2008-01-16 21:10:09 +0000127 // Should we attempt to create the database?
128 if ($create_db == TRUE)
129 {
130 // Load the DB utility class
131 $CI =& get_instance();
132 $CI->load->dbutil();
133
134 // Create the DB
Rick Ellis244b4c72008-05-12 18:21:33 +0000135 if ( ! $CI->dbutil->create_database($this->database))
Derek Allard39b622d2008-01-16 21:10:09 +0000136 {
137 log_message('error', 'Unable to create database: '.$this->database);
138
139 if ($this->db_debug)
140 {
141 $this->display_error('db_unable_to_create', $this->database);
142 }
143 return FALSE;
144 }
145 else
146 {
147 // In the event the DB was created we need to select it
148 if ($this->db_select())
149 {
Derek Jones0b59f272008-05-13 04:22:33 +0000150 if ( ! $this->db_set_charset($this->char_set, $this->dbcollat))
Derek Allard39b622d2008-01-16 21:10:09 +0000151 {
152 log_message('error', 'Unable to set database connection charset: '.$this->char_set);
153
154 if ($this->db_debug)
155 {
156 $this->display_error('db_unable_to_set_charset', $this->char_set);
157 }
158
159 return FALSE;
160 }
161
162 return TRUE;
163 }
164 }
165 }
166
Derek Allardd2df9bc2007-04-15 17:41:17 +0000167 log_message('error', 'Unable to select database: '.$this->database);
168
169 if ($this->db_debug)
170 {
171 $this->display_error('db_unable_to_select', $this->database);
172 }
173 return FALSE;
174 }
Derek Allard39b622d2008-01-16 21:10:09 +0000175
Derek Jones0b59f272008-05-13 04:22:33 +0000176 if ( ! $this->db_set_charset($this->char_set, $this->dbcollat))
Derek Allard39b622d2008-01-16 21:10:09 +0000177 {
178 log_message('error', 'Unable to set database connection charset: '.$this->char_set);
179
180 if ($this->db_debug)
181 {
182 $this->display_error('db_unable_to_set_charset', $this->char_set);
183 }
184
185 return FALSE;
186 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000187 }
188
189 return TRUE;
190 }
191
192 // --------------------------------------------------------------------
193
194 /**
195 * The name of the platform in use (mysql, mssql, etc...)
196 *
197 * @access public
198 * @return string
199 */
200 function platform()
201 {
202 return $this->dbdriver;
203 }
204
205 // --------------------------------------------------------------------
206
207 /**
208 * Database Version Number. Returns a string containing the
209 * version of the database being used
210 *
211 * @access public
212 * @return string
213 */
214 function version()
215 {
216 if (FALSE === ($sql = $this->_version()))
217 {
218 if ($this->db_debug)
219 {
220 return $this->display_error('db_unsupported_function');
221 }
222 return FALSE;
223 }
224
225 if ($this->dbdriver == 'oci8')
226 {
227 return $sql;
228 }
229
230 $query = $this->query($sql);
Derek Allard39b622d2008-01-16 21:10:09 +0000231 return $query->row('ver');
Derek Allardd2df9bc2007-04-15 17:41:17 +0000232 }
233
234 // --------------------------------------------------------------------
235
236 /**
237 * Execute the query
238 *
239 * Accepts an SQL string as input and returns a result object upon
240 * successful execution of a "read" type query. Returns boolean TRUE
241 * upon successful execution of a "write" type query. Returns boolean
242 * FALSE upon failure, and if the $db_debug variable is set to TRUE
243 * will raise an error.
244 *
245 * @access public
246 * @param string An SQL query string
247 * @param array An array of binding data
248 * @return mixed
249 */
250 function query($sql, $binds = FALSE, $return_object = TRUE)
251 {
252 if ($sql == '')
253 {
254 if ($this->db_debug)
255 {
256 log_message('error', 'Invalid query: '.$sql);
257 return $this->display_error('db_invalid_query');
258 }
259 return FALSE;
260 }
Derek Allard39b622d2008-01-16 21:10:09 +0000261
262 // Verify table prefix and replace if necessary
263 if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) )
264 {
265 $sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql);
266 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000267
268 // Is query caching enabled? If the query is a "read type"
269 // we will load the caching class and return the previously
270 // cached query if it exists
271 if ($this->cache_on == TRUE AND stristr($sql, 'SELECT'))
272 {
273 if ($this->_cache_init())
274 {
275 $this->load_rdriver();
276 if (FALSE !== ($cache = $this->CACHE->read($sql)))
277 {
278 return $cache;
279 }
280 }
281 }
282
283 // Compile binds if needed
284 if ($binds !== FALSE)
285 {
286 $sql = $this->compile_binds($sql, $binds);
287 }
288
289 // Save the query for debugging
Rick Ellis40990462007-07-17 21:40:44 +0000290 if ($this->save_queries == TRUE)
291 {
292 $this->queries[] = $sql;
293 }
Derek Allard39b622d2008-01-16 21:10:09 +0000294
Derek Allardd2df9bc2007-04-15 17:41:17 +0000295 // Start the Query Timer
296 $time_start = list($sm, $ss) = explode(' ', microtime());
297
298 // Run the Query
299 if (FALSE === ($this->result_id = $this->simple_query($sql)))
300 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000301 if ($this->save_queries == TRUE)
302 {
303 $this->query_times[] = 0;
304 }
305
Derek Allardd2df9bc2007-04-15 17:41:17 +0000306 // This will trigger a rollback if transactions are being used
Rick Ellis28239ad2007-06-11 04:26:39 +0000307 $this->_trans_status = FALSE;
Rick Ellis244b4c72008-05-12 18:21:33 +0000308
Derek Allardd2df9bc2007-04-15 17:41:17 +0000309 if ($this->db_debug)
310 {
Derek Jonesf38fe092008-05-13 20:28:11 +0000311 // grab the error number and message now, as we might run some
312 // additional queries before displaying the error
313 $error_no = $this->_error_number();
314 $error_msg = $this->_error_message();
315
Rick Ellis244b4c72008-05-12 18:21:33 +0000316 // We call this function in order to roll-back queries
317 // if transactions are enabled. If we don't call this here
318 // the error message will trigger an exit, causing the
319 // transactions to remain in limbo.
320 $this->trans_complete();
Derek Jonesf38fe092008-05-13 20:28:11 +0000321
Rick Ellis244b4c72008-05-12 18:21:33 +0000322 // Log and display errors
Derek Allardd2df9bc2007-04-15 17:41:17 +0000323 log_message('error', 'Query error: '.$this->_error_message());
324 return $this->display_error(
325 array(
Derek Jonesf38fe092008-05-13 20:28:11 +0000326 'Error Number: '.$error_no,
327 $error_msg,
Derek Allardd2df9bc2007-04-15 17:41:17 +0000328 $sql
329 )
330 );
331 }
332
Derek Allard39b622d2008-01-16 21:10:09 +0000333 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000334 }
335
336 // Stop and aggregate the query time results
337 $time_end = list($em, $es) = explode(' ', microtime());
338 $this->benchmark += ($em + $es) - ($sm + $ss);
339
Derek Jones56e9fa52008-01-23 17:26:37 +0000340 if ($this->save_queries == TRUE)
341 {
342 $this->query_times[] = ($em + $es) - ($sm + $ss);
343 }
344
Derek Allardd2df9bc2007-04-15 17:41:17 +0000345 // Increment the query counter
346 $this->query_count++;
347
348 // Was the query a "write" type?
349 // If so we'll simply return true
350 if ($this->is_write_type($sql) === TRUE)
351 {
352 // If caching is enabled we'll auto-cleanup any
353 // existing files related to this particular URI
354 if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init())
355 {
356 $this->CACHE->delete();
357 }
358
359 return TRUE;
360 }
361
362 // Return TRUE if we don't need to create a result object
363 // Currently only the Oracle driver uses this when stored
364 // procedures are used
365 if ($return_object !== TRUE)
366 {
367 return TRUE;
368 }
369
370 // Load and instantiate the result driver
371
372 $driver = $this->load_rdriver();
373 $RES = new $driver();
374 $RES->conn_id = $this->conn_id;
375 $RES->result_id = $this->result_id;
Derek Allard39b622d2008-01-16 21:10:09 +0000376 $RES->num_rows = $RES->num_rows();
Derek Allard060052d2007-07-14 14:26:13 +0000377
Derek Allardd2df9bc2007-04-15 17:41:17 +0000378 if ($this->dbdriver == 'oci8')
379 {
380 $RES->stmt_id = $this->stmt_id;
381 $RES->curs_id = NULL;
382 $RES->limit_used = $this->limit_used;
383 }
Derek Allard39b622d2008-01-16 21:10:09 +0000384
Derek Allardd2df9bc2007-04-15 17:41:17 +0000385 // Is query caching enabled? If so, we'll serialize the
386 // result object and save it to a cache file.
387 if ($this->cache_on == TRUE AND $this->_cache_init())
388 {
389 // We'll create a new instance of the result object
390 // only without the platform specific driver since
391 // we can't use it with cached data (the query result
392 // resource ID won't be any good once we've cached the
393 // result object, so we'll have to compile the data
394 // and save it)
395 $CR = new CI_DB_result();
396 $CR->num_rows = $RES->num_rows();
397 $CR->result_object = $RES->result_object();
398 $CR->result_array = $RES->result_array();
399
400 // Reset these since cached objects can not utilize resource IDs.
401 $CR->conn_id = NULL;
402 $CR->result_id = NULL;
403
404 $this->CACHE->write($sql, $CR);
405 }
406
407 return $RES;
408 }
409
410 // --------------------------------------------------------------------
411
412 /**
413 * Load the result drivers
414 *
415 * @access public
416 * @return string the name of the result class
417 */
418 function load_rdriver()
419 {
420 $driver = 'CI_DB_'.$this->dbdriver.'_result';
421
Rick Ellis244b4c72008-05-12 18:21:33 +0000422 if ( ! class_exists($driver))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000423 {
424 include_once(BASEPATH.'database/DB_result'.EXT);
425 include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result'.EXT);
426 }
427
428 return $driver;
429 }
430
431 // --------------------------------------------------------------------
432
433 /**
434 * Simple Query
435 * This is a simplified version of the query() function. Internally
436 * we only use it when running transaction commands since they do
437 * not require all the features of the main query() function.
438 *
439 * @access public
440 * @param string the sql query
441 * @return mixed
442 */
443 function simple_query($sql)
444 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000445 if ( ! $this->conn_id)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000446 {
447 $this->initialize();
448 }
449
450 return $this->_execute($sql);
451 }
452
453 // --------------------------------------------------------------------
454
455 /**
456 * Disable Transactions
457 * This permits transactions to be disabled at run-time.
458 *
459 * @access public
460 * @return void
461 */
462 function trans_off()
463 {
464 $this->trans_enabled = FALSE;
465 }
466
467 // --------------------------------------------------------------------
468
469 /**
Rick Ellis244b4c72008-05-12 18:21:33 +0000470 * Enable/disable Transaction Strict Mode
471 * When strict mode is enabled, if you are running multiple groups of
472 * transactions, if one group fails all groups will be rolled back.
473 * If strict mode is disabled, each group is treated autonomously, meaning
474 * a failure of one group will not affect any others
475 *
476 * @access public
477 * @return void
478 */
479 function trans_strict($mode = TRUE)
480 {
481 $this->trans_strict = is_bool($mode) ? $mode : TRUE;
482 }
483
484 // --------------------------------------------------------------------
485
486 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000487 * Start Transaction
488 *
489 * @access public
490 * @return void
491 */
492 function trans_start($test_mode = FALSE)
493 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000494 if ( ! $this->trans_enabled)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000495 {
496 return FALSE;
497 }
498
499 // When transactions are nested we only begin/commit/rollback the outermost ones
500 if ($this->_trans_depth > 0)
501 {
502 $this->_trans_depth += 1;
503 return;
504 }
505
506 $this->trans_begin($test_mode);
507 }
508
509 // --------------------------------------------------------------------
510
511 /**
512 * Complete Transaction
513 *
514 * @access public
515 * @return bool
516 */
517 function trans_complete()
518 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000519 if ( ! $this->trans_enabled)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000520 {
521 return FALSE;
522 }
523
524 // When transactions are nested we only begin/commit/rollback the outermost ones
525 if ($this->_trans_depth > 1)
526 {
527 $this->_trans_depth -= 1;
528 return TRUE;
529 }
530
Rick Ellis244b4c72008-05-12 18:21:33 +0000531 // The query() function will set this flag to FALSE in the event that a query failed
Rick Ellis28239ad2007-06-11 04:26:39 +0000532 if ($this->_trans_status === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000533 {
534 $this->trans_rollback();
535
Rick Ellis244b4c72008-05-12 18:21:33 +0000536 // If we are NOT running in strict mode, we will reset
537 // the _trans_status flag so that subsequent groups of transactions
538 // will be permitted.
539 if ($this->trans_strict === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000540 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000541 $this->_trans_status = TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000542 }
Rick Ellis244b4c72008-05-12 18:21:33 +0000543
544 log_message('debug', 'DB Transaction Failure');
Derek Allardd2df9bc2007-04-15 17:41:17 +0000545 return FALSE;
546 }
547
548 $this->trans_commit();
549 return TRUE;
550 }
551
552 // --------------------------------------------------------------------
553
554 /**
555 * Lets you retrieve the transaction flag to determine if it has failed
556 *
557 * @access public
558 * @return bool
559 */
560 function trans_status()
561 {
Rick Ellis28239ad2007-06-11 04:26:39 +0000562 return $this->_trans_status;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000563 }
564
565 // --------------------------------------------------------------------
566
567 /**
568 * Compile Bindings
569 *
570 * @access public
571 * @param string the sql statement
572 * @param array an array of bind data
573 * @return string
574 */
575 function compile_binds($sql, $binds)
Derek Allardc0743382008-02-11 05:54:44 +0000576 {
577 if (strpos($sql, $this->bind_marker) === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000578 {
579 return $sql;
580 }
581
Rick Ellis244b4c72008-05-12 18:21:33 +0000582 if ( ! is_array($binds))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000583 {
584 $binds = array($binds);
585 }
586
Derek Allardc0743382008-02-11 05:54:44 +0000587 // Get the sql segments around the bind markers
588 $segments = explode($this->bind_marker, $sql);
589
590 // The count of bind should be 1 less then the count of segments
591 // If there are more bind arguments trim it down
592 if (count($binds) >= count($segments)) {
593 $binds = array_slice($binds, 0, count($segments)-1);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000594 }
595
Derek Allardc0743382008-02-11 05:54:44 +0000596 // Construct the binded query
597 $result = $segments[0];
598 $i = 0;
599 foreach ($binds as $bind)
600 {
601 $result .= $this->escape($bind);
602 $result .= $segments[++$i];
603 }
604
605 return $result;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000606 }
607
608 // --------------------------------------------------------------------
609
610 /**
611 * Determines if a query is a "write" type.
612 *
613 * @access public
614 * @param string An SQL query string
615 * @return boolean
616 */
617 function is_write_type($sql)
618 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000619 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 +0000620 {
621 return FALSE;
622 }
623 return TRUE;
624 }
625
626 // --------------------------------------------------------------------
627
628 /**
629 * Calculate the aggregate query elapsed time
630 *
631 * @access public
632 * @param integer The number of decimal places
633 * @return integer
634 */
635 function elapsed_time($decimals = 6)
636 {
637 return number_format($this->benchmark, $decimals);
638 }
639
640 // --------------------------------------------------------------------
641
642 /**
643 * Returns the total number of queries
644 *
645 * @access public
646 * @return integer
647 */
648 function total_queries()
649 {
650 return $this->query_count;
651 }
652
653 // --------------------------------------------------------------------
654
655 /**
656 * Returns the last query that was executed
657 *
658 * @access public
659 * @return void
660 */
661 function last_query()
662 {
663 return end($this->queries);
664 }
665
666 // --------------------------------------------------------------------
667
668 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000669 * Protect Identifiers
670 *
671 * This function adds backticks if appropriate based on db type
672 *
673 * @access private
674 * @param mixed the item to escape
675 * @param boolean only affect the first word
676 * @return mixed the item with backticks
677 */
678 function protect_identifiers($item, $first_word_only = FALSE)
679 {
Derek Allard1a704ce2008-01-27 15:03:06 +0000680 return $this->_protect_identifiers($item, $first_word_only);
Derek Allard39b622d2008-01-16 21:10:09 +0000681 }
682
683 // --------------------------------------------------------------------
684
685 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000686 * "Smart" Escape String
687 *
688 * Escapes data based on type
689 * Sets boolean and null types
690 *
691 * @access public
692 * @param string
693 * @return integer
694 */
695 function escape($str)
696 {
697 switch (gettype($str))
698 {
699 case 'string' : $str = "'".$this->escape_str($str)."'";
700 break;
701 case 'boolean' : $str = ($str === FALSE) ? 0 : 1;
702 break;
703 default : $str = ($str === NULL) ? 'NULL' : $str;
704 break;
705 }
706
707 return $str;
708 }
709
710 // --------------------------------------------------------------------
711
712 /**
713 * Primary
714 *
715 * Retrieves the primary key. It assumes that the row in the first
716 * position is the primary key
717 *
718 * @access public
719 * @param string the table name
720 * @return string
721 */
722 function primary($table = '')
723 {
724 $fields = $this->list_fields($table);
725
Rick Ellis244b4c72008-05-12 18:21:33 +0000726 if ( ! is_array($fields))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000727 {
728 return FALSE;
729 }
730
731 return current($fields);
732 }
733
734 // --------------------------------------------------------------------
735
736 /**
737 * Returns an array of table names
738 *
739 * @access public
740 * @return array
741 */
Derek Allard39b622d2008-01-16 21:10:09 +0000742 function list_tables($constrain_by_prefix = FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000743 {
744 // Is there a cached result?
745 if (isset($this->data_cache['table_names']))
746 {
747 return $this->data_cache['table_names'];
748 }
749
Derek Allard39b622d2008-01-16 21:10:09 +0000750 if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000751 {
752 if ($this->db_debug)
753 {
754 return $this->display_error('db_unsupported_function');
755 }
756 return FALSE;
757 }
758
759 $retval = array();
760 $query = $this->query($sql);
761
762 if ($query->num_rows() > 0)
763 {
764 foreach($query->result_array() as $row)
765 {
766 if (isset($row['TABLE_NAME']))
767 {
768 $retval[] = $row['TABLE_NAME'];
769 }
770 else
771 {
772 $retval[] = array_shift($row);
773 }
774 }
775 }
776
777 $this->data_cache['table_names'] = $retval;
778 return $this->data_cache['table_names'];
779 }
780
781 // --------------------------------------------------------------------
782
783 /**
784 * Determine if a particular table exists
785 * @access public
786 * @return boolean
787 */
788 function table_exists($table_name)
789 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000790 return ( ! in_array($this->prep_tablename($table_name), $this->list_tables())) ? FALSE : TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000791 }
792
793 // --------------------------------------------------------------------
794
795 /**
796 * Fetch MySQL Field Names
797 *
798 * @access public
799 * @param string the table name
800 * @return array
801 */
802 function list_fields($table = '')
803 {
804 // Is there a cached result?
805 if (isset($this->data_cache['field_names'][$table]))
806 {
807 return $this->data_cache['field_names'][$table];
808 }
809
810 if ($table == '')
811 {
812 if ($this->db_debug)
813 {
814 return $this->display_error('db_field_param_missing');
815 }
816 return FALSE;
817 }
818
Derek Allard39b622d2008-01-16 21:10:09 +0000819 if (FALSE === ($sql = $this->_list_columns($this->prep_tablename($table))))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000820 {
821 if ($this->db_debug)
822 {
823 return $this->display_error('db_unsupported_function');
824 }
825 return FALSE;
826 }
827
828 $query = $this->query($sql);
829
830 $retval = array();
831 foreach($query->result_array() as $row)
832 {
833 if (isset($row['COLUMN_NAME']))
834 {
835 $retval[] = $row['COLUMN_NAME'];
836 }
837 else
838 {
839 $retval[] = current($row);
840 }
841 }
842
843 $this->data_cache['field_names'][$table] = $retval;
844 return $this->data_cache['field_names'][$table];
845 }
846
847 // --------------------------------------------------------------------
848
849 /**
850 * Determine if a particular field exists
851 * @access public
852 * @param string
853 * @param string
854 * @return boolean
855 */
856 function field_exists($field_name, $table_name)
857 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000858 return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000859 }
860
861 // --------------------------------------------------------------------
862
863 /**
864 * DEPRECATED - use list_fields()
865 */
866 function field_names($table = '')
867 {
868 return $this->list_fields($table);
869 }
870
871 // --------------------------------------------------------------------
872
873 /**
874 * Returns an object with field data
875 *
876 * @access public
877 * @param string the table name
878 * @return object
879 */
880 function field_data($table = '')
881 {
882 if ($table == '')
883 {
884 if ($this->db_debug)
885 {
886 return $this->display_error('db_field_param_missing');
887 }
888 return FALSE;
889 }
890
Derek Allard39b622d2008-01-16 21:10:09 +0000891 $query = $this->query($this->_field_data($this->prep_tablename($table)));
Derek Allardd2df9bc2007-04-15 17:41:17 +0000892 return $query->field_data();
893 }
894
895 // --------------------------------------------------------------------
896
897 /**
898 * Generate an insert string
899 *
900 * @access public
901 * @param string the table upon which the query will be performed
902 * @param array an associative array data of key/values
903 * @return string
904 */
905 function insert_string($table, $data)
906 {
907 $fields = array();
908 $values = array();
909
910 foreach($data as $key => $val)
911 {
912 $fields[] = $key;
913 $values[] = $this->escape($val);
914 }
Derek Allard39b622d2008-01-16 21:10:09 +0000915
916
917 return $this->_insert($this->prep_tablename($table), $fields, $values);
918 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000919
920 // --------------------------------------------------------------------
921
922 /**
923 * Generate an update string
924 *
925 * @access public
926 * @param string the table upon which the query will be performed
927 * @param array an associative array data of key/values
928 * @param mixed the "where" statement
929 * @return string
930 */
931 function update_string($table, $data, $where)
932 {
933 if ($where == '')
934 return false;
935
936 $fields = array();
937 foreach($data as $key => $val)
938 {
939 $fields[$key] = $this->escape($val);
940 }
941
Rick Ellis244b4c72008-05-12 18:21:33 +0000942 if ( ! is_array($where))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000943 {
944 $dest = array($where);
945 }
946 else
947 {
948 $dest = array();
949 foreach ($where as $key => $val)
950 {
951 $prefix = (count($dest) == 0) ? '' : ' AND ';
952
Derek Allard39b622d2008-01-16 21:10:09 +0000953 if ($val !== '')
Derek Allardd2df9bc2007-04-15 17:41:17 +0000954 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000955 if ( ! $this->_has_operator($key))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000956 {
957 $key .= ' =';
958 }
959
960 $val = ' '.$this->escape($val);
961 }
962
963 $dest[] = $prefix.$key.$val;
964 }
965 }
966
Derek Allard39b622d2008-01-16 21:10:09 +0000967 return $this->_update($this->prep_tablename($table), $fields, $dest);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000968 }
969
970 // --------------------------------------------------------------------
971
972 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000973 * Prep the table name - simply adds the table prefix if needed
974 *
975 * @access public
976 * @param string the table name
977 * @return string
978 */
979 function prep_tablename($table = '')
980 {
981 // Do we need to add the table prefix?
982 if ($this->dbprefix != '')
983 {
984 if (substr($table, 0, strlen($this->dbprefix)) != $this->dbprefix)
985 {
986 $table = $this->dbprefix.$table;
987 }
988 }
989
990 return $table;
991 }
992
993 // --------------------------------------------------------------------
994
995 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000996 * Enables a native PHP function to be run, using a platform agnostic wrapper.
997 *
998 * @access public
999 * @param string the function name
1000 * @param mixed any parameters needed by the function
1001 * @return mixed
1002 */
1003 function call_function($function)
1004 {
1005 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
1006
1007 if (FALSE === strpos($driver, $function))
1008 {
1009 $function = $driver.$function;
1010 }
1011
Rick Ellis244b4c72008-05-12 18:21:33 +00001012 if ( ! function_exists($function))
Derek Allardd2df9bc2007-04-15 17:41:17 +00001013 {
1014 if ($this->db_debug)
1015 {
1016 return $this->display_error('db_unsupported_function');
1017 }
1018 return FALSE;
1019 }
1020 else
1021 {
1022 $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
1023
1024 return call_user_func_array($function, $args);
1025 }
1026 }
1027
1028 // --------------------------------------------------------------------
1029
1030 /**
1031 * Set Cache Directory Path
1032 *
1033 * @access public
1034 * @param string the path to the cache directory
1035 * @return void
1036 */
1037 function cache_set_path($path = '')
1038 {
1039 $this->cachedir = $path;
1040 }
1041
1042 // --------------------------------------------------------------------
1043
1044 /**
1045 * Enable Query Caching
1046 *
1047 * @access public
1048 * @return void
1049 */
1050 function cache_on()
1051 {
1052 $this->cache_on = TRUE;
1053 return TRUE;
1054 }
1055
1056 // --------------------------------------------------------------------
1057
1058 /**
1059 * Disable Query Caching
1060 *
1061 * @access public
1062 * @return void
1063 */
1064 function cache_off()
1065 {
1066 $this->cache_on = FALSE;
1067 return FALSE;
1068 }
1069
1070
1071 // --------------------------------------------------------------------
1072
1073 /**
1074 * Delete the cache files associated with a particular URI
1075 *
1076 * @access public
1077 * @return void
1078 */
1079 function cache_delete($segment_one = '', $segment_two = '')
1080 {
Rick Ellis244b4c72008-05-12 18:21:33 +00001081 if ( ! $this->_cache_init())
Derek Allardd2df9bc2007-04-15 17:41:17 +00001082 {
1083 return FALSE;
1084 }
1085 return $this->CACHE->delete($segment_one, $segment_two);
1086 }
1087
1088 // --------------------------------------------------------------------
1089
1090 /**
1091 * Delete All cache files
1092 *
1093 * @access public
1094 * @return void
1095 */
1096 function cache_delete_all()
1097 {
Rick Ellis244b4c72008-05-12 18:21:33 +00001098 if ( ! $this->_cache_init())
Derek Allardd2df9bc2007-04-15 17:41:17 +00001099 {
1100 return FALSE;
1101 }
1102
1103 return $this->CACHE->delete_all();
1104 }
1105
1106 // --------------------------------------------------------------------
1107
1108 /**
1109 * Initialize the Cache Class
1110 *
1111 * @access private
1112 * @return void
1113 */
1114 function _cache_init()
1115 {
1116 if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
1117 {
1118 return TRUE;
1119 }
1120
Rick Ellis244b4c72008-05-12 18:21:33 +00001121 if ( ! @include(BASEPATH.'database/DB_cache'.EXT))
Derek Allardd2df9bc2007-04-15 17:41:17 +00001122 {
1123 return $this->cache_off();
1124 }
1125
Derek Jonesd36ade02008-05-12 15:17:41 +00001126 $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 +00001127 return TRUE;
1128 }
1129
Derek Allardd2df9bc2007-04-15 17:41:17 +00001130 // --------------------------------------------------------------------
1131
1132 /**
1133 * Close DB Connection
1134 *
1135 * @access public
1136 * @return void
1137 */
1138 function close()
1139 {
Derek Jones05097752008-05-07 19:58:23 +00001140 if (is_resource($this->conn_id) OR is_object($this->conn_id))
Derek Allardd2df9bc2007-04-15 17:41:17 +00001141 {
1142 $this->_close($this->conn_id);
1143 }
1144 $this->conn_id = FALSE;
1145 }
1146
1147 // --------------------------------------------------------------------
1148
1149 /**
1150 * Display an error message
1151 *
1152 * @access public
1153 * @param string the error message
1154 * @param string any "swap" values
1155 * @param boolean whether to localize the message
1156 * @return string sends the application/error_db.php template
1157 */
1158 function display_error($error = '', $swap = '', $native = FALSE)
1159 {
Derek Jones7f88aa52008-05-12 00:03:51 +00001160 global $LANG;
Derek Allardd2df9bc2007-04-15 17:41:17 +00001161 $LANG->load('db');
1162
Derek Jones7f88aa52008-05-12 00:03:51 +00001163 $heading = $LANG->line('db_error_heading');
1164
Derek Allardd2df9bc2007-04-15 17:41:17 +00001165 if ($native == TRUE)
1166 {
1167 $message = $error;
1168 }
1169 else
1170 {
Derek Jones0b59f272008-05-13 04:22:33 +00001171 $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
Derek Allardd2df9bc2007-04-15 17:41:17 +00001172 }
Derek Allardd2df9bc2007-04-15 17:41:17 +00001173
Derek Jones7f88aa52008-05-12 00:03:51 +00001174 $error =& load_class('Exceptions');
1175 echo $error->show_error($heading, $message, 'error_db');
Derek Allardd2df9bc2007-04-15 17:41:17 +00001176 exit;
1177 }
1178
1179}
1180
Derek Jones7f88aa52008-05-12 00:03:51 +00001181
1182/* End of file DB_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +00001183/* Location: ./system/database/DB_driver.php */