blob: 6b3a74b94ea1e3ef7f13f3ef8b9d9d4e7d5589e0 [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 *
73 * Database settings can be passed as discreet
74 * parameters or as a data source name in the first
75 * parameter. DSNs must have this prototype:
76 * $dsn = 'driver://username:password@hostname/database';
77 *
78 * @param mixed. Can be an array or a DSN string
79 */
80 function CI_DB_driver($params)
81 {
Derek Allardd2df9bc2007-04-15 17:41:17 +000082 if (is_array($params))
83 {
Derek Allard39b622d2008-01-16 21:10:09 +000084 foreach ($params as $key => $val)
Derek Allardd2df9bc2007-04-15 17:41:17 +000085 {
Derek Allard39b622d2008-01-16 21:10:09 +000086 $this->$key = $val;
Derek Allardd2df9bc2007-04-15 17:41:17 +000087 }
88 }
89 elseif (strpos($params, '://'))
90 {
91 if (FALSE === ($dsn = @parse_url($params)))
92 {
93 log_message('error', 'Invalid DB Connection String');
94
95 if ($this->db_debug)
96 {
97 return $this->display_error('db_invalid_connection_str');
98 }
99 return FALSE;
100 }
101
102 $this->hostname = ( ! isset($dsn['host'])) ? '' : rawurldecode($dsn['host']);
103 $this->username = ( ! isset($dsn['user'])) ? '' : rawurldecode($dsn['user']);
104 $this->password = ( ! isset($dsn['pass'])) ? '' : rawurldecode($dsn['pass']);
105 $this->database = ( ! isset($dsn['path'])) ? '' : rawurldecode(substr($dsn['path'], 1));
106 }
Derek Allard39b622d2008-01-16 21:10:09 +0000107
108 log_message('debug', 'Database Driver Class Initialized');
109 }
110
111 // --------------------------------------------------------------------
112
113 /**
114 * Initialize Database Settings
115 *
116 * @access private Called by the constructor
117 * @param mixed
118 * @return void
119 */
120 function initialize($create_db = FALSE)
121 {
Derek Allardd2df9bc2007-04-15 17:41:17 +0000122 // If an existing DB connection resource is supplied
123 // there is no need to connect and select the database
124 if (is_resource($this->conn_id))
125 {
126 return TRUE;
127 }
128
129 // Connect to the database
130 $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
131
132 // No connection? Throw an error
133 if ( ! $this->conn_id)
134 {
135 log_message('error', 'Unable to connect to the database');
136
137 if ($this->db_debug)
138 {
139 $this->display_error('db_unable_to_connect');
140 }
141 return FALSE;
142 }
143
144 // Select the database
145 if ($this->database != '')
146 {
147 if ( ! $this->db_select())
148 {
Derek Allard39b622d2008-01-16 21:10:09 +0000149 // Should we attempt to create the database?
150 if ($create_db == TRUE)
151 {
152 // Load the DB utility class
153 $CI =& get_instance();
154 $CI->load->dbutil();
155
156 // Create the DB
157 if ( ! $CI->dbutil->create_database($this->database))
158 {
159 log_message('error', 'Unable to create database: '.$this->database);
160
161 if ($this->db_debug)
162 {
163 $this->display_error('db_unable_to_create', $this->database);
164 }
165 return FALSE;
166 }
167 else
168 {
169 // In the event the DB was created we need to select it
170 if ($this->db_select())
171 {
172 if (! $this->db_set_charset($this->char_set, $this->dbcollat))
173 {
174 log_message('error', 'Unable to set database connection charset: '.$this->char_set);
175
176 if ($this->db_debug)
177 {
178 $this->display_error('db_unable_to_set_charset', $this->char_set);
179 }
180
181 return FALSE;
182 }
183
184 return TRUE;
185 }
186 }
187 }
188
Derek Allardd2df9bc2007-04-15 17:41:17 +0000189 log_message('error', 'Unable to select database: '.$this->database);
190
191 if ($this->db_debug)
192 {
193 $this->display_error('db_unable_to_select', $this->database);
194 }
195 return FALSE;
196 }
Derek Allard39b622d2008-01-16 21:10:09 +0000197
198 if (! $this->db_set_charset($this->char_set, $this->dbcollat))
199 {
200 log_message('error', 'Unable to set database connection charset: '.$this->char_set);
201
202 if ($this->db_debug)
203 {
204 $this->display_error('db_unable_to_set_charset', $this->char_set);
205 }
206
207 return FALSE;
208 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000209 }
210
211 return TRUE;
212 }
213
214 // --------------------------------------------------------------------
215
216 /**
217 * The name of the platform in use (mysql, mssql, etc...)
218 *
219 * @access public
220 * @return string
221 */
222 function platform()
223 {
224 return $this->dbdriver;
225 }
226
227 // --------------------------------------------------------------------
228
229 /**
230 * Database Version Number. Returns a string containing the
231 * version of the database being used
232 *
233 * @access public
234 * @return string
235 */
236 function version()
237 {
238 if (FALSE === ($sql = $this->_version()))
239 {
240 if ($this->db_debug)
241 {
242 return $this->display_error('db_unsupported_function');
243 }
244 return FALSE;
245 }
246
247 if ($this->dbdriver == 'oci8')
248 {
249 return $sql;
250 }
251
252 $query = $this->query($sql);
Derek Allard39b622d2008-01-16 21:10:09 +0000253 return $query->row('ver');
Derek Allardd2df9bc2007-04-15 17:41:17 +0000254 }
255
256 // --------------------------------------------------------------------
257
258 /**
259 * Execute the query
260 *
261 * Accepts an SQL string as input and returns a result object upon
262 * successful execution of a "read" type query. Returns boolean TRUE
263 * upon successful execution of a "write" type query. Returns boolean
264 * FALSE upon failure, and if the $db_debug variable is set to TRUE
265 * will raise an error.
266 *
267 * @access public
268 * @param string An SQL query string
269 * @param array An array of binding data
270 * @return mixed
271 */
272 function query($sql, $binds = FALSE, $return_object = TRUE)
273 {
274 if ($sql == '')
275 {
276 if ($this->db_debug)
277 {
278 log_message('error', 'Invalid query: '.$sql);
279 return $this->display_error('db_invalid_query');
280 }
281 return FALSE;
282 }
Derek Allard39b622d2008-01-16 21:10:09 +0000283
284 // Verify table prefix and replace if necessary
285 if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) )
286 {
287 $sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql);
288 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000289
290 // Is query caching enabled? If the query is a "read type"
291 // we will load the caching class and return the previously
292 // cached query if it exists
293 if ($this->cache_on == TRUE AND stristr($sql, 'SELECT'))
294 {
295 if ($this->_cache_init())
296 {
297 $this->load_rdriver();
298 if (FALSE !== ($cache = $this->CACHE->read($sql)))
299 {
300 return $cache;
301 }
302 }
303 }
304
305 // Compile binds if needed
306 if ($binds !== FALSE)
307 {
308 $sql = $this->compile_binds($sql, $binds);
309 }
310
311 // Save the query for debugging
Rick Ellis40990462007-07-17 21:40:44 +0000312 if ($this->save_queries == TRUE)
313 {
314 $this->queries[] = $sql;
315 }
Derek Allard39b622d2008-01-16 21:10:09 +0000316
Derek Allardd2df9bc2007-04-15 17:41:17 +0000317 // Start the Query Timer
318 $time_start = list($sm, $ss) = explode(' ', microtime());
319
320 // Run the Query
321 if (FALSE === ($this->result_id = $this->simple_query($sql)))
322 {
323 // This will trigger a rollback if transactions are being used
Rick Ellis28239ad2007-06-11 04:26:39 +0000324 $this->_trans_status = FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000325
326 if ($this->db_debug)
327 {
328 log_message('error', 'Query error: '.$this->_error_message());
329 return $this->display_error(
330 array(
331 'Error Number: '.$this->_error_number(),
332 $this->_error_message(),
333 $sql
334 )
335 );
336 }
337
Derek Allard39b622d2008-01-16 21:10:09 +0000338 return FALSE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000339 }
340
341 // Stop and aggregate the query time results
342 $time_end = list($em, $es) = explode(' ', microtime());
343 $this->benchmark += ($em + $es) - ($sm + $ss);
344
Derek Jones56e9fa52008-01-23 17:26:37 +0000345 if ($this->save_queries == TRUE)
346 {
347 $this->query_times[] = ($em + $es) - ($sm + $ss);
348 }
349
Derek Allardd2df9bc2007-04-15 17:41:17 +0000350 // Increment the query counter
351 $this->query_count++;
352
353 // Was the query a "write" type?
354 // If so we'll simply return true
355 if ($this->is_write_type($sql) === TRUE)
356 {
357 // If caching is enabled we'll auto-cleanup any
358 // existing files related to this particular URI
359 if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init())
360 {
361 $this->CACHE->delete();
362 }
363
364 return TRUE;
365 }
366
367 // Return TRUE if we don't need to create a result object
368 // Currently only the Oracle driver uses this when stored
369 // procedures are used
370 if ($return_object !== TRUE)
371 {
372 return TRUE;
373 }
374
375 // Load and instantiate the result driver
376
377 $driver = $this->load_rdriver();
378 $RES = new $driver();
379 $RES->conn_id = $this->conn_id;
380 $RES->result_id = $this->result_id;
Derek Allard39b622d2008-01-16 21:10:09 +0000381 $RES->num_rows = $RES->num_rows();
Derek Allard060052d2007-07-14 14:26:13 +0000382
Derek Allardd2df9bc2007-04-15 17:41:17 +0000383 if ($this->dbdriver == 'oci8')
384 {
385 $RES->stmt_id = $this->stmt_id;
386 $RES->curs_id = NULL;
387 $RES->limit_used = $this->limit_used;
388 }
Derek Allard39b622d2008-01-16 21:10:09 +0000389
Derek Allardd2df9bc2007-04-15 17:41:17 +0000390 // Is query caching enabled? If so, we'll serialize the
391 // result object and save it to a cache file.
392 if ($this->cache_on == TRUE AND $this->_cache_init())
393 {
394 // We'll create a new instance of the result object
395 // only without the platform specific driver since
396 // we can't use it with cached data (the query result
397 // resource ID won't be any good once we've cached the
398 // result object, so we'll have to compile the data
399 // and save it)
400 $CR = new CI_DB_result();
401 $CR->num_rows = $RES->num_rows();
402 $CR->result_object = $RES->result_object();
403 $CR->result_array = $RES->result_array();
404
405 // Reset these since cached objects can not utilize resource IDs.
406 $CR->conn_id = NULL;
407 $CR->result_id = NULL;
408
409 $this->CACHE->write($sql, $CR);
410 }
411
412 return $RES;
413 }
414
415 // --------------------------------------------------------------------
416
417 /**
418 * Load the result drivers
419 *
420 * @access public
421 * @return string the name of the result class
422 */
423 function load_rdriver()
424 {
425 $driver = 'CI_DB_'.$this->dbdriver.'_result';
426
427 if ( ! class_exists($driver))
428 {
429 include_once(BASEPATH.'database/DB_result'.EXT);
430 include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result'.EXT);
431 }
432
433 return $driver;
434 }
435
436 // --------------------------------------------------------------------
437
438 /**
439 * Simple Query
440 * This is a simplified version of the query() function. Internally
441 * we only use it when running transaction commands since they do
442 * not require all the features of the main query() function.
443 *
444 * @access public
445 * @param string the sql query
446 * @return mixed
447 */
448 function simple_query($sql)
449 {
450 if ( ! $this->conn_id)
451 {
452 $this->initialize();
453 }
454
455 return $this->_execute($sql);
456 }
457
458 // --------------------------------------------------------------------
459
460 /**
461 * Disable Transactions
462 * This permits transactions to be disabled at run-time.
463 *
464 * @access public
465 * @return void
466 */
467 function trans_off()
468 {
469 $this->trans_enabled = FALSE;
470 }
471
472 // --------------------------------------------------------------------
473
474 /**
475 * Start Transaction
476 *
477 * @access public
478 * @return void
479 */
480 function trans_start($test_mode = FALSE)
481 {
482 if ( ! $this->trans_enabled)
483 {
484 return FALSE;
485 }
486
487 // When transactions are nested we only begin/commit/rollback the outermost ones
488 if ($this->_trans_depth > 0)
489 {
490 $this->_trans_depth += 1;
491 return;
492 }
493
494 $this->trans_begin($test_mode);
495 }
496
497 // --------------------------------------------------------------------
498
499 /**
500 * Complete Transaction
501 *
502 * @access public
503 * @return bool
504 */
505 function trans_complete()
506 {
507 if ( ! $this->trans_enabled)
508 {
509 return FALSE;
510 }
511
512 // When transactions are nested we only begin/commit/rollback the outermost ones
513 if ($this->_trans_depth > 1)
514 {
515 $this->_trans_depth -= 1;
516 return TRUE;
517 }
518
519 // The query() function will set this flag to TRUE in the event that a query failed
Rick Ellis28239ad2007-06-11 04:26:39 +0000520 if ($this->_trans_status === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000521 {
522 $this->trans_rollback();
523
524 if ($this->db_debug)
525 {
526 return $this->display_error('db_transaction_failure');
527 }
528 return FALSE;
529 }
530
531 $this->trans_commit();
532 return TRUE;
533 }
534
535 // --------------------------------------------------------------------
536
537 /**
538 * Lets you retrieve the transaction flag to determine if it has failed
539 *
540 * @access public
541 * @return bool
542 */
543 function trans_status()
544 {
Rick Ellis28239ad2007-06-11 04:26:39 +0000545 return $this->_trans_status;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000546 }
547
548 // --------------------------------------------------------------------
549
550 /**
551 * Compile Bindings
552 *
553 * @access public
554 * @param string the sql statement
555 * @param array an array of bind data
556 * @return string
557 */
558 function compile_binds($sql, $binds)
Derek Allardc0743382008-02-11 05:54:44 +0000559 {
560 if (strpos($sql, $this->bind_marker) === FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000561 {
562 return $sql;
563 }
564
565 if ( ! is_array($binds))
566 {
567 $binds = array($binds);
568 }
569
Derek Allardc0743382008-02-11 05:54:44 +0000570 // Get the sql segments around the bind markers
571 $segments = explode($this->bind_marker, $sql);
572
573 // The count of bind should be 1 less then the count of segments
574 // If there are more bind arguments trim it down
575 if (count($binds) >= count($segments)) {
576 $binds = array_slice($binds, 0, count($segments)-1);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000577 }
578
Derek Allardc0743382008-02-11 05:54:44 +0000579 // Construct the binded query
580 $result = $segments[0];
581 $i = 0;
582 foreach ($binds as $bind)
583 {
584 $result .= $this->escape($bind);
585 $result .= $segments[++$i];
586 }
587
588 return $result;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000589 }
590
591 // --------------------------------------------------------------------
592
593 /**
594 * Determines if a query is a "write" type.
595 *
596 * @access public
597 * @param string An SQL query string
598 * @return boolean
599 */
600 function is_write_type($sql)
601 {
602 if ( ! preg_match('/^\s*"?(INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql))
603 {
604 return FALSE;
605 }
606 return TRUE;
607 }
608
609 // --------------------------------------------------------------------
610
611 /**
612 * Calculate the aggregate query elapsed time
613 *
614 * @access public
615 * @param integer The number of decimal places
616 * @return integer
617 */
618 function elapsed_time($decimals = 6)
619 {
620 return number_format($this->benchmark, $decimals);
621 }
622
623 // --------------------------------------------------------------------
624
625 /**
626 * Returns the total number of queries
627 *
628 * @access public
629 * @return integer
630 */
631 function total_queries()
632 {
633 return $this->query_count;
634 }
635
636 // --------------------------------------------------------------------
637
638 /**
639 * Returns the last query that was executed
640 *
641 * @access public
642 * @return void
643 */
644 function last_query()
645 {
646 return end($this->queries);
647 }
648
649 // --------------------------------------------------------------------
650
651 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000652 * Protect Identifiers
653 *
654 * This function adds backticks if appropriate based on db type
655 *
656 * @access private
657 * @param mixed the item to escape
658 * @param boolean only affect the first word
659 * @return mixed the item with backticks
660 */
661 function protect_identifiers($item, $first_word_only = FALSE)
662 {
Derek Allard1a704ce2008-01-27 15:03:06 +0000663 return $this->_protect_identifiers($item, $first_word_only);
Derek Allard39b622d2008-01-16 21:10:09 +0000664 }
665
666 // --------------------------------------------------------------------
667
668 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000669 * "Smart" Escape String
670 *
671 * Escapes data based on type
672 * Sets boolean and null types
673 *
674 * @access public
675 * @param string
676 * @return integer
677 */
678 function escape($str)
679 {
680 switch (gettype($str))
681 {
682 case 'string' : $str = "'".$this->escape_str($str)."'";
683 break;
684 case 'boolean' : $str = ($str === FALSE) ? 0 : 1;
685 break;
686 default : $str = ($str === NULL) ? 'NULL' : $str;
687 break;
688 }
689
690 return $str;
691 }
692
693 // --------------------------------------------------------------------
694
695 /**
696 * Primary
697 *
698 * Retrieves the primary key. It assumes that the row in the first
699 * position is the primary key
700 *
701 * @access public
702 * @param string the table name
703 * @return string
704 */
705 function primary($table = '')
706 {
707 $fields = $this->list_fields($table);
708
709 if ( ! is_array($fields))
710 {
711 return FALSE;
712 }
713
714 return current($fields);
715 }
716
717 // --------------------------------------------------------------------
718
719 /**
720 * Returns an array of table names
721 *
722 * @access public
723 * @return array
724 */
Derek Allard39b622d2008-01-16 21:10:09 +0000725 function list_tables($constrain_by_prefix = FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000726 {
727 // Is there a cached result?
728 if (isset($this->data_cache['table_names']))
729 {
730 return $this->data_cache['table_names'];
731 }
732
Derek Allard39b622d2008-01-16 21:10:09 +0000733 if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000734 {
735 if ($this->db_debug)
736 {
737 return $this->display_error('db_unsupported_function');
738 }
739 return FALSE;
740 }
741
742 $retval = array();
743 $query = $this->query($sql);
744
745 if ($query->num_rows() > 0)
746 {
747 foreach($query->result_array() as $row)
748 {
749 if (isset($row['TABLE_NAME']))
750 {
751 $retval[] = $row['TABLE_NAME'];
752 }
753 else
754 {
755 $retval[] = array_shift($row);
756 }
757 }
758 }
759
760 $this->data_cache['table_names'] = $retval;
761 return $this->data_cache['table_names'];
762 }
763
764 // --------------------------------------------------------------------
765
766 /**
767 * Determine if a particular table exists
768 * @access public
769 * @return boolean
770 */
771 function table_exists($table_name)
772 {
Derek Allard39b622d2008-01-16 21:10:09 +0000773 return ( ! in_array($this->prep_tablename($table_name), $this->list_tables())) ? FALSE : TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000774 }
775
776 // --------------------------------------------------------------------
777
778 /**
779 * Fetch MySQL Field Names
780 *
781 * @access public
782 * @param string the table name
783 * @return array
784 */
785 function list_fields($table = '')
786 {
787 // Is there a cached result?
788 if (isset($this->data_cache['field_names'][$table]))
789 {
790 return $this->data_cache['field_names'][$table];
791 }
792
793 if ($table == '')
794 {
795 if ($this->db_debug)
796 {
797 return $this->display_error('db_field_param_missing');
798 }
799 return FALSE;
800 }
801
Derek Allard39b622d2008-01-16 21:10:09 +0000802 if (FALSE === ($sql = $this->_list_columns($this->prep_tablename($table))))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000803 {
804 if ($this->db_debug)
805 {
806 return $this->display_error('db_unsupported_function');
807 }
808 return FALSE;
809 }
810
811 $query = $this->query($sql);
812
813 $retval = array();
814 foreach($query->result_array() as $row)
815 {
816 if (isset($row['COLUMN_NAME']))
817 {
818 $retval[] = $row['COLUMN_NAME'];
819 }
820 else
821 {
822 $retval[] = current($row);
823 }
824 }
825
826 $this->data_cache['field_names'][$table] = $retval;
827 return $this->data_cache['field_names'][$table];
828 }
829
830 // --------------------------------------------------------------------
831
832 /**
833 * Determine if a particular field exists
834 * @access public
835 * @param string
836 * @param string
837 * @return boolean
838 */
839 function field_exists($field_name, $table_name)
840 {
841 return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
842 }
843
844 // --------------------------------------------------------------------
845
846 /**
847 * DEPRECATED - use list_fields()
848 */
849 function field_names($table = '')
850 {
851 return $this->list_fields($table);
852 }
853
854 // --------------------------------------------------------------------
855
856 /**
857 * Returns an object with field data
858 *
859 * @access public
860 * @param string the table name
861 * @return object
862 */
863 function field_data($table = '')
864 {
865 if ($table == '')
866 {
867 if ($this->db_debug)
868 {
869 return $this->display_error('db_field_param_missing');
870 }
871 return FALSE;
872 }
873
Derek Allard39b622d2008-01-16 21:10:09 +0000874 $query = $this->query($this->_field_data($this->prep_tablename($table)));
Derek Allardd2df9bc2007-04-15 17:41:17 +0000875 return $query->field_data();
876 }
877
878 // --------------------------------------------------------------------
879
880 /**
881 * Generate an insert string
882 *
883 * @access public
884 * @param string the table upon which the query will be performed
885 * @param array an associative array data of key/values
886 * @return string
887 */
888 function insert_string($table, $data)
889 {
890 $fields = array();
891 $values = array();
892
893 foreach($data as $key => $val)
894 {
895 $fields[] = $key;
896 $values[] = $this->escape($val);
897 }
Derek Allard39b622d2008-01-16 21:10:09 +0000898
899
900 return $this->_insert($this->prep_tablename($table), $fields, $values);
901 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000902
903 // --------------------------------------------------------------------
904
905 /**
906 * Generate an update string
907 *
908 * @access public
909 * @param string the table upon which the query will be performed
910 * @param array an associative array data of key/values
911 * @param mixed the "where" statement
912 * @return string
913 */
914 function update_string($table, $data, $where)
915 {
916 if ($where == '')
917 return false;
918
919 $fields = array();
920 foreach($data as $key => $val)
921 {
922 $fields[$key] = $this->escape($val);
923 }
924
925 if ( ! is_array($where))
926 {
927 $dest = array($where);
928 }
929 else
930 {
931 $dest = array();
932 foreach ($where as $key => $val)
933 {
934 $prefix = (count($dest) == 0) ? '' : ' AND ';
935
Derek Allard39b622d2008-01-16 21:10:09 +0000936 if ($val !== '')
Derek Allardd2df9bc2007-04-15 17:41:17 +0000937 {
938 if ( ! $this->_has_operator($key))
939 {
940 $key .= ' =';
941 }
942
943 $val = ' '.$this->escape($val);
944 }
945
946 $dest[] = $prefix.$key.$val;
947 }
948 }
949
Derek Allard39b622d2008-01-16 21:10:09 +0000950 return $this->_update($this->prep_tablename($table), $fields, $dest);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000951 }
952
953 // --------------------------------------------------------------------
954
955 /**
Derek Allard39b622d2008-01-16 21:10:09 +0000956 * Prep the table name - simply adds the table prefix if needed
957 *
958 * @access public
959 * @param string the table name
960 * @return string
961 */
962 function prep_tablename($table = '')
963 {
964 // Do we need to add the table prefix?
965 if ($this->dbprefix != '')
966 {
967 if (substr($table, 0, strlen($this->dbprefix)) != $this->dbprefix)
968 {
969 $table = $this->dbprefix.$table;
970 }
971 }
972
973 return $table;
974 }
975
976 // --------------------------------------------------------------------
977
978 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000979 * Enables a native PHP function to be run, using a platform agnostic wrapper.
980 *
981 * @access public
982 * @param string the function name
983 * @param mixed any parameters needed by the function
984 * @return mixed
985 */
986 function call_function($function)
987 {
988 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
989
990 if (FALSE === strpos($driver, $function))
991 {
992 $function = $driver.$function;
993 }
994
995 if ( ! function_exists($function))
996 {
997 if ($this->db_debug)
998 {
999 return $this->display_error('db_unsupported_function');
1000 }
1001 return FALSE;
1002 }
1003 else
1004 {
1005 $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
1006
1007 return call_user_func_array($function, $args);
1008 }
1009 }
1010
1011 // --------------------------------------------------------------------
1012
1013 /**
1014 * Set Cache Directory Path
1015 *
1016 * @access public
1017 * @param string the path to the cache directory
1018 * @return void
1019 */
1020 function cache_set_path($path = '')
1021 {
1022 $this->cachedir = $path;
1023 }
1024
1025 // --------------------------------------------------------------------
1026
1027 /**
1028 * Enable Query Caching
1029 *
1030 * @access public
1031 * @return void
1032 */
1033 function cache_on()
1034 {
1035 $this->cache_on = TRUE;
1036 return TRUE;
1037 }
1038
1039 // --------------------------------------------------------------------
1040
1041 /**
1042 * Disable Query Caching
1043 *
1044 * @access public
1045 * @return void
1046 */
1047 function cache_off()
1048 {
1049 $this->cache_on = FALSE;
1050 return FALSE;
1051 }
1052
1053
1054 // --------------------------------------------------------------------
1055
1056 /**
1057 * Delete the cache files associated with a particular URI
1058 *
1059 * @access public
1060 * @return void
1061 */
1062 function cache_delete($segment_one = '', $segment_two = '')
1063 {
1064 if ( ! $this->_cache_init())
1065 {
1066 return FALSE;
1067 }
1068 return $this->CACHE->delete($segment_one, $segment_two);
1069 }
1070
1071 // --------------------------------------------------------------------
1072
1073 /**
1074 * Delete All cache files
1075 *
1076 * @access public
1077 * @return void
1078 */
1079 function cache_delete_all()
1080 {
1081 if ( ! $this->_cache_init())
1082 {
1083 return FALSE;
1084 }
1085
1086 return $this->CACHE->delete_all();
1087 }
1088
1089 // --------------------------------------------------------------------
1090
1091 /**
1092 * Initialize the Cache Class
1093 *
1094 * @access private
1095 * @return void
1096 */
1097 function _cache_init()
1098 {
1099 if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
1100 {
1101 return TRUE;
1102 }
1103
1104 if ( ! @include(BASEPATH.'database/DB_cache'.EXT))
1105 {
1106 return $this->cache_off();
1107 }
1108
1109 $this->CACHE = new CI_DB_Cache;
1110 return TRUE;
1111 }
1112
Derek Allardd2df9bc2007-04-15 17:41:17 +00001113 // --------------------------------------------------------------------
1114
1115 /**
1116 * Close DB Connection
1117 *
1118 * @access public
1119 * @return void
1120 */
1121 function close()
1122 {
1123 if (is_resource($this->conn_id))
1124 {
1125 $this->_close($this->conn_id);
1126 }
1127 $this->conn_id = FALSE;
1128 }
1129
1130 // --------------------------------------------------------------------
1131
1132 /**
1133 * Display an error message
1134 *
1135 * @access public
1136 * @param string the error message
1137 * @param string any "swap" values
1138 * @param boolean whether to localize the message
1139 * @return string sends the application/error_db.php template
1140 */
1141 function display_error($error = '', $swap = '', $native = FALSE)
1142 {
Derek Allard39b622d2008-01-16 21:10:09 +00001143// $LANG = new CI_Lang();
Derek Allardd2df9bc2007-04-15 17:41:17 +00001144 $LANG = new CI_Language();
1145 $LANG->load('db');
1146
Derek Allard1a704ce2008-01-27 15:03:06 +00001147 $heading = 'Database Error';
Derek Allardd2df9bc2007-04-15 17:41:17 +00001148
1149 if ($native == TRUE)
1150 {
1151 $message = $error;
1152 }
1153 else
1154 {
1155 $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
1156 }
1157
1158 if ( ! class_exists('CI_Exceptions'))
1159 {
Derek Allard39b622d2008-01-16 21:10:09 +00001160// include(BASEPATH.'core/Exceptions'.EXT);
Derek Allardd2df9bc2007-04-15 17:41:17 +00001161 include(BASEPATH.'libraries/Exceptions'.EXT);
1162 }
1163
1164 $error = new CI_Exceptions();
1165 echo $error->show_error('An Error Was Encountered', $message, 'error_db');
1166 exit;
1167 }
1168
1169}
1170
admin7b613c72006-09-24 18:05:17 +00001171?>