New version submitted by TomB
[carbonphp.git] / Source / carbon / database / Database_driver.php
blob001c86525590396ca3d40a1130d68c645d707d4c
1 <?php
2 /*------------------------------------------------------------
3 * CarbonPHP framework (C) Tom Bell
4 * http://tombell.org.uk
5 *------------------------------------------------------------*/
7 if (!defined('CARBON_PATH'))
9 exit('Direct script access is not allowed.');
12 class Carbon_Database_driver
14 public $username;
15 public $password;
16 public $hostname;
17 public $database;
18 public $dbdriver = 'mysql';
19 public $dbprefix = '';
20 public $autoinit = true;
21 public $swap_pre = '';
22 public $port = '';
23 public $pconnect = false;
24 public $conn_id = false;
25 public $result_id = false;
26 public $db_debug = false;
27 public $benchmark = 0;
28 public $query_count = 0;
29 public $bind_marker = '?';
30 public $save_queries = true;
31 public $queries = array();
32 public $query_times = array();
33 public $data_cache = array();
34 public $trans_enabled = true;
35 public $_trans_depth = 0;
36 public $_trans_status = true;
37 public $cache_on = false;
38 public $cachedir = '';
39 public $cache_autodel = false;
40 public $cache;
42 public $stmt_id;
43 public $curs_id;
44 public $limit_used;
46 public function __construct($params)
48 if (is_array($params))
50 foreach ($params as $key => $value)
52 $this->$key = $value;
56 log_message('debug', 'Database_driver.php - Carbon_Database_driver class initialised');
59 public function initialise($create_db = false)
61 if (is_resource($this->conn_id))
63 return true;
66 $this->conn_id = ($this->pconnect == false) ? $this->database_connect() : $this->database_pconnect();
68 if (!$this->conn_id)
70 log_message('error', 'Database_driver.php - Unable to connect to the database');
72 if ($this->db_debug)
74 $this->display_error('database_unable_to_connect');
77 return false;
80 if ($this->database != '')
82 if (!$this->database_select())
84 if ($create_db == true)
86 $carbon =& get_instance();
87 $carbon->load->dbutil();
89 if (!$carbon->dbutil->create_database($this->database))
91 log_message('error', 'Database_driver.php - Unable to create the database: ' . $this->database);
93 if ($this->db_debug)
95 $this->display_error('database_unable_to_create', $this->database);
98 return false;
100 else
102 if ($this->database_select())
104 if (!$this->database_set_charset($this->char_set, $this->dbcollat))
106 log_message('error', 'Database_driver.php - Unable to set the database connection charset: ' . $this->char_set);
108 if ($this->db_debug)
110 $this->display_error('database_unable_to_set_charset', $this->char_set);
113 return false;
116 return true;
121 log_message('error', 'Database_driver.php - Unable to select the database: ' . $this->database);
123 if ($this->db_debug)
125 $this->display_error('database_unable_to_select', $this->database);
128 return false;
131 if (!$this->database_set_charset($this->char_set, $this->dbcollat))
133 log_message('error', 'Database_driver.php - Unable to set the database connection charset: ' . $this->char_set);
135 if ($this->db_debug)
137 $this->display_error('database_unable_to_set_charset', $this->char_set);
140 return false;
144 return true;
147 public function platform()
149 return $this->dbdriver;
152 public function version()
154 $sql = $this->database_version();
156 if ($sql === false)
158 if ($this->db_debug)
160 return $this->display_error('database_unsupported_function');
163 return false;
166 if ($this->dbdriver == 'oci8')
168 return $sql;
171 $query = $this->query($sql);
172 return $row->row('ver');
175 public function query($sql, $binds = false, $return_object = true)
177 if ($sql == '')
179 log_message('error', 'Database_driver.php - Invalid query: ' . $sql);
181 if ($this->db_debug)
183 return $this->display_error('database_invalid_query');
186 return false;
189 if (($this->dbprefix != '' && $this->swap_pre != '') && ($this->dbprefix != $this->swap_pre))
191 $sql = preg_replace("/(\W)" . $this->swap_pre . "(\S+?)/", "\\1" . $this->dbprefix . "\\2", $sql);
194 if ($this->cache_on == true && stristr($sql, 'SELECT'))
196 if ($this->database_cache_init())
198 $this->load_result_driver();
199 $cache = $this->cache->read($sql);
201 if ($cache !== false)
203 return $cache;
208 if ($binds !== false)
210 $sql = $this->compile_binds($sql, $binds);
213 if ($this->save_queries == true)
215 $this->queries[] = $sql;
218 $time_start = list($sm, $ss) = explode(' ', microtime());
219 $this->result_id = $this->simple_query($sql);
221 if ($this->result_id === false)
223 $this->_trans_status = false;
225 log_message('error', 'Database_driver.php - Query error: ' . $this->database_error_message());
227 if ($this->db_debug)
229 return $this->display_error(array('Error number: ' . $this->database_error_number(), $this->database_error_message(), $sql));
232 return false;
235 $time_end = list($em, $es) = explode(' ', microtime());
236 $this->benchmark += ($em + $es) - ($sm + $ss);
238 if ($this->save_queries == true)
240 $this->query_times[] = ($em + $es) - ($sm + $ss);
243 $this->query_count++;
245 if ($this->is_write_type($sql) === true)
247 if ($this->cache_on == true && $this->cache_autodel == true && $this->database_cache_init())
249 $this->cache->delete();
252 return true;
255 if ($return_object !== true)
257 return true;
260 $driver = $this->load_result_driver();
262 $result = new $driver();
264 $result->conn_id = $this->conn_id;
265 $result->result_id = $this->result_id;
266 $result->num_rows = $result->num_rows();
268 if ($this->dbdriver == 'oci8')
270 $result->stmt_id = $this->stmt_id;
271 $result->curs_id = $this->curs_id;
272 $result->limit_used = $this->limit_used;
275 if ($this->cache_on == true && $this->database_cache_init())
277 $cache_result = new Carbon_Database_result();
279 $cache_result->num_rows = $result->num_rows();
280 $cache_result->result_object = $result->result_object();
281 $cache_result->result_array = $result->result_array();
283 $cache_result->conn_id = null;
284 $cache_result->result_id = null;
286 $this->cache->write($sql, $cache_result);
289 return $result;
292 public function load_result_driver()
294 $driver = 'Carbon_Database_' . $this->dbdriver . '_result';
296 if (!class_exists($driver))
298 include_once(CARBON_PATH . 'database/Database_result' . FILE_EXT);
299 include_once(CARBON_PATH . 'database/drivers/' . $this->dbdriver . '/' . $this->dbdriver . '_result' . FILE_EXT);
302 return $driver;
305 public function simple_query($sql)
307 if (!$this->conn_id)
309 $this->initialise();
312 return $this->database_execute($sql);
315 public function trans_off()
317 $this->trans_enabled = false;
320 public function trans_start($test_mode = false)
322 if (!$this->trans_enabled)
324 return false;
327 if ($this->_trans_depth > 0)
329 $this->_trans_depth += 1;
330 return;
333 $this->trans_begin($test_mode);
336 public function trans_complete()
338 if (!$this->trans_enabled)
340 return false;
343 if ($this->_trans_depth > 1)
345 $this->_trans_depth -= 1;
346 return true;
349 if ($this->_trans_status === false)
351 $this->trans_rollback();
353 if ($this->db_debug)
355 return $this->display_error('database_transaction_failure');
358 return false;
361 $this->trans_commit();
362 return true;
365 public function trans_status()
367 return $this->_trans_status;
370 public function compile_binds($sql, $binds)
372 if (strpos($sql, $this->bind_marker) === false)
374 return $sql;
377 if (!is_array($binds))
379 $binds = array($binds);
382 $segments = explode($this->bind_marker, $sql);
384 if (count($binds) >= count($segments))
386 $binds = array_slice($binds, 0, count($segments) - 1);
389 $result = $segments[0];
390 $i = 0;
392 foreach ($binds as $bind)
394 $result .= $this->escape($bind);
395 $result .= $segments[++$i];
398 return $result;
401 public function is_write_type($sql)
403 if (!preg_match('/^\s*"?(INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql))
405 return false;
408 return true;
411 public function elapsed_time($precision = 6)
413 return number_format($this->benchmark, $precision);
416 public function total_queries()
418 return $this->query_count;
421 public function last_query()
423 return end($this->queries);
426 public function protect_identifiers($item, $first_word_only = false)
428 return $this->database_protect_identifiers($item, $first_word_only);
431 public function escape($string)
434 if (is_numeric ($string))
436 return $string;
438 else if (is_string ($string))
440 return "'" . $this->escape_string ($string) . "'";
442 else if (is_bool ($string))
444 return ($string === false) ? 0 : 1;
446 else
448 return $string;
452 public function primary($table = '')
454 $fields = $this->list_fields($table);
456 if (!is_array($fields))
458 return false;
461 return current($fields);
464 public function list_tables($constrain_by_prefix = false)
466 if (isset($this->data_cache['table_names']))
468 return $this->data_cache['table_names'];
471 $sql = $this->database_list_tables($constrain_by_prefix);
473 if ($sql === false)
475 if ($this->db_debug)
477 return $this->display_error('database_unsupported_function');
480 return false;
483 $retval = array();
484 $query = $this->query($sql);
486 if ($query->num_rows() > 0)
488 foreach ($query->result_array() as $row)
490 if (isset($row['TABLE_NAME']))
492 $retval[] = $row['TABLE_NAME'];
494 else
496 $retval[] = array_shift($row);
501 $this->data_cache['table_names'] = $retval;
503 return $this->data_cache['table_names'];
506 public function table_exist($table_name)
508 return (!in_array($this->prep_tablename($table_name), $this->list_tables())) ? false : true;
511 public function list_fields($table = '')
513 if (isset($this->data_cache['field_names'][$table]))
515 return $this->data_cache['field_names'][$table];
518 if ($table == '')
520 if ($this->db_debug)
522 return $this->display_error('database_field_param_missing');
525 return false;
528 $sql = $this->database_list_columns($this->dbprefix . $table);
530 if ($sql === false)
532 if ($this->db_debug)
534 return $this->display_error('database_unsupported_function');
537 return false;
540 $query = $this->query($sql);
542 $retval = array();
544 foreach ($query->result_array() as $row)
546 if (isset($row['COLUMN_NAME']))
548 $retval[] = $row['COLUMN_NAME'];
550 else
552 $retval[] = current($row);
556 $this->data_cache['field_names'][$table] = $retval;
558 return $this->data_cache['field_names'][$table];
561 public function field_exists($field_names, $table_name)
563 return (!in_array($field_names, $this->list_fields($table_name))) ? false : true;
566 public function field_names($table = '')
568 return $this->list_fields($table);
571 public function field_data($table = '')
573 if ($table == '')
575 if ($this->db_debug)
577 return $this->display_error('database_field_param_missing');
580 return false;
583 $query = $this->query($this->database_field_data($this->dbprefix . $table));
585 return $query->field_data();
588 public function insert_string($table, $data)
590 $fields = array();
591 $values = array();
593 foreach ($data as $key => $val)
595 $fields[] = $key;
596 $values[] = $this->escape($val);
599 return $this->database_insert($this->dbprefix . $table, $fields, $values);
602 public function update_string($table, $data, $where)
604 if ($where == '')
606 return false;
609 $fields = array();
611 foreach ($data as $key => $val)
613 $fields[$key] = $this->escape($val);
616 if (!is_array($where))
618 $dest = array($where);
620 else
622 $dest = array();
624 foreach ($where as $key => $val)
626 $prefix = (count($dest) == 0) ? '' : ' AND ';
628 if ($val != '')
630 if (!$this->database_has_operator($key))
632 $key .= ' =';
635 $val = ' ' . $this->escape($val);
638 $dest[] = $prefix . $key . $val;
642 return $this->database_update($this->dbprefix . $table, $fields, $dest);
645 public function prep_tablename($table = '')
647 if ($this->dbprefix != '')
649 if (substr($table, 0, strlen($this->dbprefix)) != $this->dbprefix)
651 $table = $this->dbprefix . $table;
655 return $table;
658 public function call_function($function)
660 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver . '_';
662 if (strpos($driver, $function) === false)
664 $function = $driver . $function;
667 if (!function_exists($function))
669 if ($this->db_debug)
671 return $this->display_error('database_unsupported_function');
674 return false;
676 else
678 $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
680 return call_user_func_array($function, $args);
684 public function cache_set_path($path = '')
686 $this->cachedir = $path;
689 public function cache_on()
691 $this->cache_on = true;
693 return true;
696 public function cache_off()
698 $this->cache_on = false;
700 return false;
703 public function cache_delete($segment_one = '', $segment_two = '')
705 if (!$this->_cache_init())
707 return false;
710 return $this->cache->delete($segment_one, $segment_two);
713 public function cache_delete_all()
715 if (!$this->_cache_init())
717 return false;
720 return $this->cache->delete_all();
723 public function database_cache_init()
725 if (is_object($this->cache) && class_exists('Carbon_Database_Cache'))
727 return true;
730 if (!@include(CARBON_PATH . 'database/Database_cache' . FILE_EXT))
732 return $this->cache_off();
735 $this->cache = new Carbon_Database_Cache;
737 return true;
740 public function close()
742 if (is_resource($this->conn_id))
744 $this->database_close($this->conn_id);
747 $this->conn_id = false;
750 public function display_error($error = '', $swap = '', $native = false)
752 $lang = load_class('Language');
753 $lang->load('database');
755 if ($native == true)
757 $message = $error;
759 else
761 $message = (!is_array($error)) ? array(str_replace('%s', $swap, $lang->line($error))) : $error;
764 $error = load_class('Exception');
765 echo $error->display_error('An error has been encountered', $message, 'error_database');
766 exit;