blob: a7a89a953563118ac214e9d21b9374a1eff5ddca [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 {
admindb8a3742006-10-04 07:43:35 +0000159 $this->cache_set_path($this->cachedir);
admin6871d952006-10-04 00:36:18 +0000160 }
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)
admindb8a3742006-10-04 07:43:35 +0000224 {
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'))
admindb8a3742006-10-04 07:43:35 +0000238 {
admin6871d952006-10-04 00:36:18 +0000239 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)
admindb8a3742006-10-04 07:43:35 +0000288 {
289 // If caching is enabled we'll auto-cleanup any
290 // existing files related to this particular URI
291
292 if ($this->cache_on == TRUE)
293 {
294 $this->cache_delete();
295 }
296
admin7b613c72006-09-24 18:05:17 +0000297 return TRUE;
298 }
299
300 // Return TRUE if we don't need to create a result object
301 // Currently only the Oracle driver uses this when stored
302 // procedures are used
303 if ($return_object !== TRUE)
304 {
305 return TRUE;
306 }
admindb8a3742006-10-04 07:43:35 +0000307
308 // Load and instantiate the result driver
admin7b613c72006-09-24 18:05:17 +0000309
admindb8a3742006-10-04 07:43:35 +0000310 $driver = $this->load_rdriver();
311
312 $RES = new $driver();
admin6871d952006-10-04 00:36:18 +0000313 $RES->conn_id = $this->conn_id;
314 $RES->db_debug = $this->db_debug;
315 $RES->result_id = $this->result_id;
316
317 if ($this->dbdriver == 'oci8')
318 {
admin7b613c72006-09-24 18:05:17 +0000319 $RES->stmt_id = $this->stmt_id;
320 $RES->curs_id = NULL;
321 $RES->limit_used = $this->limit_used;
admin6871d952006-10-04 00:36:18 +0000322 }
admindb8a3742006-10-04 07:43:35 +0000323
324 // Is query caching enabled? If so, we'll serialize the
325 // result object and save it to a cache file
326 if ($this->cache_on == TRUE)
327 {
328 $this->cache_write($sql, $RES);
329 }
330
admin7b613c72006-09-24 18:05:17 +0000331 return $RES;
332 }
admindb8a3742006-10-04 07:43:35 +0000333
334 // --------------------------------------------------------------------
335
336 /**
337 * Load the result drivers
338 *
339 * @access public
340 * @return string the name of the result class
341 */
342 function load_rdriver()
343 {
344 $driver = 'CI_DB_'.$this->dbdriver.'_result';
345
346 if ( ! class_exists($driver))
347 {
348 include_once(BASEPATH.'database/DB_result'.EXT);
349 include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result'.EXT);
350 }
351
352 return $driver;
353 }
admin7b613c72006-09-24 18:05:17 +0000354
355 // --------------------------------------------------------------------
356
357 /**
358 * Simple Query
359 * This is a simiplified version of the query() function. Internally
360 * we only use it when running transaction commands since they do
361 * not require all the features of the main query() function.
362 *
363 * @access public
364 * @param string the sql query
365 * @return mixed
366 */
367 function simple_query($sql)
368 {
369 if ( ! $this->conn_id)
370 {
371 $this->initialize();
372 }
373
374 return $this->_execute($sql, $this->conn_id);
375 }
376
377 // --------------------------------------------------------------------
378
379 /**
380 * Disable Transactions
381 * This permits transactions to be disabled at run-time.
382 *
383 * @access public
384 * @return void
385 */
386 function trans_off()
387 {
388 $this->trans_enabled = FALSE;
389 }
390
391 // --------------------------------------------------------------------
392
393 /**
394 * Start Transaction
395 *
396 * @access public
397 * @return void
398 */
399 function trans_start($test_mode = FALSE)
400 {
401 if ( ! $this->trans_enabled)
402 {
403 return FALSE;
404 }
405
406 // When transactions are nested we only begin/commit/rollback the outermost ones
407 if ($this->_trans_depth > 0)
408 {
409 $this->_trans_depth += 1;
410 return;
411 }
412
413 $this->trans_begin($test_mode);
414 }
415
416 // --------------------------------------------------------------------
417
418 /**
419 * Complete Transaction
420 *
421 * @access public
422 * @return bool
423 */
424 function trans_complete()
425 {
426 if ( ! $this->trans_enabled)
427 {
428 return FALSE;
429 }
430
431 // When transactions are nested we only begin/commit/rollback the outermost ones
432 if ($this->_trans_depth > 1)
433 {
434 $this->_trans_depth -= 1;
435 return TRUE;
436 }
437
438 // The query() function will set this flag to TRUE in the event that a query failed
439 if ($this->_trans_failure === TRUE)
440 {
441 $this->trans_rollback();
442
443 if ($this->db_debug)
444 {
445 return $this->display_error('db_transaction_failure');
446 }
447 return FALSE;
448 }
449
450 $this->trans_commit();
451 return TRUE;
452 }
453
454 // --------------------------------------------------------------------
455
456 /**
457 * Lets you retrieve the transaction flag to determine if it has failed
458 *
459 * @access public
460 * @return bool
461 */
462 function trans_status()
463 {
464 return $this->_trans_failure;
465 }
466
467 // --------------------------------------------------------------------
468
469 /**
470 * Compile Bindings
471 *
472 * @access public
473 * @param string the sql statement
474 * @param array an array of bind data
475 * @return string
476 */
477 function compile_binds($sql, $binds)
478 {
479 if (FALSE === strpos($sql, $this->bind_marker))
480 {
481 return $sql;
482 }
483
484 if ( ! is_array($binds))
485 {
486 $binds = array($binds);
487 }
488
489 foreach ($binds as $val)
490 {
491 $val = $this->escape($val);
492
493 // Just in case the replacement string contains the bind
494 // character we'll temporarily replace it with a marker
495 $val = str_replace($this->bind_marker, '{%bind_marker%}', $val);
496 $sql = preg_replace("#".preg_quote($this->bind_marker, '#')."#", str_replace('$', '\$', $val), $sql, 1);
497 }
498
499 return str_replace('{%bind_marker%}', $this->bind_marker, $sql);
500 }
501
502 // --------------------------------------------------------------------
503
504 /**
505 * Determines if a query is a "write" type.
506 *
507 * @access public
508 * @param string An SQL query string
509 * @return boolean
510 */
511 function is_write_type($sql)
512 {
513 if ( ! preg_match('/^\s*"?(INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql))
514 {
515 return FALSE;
516 }
517 return TRUE;
518 }
519
520 // --------------------------------------------------------------------
521
522 /**
523 * Calculate the aggregate query elapsed time
524 *
525 * @access public
526 * @param intiger The number of decimal places
527 * @return integer
528 */
529 function elapsed_time($decimals = 6)
530 {
531 return number_format($this->benchmark, $decimals);
532 }
533
534 // --------------------------------------------------------------------
535
536 /**
537 * Returns the total number of queries
538 *
539 * @access public
540 * @return integer
541 */
542 function total_queries()
543 {
544 return $this->query_count;
545 }
546
547 // --------------------------------------------------------------------
548
549 /**
550 * Returns the last query that was executed
551 *
552 * @access public
553 * @return void
554 */
555 function last_query()
556 {
557 return end($this->queries);
558 }
559
560 // --------------------------------------------------------------------
561
562 /**
563 * "Smart" Escape String
564 *
565 * Escapes data based on type
566 * Sets boolean and null types
567 *
568 * @access public
569 * @param string
570 * @return integer
571 */
572 function escape($str)
573 {
574 switch (gettype($str))
575 {
576 case 'string' : $str = "'".$this->escape_str($str)."'";
577 break;
578 case 'boolean' : $str = ($str === FALSE) ? 0 : 1;
579 break;
580 default : $str = ($str === NULL) ? 'NULL' : $str;
581 break;
582 }
583
584 return $str;
adminbb1d4392006-09-24 20:14:38 +0000585 }
586
admin9cd4e8e2006-09-25 23:26:25 +0000587
588
589 // --------------------------------------------------------------------
590
591 /**
592 * Primary
593 *
594 * Retrieves the primary key. It assumes that the row in the first
595 * position is the primary key
596 *
597 * @access public
598 * @param string the table name
599 * @return string
600 */
601 function primary($table = '')
602 {
603 $fields = $this->field_names($table);
604
605 if ( ! is_array($fields))
606 {
607 return FALSE;
608 }
609
610 return current($fields);
611 }
612
613 // --------------------------------------------------------------------
614
admin3dd978f2006-09-30 19:24:45 +0000615 /**
616 * Returns an array of table names
617 *
618 * @access public
619 * @return array
620 */
621 function list_tables()
622 {
623 // Is there a cached result?
admine8f6eb62006-10-02 06:46:16 +0000624 if (isset($this->data_cache['table_names']))
admin3dd978f2006-09-30 19:24:45 +0000625 {
admine8f6eb62006-10-02 06:46:16 +0000626 return $this->data_cache['table_names'];
admin3dd978f2006-09-30 19:24:45 +0000627 }
628
629 if (FALSE === ($sql = $this->_list_tables()))
630 {
admin6871d952006-10-04 00:36:18 +0000631 if ($this->db_debug)
632 {
admin3dd978f2006-09-30 19:24:45 +0000633 return $this->display_error('db_unsupported_function');
admin6871d952006-10-04 00:36:18 +0000634 }
635 return FALSE;
admin3dd978f2006-09-30 19:24:45 +0000636 }
637
638 $retval = array();
639 $query = $this->query($sql);
640
641 if ($query->num_rows() > 0)
642 {
643 foreach($query->result_array() as $row)
644 {
645 if (isset($row['TABLE_NAME']))
646 {
647 $retval[] = $row['TABLE_NAME'];
648 }
649 else
650 {
651 $retval[] = array_shift($row);
652 }
653 }
654 }
655
admine8f6eb62006-10-02 06:46:16 +0000656 return $this->data_cache['table_names'] =& $retval;
admin3dd978f2006-09-30 19:24:45 +0000657 }
658
659 // --------------------------------------------------------------------
660
661 /**
662 * Determine if a particular table exists
663 * @access public
664 * @return boolean
665 */
666 function table_exists($table_name)
667 {
668 return ( ! in_array($this->dbprefix.$table_name, $this->list_tables())) ? FALSE : TRUE;
669 }
670
671 // --------------------------------------------------------------------
672
admin9cd4e8e2006-09-25 23:26:25 +0000673 /**
674 * Fetch MySQL Field Names
675 *
676 * @access public
677 * @param string the table name
678 * @return array
679 */
admin6871d952006-10-04 00:36:18 +0000680 function list_fields($table = '')
681 {
admin3ed8c512006-09-29 23:26:28 +0000682 // Is there a cached result?
admine8f6eb62006-10-02 06:46:16 +0000683 if (isset($this->data_cache['field_names'][$table]))
admin3ed8c512006-09-29 23:26:28 +0000684 {
admine8f6eb62006-10-02 06:46:16 +0000685 return $this->data_cache['field_names'][$table];
admin3ed8c512006-09-29 23:26:28 +0000686 }
admin6871d952006-10-04 00:36:18 +0000687
688 if ($table == '')
689 {
admin9cd4e8e2006-09-25 23:26:25 +0000690 if ($this->db_debug)
691 {
692 return $this->display_error('db_field_param_missing');
693 }
694 return FALSE;
admin6871d952006-10-04 00:36:18 +0000695 }
696
admin9cd4e8e2006-09-25 23:26:25 +0000697 if (FALSE === ($sql = $this->_list_columns($this->dbprefix.$table)))
698 {
admin6871d952006-10-04 00:36:18 +0000699 if ($this->db_debug)
700 {
admin9cd4e8e2006-09-25 23:26:25 +0000701 return $this->display_error('db_unsupported_function');
admin6871d952006-10-04 00:36:18 +0000702 }
703 return FALSE;
admin9cd4e8e2006-09-25 23:26:25 +0000704 }
admin6871d952006-10-04 00:36:18 +0000705
706 $query = $this->query($sql);
707
708 $retval = array();
admin9cd4e8e2006-09-25 23:26:25 +0000709 foreach($query->result_array() as $row)
710 {
711 if (isset($row['COLUMN_NAME']))
712 {
713 $retval[] = $row['COLUMN_NAME'];
714 }
715 else
716 {
717 $retval[] = current($row);
admin6871d952006-10-04 00:36:18 +0000718 }
admin9cd4e8e2006-09-25 23:26:25 +0000719 }
admin6871d952006-10-04 00:36:18 +0000720
admine8f6eb62006-10-02 06:46:16 +0000721 return $this->data_cache['field_names'][$table] =& $retval;
admin6871d952006-10-04 00:36:18 +0000722 }
adminb2a9cec2006-10-01 03:38:04 +0000723
724 // --------------------------------------------------------------------
725
726 /**
727 * Determine if a particular field exists
728 * @access public
729 * @param string
730 * @param string
731 * @return boolean
732 */
733 function field_exists($field_name, $table_name)
734 {
735 return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
736 }
admin6871d952006-10-04 00:36:18 +0000737
admin3dd978f2006-09-30 19:24:45 +0000738 // --------------------------------------------------------------------
739
740 /**
741 * DEPRECATED - use list_fields()
742 */
admin6871d952006-10-04 00:36:18 +0000743 function field_names($table = '')
744 {
745 return $this->list_fields($table);
746 }
admin9cd4e8e2006-09-25 23:26:25 +0000747
748 // --------------------------------------------------------------------
749
750 /**
751 * Returns an object with field data
752 *
753 * @access public
754 * @param string the table name
755 * @return object
756 */
757 function field_data($table = '')
758 {
admin6871d952006-10-04 00:36:18 +0000759 if ($table == '')
760 {
admin9cd4e8e2006-09-25 23:26:25 +0000761 if ($this->db_debug)
762 {
763 return $this->display_error('db_field_param_missing');
764 }
765 return FALSE;
admin6871d952006-10-04 00:36:18 +0000766 }
767
admin9cd4e8e2006-09-25 23:26:25 +0000768 $query = $this->query($this->_field_data($this->dbprefix.$table));
769 return $query->field_data();
770 }
771
adminbb1d4392006-09-24 20:14:38 +0000772 // --------------------------------------------------------------------
773
774 /**
775 * Generate an insert string
776 *
777 * @access public
778 * @param string the table upon which the query will be performed
779 * @param array an associative array data of key/values
780 * @return string
781 */
782 function insert_string($table, $data)
783 {
admin6871d952006-10-04 00:36:18 +0000784 $fields = array();
adminbb1d4392006-09-24 20:14:38 +0000785 $values = array();
786
787 foreach($data as $key => $val)
788 {
789 $fields[] = $key;
790 $values[] = $this->escape($val);
791 }
792
793 return $this->_insert($this->dbprefix.$table, $fields, $values);
794 }
795
796 // --------------------------------------------------------------------
797
798 /**
799 * Generate an update string
800 *
801 * @access public
802 * @param string the table upon which the query will be performed
803 * @param array an associative array data of key/values
804 * @param mixed the "where" statement
805 * @return string
806 */
807 function update_string($table, $data, $where)
808 {
809 if ($where == '')
810 return false;
811
812 $fields = array();
813 foreach($data as $key => $val)
814 {
815 $fields[$key] = $this->escape($val);
816 }
817
818 if ( ! is_array($where))
819 {
820 $dest = array($where);
821 }
822 else
823 {
824 $dest = array();
825 foreach ($where as $key => $val)
826 {
827 $prefix = (count($dest) == 0) ? '' : ' AND ';
828
829 if ($val != '')
830 {
831 if ( ! $this->_has_operator($key))
832 {
833 $key .= ' =';
834 }
835
836 $val = ' '.$this->escape($val);
837 }
838
839 $dest[] = $prefix.$key.$val;
840 }
841 }
842
843 return $this->_update($this->dbprefix.$table, $fields, $dest);
admin6871d952006-10-04 00:36:18 +0000844 }
admin7b613c72006-09-24 18:05:17 +0000845
846 // --------------------------------------------------------------------
847
848 /**
849 * Enables a native PHP function to be run, using a platform agnostic wrapper.
850 *
851 * @access public
852 * @param string the function name
853 * @param mixed any parameters needed by the function
854 * @return mixed
855 */
856 function call_function($function)
857 {
858 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
859
860 if (FALSE === strpos($driver, $function))
861 {
862 $function = $driver.$function;
863 }
864
865 if ( ! function_exists($function))
866 {
867 if ($this->db_debug)
868 {
869 return $this->display_error('db_unsupported_function');
870 }
871 return FALSE;
872 }
873 else
874 {
adminee54c112006-09-28 17:13:38 +0000875 $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
876
admin7b613c72006-09-24 18:05:17 +0000877 return call_user_func_array($function, $args);
878 }
879 }
admine8f6eb62006-10-02 06:46:16 +0000880
881 // --------------------------------------------------------------------
882
883 /**
884 * Enable Query Caching
885 *
886 * @access public
887 * @return void
888 */
889 function cache_on()
890 {
admindb8a3742006-10-04 07:43:35 +0000891 return $this->query_caching = TRUE;
admine8f6eb62006-10-02 06:46:16 +0000892 }
893
894 // --------------------------------------------------------------------
895
896 /**
897 * Disable Query Caching
898 *
899 * @access public
900 * @return void
901 */
902 function cache_off()
903 {
admindb8a3742006-10-04 07:43:35 +0000904 return $this->query_caching = FALSE;
admine8f6eb62006-10-02 06:46:16 +0000905 }
admin6871d952006-10-04 00:36:18 +0000906
907 // --------------------------------------------------------------------
908
909 /**
910 * Set Cache Directory Path
911 *
912 * @access public
913 * @param string the path to the cache directory
admindb8a3742006-10-04 07:43:35 +0000914 * @return bool
admin6871d952006-10-04 00:36:18 +0000915 */
admindb8a3742006-10-04 07:43:35 +0000916 function cache_set_path($path = '')
admin6871d952006-10-04 00:36:18 +0000917 {
admindb8a3742006-10-04 07:43:35 +0000918 if ($path == '')
919 {
920 return $this->cache_off();
921 }
922
admin6871d952006-10-04 00:36:18 +0000923 // Add a trailing slash to the path if needed
924 $path = preg_replace("/(.+?)\/*$/", "\\1/", $path);
925
926 if ( ! is_dir($path) OR ! is_writable($path))
927 {
928 if ($this->db_debug)
929 {
930 return $this->display_error('db_invalid_cache_path');
931 }
932
admindb8a3742006-10-04 07:43:35 +0000933 // If the path is wrong we'll turn off caching
934 return $this->cache_off();
admin6871d952006-10-04 00:36:18 +0000935 }
936
937 $this->cache_dir = $path;
admindb8a3742006-10-04 07:43:35 +0000938 return TRUE;
admin6871d952006-10-04 00:36:18 +0000939 }
940
941 // --------------------------------------------------------------------
942
943 /**
944 * Retreive a cached query
945 *
admindb8a3742006-10-04 07:43:35 +0000946 * The URI being requested will become the name of the cache sub-folder.
947 * An MD5 hash of the SQL statement will become the cache file name
948 *
admin6871d952006-10-04 00:36:18 +0000949 * @access public
950 * @return string
951 */
952 function cache_read($sql)
admindb8a3742006-10-04 07:43:35 +0000953 {
954 if ( ! $this->cache_set_path($this->cache_dir))
admin6871d952006-10-04 00:36:18 +0000955 {
admindb8a3742006-10-04 07:43:35 +0000956 return $this->cache_off();
admin6871d952006-10-04 00:36:18 +0000957 }
958
admindb8a3742006-10-04 07:43:35 +0000959 $obj =& get_instance();
960 $uri = ($obj->uri->segment(1) == FALSE) ? 'base' : $obj->uri->segment(2);
961 $uri .= ($obj->uri->segment(2) == FALSE) ? 'index' : $obj->uri->segment(2);
admin6871d952006-10-04 00:36:18 +0000962
admindb8a3742006-10-04 07:43:35 +0000963 $filepath = md5($uri).'/'.md5($sql);
admin6871d952006-10-04 00:36:18 +0000964
admindb8a3742006-10-04 07:43:35 +0000965 $obj->load->helper('file');
966 if (FALSE === ($cachedata = read_file($this->cache_dir.$filepath)))
admin6871d952006-10-04 00:36:18 +0000967 {
968 return FALSE;
969 }
970
971 return unserialize($cachedata);
972 }
admine8f6eb62006-10-02 06:46:16 +0000973
974 // --------------------------------------------------------------------
975
976 /**
admin6871d952006-10-04 00:36:18 +0000977 * Write a query to a cache file
978 *
979 * @access public
980 * @return bool
981 */
982 function cache_write($sql, $object)
admine8f6eb62006-10-02 06:46:16 +0000983 {
admindb8a3742006-10-04 07:43:35 +0000984 if ( ! $this->cache_set_path($this->cache_dir))
admine8f6eb62006-10-02 06:46:16 +0000985 {
admindb8a3742006-10-04 07:43:35 +0000986 return $this->cache_off();
admine8f6eb62006-10-02 06:46:16 +0000987 }
admindb8a3742006-10-04 07:43:35 +0000988
989 $obj =& get_instance();
990 $uri = ($obj->uri->segment(1) == FALSE) ? 'base' : $obj->uri->segment(2);
991 $uri .= ($obj->uri->segment(2) == FALSE) ? 'index' : $obj->uri->segment(2);
admin6871d952006-10-04 00:36:18 +0000992
admindb8a3742006-10-04 07:43:35 +0000993 $dir_path = $this->cache_dir.md5($uri).'/';
admin6871d952006-10-04 00:36:18 +0000994
admindb8a3742006-10-04 07:43:35 +0000995 $filename = md5($sql);
996
997 if ( ! @is_dir($dir_path))
998 {
999 if ( ! @mkdir($dir_path, 0777))
admin6871d952006-10-04 00:36:18 +00001000 {
admindb8a3742006-10-04 07:43:35 +00001001 return FALSE;
admin6871d952006-10-04 00:36:18 +00001002 }
admindb8a3742006-10-04 07:43:35 +00001003
1004 @chmod($dir_path, 0777);
admin6871d952006-10-04 00:36:18 +00001005 }
admindb8a3742006-10-04 07:43:35 +00001006
1007 $obj->load->helper('file');
1008 if (write_file($dir_path.$filename, serialize($object)) === FALSE)
admin6871d952006-10-04 00:36:18 +00001009 {
1010 return FALSE;
1011 }
1012
admindb8a3742006-10-04 07:43:35 +00001013 @chmod($dir_path.$filename, 0777);
admin6871d952006-10-04 00:36:18 +00001014 return TRUE;
1015 }
1016
admin7b613c72006-09-24 18:05:17 +00001017 // --------------------------------------------------------------------
1018
1019 /**
admindb8a3742006-10-04 07:43:35 +00001020 * Delete cache files within a particular directory
1021 *
1022 * @access public
1023 * @return bool
1024 */
1025 function cache_delete()
1026 {
1027 $obj =& get_instance();
1028 $uri = ($obj->uri->segment(1) == FALSE) ? 'base' : $obj->uri->segment(2);
1029 $uri .= ($obj->uri->segment(2) == FALSE) ? 'index' : $obj->uri->segment(2);
1030
1031 $dir_path = $this->cache_dir.md5($uri).'/';
1032
1033 $obj->load->helper('file');
1034 delete_files($dir_path, TRUE);
1035 }
1036
1037 // --------------------------------------------------------------------
1038
1039 /**
1040 * Delete all existing cache files
1041 *
1042 * @access public
1043 * @return bool
1044 */
1045 // --------------------------------------------------------------------
1046
1047 function cache_delete_all()
1048 {
1049 $obj =& get_instance();
1050 $obj->load->helper('file');
1051 delete_files($this->cache_dir, TRUE);
1052 }
1053
1054 // --------------------------------------------------------------------
1055
1056 /**
admin7b613c72006-09-24 18:05:17 +00001057 * Close DB Connection
1058 *
1059 * @access public
1060 * @return void
1061 */
admin6871d952006-10-04 00:36:18 +00001062 function close()
1063 {
1064 if (is_resource($this->conn_id))
1065 {
1066 $this->_close($this->conn_id);
admin7b613c72006-09-24 18:05:17 +00001067 }
1068 $this->conn_id = FALSE;
admin6871d952006-10-04 00:36:18 +00001069 }
admin7b613c72006-09-24 18:05:17 +00001070
1071 // --------------------------------------------------------------------
1072
1073 /**
1074 * Display an error message
1075 *
1076 * @access public
1077 * @param string the error message
1078 * @param string any "swap" values
1079 * @param boolean whether to localize the message
1080 * @return string sends the application/errror_db.php template
1081 */
admin6871d952006-10-04 00:36:18 +00001082 function display_error($error = '', $swap = '', $native = FALSE)
1083 {
admin7b613c72006-09-24 18:05:17 +00001084 $LANG = new CI_Language();
1085 $LANG->load('db');
1086
1087 $heading = 'MySQL Error';
1088
1089 if ($native == TRUE)
1090 {
1091 $message = $error;
1092 }
1093 else
1094 {
1095 $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
1096 }
1097
1098 if ( ! class_exists('CI_Exceptions'))
1099 {
1100 include_once(BASEPATH.'libraries/Exceptions'.EXT);
1101 }
1102
1103 $error = new CI_Exceptions();
1104 echo $error->show_error('An Error Was Encountered', $message, 'error_db');
1105 exit;
1106
admin6871d952006-10-04 00:36:18 +00001107 }
admin7b613c72006-09-24 18:05:17 +00001108
1109}
1110
1111?>