blob: 811f090935397dc1045bbe6227365959434ab561 [file] [log] [blame]
admin7b613c72006-09-24 18:05:17 +00001<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * Code Igniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author Rick Ellis
9 * @copyright Copyright (c) 2006, pMachine, Inc.
10 * @license http://www.codeignitor.com/user_guide/license.html
11 * @link http://www.codeigniter.com
12 * @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
28 * @author Rick Ellis
29 * @link http://www.codeigniter.com/user_guide/database/
30 */
31class CI_DB_driver {
32
33 var $username;
34 var $password;
35 var $hostname;
36 var $database;
37 var $dbdriver = 'mysql';
38 var $dbprefix = '';
39 var $port = '';
40 var $pconnect = FALSE;
41 var $conn_id = FALSE;
42 var $result_id = FALSE;
43 var $db_debug = FALSE;
44 var $benchmark = 0;
45 var $query_count = 0;
46 var $bind_marker = '?';
47 var $queries = array();
admine8f6eb62006-10-02 06:46:16 +000048 var $data_cache = array();
admin7b613c72006-09-24 18:05:17 +000049 var $trans_enabled = TRUE;
50 var $_trans_depth = 0;
51 var $_trans_failure = FALSE; // Used with transactions to determine if a rollback should occur
admin6871d952006-10-04 00:36:18 +000052 var $cache_on = FALSE;
53 var $cachedir = '';
admin7b613c72006-09-24 18:05:17 +000054
admin6871d952006-10-04 00:36:18 +000055
56 // These are use with Oracle
57 var $stmt_id;
58 var $curs_id;
59 var $limit_used;
admin7b613c72006-09-24 18:05:17 +000060
admine8f6eb62006-10-02 06:46:16 +000061
admin7b613c72006-09-24 18:05:17 +000062
63 /**
64 * Constructor. Accepts one parameter containing the database
65 * connection settings.
66 *
67 * Database settings can be passed as discreet
68 * parameters or as a data source name in the first
69 * parameter. DSNs must have this prototype:
70 * $dsn = 'driver://username:password@hostname/database';
71 *
72 * @param mixed. Can be an array or a DSN string
73 */
74 function CI_DB_driver($params)
75 {
76 $this->initialize($params);
77 log_message('debug', 'Database Driver Class Initialized');
78 }
79
80 // --------------------------------------------------------------------
81
82 /**
83 * Initialize Database Settings
84 *
85 * @access private Called by the constructor
86 * @param mixed
87 * @return void
88 */
89 function initialize($params = '')
admin6871d952006-10-04 00:36:18 +000090 {
admin7b613c72006-09-24 18:05:17 +000091 if (is_array($params))
92 {
admin6871d952006-10-04 00:36:18 +000093 $defaults = array(
94 'hostname' => '',
95 'username' => '',
96 'password' => '',
97 'database' => '',
98 'dbdriver' => 'mysql',
99 'dbprefix' => '',
100 'port' => '',
101 'pconnect' => FALSE,
102 'db_debug' => FALSE,
103 'cachedir' => '',
104 'cache_on' => FALSE
105 );
106
107 foreach ($defaults as $key => $val)
admin7b613c72006-09-24 18:05:17 +0000108 {
109 $this->$key = ( ! isset($params[$key])) ? $val : $params[$key];
110 }
111 }
112 elseif (strpos($params, '://'))
113 {
114 if (FALSE === ($dsn = @parse_url($params)))
115 {
116 log_message('error', 'Invalid DB Connection String');
117
118 if ($this->db_debug)
119 {
120 return $this->display_error('db_invalid_connection_str');
121 }
122 return FALSE;
123 }
124
125 $this->hostname = ( ! isset($dsn['host'])) ? '' : rawurldecode($dsn['host']);
126 $this->username = ( ! isset($dsn['user'])) ? '' : rawurldecode($dsn['user']);
127 $this->password = ( ! isset($dsn['pass'])) ? '' : rawurldecode($dsn['pass']);
128 $this->database = ( ! isset($dsn['path'])) ? '' : rawurldecode(substr($dsn['path'], 1));
129 }
admin6871d952006-10-04 00:36:18 +0000130
131 // Connect to the database
132 $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
133
134 if ( ! $this->conn_id)
135 {
admin7b613c72006-09-24 18:05:17 +0000136 log_message('error', 'Unable to connect to the database');
137
admin6871d952006-10-04 00:36:18 +0000138 if ($this->db_debug)
139 {
admin7b613c72006-09-24 18:05:17 +0000140 $this->display_error('db_unable_to_connect');
admin6871d952006-10-04 00:36:18 +0000141 }
142 }
admin7b613c72006-09-24 18:05:17 +0000143 else
144 {
145 if ( ! $this->db_select())
146 {
147 log_message('error', 'Unable to select database: '.$this->database);
148
149 if ($this->db_debug)
150 {
151 $this->display_error('db_unable_to_select', $this->database);
152 }
153 }
admin6871d952006-10-04 00:36:18 +0000154 }
155
156 // Is there a cache direcotry specified in the config file?
157 if ($this->cachedir != '')
158 {
159 $this->cache_set_dir($this->cachedir);
160 }
admin7b613c72006-09-24 18:05:17 +0000161 }
162
163
164 // --------------------------------------------------------------------
165
166 /**
admin9cd4e8e2006-09-25 23:26:25 +0000167 * The name of the platform in use (mysql, mssql, etc...)
168 *
169 * @access public
170 * @return string
171 */
172 function platform()
173 {
174 return $this->dbdriver;
175 }
176
177 // --------------------------------------------------------------------
178
179 /**
180 * Database Version Number. Returns a string containing the
181 * version of the database being used
182 *
183 * @access public
184 * @return string
185 */
186 function version()
187 {
188 if (FALSE === ($sql = $this->_version()))
189 {
admin6871d952006-10-04 00:36:18 +0000190 if ($this->db_debug)
191 {
admin9cd4e8e2006-09-25 23:26:25 +0000192 return $this->display_error('db_unsupported_function');
admin6871d952006-10-04 00:36:18 +0000193 }
194 return FALSE;
admin9cd4e8e2006-09-25 23:26:25 +0000195 }
196
admin6871d952006-10-04 00:36:18 +0000197 if ($this->dbdriver == 'oci8')
198 {
admin9cd4e8e2006-09-25 23:26:25 +0000199 return $sql;
200 }
201
202 $query = $this->query($sql);
203 $row = $query->row();
204 return $row->ver;
205 }
206
207 // --------------------------------------------------------------------
208
209 /**
admin7b613c72006-09-24 18:05:17 +0000210 * Execute the query
211 *
212 * Accepts an SQL string as input and returns a result object upon
213 * successful execution of a "read" type query. Returns boolean TRUE
214 * upon successful execution of a "write" type query. Returns boolean
215 * FALSE upon failure, and if the $db_debug variable is set to TRUE
216 * will raise an error.
217 *
218 * @access public
219 * @param string An SQL query string
220 * @param array An array of binding data
221 * @return mixed
222 */
admin6871d952006-10-04 00:36:18 +0000223 function query($sql, $binds = FALSE, $return_object = TRUE)
224 {
admin7b613c72006-09-24 18:05:17 +0000225 if ($sql == '')
226 {
admin6871d952006-10-04 00:36:18 +0000227 if ($this->db_debug)
228 {
admin7b613c72006-09-24 18:05:17 +0000229 log_message('error', 'Invalid query: '.$sql);
230 return $this->display_error('db_invalid_query');
admin6871d952006-10-04 00:36:18 +0000231 }
232 return FALSE;
admin7b613c72006-09-24 18:05:17 +0000233 }
234
admin6871d952006-10-04 00:36:18 +0000235 // Is query caching enabled? If the query is a "read type" we will
admine8f6eb62006-10-02 06:46:16 +0000236 // grab the previously cached query if it exists and return it.
admin6871d952006-10-04 00:36:18 +0000237 if ($this->cache_on == TRUE AND stristr($sql, 'SELECT'))
238 {
239 if (FALSE !== ($cache = $this->cache_read($sql)))
admine8f6eb62006-10-02 06:46:16 +0000240 {
admin6871d952006-10-04 00:36:18 +0000241 return $cache;
admine8f6eb62006-10-02 06:46:16 +0000242 }
243 }
244
admin7b613c72006-09-24 18:05:17 +0000245 // Compile binds if needed
246 if ($binds !== FALSE)
247 {
248 $sql = $this->compile_binds($sql, $binds);
249 }
250
admin6871d952006-10-04 00:36:18 +0000251 // Save the query for debugging
252 $this->queries[] = $sql;
admin7b613c72006-09-24 18:05:17 +0000253
254 // Start the Query Timer
admin6871d952006-10-04 00:36:18 +0000255 $time_start = list($sm, $ss) = explode(' ', microtime());
256
admin7b613c72006-09-24 18:05:17 +0000257 // Run the Query
admin6871d952006-10-04 00:36:18 +0000258 if (FALSE === ($this->result_id = $this->simple_query($sql)))
259 {
260 // This will trigger a rollback if transactions are being used
261 $this->_trans_failure = TRUE;
262
263 if ($this->db_debug)
264 {
adminbb1d4392006-09-24 20:14:38 +0000265 log_message('error', 'Query error: '.$this->_error_message());
admin7b613c72006-09-24 18:05:17 +0000266 return $this->display_error(
267 array(
adminbb1d4392006-09-24 20:14:38 +0000268 'Error Number: '.$this->_error_number(),
269 $this->_error_message(),
admin7b613c72006-09-24 18:05:17 +0000270 $sql
271 )
272 );
admin6871d952006-10-04 00:36:18 +0000273 }
274
275 return FALSE;
276 }
277
admin7b613c72006-09-24 18:05:17 +0000278 // Stop and aggregate the query time results
279 $time_end = list($em, $es) = explode(' ', microtime());
280 $this->benchmark += ($em + $es) - ($sm + $ss);
281
282 // Increment the query counter
admin6871d952006-10-04 00:36:18 +0000283 $this->query_count++;
284
admin7b613c72006-09-24 18:05:17 +0000285 // Was the query a "write" type?
286 // If so we'll simply return true
287 if ($this->is_write_type($sql) === TRUE)
admine8f6eb62006-10-02 06:46:16 +0000288 {
admin7b613c72006-09-24 18:05:17 +0000289 return TRUE;
290 }
291
292 // Return TRUE if we don't need to create a result object
293 // Currently only the Oracle driver uses this when stored
294 // procedures are used
295 if ($return_object !== TRUE)
296 {
297 return TRUE;
298 }
299
300 // Define the result driver name
301 $result = 'CI_DB_'.$this->dbdriver.'_result';
302
303 // Load the result classes
304 if ( ! class_exists($result))
305 {
306 include_once(BASEPATH.'database/DB_result'.EXT);
307 include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result'.EXT);
308 }
309
310 // Instantiate the result object
admin6871d952006-10-04 00:36:18 +0000311 $RES = new $result();
312 $RES->conn_id = $this->conn_id;
313 $RES->db_debug = $this->db_debug;
314 $RES->result_id = $this->result_id;
315
316 if ($this->dbdriver == 'oci8')
317 {
admin7b613c72006-09-24 18:05:17 +0000318 $RES->stmt_id = $this->stmt_id;
319 $RES->curs_id = NULL;
320 $RES->limit_used = $this->limit_used;
admin6871d952006-10-04 00:36:18 +0000321 }
admin7b613c72006-09-24 18:05:17 +0000322
323 return $RES;
324 }
325
326 // --------------------------------------------------------------------
327
328 /**
329 * Simple Query
330 * This is a simiplified version of the query() function. Internally
331 * we only use it when running transaction commands since they do
332 * not require all the features of the main query() function.
333 *
334 * @access public
335 * @param string the sql query
336 * @return mixed
337 */
338 function simple_query($sql)
339 {
340 if ( ! $this->conn_id)
341 {
342 $this->initialize();
343 }
344
345 return $this->_execute($sql, $this->conn_id);
346 }
347
348 // --------------------------------------------------------------------
349
350 /**
351 * Disable Transactions
352 * This permits transactions to be disabled at run-time.
353 *
354 * @access public
355 * @return void
356 */
357 function trans_off()
358 {
359 $this->trans_enabled = FALSE;
360 }
361
362 // --------------------------------------------------------------------
363
364 /**
365 * Start Transaction
366 *
367 * @access public
368 * @return void
369 */
370 function trans_start($test_mode = FALSE)
371 {
372 if ( ! $this->trans_enabled)
373 {
374 return FALSE;
375 }
376
377 // When transactions are nested we only begin/commit/rollback the outermost ones
378 if ($this->_trans_depth > 0)
379 {
380 $this->_trans_depth += 1;
381 return;
382 }
383
384 $this->trans_begin($test_mode);
385 }
386
387 // --------------------------------------------------------------------
388
389 /**
390 * Complete Transaction
391 *
392 * @access public
393 * @return bool
394 */
395 function trans_complete()
396 {
397 if ( ! $this->trans_enabled)
398 {
399 return FALSE;
400 }
401
402 // When transactions are nested we only begin/commit/rollback the outermost ones
403 if ($this->_trans_depth > 1)
404 {
405 $this->_trans_depth -= 1;
406 return TRUE;
407 }
408
409 // The query() function will set this flag to TRUE in the event that a query failed
410 if ($this->_trans_failure === TRUE)
411 {
412 $this->trans_rollback();
413
414 if ($this->db_debug)
415 {
416 return $this->display_error('db_transaction_failure');
417 }
418 return FALSE;
419 }
420
421 $this->trans_commit();
422 return TRUE;
423 }
424
425 // --------------------------------------------------------------------
426
427 /**
428 * Lets you retrieve the transaction flag to determine if it has failed
429 *
430 * @access public
431 * @return bool
432 */
433 function trans_status()
434 {
435 return $this->_trans_failure;
436 }
437
438 // --------------------------------------------------------------------
439
440 /**
441 * Compile Bindings
442 *
443 * @access public
444 * @param string the sql statement
445 * @param array an array of bind data
446 * @return string
447 */
448 function compile_binds($sql, $binds)
449 {
450 if (FALSE === strpos($sql, $this->bind_marker))
451 {
452 return $sql;
453 }
454
455 if ( ! is_array($binds))
456 {
457 $binds = array($binds);
458 }
459
460 foreach ($binds as $val)
461 {
462 $val = $this->escape($val);
463
464 // Just in case the replacement string contains the bind
465 // character we'll temporarily replace it with a marker
466 $val = str_replace($this->bind_marker, '{%bind_marker%}', $val);
467 $sql = preg_replace("#".preg_quote($this->bind_marker, '#')."#", str_replace('$', '\$', $val), $sql, 1);
468 }
469
470 return str_replace('{%bind_marker%}', $this->bind_marker, $sql);
471 }
472
473 // --------------------------------------------------------------------
474
475 /**
476 * Determines if a query is a "write" type.
477 *
478 * @access public
479 * @param string An SQL query string
480 * @return boolean
481 */
482 function is_write_type($sql)
483 {
484 if ( ! preg_match('/^\s*"?(INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql))
485 {
486 return FALSE;
487 }
488 return TRUE;
489 }
490
491 // --------------------------------------------------------------------
492
493 /**
494 * Calculate the aggregate query elapsed time
495 *
496 * @access public
497 * @param intiger The number of decimal places
498 * @return integer
499 */
500 function elapsed_time($decimals = 6)
501 {
502 return number_format($this->benchmark, $decimals);
503 }
504
505 // --------------------------------------------------------------------
506
507 /**
508 * Returns the total number of queries
509 *
510 * @access public
511 * @return integer
512 */
513 function total_queries()
514 {
515 return $this->query_count;
516 }
517
518 // --------------------------------------------------------------------
519
520 /**
521 * Returns the last query that was executed
522 *
523 * @access public
524 * @return void
525 */
526 function last_query()
527 {
528 return end($this->queries);
529 }
530
531 // --------------------------------------------------------------------
532
533 /**
534 * "Smart" Escape String
535 *
536 * Escapes data based on type
537 * Sets boolean and null types
538 *
539 * @access public
540 * @param string
541 * @return integer
542 */
543 function escape($str)
544 {
545 switch (gettype($str))
546 {
547 case 'string' : $str = "'".$this->escape_str($str)."'";
548 break;
549 case 'boolean' : $str = ($str === FALSE) ? 0 : 1;
550 break;
551 default : $str = ($str === NULL) ? 'NULL' : $str;
552 break;
553 }
554
555 return $str;
adminbb1d4392006-09-24 20:14:38 +0000556 }
557
admin9cd4e8e2006-09-25 23:26:25 +0000558
559
560 // --------------------------------------------------------------------
561
562 /**
563 * Primary
564 *
565 * Retrieves the primary key. It assumes that the row in the first
566 * position is the primary key
567 *
568 * @access public
569 * @param string the table name
570 * @return string
571 */
572 function primary($table = '')
573 {
574 $fields = $this->field_names($table);
575
576 if ( ! is_array($fields))
577 {
578 return FALSE;
579 }
580
581 return current($fields);
582 }
583
584 // --------------------------------------------------------------------
585
admin3dd978f2006-09-30 19:24:45 +0000586 /**
587 * Returns an array of table names
588 *
589 * @access public
590 * @return array
591 */
592 function list_tables()
593 {
594 // Is there a cached result?
admine8f6eb62006-10-02 06:46:16 +0000595 if (isset($this->data_cache['table_names']))
admin3dd978f2006-09-30 19:24:45 +0000596 {
admine8f6eb62006-10-02 06:46:16 +0000597 return $this->data_cache['table_names'];
admin3dd978f2006-09-30 19:24:45 +0000598 }
599
600 if (FALSE === ($sql = $this->_list_tables()))
601 {
admin6871d952006-10-04 00:36:18 +0000602 if ($this->db_debug)
603 {
admin3dd978f2006-09-30 19:24:45 +0000604 return $this->display_error('db_unsupported_function');
admin6871d952006-10-04 00:36:18 +0000605 }
606 return FALSE;
admin3dd978f2006-09-30 19:24:45 +0000607 }
608
609 $retval = array();
610 $query = $this->query($sql);
611
612 if ($query->num_rows() > 0)
613 {
614 foreach($query->result_array() as $row)
615 {
616 if (isset($row['TABLE_NAME']))
617 {
618 $retval[] = $row['TABLE_NAME'];
619 }
620 else
621 {
622 $retval[] = array_shift($row);
623 }
624 }
625 }
626
admine8f6eb62006-10-02 06:46:16 +0000627 return $this->data_cache['table_names'] =& $retval;
admin3dd978f2006-09-30 19:24:45 +0000628 }
629
630 // --------------------------------------------------------------------
631
632 /**
633 * Determine if a particular table exists
634 * @access public
635 * @return boolean
636 */
637 function table_exists($table_name)
638 {
639 return ( ! in_array($this->dbprefix.$table_name, $this->list_tables())) ? FALSE : TRUE;
640 }
641
642 // --------------------------------------------------------------------
643
admin9cd4e8e2006-09-25 23:26:25 +0000644 /**
645 * Fetch MySQL Field Names
646 *
647 * @access public
648 * @param string the table name
649 * @return array
650 */
admin6871d952006-10-04 00:36:18 +0000651 function list_fields($table = '')
652 {
admin3ed8c512006-09-29 23:26:28 +0000653 // Is there a cached result?
admine8f6eb62006-10-02 06:46:16 +0000654 if (isset($this->data_cache['field_names'][$table]))
admin3ed8c512006-09-29 23:26:28 +0000655 {
admine8f6eb62006-10-02 06:46:16 +0000656 return $this->data_cache['field_names'][$table];
admin3ed8c512006-09-29 23:26:28 +0000657 }
admin6871d952006-10-04 00:36:18 +0000658
659 if ($table == '')
660 {
admin9cd4e8e2006-09-25 23:26:25 +0000661 if ($this->db_debug)
662 {
663 return $this->display_error('db_field_param_missing');
664 }
665 return FALSE;
admin6871d952006-10-04 00:36:18 +0000666 }
667
admin9cd4e8e2006-09-25 23:26:25 +0000668 if (FALSE === ($sql = $this->_list_columns($this->dbprefix.$table)))
669 {
admin6871d952006-10-04 00:36:18 +0000670 if ($this->db_debug)
671 {
admin9cd4e8e2006-09-25 23:26:25 +0000672 return $this->display_error('db_unsupported_function');
admin6871d952006-10-04 00:36:18 +0000673 }
674 return FALSE;
admin9cd4e8e2006-09-25 23:26:25 +0000675 }
admin6871d952006-10-04 00:36:18 +0000676
677 $query = $this->query($sql);
678
679 $retval = array();
admin9cd4e8e2006-09-25 23:26:25 +0000680 foreach($query->result_array() as $row)
681 {
682 if (isset($row['COLUMN_NAME']))
683 {
684 $retval[] = $row['COLUMN_NAME'];
685 }
686 else
687 {
688 $retval[] = current($row);
admin6871d952006-10-04 00:36:18 +0000689 }
admin9cd4e8e2006-09-25 23:26:25 +0000690 }
admin6871d952006-10-04 00:36:18 +0000691
admine8f6eb62006-10-02 06:46:16 +0000692 return $this->data_cache['field_names'][$table] =& $retval;
admin6871d952006-10-04 00:36:18 +0000693 }
adminb2a9cec2006-10-01 03:38:04 +0000694
695 // --------------------------------------------------------------------
696
697 /**
698 * Determine if a particular field exists
699 * @access public
700 * @param string
701 * @param string
702 * @return boolean
703 */
704 function field_exists($field_name, $table_name)
705 {
706 return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
707 }
admin6871d952006-10-04 00:36:18 +0000708
admin3dd978f2006-09-30 19:24:45 +0000709 // --------------------------------------------------------------------
710
711 /**
712 * DEPRECATED - use list_fields()
713 */
admin6871d952006-10-04 00:36:18 +0000714 function field_names($table = '')
715 {
716 return $this->list_fields($table);
717 }
admin9cd4e8e2006-09-25 23:26:25 +0000718
719 // --------------------------------------------------------------------
720
721 /**
722 * Returns an object with field data
723 *
724 * @access public
725 * @param string the table name
726 * @return object
727 */
728 function field_data($table = '')
729 {
admin6871d952006-10-04 00:36:18 +0000730 if ($table == '')
731 {
admin9cd4e8e2006-09-25 23:26:25 +0000732 if ($this->db_debug)
733 {
734 return $this->display_error('db_field_param_missing');
735 }
736 return FALSE;
admin6871d952006-10-04 00:36:18 +0000737 }
738
admin9cd4e8e2006-09-25 23:26:25 +0000739 $query = $this->query($this->_field_data($this->dbprefix.$table));
740 return $query->field_data();
741 }
742
adminbb1d4392006-09-24 20:14:38 +0000743 // --------------------------------------------------------------------
744
745 /**
746 * Generate an insert string
747 *
748 * @access public
749 * @param string the table upon which the query will be performed
750 * @param array an associative array data of key/values
751 * @return string
752 */
753 function insert_string($table, $data)
754 {
admin6871d952006-10-04 00:36:18 +0000755 $fields = array();
adminbb1d4392006-09-24 20:14:38 +0000756 $values = array();
757
758 foreach($data as $key => $val)
759 {
760 $fields[] = $key;
761 $values[] = $this->escape($val);
762 }
763
764 return $this->_insert($this->dbprefix.$table, $fields, $values);
765 }
766
767 // --------------------------------------------------------------------
768
769 /**
770 * Generate an update string
771 *
772 * @access public
773 * @param string the table upon which the query will be performed
774 * @param array an associative array data of key/values
775 * @param mixed the "where" statement
776 * @return string
777 */
778 function update_string($table, $data, $where)
779 {
780 if ($where == '')
781 return false;
782
783 $fields = array();
784 foreach($data as $key => $val)
785 {
786 $fields[$key] = $this->escape($val);
787 }
788
789 if ( ! is_array($where))
790 {
791 $dest = array($where);
792 }
793 else
794 {
795 $dest = array();
796 foreach ($where as $key => $val)
797 {
798 $prefix = (count($dest) == 0) ? '' : ' AND ';
799
800 if ($val != '')
801 {
802 if ( ! $this->_has_operator($key))
803 {
804 $key .= ' =';
805 }
806
807 $val = ' '.$this->escape($val);
808 }
809
810 $dest[] = $prefix.$key.$val;
811 }
812 }
813
814 return $this->_update($this->dbprefix.$table, $fields, $dest);
admin6871d952006-10-04 00:36:18 +0000815 }
admin7b613c72006-09-24 18:05:17 +0000816
817 // --------------------------------------------------------------------
818
819 /**
820 * Enables a native PHP function to be run, using a platform agnostic wrapper.
821 *
822 * @access public
823 * @param string the function name
824 * @param mixed any parameters needed by the function
825 * @return mixed
826 */
827 function call_function($function)
828 {
829 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
830
831 if (FALSE === strpos($driver, $function))
832 {
833 $function = $driver.$function;
834 }
835
836 if ( ! function_exists($function))
837 {
838 if ($this->db_debug)
839 {
840 return $this->display_error('db_unsupported_function');
841 }
842 return FALSE;
843 }
844 else
845 {
adminee54c112006-09-28 17:13:38 +0000846 $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
847
admin7b613c72006-09-24 18:05:17 +0000848 return call_user_func_array($function, $args);
849 }
850 }
admine8f6eb62006-10-02 06:46:16 +0000851
852 // --------------------------------------------------------------------
853
854 /**
855 * Enable Query Caching
856 *
857 * @access public
858 * @return void
859 */
860 function cache_on()
861 {
862 $this->query_caching = TRUE;
863 }
864
865 // --------------------------------------------------------------------
866
867 /**
868 * Disable Query Caching
869 *
870 * @access public
871 * @return void
872 */
873 function cache_off()
874 {
875 $this->query_caching = FALSE;
876 }
admin6871d952006-10-04 00:36:18 +0000877
878 // --------------------------------------------------------------------
879
880 /**
881 * Set Cache Directory Path
882 *
883 * @access public
884 * @param string the path to the cache directory
885 * @return void
886 */
887 function cache_set_dir($path = '')
888 {
889 // Add a trailing slash to the path if needed
890 $path = preg_replace("/(.+?)\/*$/", "\\1/", $path);
891
892 if ( ! is_dir($path) OR ! is_writable($path))
893 {
894 if ($this->db_debug)
895 {
896 return $this->display_error('db_invalid_cache_path');
897 }
898
899 $this->enable_caching(FALSE);
900 return FALSE;
901 }
902
903 $this->cache_dir = $path;
904 }
905
906 // --------------------------------------------------------------------
907
908 /**
909 * Set Cache Path
910 *
911 * @access public
912 * @param string the path to the cache directory
913 * @return void
914 */
915 function cache_set_path($sql)
916 {
917 $obj =& get_instance();
918
919 // The URI being requested will become the name of the cache sub-folder
920
921 $uri = ($obj->uri->uri_string() == '') ? 'index' : $obj->uri->uri_string();
922
923 // Convert the SQL query into a hash. This will become the cache file name.
924
925 return md5($uri).'/'.md5($sql);
926 }
927
928 // --------------------------------------------------------------------
929
930 /**
931 * Retreive a cached query
932 *
933 * @access public
934 * @return string
935 */
936 function cache_read($sql)
937 {
938 if ( ! @is_dir($this->cache_dir))
939 {
940 return $this->cache_on = FALSE;
941 }
942
943 $filepath = $this->cache_set_path($sql);
944
945 if ( ! @file_exists($this->cache_dir.$filepath))
946 {
947 return FALSE;
948 }
949
950 if ( ! $fp = @fopen($this->cache_dir.$filepath, 'rb'))
951 {
952 return FALSE;
953 }
954
955 $cachedata = file_get_contents($this->cache_dir.$filepath);
956
957 if ( ! is_string($cachedata))
958 {
959 return FALSE;
960 }
961
962 return unserialize($cachedata);
963 }
admine8f6eb62006-10-02 06:46:16 +0000964
965 // --------------------------------------------------------------------
966
967 /**
admin6871d952006-10-04 00:36:18 +0000968 * Write a query to a cache file
969 *
970 * @access public
971 * @return bool
972 */
973 function cache_write($sql, $object)
admine8f6eb62006-10-02 06:46:16 +0000974 {
admin6871d952006-10-04 00:36:18 +0000975 if ( ! @is_dir($this->cache_dir))
admine8f6eb62006-10-02 06:46:16 +0000976 {
admin6871d952006-10-04 00:36:18 +0000977 return $this->cache_on = FALSE;
admine8f6eb62006-10-02 06:46:16 +0000978 }
979
admin6871d952006-10-04 00:36:18 +0000980 $filepath = $this->cache_set_path($sql);
admin7b613c72006-09-24 18:05:17 +0000981
admin6871d952006-10-04 00:36:18 +0000982
983
984
985
986
987 $dirs = array(PATH_CACHE.'db_cache', substr($this->cache_dir, 0, -1));
988
989 foreach ($dirs as $dir)
990 {
991 if ( ! @is_dir($dir))
992 {
993 if ( ! @mkdir($dir, 0777))
994 {
995 return;
996 }
997
998 @chmod($dir, 0777);
999 }
1000 }
1001
1002 if ( ! $fp = @fopen($this->cache_dir.$this->cache_file, 'wb'))
1003 {
1004 return FALSE;
1005 }
1006
1007 flock($fp, LOCK_EX);
1008 fwrite($fp, $object);
1009 flock($fp, LOCK_UN);
1010 fclose($fp);
1011
1012 @chmod($this->cache_dir.$this->cache_file, 0777);
1013
1014 return TRUE;
1015 }
1016
admin7b613c72006-09-24 18:05:17 +00001017 // --------------------------------------------------------------------
1018
1019 /**
1020 * Close DB Connection
1021 *
1022 * @access public
1023 * @return void
1024 */
admin6871d952006-10-04 00:36:18 +00001025 function close()
1026 {
1027 if (is_resource($this->conn_id))
1028 {
1029 $this->_close($this->conn_id);
admin7b613c72006-09-24 18:05:17 +00001030 }
1031 $this->conn_id = FALSE;
admin6871d952006-10-04 00:36:18 +00001032 }
admin7b613c72006-09-24 18:05:17 +00001033
1034 // --------------------------------------------------------------------
1035
1036 /**
1037 * Display an error message
1038 *
1039 * @access public
1040 * @param string the error message
1041 * @param string any "swap" values
1042 * @param boolean whether to localize the message
1043 * @return string sends the application/errror_db.php template
1044 */
admin6871d952006-10-04 00:36:18 +00001045 function display_error($error = '', $swap = '', $native = FALSE)
1046 {
admin7b613c72006-09-24 18:05:17 +00001047 $LANG = new CI_Language();
1048 $LANG->load('db');
1049
1050 $heading = 'MySQL Error';
1051
1052 if ($native == TRUE)
1053 {
1054 $message = $error;
1055 }
1056 else
1057 {
1058 $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
1059 }
1060
1061 if ( ! class_exists('CI_Exceptions'))
1062 {
1063 include_once(BASEPATH.'libraries/Exceptions'.EXT);
1064 }
1065
1066 $error = new CI_Exceptions();
1067 echo $error->show_error('An Error Was Encountered', $message, 'error_db');
1068 exit;
1069
admin6871d952006-10-04 00:36:18 +00001070 }
admin7b613c72006-09-24 18:05:17 +00001071
1072}
1073
1074?>