blob: b055d6dc3e86c41f1cfa90a6aca2abb41cd100fc [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;
54 var $_trans_depth = 0;
Rick Ellis28239ad2007-06-11 04:26:39 +000055 var $_trans_status = TRUE; // Used with transactions to determine if a rollback should occur
Derek Allardd2df9bc2007-04-15 17:41:17 +000056 var $cache_on = FALSE;
57 var $cachedir = '';
58 var $cache_autodel = FALSE;
59 var $CACHE; // The cache class object
60
61
62 // These are use with Oracle
63 var $stmt_id;
64 var $curs_id;
65 var $limit_used;
66
67
68
69 /**
70 * Constructor. Accepts one parameter containing the database
71 * connection settings.
72 *
Derek Jones7dd38382008-02-13 04:52:58 +000073 * @param array
Derek Allardd2df9bc2007-04-15 17:41:17 +000074 */
75 function CI_DB_driver($params)
76 {
Derek Allardd2df9bc2007-04-15 17:41:17 +000077 if (is_array($params))
78 {
Derek Allard39b622d2008-01-16 21:10:09 +000079 foreach ($params as $key => $val)
Derek Allardd2df9bc2007-04-15 17:41:17 +000080 {
Derek Allard39b622d2008-01-16 21:10:09 +000081 $this->$key = $val;
Derek Allardd2df9bc2007-04-15 17:41:17 +000082 }
83 }
Derek Allard39b622d2008-01-16 21:10:09 +000084
85 log_message('debug', 'Database Driver Class Initialized');
86 }
87
88 // --------------------------------------------------------------------
89
90 /**
91 * Initialize Database Settings
92 *
93 * @access private Called by the constructor
94 * @param mixed
95 * @return void
96 */
97 function initialize($create_db = FALSE)
98 {
Derek Allardd2df9bc2007-04-15 17:41:17 +000099 // If an existing DB connection resource is supplied
100 // there is no need to connect and select the database
Derek Jones05097752008-05-07 19:58:23 +0000101 if (is_resource($this->conn_id) OR is_object($this->conn_id))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000102 {
103 return TRUE;
104 }
105
106 // Connect to the database
107 $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
108
109 // No connection? Throw an error
Derek Allard73274992008-05-05 16:39:18 +0000110 if (! $this->conn_id)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000111 {
112 log_message('error', 'Unable to connect to the database');
113
114 if ($this->db_debug)
115 {
116 $this->display_error('db_unable_to_connect');
117 }
118 return FALSE;
119 }
120
121 // Select the database
122 if ($this->database != '')
123 {
Derek Allard73274992008-05-05 16:39:18 +0000124 if (! $this->db_select())
Derek Allardd2df9bc2007-04-15 17:41:17 +0000125 {
Derek Allard39b622d2008-01-16 21:10:09 +0000126 // Should we attempt to create the database?
127 if ($create_db == TRUE)
128 {
129 // Load the DB utility class
130 $CI =& get_instance();
131 $CI->load->dbutil();
132
133 // Create the DB
Derek Allard73274992008-05-05 16:39:18 +0000134 if (! $CI->dbutil->create_database($this->database))
Derek Allard39b622d2008-01-16 21:10:09 +0000135 {
136 log_message('error', 'Unable to create database: '.$this->database);
137
138 if ($this->db_debug)
139 {
140 $this->display_error('db_unable_to_create', $this->database);
141 }
142 return FALSE;
143 }
144 else
145 {
146 // In the event the DB was created we need to select it
147 if ($this->db_select())
148 {
149 if (! $this->db_set_charset($this->char_set, $this->dbcollat))
150 {
151 log_message('error', 'Unable to set database connection charset: '.$this->char_set);
152
153 if ($this->db_debug)
154 {
155 $this->display_error('db_unable_to_set_charset', $this->char_set);
156 }
157
158 return FALSE;
159 }
160
161 return TRUE;
162 }
163 }
164 }
165
Derek Allardd2df9bc2007-04-15 17:41:17 +0000166 log_message('error', 'Unable to select database: '.$this->database);
167
168 if ($this->db_debug)
169 {
170 $this->display_error('db_unable_to_select', $this->database);
171 }
172 return FALSE;
173 }
Derek Allard39b622d2008-01-16 21:10:09 +0000174
175 if (! $this->db_set_charset($this->char_set, $this->dbcollat))
176 {
177 log_message('error', 'Unable to set database connection charset: '.$this->char_set);
178
179 if ($this->db_debug)
180 {
181 $this->display_error('db_unable_to_set_charset', $this->char_set);
182 }
183
184 return FALSE;
185 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000186 }
187
188 return TRUE;
189 }
190
191 // --------------------------------------------------------------------
192
193 /**
194 * The name of the platform in use (mysql, mssql, etc...)
195 *
196 * @access public
197 * @return string
198 */
199 function platform()
200 {
201 return $this->dbdriver;
202 }
203
204 // --------------------------------------------------------------------
205
206 /**
207 * Database Version Number. Returns a string containing the
208 * version of the database being used
209 *
210 * @access public
211 * @return string
212 */
213 function version()
214 {
215 if (FALSE === ($sql = $this->_version()))
216 {
217 if ($this->db_debug)
218 {
219 return $this->display_error('db_unsupported_function');
220 }
221 return FALSE;
222 }
223
224 if ($this->dbdriver == 'oci8')
225 {
226 return $sql;
227 }
228
229 $query = $this->query($sql);
Derek Allard39b622d2008-01-16 21:10:09 +0000230 return $query->row('ver');
Derek Allardd2df9bc2007-04-15 17:41:17 +0000231 }
232
233 // --------------------------------------------------------------------
234
235 /**
236 * Execute the query
237 *
238 * Accepts an SQL string as input and returns a result object upon
239 * successful execution of a "read" type query. Returns boolean TRUE
240 * upon successful execution of a "write" type query. Returns boolean
241 * FALSE upon failure, and if the $db_debug variable is set to TRUE
242 * will raise an error.
243 *
244 * @access public
245 * @param string An SQL query string
246 * @param array An array of binding data
247 * @return mixed
248 */
249 function query($sql, $binds = FALSE, $return_object = TRUE)
250 {
251 if ($sql == '')
252 {
253 if ($this->db_debug)
254 {
255 log_message('error', 'Invalid query: '.$sql);
256 return $this->display_error('db_invalid_query');
257 }
258 return FALSE;
259 }
Derek Allard39b622d2008-01-16 21:10:09 +0000260
261 // Verify table prefix and replace if necessary
262 if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) )
263 {
264 $sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql);
265 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000266
267 // Is query caching enabled? If the query is a "read type"
268 // we will load the caching class and return the previously
269 // cached query if it exists
270 if ($this->cache_on == TRUE AND stristr($sql, 'SELECT'))
271 {
272 if ($this->_cache_init())
273 {
274 $this->load_rdriver();
275 if (FALSE !== ($cache = $this->CACHE->read($sql)))
276 {
277 return $cache;
278 }
279 }
280 }
281
282 // Compile binds if needed
283 if ($binds !== FALSE)
284 {
285 $sql = $this->compile_binds($sql, $binds);
286 }
287
288 // Save the query for debugging
Rick Ellis40990462007-07-17 21:40:44 +0000289 if ($this->save_queries == TRUE)
290 {
291 $this->queries[] = $sql;
292 }
Derek Allard39b622d2008-01-16 21:10:09 +0000293
Derek Allardd2df9bc2007-04-15 17:41:17 +0000294 // Start the Query Timer
295 $time_start = list($sm, $ss) = explode(' ', microtime());
296
297 // Run the Query
298 if (FALSE === ($this->result_id = $this->simple_query($sql)))
299 {
300 // This will trigger a rollback if transactions are being used
Rick Ellis28239ad2007-06-11 04:26:39 +0000301 $this->_trans_status = FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000302
303 if ($this->db_debug)
304 {
305 log_message('error', 'Query error: '.$this->_error_message());
306 return $this->display_error(
307 array(
308 'Error Number: '.$this->_error_number(),
309 $this->_error_message(),
310 $sql
311 )
312 );
313 }
314
Derek Allard39b622d2008-01-16 21:10:09 +0000315 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000316 }
317
318 // Stop and aggregate the query time results
319 $time_end = list($em, $es) = explode(' ', microtime());
320 $this->benchmark += ($em + $es) - ($sm + $ss);
321
Derek Jones56e9fa52008-01-23 17:26:37 +0000322 if ($this->save_queries == TRUE)
323 {
324 $this->query_times[] = ($em + $es) - ($sm + $ss);
325 }
326
Derek Allardd2df9bc2007-04-15 17:41:17 +0000327 // Increment the query counter
328 $this->query_count++;
329
330 // Was the query a "write" type?
331 // If so we'll simply return true
332 if ($this->is_write_type($sql) === TRUE)
333 {
334 // If caching is enabled we'll auto-cleanup any
335 // existing files related to this particular URI
336 if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init())
337 {
338 $this->CACHE->delete();
339 }
340
341 return TRUE;
342 }
343
344 // Return TRUE if we don't need to create a result object
345 // Currently only the Oracle driver uses this when stored
346 // procedures are used
347 if ($return_object !== TRUE)
348 {
349 return TRUE;
350 }
351
352 // Load and instantiate the result driver
353
354 $driver = $this->load_rdriver();
355 $RES = new $driver();
356 $RES->conn_id = $this->conn_id;
357 $RES->result_id = $this->result_id;
Derek Allard39b622d2008-01-16 21:10:09 +0000358 $RES->num_rows = $RES->num_rows();
Derek Allard060052d2007-07-14 14:26:13 +0000359
Derek Allardd2df9bc2007-04-15 17:41:17 +0000360 if ($this->dbdriver == 'oci8')
361 {
362 $RES->stmt_id = $this->stmt_id;
363 $RES->curs_id = NULL;
364 $RES->limit_used = $this->limit_used;
365 }
Derek Allard39b622d2008-01-16 21:10:09 +0000366
Derek Allardd2df9bc2007-04-15 17:41:17 +0000367 // Is query caching enabled? If so, we'll serialize the
368 // result object and save it to a cache file.
369 if ($this->cache_on == TRUE AND $this->_cache_init())
370 {
371 // We'll create a new instance of the result object
372 // only without the platform specific driver since
373 // we can't use it with cached data (the query result
374 // resource ID won't be any good once we've cached the
375 // result object, so we'll have to compile the data
376 // and save it)
377 $CR = new CI_DB_result();
378 $CR->num_rows = $RES->num_rows();
379 $CR->result_object = $RES->result_object();
380 $CR->result_array = $RES->result_array();
381
382 // Reset these since cached objects can not utilize resource IDs.
383 $CR->conn_id = NULL;
384 $CR->result_id = NULL;
385
386 $this->CACHE->write($sql, $CR);
387 }
388
389 return $RES;
390 }
391
392 // --------------------------------------------------------------------
393
394 /**
395 * Load the result drivers
396 *
397 * @access public
398 * @return string the name of the result class
399 */
400 function load_rdriver()
401 {
402 $driver = 'CI_DB_'.$this->dbdriver.'_result';
403
Derek Allard73274992008-05-05 16:39:18 +0000404 if (! class_exists($driver))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000405 {
406 include_once(BASEPATH.'database/DB_result'.EXT);
407 include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result'.EXT);
408 }
409
410 return $driver;
411 }
412
413 // --------------------------------------------------------------------
414
415 /**
416 * Simple Query
417 * This is a simplified version of the query() function. Internally
418 * we only use it when running transaction commands since they do
419 * not require all the features of the main query() function.
420 *
421 * @access public
422 * @param string the sql query
423 * @return mixed
424 */
425 function simple_query($sql)
426 {
Derek Allard73274992008-05-05 16:39:18 +0000427 if (! $this->conn_id)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000428 {
429 $this->initialize();
430 }
431
432 return $this->_execute($sql);
433 }
434
435 // --------------------------------------------------------------------
436
437 /**
438 * Disable Transactions
439 * This permits transactions to be disabled at run-time.
440 *
441 * @access public
442 * @return void
443 */
444 function trans_off()
445 {
446 $this->trans_enabled = FALSE;
447 }
448
449 // --------------------------------------------------------------------
450
451 /**
452 * Start Transaction
453 *
454 * @access public
455 * @return void
456 */
457 function trans_start($test_mode = FALSE)
458 {
Derek Allard73274992008-05-05 16:39:18 +0000459 if (! $this->trans_enabled)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000460 {
461 return FALSE;
462 }
463
464 // When transactions are nested we only begin/commit/rollback the outermost ones
465 if ($this->_trans_depth > 0)
466 {
467 $this->_trans_depth += 1;
468 return;
469 }
470
471 $this->trans_begin($test_mode);
472 }
473
474 // --------------------------------------------------------------------
475
476 /**
477 * Complete Transaction
478 *
479 * @access public
480 * @return bool
481 */
482 function trans_complete()
483 {
Derek Allard73274992008-05-05 16:39:18 +0000484 if (! $this->trans_enabled)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000485 {
486 return FALSE;
487 }
488
489 // When transactions are nested we only begin/commit/rollback the outermost ones
490 if ($this->_trans_depth > 1)
491 {
492 $this->_trans_depth -= 1;
493 return TRUE;
494 }
495
496 // The query() function will set this flag to TRUE in the event that a query failed
Rick Ellis28239ad2007-06-11 04:26:39 +0000497 if ($this->_trans_status === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000498 {
499 $this->trans_rollback();
500
501 if ($this->db_debug)
502 {
503 return $this->display_error('db_transaction_failure');
504 }
505 return FALSE;
506 }
507
508 $this->trans_commit();
509 return TRUE;
510 }
511
512 // --------------------------------------------------------------------
513
514 /**
515 * Lets you retrieve the transaction flag to determine if it has failed
516 *
517 * @access public
518 * @return bool
519 */
520 function trans_status()
521 {
Rick Ellis28239ad2007-06-11 04:26:39 +0000522 return $this->_trans_status;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000523 }
524
525 // --------------------------------------------------------------------
526
527 /**
528 * Compile Bindings
529 *
530 * @access public
531 * @param string the sql statement
532 * @param array an array of bind data
533 * @return string
534 */
535 function compile_binds($sql, $binds)
Derek Allardc0743382008-02-11 05:54:44 +0000536 {
537 if (strpos($sql, $this->bind_marker) === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000538 {
539 return $sql;
540 }
541
Derek Allard73274992008-05-05 16:39:18 +0000542 if (! is_array($binds))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000543 {
544 $binds = array($binds);
545 }
546
Derek Allardc0743382008-02-11 05:54:44 +0000547 // Get the sql segments around the bind markers
548 $segments = explode($this->bind_marker, $sql);
549
550 // The count of bind should be 1 less then the count of segments
551 // If there are more bind arguments trim it down
552 if (count($binds) >= count($segments)) {
553 $binds = array_slice($binds, 0, count($segments)-1);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000554 }
555
Derek Allardc0743382008-02-11 05:54:44 +0000556 // Construct the binded query
557 $result = $segments[0];
558 $i = 0;
559 foreach ($binds as $bind)
560 {
561 $result .= $this->escape($bind);
562 $result .= $segments[++$i];
563 }
564
565 return $result;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000566 }
567
568 // --------------------------------------------------------------------
569
570 /**
571 * Determines if a query is a "write" type.
572 *
573 * @access public
574 * @param string An SQL query string
575 * @return boolean
576 */
577 function is_write_type($sql)
578 {
Derek Jones0f13a132008-05-08 18:54:03 +0000579 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 +0000580 {
581 return FALSE;
582 }
583 return TRUE;
584 }
585
586 // --------------------------------------------------------------------
587
588 /**
589 * Calculate the aggregate query elapsed time
590 *
591 * @access public
592 * @param integer The number of decimal places
593 * @return integer
594 */
595 function elapsed_time($decimals = 6)
596 {
597 return number_format($this->benchmark, $decimals);
598 }
599
600 // --------------------------------------------------------------------
601
602 /**
603 * Returns the total number of queries
604 *
605 * @access public
606 * @return integer
607 */
608 function total_queries()
609 {
610 return $this->query_count;
611 }
612
613 // --------------------------------------------------------------------
614
615 /**
616 * Returns the last query that was executed
617 *
618 * @access public
619 * @return void
620 */
621 function last_query()
622 {
623 return end($this->queries);
624 }
625
626 // --------------------------------------------------------------------
627
628 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000629 * Protect Identifiers
630 *
631 * This function adds backticks if appropriate based on db type
632 *
633 * @access private
634 * @param mixed the item to escape
635 * @param boolean only affect the first word
636 * @return mixed the item with backticks
637 */
638 function protect_identifiers($item, $first_word_only = FALSE)
639 {
Derek Allard1a704ce2008-01-27 15:03:06 +0000640 return $this->_protect_identifiers($item, $first_word_only);
Derek Allard39b622d2008-01-16 21:10:09 +0000641 }
642
643 // --------------------------------------------------------------------
644
645 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000646 * "Smart" Escape String
647 *
648 * Escapes data based on type
649 * Sets boolean and null types
650 *
651 * @access public
652 * @param string
653 * @return integer
654 */
655 function escape($str)
656 {
657 switch (gettype($str))
658 {
659 case 'string' : $str = "'".$this->escape_str($str)."'";
660 break;
661 case 'boolean' : $str = ($str === FALSE) ? 0 : 1;
662 break;
663 default : $str = ($str === NULL) ? 'NULL' : $str;
664 break;
665 }
666
667 return $str;
668 }
669
670 // --------------------------------------------------------------------
671
672 /**
673 * Primary
674 *
675 * Retrieves the primary key. It assumes that the row in the first
676 * position is the primary key
677 *
678 * @access public
679 * @param string the table name
680 * @return string
681 */
682 function primary($table = '')
683 {
684 $fields = $this->list_fields($table);
685
Derek Allard73274992008-05-05 16:39:18 +0000686 if (! is_array($fields))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000687 {
688 return FALSE;
689 }
690
691 return current($fields);
692 }
693
694 // --------------------------------------------------------------------
695
696 /**
697 * Returns an array of table names
698 *
699 * @access public
700 * @return array
701 */
Derek Allard39b622d2008-01-16 21:10:09 +0000702 function list_tables($constrain_by_prefix = FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000703 {
704 // Is there a cached result?
705 if (isset($this->data_cache['table_names']))
706 {
707 return $this->data_cache['table_names'];
708 }
709
Derek Allard39b622d2008-01-16 21:10:09 +0000710 if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000711 {
712 if ($this->db_debug)
713 {
714 return $this->display_error('db_unsupported_function');
715 }
716 return FALSE;
717 }
718
719 $retval = array();
720 $query = $this->query($sql);
721
722 if ($query->num_rows() > 0)
723 {
724 foreach($query->result_array() as $row)
725 {
726 if (isset($row['TABLE_NAME']))
727 {
728 $retval[] = $row['TABLE_NAME'];
729 }
730 else
731 {
732 $retval[] = array_shift($row);
733 }
734 }
735 }
736
737 $this->data_cache['table_names'] = $retval;
738 return $this->data_cache['table_names'];
739 }
740
741 // --------------------------------------------------------------------
742
743 /**
744 * Determine if a particular table exists
745 * @access public
746 * @return boolean
747 */
748 function table_exists($table_name)
749 {
Derek Allard73274992008-05-05 16:39:18 +0000750 return (! in_array($this->prep_tablename($table_name), $this->list_tables())) ? FALSE : TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000751 }
752
753 // --------------------------------------------------------------------
754
755 /**
756 * Fetch MySQL Field Names
757 *
758 * @access public
759 * @param string the table name
760 * @return array
761 */
762 function list_fields($table = '')
763 {
764 // Is there a cached result?
765 if (isset($this->data_cache['field_names'][$table]))
766 {
767 return $this->data_cache['field_names'][$table];
768 }
769
770 if ($table == '')
771 {
772 if ($this->db_debug)
773 {
774 return $this->display_error('db_field_param_missing');
775 }
776 return FALSE;
777 }
778
Derek Allard39b622d2008-01-16 21:10:09 +0000779 if (FALSE === ($sql = $this->_list_columns($this->prep_tablename($table))))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000780 {
781 if ($this->db_debug)
782 {
783 return $this->display_error('db_unsupported_function');
784 }
785 return FALSE;
786 }
787
788 $query = $this->query($sql);
789
790 $retval = array();
791 foreach($query->result_array() as $row)
792 {
793 if (isset($row['COLUMN_NAME']))
794 {
795 $retval[] = $row['COLUMN_NAME'];
796 }
797 else
798 {
799 $retval[] = current($row);
800 }
801 }
802
803 $this->data_cache['field_names'][$table] = $retval;
804 return $this->data_cache['field_names'][$table];
805 }
806
807 // --------------------------------------------------------------------
808
809 /**
810 * Determine if a particular field exists
811 * @access public
812 * @param string
813 * @param string
814 * @return boolean
815 */
816 function field_exists($field_name, $table_name)
817 {
Derek Allard73274992008-05-05 16:39:18 +0000818 return (! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000819 }
820
821 // --------------------------------------------------------------------
822
823 /**
824 * DEPRECATED - use list_fields()
825 */
826 function field_names($table = '')
827 {
828 return $this->list_fields($table);
829 }
830
831 // --------------------------------------------------------------------
832
833 /**
834 * Returns an object with field data
835 *
836 * @access public
837 * @param string the table name
838 * @return object
839 */
840 function field_data($table = '')
841 {
842 if ($table == '')
843 {
844 if ($this->db_debug)
845 {
846 return $this->display_error('db_field_param_missing');
847 }
848 return FALSE;
849 }
850
Derek Allard39b622d2008-01-16 21:10:09 +0000851 $query = $this->query($this->_field_data($this->prep_tablename($table)));
Derek Allardd2df9bc2007-04-15 17:41:17 +0000852 return $query->field_data();
853 }
854
855 // --------------------------------------------------------------------
856
857 /**
858 * Generate an insert string
859 *
860 * @access public
861 * @param string the table upon which the query will be performed
862 * @param array an associative array data of key/values
863 * @return string
864 */
865 function insert_string($table, $data)
866 {
867 $fields = array();
868 $values = array();
869
870 foreach($data as $key => $val)
871 {
872 $fields[] = $key;
873 $values[] = $this->escape($val);
874 }
Derek Allard39b622d2008-01-16 21:10:09 +0000875
876
877 return $this->_insert($this->prep_tablename($table), $fields, $values);
878 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000879
880 // --------------------------------------------------------------------
881
882 /**
883 * Generate an update string
884 *
885 * @access public
886 * @param string the table upon which the query will be performed
887 * @param array an associative array data of key/values
888 * @param mixed the "where" statement
889 * @return string
890 */
891 function update_string($table, $data, $where)
892 {
893 if ($where == '')
894 return false;
895
896 $fields = array();
897 foreach($data as $key => $val)
898 {
899 $fields[$key] = $this->escape($val);
900 }
901
Derek Allard73274992008-05-05 16:39:18 +0000902 if (! is_array($where))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000903 {
904 $dest = array($where);
905 }
906 else
907 {
908 $dest = array();
909 foreach ($where as $key => $val)
910 {
911 $prefix = (count($dest) == 0) ? '' : ' AND ';
912
Derek Allard39b622d2008-01-16 21:10:09 +0000913 if ($val !== '')
Derek Allardd2df9bc2007-04-15 17:41:17 +0000914 {
Derek Allard73274992008-05-05 16:39:18 +0000915 if (! $this->_has_operator($key))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000916 {
917 $key .= ' =';
918 }
919
920 $val = ' '.$this->escape($val);
921 }
922
923 $dest[] = $prefix.$key.$val;
924 }
925 }
926
Derek Allard39b622d2008-01-16 21:10:09 +0000927 return $this->_update($this->prep_tablename($table), $fields, $dest);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000928 }
929
930 // --------------------------------------------------------------------
931
932 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000933 * Prep the table name - simply adds the table prefix if needed
934 *
935 * @access public
936 * @param string the table name
937 * @return string
938 */
939 function prep_tablename($table = '')
940 {
941 // Do we need to add the table prefix?
942 if ($this->dbprefix != '')
943 {
944 if (substr($table, 0, strlen($this->dbprefix)) != $this->dbprefix)
945 {
946 $table = $this->dbprefix.$table;
947 }
948 }
949
950 return $table;
951 }
952
953 // --------------------------------------------------------------------
954
955 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000956 * Enables a native PHP function to be run, using a platform agnostic wrapper.
957 *
958 * @access public
959 * @param string the function name
960 * @param mixed any parameters needed by the function
961 * @return mixed
962 */
963 function call_function($function)
964 {
965 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
966
967 if (FALSE === strpos($driver, $function))
968 {
969 $function = $driver.$function;
970 }
971
Derek Allard73274992008-05-05 16:39:18 +0000972 if (! function_exists($function))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000973 {
974 if ($this->db_debug)
975 {
976 return $this->display_error('db_unsupported_function');
977 }
978 return FALSE;
979 }
980 else
981 {
982 $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
983
984 return call_user_func_array($function, $args);
985 }
986 }
987
988 // --------------------------------------------------------------------
989
990 /**
991 * Set Cache Directory Path
992 *
993 * @access public
994 * @param string the path to the cache directory
995 * @return void
996 */
997 function cache_set_path($path = '')
998 {
999 $this->cachedir = $path;
1000 }
1001
1002 // --------------------------------------------------------------------
1003
1004 /**
1005 * Enable Query Caching
1006 *
1007 * @access public
1008 * @return void
1009 */
1010 function cache_on()
1011 {
1012 $this->cache_on = TRUE;
1013 return TRUE;
1014 }
1015
1016 // --------------------------------------------------------------------
1017
1018 /**
1019 * Disable Query Caching
1020 *
1021 * @access public
1022 * @return void
1023 */
1024 function cache_off()
1025 {
1026 $this->cache_on = FALSE;
1027 return FALSE;
1028 }
1029
1030
1031 // --------------------------------------------------------------------
1032
1033 /**
1034 * Delete the cache files associated with a particular URI
1035 *
1036 * @access public
1037 * @return void
1038 */
1039 function cache_delete($segment_one = '', $segment_two = '')
1040 {
Derek Allard73274992008-05-05 16:39:18 +00001041 if (! $this->_cache_init())
Derek Allardd2df9bc2007-04-15 17:41:17 +00001042 {
1043 return FALSE;
1044 }
1045 return $this->CACHE->delete($segment_one, $segment_two);
1046 }
1047
1048 // --------------------------------------------------------------------
1049
1050 /**
1051 * Delete All cache files
1052 *
1053 * @access public
1054 * @return void
1055 */
1056 function cache_delete_all()
1057 {
Derek Allard73274992008-05-05 16:39:18 +00001058 if (! $this->_cache_init())
Derek Allardd2df9bc2007-04-15 17:41:17 +00001059 {
1060 return FALSE;
1061 }
1062
1063 return $this->CACHE->delete_all();
1064 }
1065
1066 // --------------------------------------------------------------------
1067
1068 /**
1069 * Initialize the Cache Class
1070 *
1071 * @access private
1072 * @return void
1073 */
1074 function _cache_init()
1075 {
1076 if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
1077 {
1078 return TRUE;
1079 }
1080
Derek Allard73274992008-05-05 16:39:18 +00001081 if (! @include(BASEPATH.'database/DB_cache'.EXT))
Derek Allardd2df9bc2007-04-15 17:41:17 +00001082 {
1083 return $this->cache_off();
1084 }
1085
Derek Jonesd36ade02008-05-12 15:17:41 +00001086 $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 +00001087 return TRUE;
1088 }
1089
Derek Allardd2df9bc2007-04-15 17:41:17 +00001090 // --------------------------------------------------------------------
1091
1092 /**
1093 * Close DB Connection
1094 *
1095 * @access public
1096 * @return void
1097 */
1098 function close()
1099 {
Derek Jones05097752008-05-07 19:58:23 +00001100 if (is_resource($this->conn_id) OR is_object($this->conn_id))
Derek Allardd2df9bc2007-04-15 17:41:17 +00001101 {
1102 $this->_close($this->conn_id);
1103 }
1104 $this->conn_id = FALSE;
1105 }
1106
1107 // --------------------------------------------------------------------
1108
1109 /**
1110 * Display an error message
1111 *
1112 * @access public
1113 * @param string the error message
1114 * @param string any "swap" values
1115 * @param boolean whether to localize the message
1116 * @return string sends the application/error_db.php template
1117 */
1118 function display_error($error = '', $swap = '', $native = FALSE)
1119 {
Derek Jones7f88aa52008-05-12 00:03:51 +00001120 global $LANG;
Derek Allardd2df9bc2007-04-15 17:41:17 +00001121 $LANG->load('db');
1122
Derek Jones7f88aa52008-05-12 00:03:51 +00001123 $heading = $LANG->line('db_error_heading');
1124
Derek Allardd2df9bc2007-04-15 17:41:17 +00001125 if ($native == TRUE)
1126 {
1127 $message = $error;
1128 }
1129 else
1130 {
Derek Allard73274992008-05-05 16:39:18 +00001131 $message = (! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
Derek Allardd2df9bc2007-04-15 17:41:17 +00001132 }
Derek Allardd2df9bc2007-04-15 17:41:17 +00001133
Derek Jones7f88aa52008-05-12 00:03:51 +00001134 $error =& load_class('Exceptions');
1135 echo $error->show_error($heading, $message, 'error_db');
Derek Allardd2df9bc2007-04-15 17:41:17 +00001136 exit;
1137 }
1138
1139}
1140
Derek Jones7f88aa52008-05-12 00:03:51 +00001141
1142/* End of file DB_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +00001143/* Location: ./system/database/DB_driver.php */