escape_table($table).' WHERE '.implode(' ', $where); } public function update($table, $values, $where) { foreach ($values as $key => $val) { $valstr[] = $this->escape_column($key).' = '.$val; } return 'UPDATE '.$this->escape_table($table).' SET '.implode(', ', $valstr).' WHERE '.implode(' ',$where); } public function set_charset($charset) { throw new Kohana_Database_Exception('database.not_implemented', __FUNCTION__); } abstract public function escape_table($table); abstract public function escape_column($column); public function where($key, $value, $type, $num_wheres, $quote) { $prefix = ($num_wheres == 0) ? '' : $type; if ($quote === -1) { $value = ''; } else { if ($value === NULL) { if ( ! $this->has_operator($key)) { $key .= ' IS'; } $value = ' NULL'; } elseif (is_bool($value)) { if ( ! $this->has_operator($key)) { $key .= ' ='; } $value = ($value == TRUE) ? ' 1' : ' 0'; } else { if ( ! $this->has_operator($key) AND ! empty($key)) { $key = $this->escape_column($key).' ='; } else { preg_match('/^(.+?)([<>!=]+|\bIS(?:\s+NULL))\s*$/i', $key, $matches); if (isset($matches[1]) AND isset($matches[2])) { $key = $this->escape_column(trim($matches[1])).' '.trim($matches[2]); } } $value = ' '.(($quote == TRUE) ? $this->escape($value) : $value); } } return $prefix.$key.$value; } public function like($field, $match, $auto, $type, $num_likes) { $prefix = ($num_likes == 0) ? '' : $type; $match = $this->escape_str($match); if ($auto === TRUE) { $match = '%'.str_replace('%', '\\%', $match).'%'; } return $prefix.' '.$this->escape_column($field).' LIKE \''.$match . '\''; } public function notlike($field, $match, $auto, $type, $num_likes) { $prefix = ($num_likes == 0) ? '' : $type; $match = $this->escape_str($match); if ($auto === TRUE) { $match = '%'.$match.'%'; } return $prefix.' '.$this->escape_column($field).' NOT LIKE \''.$match.'\''; } public function regex($field, $match, $type, $num_regexs) { throw new Kohana_Database_Exception('database.not_implemented', __FUNCTION__); } public function notregex($field, $match, $type, $num_regexs) { throw new Kohana_Database_Exception('database.not_implemented', __FUNCTION__); } public function insert($table, $keys, $values) { foreach ($keys as $key => $value) { $keys[$key] = $this->escape_column($value); } return 'INSERT INTO '.$this->escape_table($table).' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')'; } public function merge($table, $keys, $values) { throw new Kohana_Database_Exception('database.not_implemented', __FUNCTION__); } abstract public function limit($limit, $offset = 0); public function stmt_prepare($sql = '') { throw new Kohana_Database_Exception('database.not_implemented', __FUNCTION__); } abstract public function compile_select($database); public function has_operator($str) { return (bool) preg_match('/[<>!=]|\sIS(?:\s+NOT\s+)?\b|BETWEEN/i', trim($str)); } public function escape($value) { if ( ! $this->db_config['escape']) return $value; switch (gettype($value)) { case 'string': $value = '\''.$this->escape_str($value).'\''; break; case 'boolean': $value = (int) $value; break; case 'double': $value = sprintf('%F', $value); break; default: $value = ($value === NULL) ? 'NULL' : $value; break; } return (string) $value; } abstract public function escape_str($str); abstract public function list_tables(); abstract function list_fields($table); abstract public function show_error(); abstract public function field_data($table); protected function sql_type($str) { static $sql_types; if ($sql_types === NULL) { $sql_types = Kohana::config('sql_types'); } $str = strtolower(trim($str)); if (($open = strpos($str, '(')) !== FALSE) { $close = strpos($str, ')', $open) - 1; $type = substr($str, 0, $open); } else { $type = $str; } empty($sql_types[$type]) and exit ( 'Unknown field type: '.$type.'. '. 'Please report this: http://trac.kohanaphp.com/newticket' ); $field = $sql_types[$type]; switch ($field['type']) { case 'string': case 'float': if (isset($close)) { $field['length'] = substr($str, $open + 1, $close - $open); } break; case 'int': $field['unsigned'] = (strpos($str, 'unsigned') !== FALSE); break; } return $field; } public function clear_cache($sql = NULL) { if (empty($sql)) { $this->query_cache = array(); } else { unset($this->query_cache[$this->query_hash($sql)]); } Kohana::log('debug', 'Database cache cleared: '.get_class($this)); } protected function query_hash($sql) { return sha1(str_replace("\n", ' ', trim($sql))); } } abstract class Database_Result implements ArrayAccess, Iterator, Countable { protected $result; protected $insert_id; protected $sql; protected $current_row = 0; protected $total_rows = 0; protected $fetch_type; protected $return_type; public function sql() { return $this->sql; } public function insert_id() { return $this->insert_id; } abstract function result($object = TRUE, $type = FALSE); abstract function result_array($object = NULL, $type = FALSE); abstract public function list_fields(); abstract public function seek($offset); public function count() { return $this->total_rows; } public function offsetExists($offset) { if ($this->total_rows > 0) { $min = 0; $max = $this->total_rows - 1; return ! ($offset < $min OR $offset > $max); } return FALSE; } public function offsetGet($offset) { if ( ! $this->seek($offset)) return FALSE; return call_user_func($this->fetch_type, $this->result, $this->return_type); } final public function offsetSet($offset, $value) { throw new Kohana_Database_Exception('database.result_read_only'); } final public function offsetUnset($offset) { throw new Kohana_Database_Exception('database.result_read_only'); } public function current() { return $this->offsetGet($this->current_row); } public function key() { return $this->current_row; } public function next() { ++$this->current_row; return $this; } public function prev() { --$this->current_row; return $this; } public function rewind() { $this->current_row = 0; return $this; } public function valid() { return $this->offsetExists($this->current_row); } }