blob: 9ad235ded97b9ddc1134a0bc99864a78fa3e8f22 [file] [log] [blame]
Derek Allardd2df9bc2007-04-15 17:41:17 +00001<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
2/**
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 {
150 if (! $this->db_set_charset($this->char_set, $this->dbcollat))
151 {
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
176 if (! $this->db_set_charset($this->char_set, $this->dbcollat))
177 {
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 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000311 // We call this function in order to roll-back queries
312 // if transactions are enabled. If we don't call this here
313 // the error message will trigger an exit, causing the
314 // transactions to remain in limbo.
315 $this->trans_complete();
316
317 // Log and display errors
Derek Allardd2df9bc2007-04-15 17:41:17 +0000318 log_message('error', 'Query error: '.$this->_error_message());
319 return $this->display_error(
320 array(
321 'Error Number: '.$this->_error_number(),
322 $this->_error_message(),
323 $sql
324 )
325 );
326 }
327
Derek Allard39b622d2008-01-16 21:10:09 +0000328 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000329 }
330
331 // Stop and aggregate the query time results
332 $time_end = list($em, $es) = explode(' ', microtime());
333 $this->benchmark += ($em + $es) - ($sm + $ss);
334
Derek Jones56e9fa52008-01-23 17:26:37 +0000335 if ($this->save_queries == TRUE)
336 {
337 $this->query_times[] = ($em + $es) - ($sm + $ss);
338 }
339
Derek Allardd2df9bc2007-04-15 17:41:17 +0000340 // Increment the query counter
341 $this->query_count++;
342
343 // Was the query a "write" type?
344 // If so we'll simply return true
345 if ($this->is_write_type($sql) === TRUE)
346 {
347 // If caching is enabled we'll auto-cleanup any
348 // existing files related to this particular URI
349 if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init())
350 {
351 $this->CACHE->delete();
352 }
353
354 return TRUE;
355 }
356
357 // Return TRUE if we don't need to create a result object
358 // Currently only the Oracle driver uses this when stored
359 // procedures are used
360 if ($return_object !== TRUE)
361 {
362 return TRUE;
363 }
364
365 // Load and instantiate the result driver
366
367 $driver = $this->load_rdriver();
368 $RES = new $driver();
369 $RES->conn_id = $this->conn_id;
370 $RES->result_id = $this->result_id;
Derek Allard39b622d2008-01-16 21:10:09 +0000371 $RES->num_rows = $RES->num_rows();
Derek Allard060052d2007-07-14 14:26:13 +0000372
Derek Allardd2df9bc2007-04-15 17:41:17 +0000373 if ($this->dbdriver == 'oci8')
374 {
375 $RES->stmt_id = $this->stmt_id;
376 $RES->curs_id = NULL;
377 $RES->limit_used = $this->limit_used;
378 }
Derek Allard39b622d2008-01-16 21:10:09 +0000379
Derek Allardd2df9bc2007-04-15 17:41:17 +0000380 // Is query caching enabled? If so, we'll serialize the
381 // result object and save it to a cache file.
382 if ($this->cache_on == TRUE AND $this->_cache_init())
383 {
384 // We'll create a new instance of the result object
385 // only without the platform specific driver since
386 // we can't use it with cached data (the query result
387 // resource ID won't be any good once we've cached the
388 // result object, so we'll have to compile the data
389 // and save it)
390 $CR = new CI_DB_result();
391 $CR->num_rows = $RES->num_rows();
392 $CR->result_object = $RES->result_object();
393 $CR->result_array = $RES->result_array();
394
395 // Reset these since cached objects can not utilize resource IDs.
396 $CR->conn_id = NULL;
397 $CR->result_id = NULL;
398
399 $this->CACHE->write($sql, $CR);
400 }
401
402 return $RES;
403 }
404
405 // --------------------------------------------------------------------
406
407 /**
408 * Load the result drivers
409 *
410 * @access public
411 * @return string the name of the result class
412 */
413 function load_rdriver()
414 {
415 $driver = 'CI_DB_'.$this->dbdriver.'_result';
416
Rick Ellis244b4c72008-05-12 18:21:33 +0000417 if ( ! class_exists($driver))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000418 {
419 include_once(BASEPATH.'database/DB_result'.EXT);
420 include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result'.EXT);
421 }
422
423 return $driver;
424 }
425
426 // --------------------------------------------------------------------
427
428 /**
429 * Simple Query
430 * This is a simplified version of the query() function. Internally
431 * we only use it when running transaction commands since they do
432 * not require all the features of the main query() function.
433 *
434 * @access public
435 * @param string the sql query
436 * @return mixed
437 */
438 function simple_query($sql)
439 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000440 if ( ! $this->conn_id)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000441 {
442 $this->initialize();
443 }
444
445 return $this->_execute($sql);
446 }
447
448 // --------------------------------------------------------------------
449
450 /**
451 * Disable Transactions
452 * This permits transactions to be disabled at run-time.
453 *
454 * @access public
455 * @return void
456 */
457 function trans_off()
458 {
459 $this->trans_enabled = FALSE;
460 }
461
462 // --------------------------------------------------------------------
463
464 /**
Rick Ellis244b4c72008-05-12 18:21:33 +0000465 * Enable/disable Transaction Strict Mode
466 * When strict mode is enabled, if you are running multiple groups of
467 * transactions, if one group fails all groups will be rolled back.
468 * If strict mode is disabled, each group is treated autonomously, meaning
469 * a failure of one group will not affect any others
470 *
471 * @access public
472 * @return void
473 */
474 function trans_strict($mode = TRUE)
475 {
476 $this->trans_strict = is_bool($mode) ? $mode : TRUE;
477 }
478
479 // --------------------------------------------------------------------
480
481 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000482 * Start Transaction
483 *
484 * @access public
485 * @return void
486 */
487 function trans_start($test_mode = FALSE)
488 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000489 if ( ! $this->trans_enabled)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000490 {
491 return FALSE;
492 }
493
494 // When transactions are nested we only begin/commit/rollback the outermost ones
495 if ($this->_trans_depth > 0)
496 {
497 $this->_trans_depth += 1;
498 return;
499 }
500
501 $this->trans_begin($test_mode);
502 }
503
504 // --------------------------------------------------------------------
505
506 /**
507 * Complete Transaction
508 *
509 * @access public
510 * @return bool
511 */
512 function trans_complete()
513 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000514 if ( ! $this->trans_enabled)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000515 {
516 return FALSE;
517 }
518
519 // When transactions are nested we only begin/commit/rollback the outermost ones
520 if ($this->_trans_depth > 1)
521 {
522 $this->_trans_depth -= 1;
523 return TRUE;
524 }
525
Rick Ellis244b4c72008-05-12 18:21:33 +0000526 // The query() function will set this flag to FALSE in the event that a query failed
Rick Ellis28239ad2007-06-11 04:26:39 +0000527 if ($this->_trans_status === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000528 {
529 $this->trans_rollback();
530
Rick Ellis244b4c72008-05-12 18:21:33 +0000531 // If we are NOT running in strict mode, we will reset
532 // the _trans_status flag so that subsequent groups of transactions
533 // will be permitted.
534 if ($this->trans_strict === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000535 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000536 $this->_trans_status = TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000537 }
Rick Ellis244b4c72008-05-12 18:21:33 +0000538
539 log_message('debug', 'DB Transaction Failure');
Derek Allardd2df9bc2007-04-15 17:41:17 +0000540 return FALSE;
541 }
542
543 $this->trans_commit();
544 return TRUE;
545 }
546
547 // --------------------------------------------------------------------
548
549 /**
550 * Lets you retrieve the transaction flag to determine if it has failed
551 *
552 * @access public
553 * @return bool
554 */
555 function trans_status()
556 {
Rick Ellis28239ad2007-06-11 04:26:39 +0000557 return $this->_trans_status;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000558 }
559
560 // --------------------------------------------------------------------
561
562 /**
563 * Compile Bindings
564 *
565 * @access public
566 * @param string the sql statement
567 * @param array an array of bind data
568 * @return string
569 */
570 function compile_binds($sql, $binds)
Derek Allardc0743382008-02-11 05:54:44 +0000571 {
572 if (strpos($sql, $this->bind_marker) === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000573 {
574 return $sql;
575 }
576
Rick Ellis244b4c72008-05-12 18:21:33 +0000577 if ( ! is_array($binds))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000578 {
579 $binds = array($binds);
580 }
581
Derek Allardc0743382008-02-11 05:54:44 +0000582 // Get the sql segments around the bind markers
583 $segments = explode($this->bind_marker, $sql);
584
585 // The count of bind should be 1 less then the count of segments
586 // If there are more bind arguments trim it down
587 if (count($binds) >= count($segments)) {
588 $binds = array_slice($binds, 0, count($segments)-1);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000589 }
590
Derek Allardc0743382008-02-11 05:54:44 +0000591 // Construct the binded query
592 $result = $segments[0];
593 $i = 0;
594 foreach ($binds as $bind)
595 {
596 $result .= $this->escape($bind);
597 $result .= $segments[++$i];
598 }
599
600 return $result;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000601 }
602
603 // --------------------------------------------------------------------
604
605 /**
606 * Determines if a query is a "write" type.
607 *
608 * @access public
609 * @param string An SQL query string
610 * @return boolean
611 */
612 function is_write_type($sql)
613 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000614 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 +0000615 {
616 return FALSE;
617 }
618 return TRUE;
619 }
620
621 // --------------------------------------------------------------------
622
623 /**
624 * Calculate the aggregate query elapsed time
625 *
626 * @access public
627 * @param integer The number of decimal places
628 * @return integer
629 */
630 function elapsed_time($decimals = 6)
631 {
632 return number_format($this->benchmark, $decimals);
633 }
634
635 // --------------------------------------------------------------------
636
637 /**
638 * Returns the total number of queries
639 *
640 * @access public
641 * @return integer
642 */
643 function total_queries()
644 {
645 return $this->query_count;
646 }
647
648 // --------------------------------------------------------------------
649
650 /**
651 * Returns the last query that was executed
652 *
653 * @access public
654 * @return void
655 */
656 function last_query()
657 {
658 return end($this->queries);
659 }
660
661 // --------------------------------------------------------------------
662
663 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000664 * Protect Identifiers
665 *
666 * This function adds backticks if appropriate based on db type
667 *
668 * @access private
669 * @param mixed the item to escape
670 * @param boolean only affect the first word
671 * @return mixed the item with backticks
672 */
673 function protect_identifiers($item, $first_word_only = FALSE)
674 {
Derek Allard1a704ce2008-01-27 15:03:06 +0000675 return $this->_protect_identifiers($item, $first_word_only);
Derek Allard39b622d2008-01-16 21:10:09 +0000676 }
677
678 // --------------------------------------------------------------------
679
680 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000681 * "Smart" Escape String
682 *
683 * Escapes data based on type
684 * Sets boolean and null types
685 *
686 * @access public
687 * @param string
688 * @return integer
689 */
690 function escape($str)
691 {
692 switch (gettype($str))
693 {
694 case 'string' : $str = "'".$this->escape_str($str)."'";
695 break;
696 case 'boolean' : $str = ($str === FALSE) ? 0 : 1;
697 break;
698 default : $str = ($str === NULL) ? 'NULL' : $str;
699 break;
700 }
701
702 return $str;
703 }
704
705 // --------------------------------------------------------------------
706
707 /**
708 * Primary
709 *
710 * Retrieves the primary key. It assumes that the row in the first
711 * position is the primary key
712 *
713 * @access public
714 * @param string the table name
715 * @return string
716 */
717 function primary($table = '')
718 {
719 $fields = $this->list_fields($table);
720
Rick Ellis244b4c72008-05-12 18:21:33 +0000721 if ( ! is_array($fields))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000722 {
723 return FALSE;
724 }
725
726 return current($fields);
727 }
728
729 // --------------------------------------------------------------------
730
731 /**
732 * Returns an array of table names
733 *
734 * @access public
735 * @return array
736 */
Derek Allard39b622d2008-01-16 21:10:09 +0000737 function list_tables($constrain_by_prefix = FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000738 {
739 // Is there a cached result?
740 if (isset($this->data_cache['table_names']))
741 {
742 return $this->data_cache['table_names'];
743 }
744
Derek Allard39b622d2008-01-16 21:10:09 +0000745 if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000746 {
747 if ($this->db_debug)
748 {
749 return $this->display_error('db_unsupported_function');
750 }
751 return FALSE;
752 }
753
754 $retval = array();
755 $query = $this->query($sql);
756
757 if ($query->num_rows() > 0)
758 {
759 foreach($query->result_array() as $row)
760 {
761 if (isset($row['TABLE_NAME']))
762 {
763 $retval[] = $row['TABLE_NAME'];
764 }
765 else
766 {
767 $retval[] = array_shift($row);
768 }
769 }
770 }
771
772 $this->data_cache['table_names'] = $retval;
773 return $this->data_cache['table_names'];
774 }
775
776 // --------------------------------------------------------------------
777
778 /**
779 * Determine if a particular table exists
780 * @access public
781 * @return boolean
782 */
783 function table_exists($table_name)
784 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000785 return ( ! in_array($this->prep_tablename($table_name), $this->list_tables())) ? FALSE : TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000786 }
787
788 // --------------------------------------------------------------------
789
790 /**
791 * Fetch MySQL Field Names
792 *
793 * @access public
794 * @param string the table name
795 * @return array
796 */
797 function list_fields($table = '')
798 {
799 // Is there a cached result?
800 if (isset($this->data_cache['field_names'][$table]))
801 {
802 return $this->data_cache['field_names'][$table];
803 }
804
805 if ($table == '')
806 {
807 if ($this->db_debug)
808 {
809 return $this->display_error('db_field_param_missing');
810 }
811 return FALSE;
812 }
813
Derek Allard39b622d2008-01-16 21:10:09 +0000814 if (FALSE === ($sql = $this->_list_columns($this->prep_tablename($table))))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000815 {
816 if ($this->db_debug)
817 {
818 return $this->display_error('db_unsupported_function');
819 }
820 return FALSE;
821 }
822
823 $query = $this->query($sql);
824
825 $retval = array();
826 foreach($query->result_array() as $row)
827 {
828 if (isset($row['COLUMN_NAME']))
829 {
830 $retval[] = $row['COLUMN_NAME'];
831 }
832 else
833 {
834 $retval[] = current($row);
835 }
836 }
837
838 $this->data_cache['field_names'][$table] = $retval;
839 return $this->data_cache['field_names'][$table];
840 }
841
842 // --------------------------------------------------------------------
843
844 /**
845 * Determine if a particular field exists
846 * @access public
847 * @param string
848 * @param string
849 * @return boolean
850 */
851 function field_exists($field_name, $table_name)
852 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000853 return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000854 }
855
856 // --------------------------------------------------------------------
857
858 /**
859 * DEPRECATED - use list_fields()
860 */
861 function field_names($table = '')
862 {
863 return $this->list_fields($table);
864 }
865
866 // --------------------------------------------------------------------
867
868 /**
869 * Returns an object with field data
870 *
871 * @access public
872 * @param string the table name
873 * @return object
874 */
875 function field_data($table = '')
876 {
877 if ($table == '')
878 {
879 if ($this->db_debug)
880 {
881 return $this->display_error('db_field_param_missing');
882 }
883 return FALSE;
884 }
885
Derek Allard39b622d2008-01-16 21:10:09 +0000886 $query = $this->query($this->_field_data($this->prep_tablename($table)));
Derek Allardd2df9bc2007-04-15 17:41:17 +0000887 return $query->field_data();
888 }
889
890 // --------------------------------------------------------------------
891
892 /**
893 * Generate an insert string
894 *
895 * @access public
896 * @param string the table upon which the query will be performed
897 * @param array an associative array data of key/values
898 * @return string
899 */
900 function insert_string($table, $data)
901 {
902 $fields = array();
903 $values = array();
904
905 foreach($data as $key => $val)
906 {
907 $fields[] = $key;
908 $values[] = $this->escape($val);
909 }
Derek Allard39b622d2008-01-16 21:10:09 +0000910
911
912 return $this->_insert($this->prep_tablename($table), $fields, $values);
913 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000914
915 // --------------------------------------------------------------------
916
917 /**
918 * Generate an update string
919 *
920 * @access public
921 * @param string the table upon which the query will be performed
922 * @param array an associative array data of key/values
923 * @param mixed the "where" statement
924 * @return string
925 */
926 function update_string($table, $data, $where)
927 {
928 if ($where == '')
929 return false;
930
931 $fields = array();
932 foreach($data as $key => $val)
933 {
934 $fields[$key] = $this->escape($val);
935 }
936
Rick Ellis244b4c72008-05-12 18:21:33 +0000937 if ( ! is_array($where))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000938 {
939 $dest = array($where);
940 }
941 else
942 {
943 $dest = array();
944 foreach ($where as $key => $val)
945 {
946 $prefix = (count($dest) == 0) ? '' : ' AND ';
947
Derek Allard39b622d2008-01-16 21:10:09 +0000948 if ($val !== '')
Derek Allardd2df9bc2007-04-15 17:41:17 +0000949 {
Rick Ellis244b4c72008-05-12 18:21:33 +0000950 if ( ! $this->_has_operator($key))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000951 {
952 $key .= ' =';
953 }
954
955 $val = ' '.$this->escape($val);
956 }
957
958 $dest[] = $prefix.$key.$val;
959 }
960 }
961
Derek Allard39b622d2008-01-16 21:10:09 +0000962 return $this->_update($this->prep_tablename($table), $fields, $dest);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000963 }
964
965 // --------------------------------------------------------------------
966
967 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000968 * Prep the table name - simply adds the table prefix if needed
969 *
970 * @access public
971 * @param string the table name
972 * @return string
973 */
974 function prep_tablename($table = '')
975 {
976 // Do we need to add the table prefix?
977 if ($this->dbprefix != '')
978 {
979 if (substr($table, 0, strlen($this->dbprefix)) != $this->dbprefix)
980 {
981 $table = $this->dbprefix.$table;
982 }
983 }
984
985 return $table;
986 }
987
988 // --------------------------------------------------------------------
989
990 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000991 * Enables a native PHP function to be run, using a platform agnostic wrapper.
992 *
993 * @access public
994 * @param string the function name
995 * @param mixed any parameters needed by the function
996 * @return mixed
997 */
998 function call_function($function)
999 {
1000 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
1001
1002 if (FALSE === strpos($driver, $function))
1003 {
1004 $function = $driver.$function;
1005 }
1006
Rick Ellis244b4c72008-05-12 18:21:33 +00001007 if ( ! function_exists($function))
Derek Allardd2df9bc2007-04-15 17:41:17 +00001008 {
1009 if ($this->db_debug)
1010 {
1011 return $this->display_error('db_unsupported_function');
1012 }
1013 return FALSE;
1014 }
1015 else
1016 {
1017 $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
1018
1019 return call_user_func_array($function, $args);
1020 }
1021 }
1022
1023 // --------------------------------------------------------------------
1024
1025 /**
1026 * Set Cache Directory Path
1027 *
1028 * @access public
1029 * @param string the path to the cache directory
1030 * @return void
1031 */
1032 function cache_set_path($path = '')
1033 {
1034 $this->cachedir = $path;
1035 }
1036
1037 // --------------------------------------------------------------------
1038
1039 /**
1040 * Enable Query Caching
1041 *
1042 * @access public
1043 * @return void
1044 */
1045 function cache_on()
1046 {
1047 $this->cache_on = TRUE;
1048 return TRUE;
1049 }
1050
1051 // --------------------------------------------------------------------
1052
1053 /**
1054 * Disable Query Caching
1055 *
1056 * @access public
1057 * @return void
1058 */
1059 function cache_off()
1060 {
1061 $this->cache_on = FALSE;
1062 return FALSE;
1063 }
1064
1065
1066 // --------------------------------------------------------------------
1067
1068 /**
1069 * Delete the cache files associated with a particular URI
1070 *
1071 * @access public
1072 * @return void
1073 */
1074 function cache_delete($segment_one = '', $segment_two = '')
1075 {
Rick Ellis244b4c72008-05-12 18:21:33 +00001076 if ( ! $this->_cache_init())
Derek Allardd2df9bc2007-04-15 17:41:17 +00001077 {
1078 return FALSE;
1079 }
1080 return $this->CACHE->delete($segment_one, $segment_two);
1081 }
1082
1083 // --------------------------------------------------------------------
1084
1085 /**
1086 * Delete All cache files
1087 *
1088 * @access public
1089 * @return void
1090 */
1091 function cache_delete_all()
1092 {
Rick Ellis244b4c72008-05-12 18:21:33 +00001093 if ( ! $this->_cache_init())
Derek Allardd2df9bc2007-04-15 17:41:17 +00001094 {
1095 return FALSE;
1096 }
1097
1098 return $this->CACHE->delete_all();
1099 }
1100
1101 // --------------------------------------------------------------------
1102
1103 /**
1104 * Initialize the Cache Class
1105 *
1106 * @access private
1107 * @return void
1108 */
1109 function _cache_init()
1110 {
1111 if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
1112 {
1113 return TRUE;
1114 }
1115
Rick Ellis244b4c72008-05-12 18:21:33 +00001116 if ( ! @include(BASEPATH.'database/DB_cache'.EXT))
Derek Allardd2df9bc2007-04-15 17:41:17 +00001117 {
1118 return $this->cache_off();
1119 }
1120
Derek Jonesd36ade02008-05-12 15:17:41 +00001121 $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 +00001122 return TRUE;
1123 }
1124
Derek Allardd2df9bc2007-04-15 17:41:17 +00001125 // --------------------------------------------------------------------
1126
1127 /**
1128 * Close DB Connection
1129 *
1130 * @access public
1131 * @return void
1132 */
1133 function close()
1134 {
Derek Jones05097752008-05-07 19:58:23 +00001135 if (is_resource($this->conn_id) OR is_object($this->conn_id))
Derek Allardd2df9bc2007-04-15 17:41:17 +00001136 {
1137 $this->_close($this->conn_id);
1138 }
1139 $this->conn_id = FALSE;
1140 }
1141
1142 // --------------------------------------------------------------------
1143
1144 /**
1145 * Display an error message
1146 *
1147 * @access public
1148 * @param string the error message
1149 * @param string any "swap" values
1150 * @param boolean whether to localize the message
1151 * @return string sends the application/error_db.php template
1152 */
1153 function display_error($error = '', $swap = '', $native = FALSE)
1154 {
Derek Jones7f88aa52008-05-12 00:03:51 +00001155 global $LANG;
Derek Allardd2df9bc2007-04-15 17:41:17 +00001156 $LANG->load('db');
1157
Derek Jones7f88aa52008-05-12 00:03:51 +00001158 $heading = $LANG->line('db_error_heading');
1159
Derek Allardd2df9bc2007-04-15 17:41:17 +00001160 if ($native == TRUE)
1161 {
1162 $message = $error;
1163 }
1164 else
1165 {
Derek Allard73274992008-05-05 16:39:18 +00001166 $message = (! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
Derek Allardd2df9bc2007-04-15 17:41:17 +00001167 }
Derek Allardd2df9bc2007-04-15 17:41:17 +00001168
Derek Jones7f88aa52008-05-12 00:03:51 +00001169 $error =& load_class('Exceptions');
1170 echo $error->show_error($heading, $message, 'error_db');
Derek Allardd2df9bc2007-04-15 17:41:17 +00001171 exit;
1172 }
1173
1174}
1175
Derek Jones7f88aa52008-05-12 00:03:51 +00001176
1177/* End of file DB_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +00001178/* Location: ./system/database/DB_driver.php */