freenetis-github/system/libraries/Database.php @ f5adf00c
8baed187 | Michal Kliment | <?php defined('SYSPATH') OR die('No direct access allowed.');
|
|
/**
|
|||
* Provides database access in a platform agnostic way, using simple query building blocks.
|
|||
*
|
|||
* $Id: Database.php 4342 2009-05-08 16:56:01Z jheathco $
|
|||
*
|
|||
* @package Core
|
|||
* @author Kohana Team
|
|||
* @copyright (c) 2007-2008 Kohana Team
|
|||
* @license http://kohanaphp.com/license.html
|
|||
*/
|
|||
class Database {
|
|||
// Database instances
|
|||
public static $instances = array();
|
|||
// Global benchmark
|
|||
public static $benchmarks = array();
|
|||
// Configuration
|
|||
protected $config = array
|
|||
(
|
|||
'benchmark' => FALSE,
|
|||
'persistent' => FALSE,
|
|||
'connection' => '',
|
|||
'character_set' => 'utf8',
|
|||
'table_prefix' => '',
|
|||
'object' => TRUE,
|
|||
'cache' => FALSE,
|
|||
'escape' => TRUE,
|
|||
);
|
|||
// Database driver object
|
|||
protected $driver;
|
|||
protected $link;
|
|||
// Un-compiled parts of the SQL query
|
|||
protected $select = array();
|
|||
protected $set = array();
|
|||
protected $from = array();
|
|||
protected $join = array();
|
|||
protected $where = array();
|
|||
protected $orderby = array();
|
|||
protected $order = array();
|
|||
protected $groupby = array();
|
|||
protected $having = array();
|
|||
protected $distinct = FALSE;
|
|||
protected $limit = FALSE;
|
|||
protected $offset = FALSE;
|
|||
protected $last_query = '';
|
|||
// Stack of queries for push/pop
|
|||
protected $query_history = array();
|
|||
/**
|
|||
* Returns a singleton instance of Database.
|
|||
*
|
|||
* @param mixed configuration array or DSN
|
|||
* @return Database
|
|||
*/
|
|||
public static function & instance($name = 'default', $config = NULL)
|
|||
{
|
|||
if ( ! isset(Database::$instances[$name]))
|
|||
{
|
|||
// Create a new instance
|
|||
Database::$instances[$name] = new Database($config === NULL ? $name : $config);
|
|||
}
|
|||
return Database::$instances[$name];
|
|||
}
|
|||
/**
|
|||
* Returns the name of a given database instance.
|
|||
*
|
|||
* @param Database instance of Database
|
|||
* @return string
|
|||
*/
|
|||
public static function instance_name(Database $db)
|
|||
{
|
|||
return array_search($db, Database::$instances, TRUE);
|
|||
}
|
|||
/**
|
|||
* Sets up the database configuration, loads the Database_Driver.
|
|||
*
|
|||
* @throws Kohana_Database_Exception
|
|||
*/
|
|||
public function __construct($config = array())
|
|||
{
|
|||
f5adf00c | Ondřej Fibich | if (!is_array($config) && is_string($config) && strlen($config))
|
|
c2e44ab0 | Michal Kliment | {
|
|
// Parse the DSN, creating an array to hold the connection parameters
|
|||
$db = array
|
|||
(
|
|||
'type' => 'mysql',
|
|||
'user' => FALSE,
|
|||
'pass' => FALSE,
|
|||
'host' => FALSE,
|
|||
'port' => FALSE,
|
|||
'socket' => FALSE,
|
|||
'database' => FALSE
|
|||
);
|
|||
// Reset the connection array to the database config
|
|||
$this->config['connection'] = $db;
|
|||
1c861ddd | Ondřej Fibich | $this->config['connection']['type'] = (defined('PHP_VERSION_ID') && PHP_VERSION_ID >= 60000) ? 'mysqli' : 'mysql';
|
|
c2e44ab0 | Michal Kliment | $this->config['connection']['user'] = Config::get('db_user');
|
|
$this->config['connection']['pass'] = Config::get('db_password');
|
|||
$this->config['connection']['host'] = Config::get('db_host');
|
|||
$this->config['connection']['database'] = Config::get('db_name');
|
|||
$this->config['table_prefix'] = Config::get('db_table_prefix');
|
|||
}
|
|||
else
|
|||
{
|
|||
$this->config['connection'] = $config;
|
|||
}
|
|||
8baed187 | Michal Kliment | ||
// Set driver name
|
|||
$driver = 'Database_'.ucfirst($this->config['connection']['type']).'_Driver';
|
|||
// Load the driver
|
|||
if ( ! Kohana::auto_load($driver))
|
|||
throw new Kohana_Database_Exception('core.driver_not_found', $this->config['connection']['type'], get_class($this));
|
|||
// Initialize the driver
|
|||
$this->driver = new $driver($this->config);
|
|||
// Validate the driver
|
|||
if ( ! ($this->driver instanceof Database_Driver))
|
|||
throw new Kohana_Database_Exception('core.driver_implements', $this->config['connection']['type'], get_class($this), 'Database_Driver');
|
|||
Log::add('debug', 'Database Library initialized');
|
|||
}
|
|||
/**
|
|||
* Simple connect method to get the database queries up and running.
|
|||
*
|
|||
* @return void
|
|||
*/
|
|||
public function connect()
|
|||
{
|
|||
// A link can be a resource or an object
|
|||
if ( ! is_resource($this->link) AND ! is_object($this->link))
|
|||
{
|
|||
$this->link = $this->driver->connect();
|
|||
if ( ! is_resource($this->link) AND ! is_object($this->link))
|
|||
throw new Kohana_Database_Exception('database.connection', $this->driver->show_error());
|
|||
// Clear password after successful connect
|
|||
$this->config['connection']['pass'] = NULL;
|
|||
}
|
|||
}
|
|||
/**
|
|||
* Runs a query into the driver and returns the result.
|
|||
*
|
|||
* @param string SQL query to execute
|
|||
* @return Database_Result
|
|||
*/
|
|||
public function query($sql = '')
|
|||
{
|
|||
if ($sql == '') return FALSE;
|
|||
// No link? Connect!
|
|||
$this->link or $this->connect();
|
|||
// Start the benchmark
|
|||
$start = microtime(TRUE);
|
|||
if (func_num_args() > 1) //if we have more than one argument ($sql)
|
|||
{
|
|||
$argv = func_get_args();
|
|||
$binds = (is_array(next($argv))) ? current($argv) : array_slice($argv, 1);
|
|||
}
|
|||
// Compile binds if needed
|
|||
if (isset($binds))
|
|||
{
|
|||
$sql = $this->compile_binds($sql, $binds);
|
|||
}
|
|||
// Fetch the result
|
|||
$result = $this->driver->query($this->last_query = $sql);
|
|||
// Stop the benchmark
|
|||
$stop = microtime(TRUE);
|
|||
if ($this->config['benchmark'] == TRUE)
|
|||
{
|
|||
// Benchmark the query
|
|||
Database::$benchmarks[] = array('query' => $sql, 'time' => $stop - $start, 'rows' => count($result));
|
|||
}
|
|||
return $result;
|
|||
}
|
|||
/**
|
|||
* Selects the column names for a database query.
|
|||
*
|
|||
* @param string string or array of column names to select
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function select($sql = '*')
|
|||
{
|
|||
if (func_num_args() > 1)
|
|||
{
|
|||
$sql = func_get_args();
|
|||
}
|
|||
elseif (is_string($sql))
|
|||
{
|
|||
$sql = explode(',', $sql);
|
|||
}
|
|||
else
|
|||
{
|
|||
$sql = (array) $sql;
|
|||
}
|
|||
foreach ($sql as $val)
|
|||
{
|
|||
if (($val = trim($val)) === '') continue;
|
|||
if (strpos($val, '(') === FALSE AND $val !== '*')
|
|||
{
|
|||
if (preg_match('/^DISTINCT\s++(.+)$/i', $val, $matches))
|
|||
{
|
|||
// Only prepend with table prefix if table name is specified
|
|||
$val = (strpos($matches[1], '.') !== FALSE) ? $this->config['table_prefix'].$matches[1] : $matches[1];
|
|||
$this->distinct = TRUE;
|
|||
}
|
|||
else
|
|||
{
|
|||
$val = (strpos($val, '.') !== FALSE) ? $this->config['table_prefix'].$val : $val;
|
|||
}
|
|||
$val = $this->driver->escape_column($val);
|
|||
}
|
|||
$this->select[] = $val;
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the from table(s) for a database query.
|
|||
*
|
|||
* @param string string or array of tables to select
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function from($sql)
|
|||
{
|
|||
if (func_num_args() > 1)
|
|||
{
|
|||
$sql = func_get_args();
|
|||
}
|
|||
elseif (is_string($sql))
|
|||
{
|
|||
$sql = explode(',', $sql);
|
|||
}
|
|||
else
|
|||
{
|
|||
$sql = array($sql);
|
|||
}
|
|||
foreach ($sql as $val)
|
|||
{
|
|||
if (is_string($val))
|
|||
{
|
|||
if (($val = trim($val)) === '') continue;
|
|||
// TODO: Temporary solution, this should be moved to database driver (AS is checked for twice)
|
|||
if (stripos($val, ' AS ') !== FALSE)
|
|||
{
|
|||
$val = str_ireplace(' AS ', ' AS ', $val);
|
|||
list($table, $alias) = explode(' AS ', $val);
|
|||
// Attach prefix to both sides of the AS
|
|||
$val = $this->config['table_prefix'].$table.' AS '.$this->config['table_prefix'].$alias;
|
|||
}
|
|||
else
|
|||
{
|
|||
$val = $this->config['table_prefix'].$val;
|
|||
}
|
|||
}
|
|||
$this->from[] = $val;
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Generates the JOIN portion of the query.
|
|||
*
|
|||
* @param string table name
|
|||
* @param string|array where key or array of key => value pairs
|
|||
* @param string where value
|
|||
* @param string type of join
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function join($table, $key, $value = NULL, $type = '')
|
|||
{
|
|||
$join = array();
|
|||
if ( ! empty($type))
|
|||
{
|
|||
$type = strtoupper(trim($type));
|
|||
if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'), TRUE))
|
|||
{
|
|||
$type = '';
|
|||
}
|
|||
else
|
|||
{
|
|||
$type .= ' ';
|
|||
}
|
|||
}
|
|||
$cond = array();
|
|||
$keys = is_array($key) ? $key : array($key => $value);
|
|||
foreach ($keys as $key => $value)
|
|||
{
|
|||
$key = (strpos($key, '.') !== FALSE) ? $this->config['table_prefix'].$key : $key;
|
|||
if (is_string($value))
|
|||
{
|
|||
// Only escape if it's a string
|
|||
$value = $this->driver->escape_column($this->config['table_prefix'].$value);
|
|||
}
|
|||
$cond[] = $this->driver->where($key, $value, 'AND ', count($cond), FALSE);
|
|||
}
|
|||
if ( ! is_array($this->join))
|
|||
{
|
|||
$this->join = array();
|
|||
}
|
|||
if ( ! is_array($table))
|
|||
{
|
|||
$table = array($table);
|
|||
}
|
|||
foreach ($table as $t)
|
|||
{
|
|||
if (is_string($t))
|
|||
{
|
|||
// TODO: Temporary solution, this should be moved to database driver (AS is checked for twice)
|
|||
if (stripos($t, ' AS ') !== FALSE)
|
|||
{
|
|||
$t = str_ireplace(' AS ', ' AS ', $t);
|
|||
list($table, $alias) = explode(' AS ', $t);
|
|||
// Attach prefix to both sides of the AS
|
|||
$t = $this->config['table_prefix'].$table.' AS '.$this->config['table_prefix'].$alias;
|
|||
}
|
|||
else
|
|||
{
|
|||
$t = $this->config['table_prefix'].$t;
|
|||
}
|
|||
}
|
|||
$join['tables'][] = $this->driver->escape_column($t);
|
|||
}
|
|||
$join['conditions'] = '('.trim(implode(' ', $cond)).')';
|
|||
$join['type'] = $type;
|
|||
$this->join[] = $join;
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the where(s) for a database query.
|
|||
*
|
|||
* @param string|array key name or array of key => value pairs
|
|||
* @param string value to match with key
|
|||
* @param boolean disable quoting of WHERE clause
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function where($key, $value = NULL, $quote = TRUE)
|
|||
{
|
|||
$quote = (func_num_args() < 2 AND ! is_array($key)) ? -1 : $quote;
|
|||
if (is_object($key))
|
|||
{
|
|||
$keys = array((string) $key => '');
|
|||
}
|
|||
elseif ( ! is_array($key))
|
|||
{
|
|||
$keys = array($key => $value);
|
|||
}
|
|||
else
|
|||
{
|
|||
$keys = $key;
|
|||
}
|
|||
foreach ($keys as $key => $value)
|
|||
{
|
|||
$key = (strpos($key, '.') !== FALSE) ? $this->config['table_prefix'].$key : $key;
|
|||
$this->where[] = $this->driver->where($key, $value, 'AND ', count($this->where), $quote);
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the or where(s) for a database query.
|
|||
*
|
|||
* @param string|array key name or array of key => value pairs
|
|||
* @param string value to match with key
|
|||
* @param boolean disable quoting of WHERE clause
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function orwhere($key, $value = NULL, $quote = TRUE)
|
|||
{
|
|||
$quote = (func_num_args() < 2 AND ! is_array($key)) ? -1 : $quote;
|
|||
if (is_object($key))
|
|||
{
|
|||
$keys = array((string) $key => '');
|
|||
}
|
|||
elseif ( ! is_array($key))
|
|||
{
|
|||
$keys = array($key => $value);
|
|||
}
|
|||
else
|
|||
{
|
|||
$keys = $key;
|
|||
}
|
|||
foreach ($keys as $key => $value)
|
|||
{
|
|||
$key = (strpos($key, '.') !== FALSE) ? $this->config['table_prefix'].$key : $key;
|
|||
$this->where[] = $this->driver->where($key, $value, 'OR ', count($this->where), $quote);
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the like(s) for a database query.
|
|||
*
|
|||
* @param string|array field name or array of field => match pairs
|
|||
* @param string like value to match with field
|
|||
* @param boolean automatically add starting and ending wildcards
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function like($field, $match = '', $auto = TRUE)
|
|||
{
|
|||
$fields = is_array($field) ? $field : array($field => $match);
|
|||
foreach ($fields as $field => $match)
|
|||
{
|
|||
$field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field;
|
|||
$this->where[] = $this->driver->like($field, $match, $auto, 'AND ', count($this->where));
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the or like(s) for a database query.
|
|||
*
|
|||
* @param string|array field name or array of field => match pairs
|
|||
* @param string like value to match with field
|
|||
* @param boolean automatically add starting and ending wildcards
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function orlike($field, $match = '', $auto = TRUE)
|
|||
{
|
|||
$fields = is_array($field) ? $field : array($field => $match);
|
|||
foreach ($fields as $field => $match)
|
|||
{
|
|||
$field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field;
|
|||
$this->where[] = $this->driver->like($field, $match, $auto, 'OR ', count($this->where));
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the not like(s) for a database query.
|
|||
*
|
|||
* @param string|array field name or array of field => match pairs
|
|||
* @param string like value to match with field
|
|||
* @param boolean automatically add starting and ending wildcards
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function notlike($field, $match = '', $auto = TRUE)
|
|||
{
|
|||
$fields = is_array($field) ? $field : array($field => $match);
|
|||
foreach ($fields as $field => $match)
|
|||
{
|
|||
$field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field;
|
|||
$this->where[] = $this->driver->notlike($field, $match, $auto, 'AND ', count($this->where));
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the or not like(s) for a database query.
|
|||
*
|
|||
* @param string|array field name or array of field => match pairs
|
|||
* @param string like value to match with field
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function ornotlike($field, $match = '', $auto = TRUE)
|
|||
{
|
|||
$fields = is_array($field) ? $field : array($field => $match);
|
|||
foreach ($fields as $field => $match)
|
|||
{
|
|||
$field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field;
|
|||
$this->where[] = $this->driver->notlike($field, $match, $auto, 'OR ', count($this->where));
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the like(s) for a database query.
|
|||
*
|
|||
* @param string|array field name or array of field => match pairs
|
|||
* @param string like value to match with field
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function regex($field, $match = '')
|
|||
{
|
|||
$fields = is_array($field) ? $field : array($field => $match);
|
|||
foreach ($fields as $field => $match)
|
|||
{
|
|||
$field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field;
|
|||
$this->where[] = $this->driver->regex($field, $match, 'AND ', count($this->where));
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the or like(s) for a database query.
|
|||
*
|
|||
* @param string|array field name or array of field => match pairs
|
|||
* @param string like value to match with field
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function orregex($field, $match = '')
|
|||
{
|
|||
$fields = is_array($field) ? $field : array($field => $match);
|
|||
foreach ($fields as $field => $match)
|
|||
{
|
|||
$field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field;
|
|||
$this->where[] = $this->driver->regex($field, $match, 'OR ', count($this->where));
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the not regex(s) for a database query.
|
|||
*
|
|||
* @param string|array field name or array of field => match pairs
|
|||
* @param string regex value to match with field
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function notregex($field, $match = '')
|
|||
{
|
|||
$fields = is_array($field) ? $field : array($field => $match);
|
|||
foreach ($fields as $field => $match)
|
|||
{
|
|||
$field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field;
|
|||
$this->where[] = $this->driver->notregex($field, $match, 'AND ', count($this->where));
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the or not regex(s) for a database query.
|
|||
*
|
|||
* @param string|array field name or array of field => match pairs
|
|||
* @param string regex value to match with field
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function ornotregex($field, $match = '')
|
|||
{
|
|||
$fields = is_array($field) ? $field : array($field => $match);
|
|||
foreach ($fields as $field => $match)
|
|||
{
|
|||
$field = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field;
|
|||
$this->where[] = $this->driver->notregex($field, $match, 'OR ', count($this->where));
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Chooses the column to group by in a select query.
|
|||
*
|
|||
* @param string column name to group by
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function groupby($by)
|
|||
{
|
|||
if ( ! is_array($by))
|
|||
{
|
|||
$by = explode(',', (string) $by);
|
|||
}
|
|||
foreach ($by as $val)
|
|||
{
|
|||
$val = trim($val);
|
|||
if ($val != '')
|
|||
{
|
|||
// Add the table prefix if we are using table.column names
|
|||
if(strpos($val, '.'))
|
|||
{
|
|||
$val = $this->config['table_prefix'].$val;
|
|||
}
|
|||
$this->groupby[] = $this->driver->escape_column($val);
|
|||
}
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the having(s) for a database query.
|
|||
*
|
|||
* @param string|array key name or array of key => value pairs
|
|||
* @param string value to match with key
|
|||
* @param boolean disable quoting of WHERE clause
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function having($key, $value = '', $quote = TRUE)
|
|||
{
|
|||
$this->having[] = $this->driver->where($key, $value, 'AND', count($this->having), TRUE);
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the or having(s) for a database query.
|
|||
*
|
|||
* @param string|array key name or array of key => value pairs
|
|||
* @param string value to match with key
|
|||
* @param boolean disable quoting of WHERE clause
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function orhaving($key, $value = '', $quote = TRUE)
|
|||
{
|
|||
$this->having[] = $this->driver->where($key, $value, 'OR', count($this->having), TRUE);
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Chooses which column(s) to order the select query by.
|
|||
*
|
|||
* @param string|array column(s) to order on, can be an array, single column, or comma seperated list of columns
|
|||
* @param string direction of the order
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function orderby($orderby, $direction = NULL)
|
|||
{
|
|||
if ( ! is_array($orderby))
|
|||
{
|
|||
$orderby = array($orderby => $direction);
|
|||
}
|
|||
foreach ($orderby as $column => $direction)
|
|||
{
|
|||
$direction = strtoupper(trim($direction));
|
|||
// Add a direction if the provided one isn't valid
|
|||
if ( ! in_array($direction, array('ASC', 'DESC', 'RAND()', 'RANDOM()', 'NULL')))
|
|||
{
|
|||
$direction = 'ASC';
|
|||
}
|
|||
// Add the table prefix if a table.column was passed
|
|||
if (strpos($column, '.'))
|
|||
{
|
|||
$column = $this->config['table_prefix'].$column;
|
|||
}
|
|||
$this->orderby[] = $this->driver->escape_column($column).' '.$direction;
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Selects the limit section of a query.
|
|||
*
|
|||
* @param integer number of rows to limit result to
|
|||
* @param integer offset in result to start returning rows from
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function limit($limit, $offset = NULL)
|
|||
{
|
|||
$this->limit = (int) $limit;
|
|||
if ($offset !== NULL OR ! is_int($this->offset))
|
|||
{
|
|||
$this->offset($offset);
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Sets the offset portion of a query.
|
|||
*
|
|||
* @param integer offset value
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function offset($value)
|
|||
{
|
|||
$this->offset = (int) $value;
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Allows key/value pairs to be set for inserting or updating.
|
|||
*
|
|||
* @param string|array key name or array of key => value pairs
|
|||
* @param string value to match with key
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function set($key, $value = '')
|
|||
{
|
|||
if ( ! is_array($key))
|
|||
{
|
|||
$key = array($key => $value);
|
|||
}
|
|||
foreach ($key as $k => $v)
|
|||
{
|
|||
// Add a table prefix if the column includes the table.
|
|||
if (strpos($k, '.'))
|
|||
$k = $this->config['table_prefix'].$k;
|
|||
$this->set[$k] = $this->driver->escape($v);
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Compiles the select statement based on the other functions called and runs the query.
|
|||
*
|
|||
* @param string table name
|
|||
* @param string limit clause
|
|||
* @param string offset clause
|
|||
* @return Database_Result
|
|||
*/
|
|||
public function get($table = '', $limit = NULL, $offset = NULL)
|
|||
{
|
|||
if ($table != '')
|
|||
{
|
|||
$this->from($table);
|
|||
}
|
|||
if ( ! is_null($limit))
|
|||
{
|
|||
$this->limit($limit, $offset);
|
|||
}
|
|||
$sql = $this->driver->compile_select(get_object_vars($this));
|
|||
$this->reset_select();
|
|||
$result = $this->query($sql);
|
|||
$this->last_query = $sql;
|
|||
return $result;
|
|||
}
|
|||
/**
|
|||
* Compiles the select statement based on the other functions called and runs the query.
|
|||
*
|
|||
* @param string table name
|
|||
* @param array where clause
|
|||
* @param string limit clause
|
|||
* @param string offset clause
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function getwhere($table = '', $where = NULL, $limit = NULL, $offset = NULL)
|
|||
{
|
|||
if ($table != '')
|
|||
{
|
|||
$this->from($table);
|
|||
}
|
|||
if ( ! is_null($where))
|
|||
{
|
|||
$this->where($where);
|
|||
}
|
|||
if ( ! is_null($limit))
|
|||
{
|
|||
$this->limit($limit, $offset);
|
|||
}
|
|||
$sql = $this->driver->compile_select(get_object_vars($this));
|
|||
$this->reset_select();
|
|||
$result = $this->query($sql);
|
|||
return $result;
|
|||
}
|
|||
/**
|
|||
* Compiles the select statement based on the other functions called and returns the query string.
|
|||
*
|
|||
* @param string table name
|
|||
* @param string limit clause
|
|||
* @param string offset clause
|
|||
* @return string sql string
|
|||
*/
|
|||
public function compile($table = '', $limit = NULL, $offset = NULL)
|
|||
{
|
|||
if ($table != '')
|
|||
{
|
|||
$this->from($table);
|
|||
}
|
|||
if ( ! is_null($limit))
|
|||
{
|
|||
$this->limit($limit, $offset);
|
|||
}
|
|||
$sql = $this->driver->compile_select(get_object_vars($this));
|
|||
$this->reset_select();
|
|||
return $sql;
|
|||
}
|
|||
/**
|
|||
* Compiles an insert string and runs the query.
|
|||
*
|
|||
* @param string table name
|
|||
* @param array array of key/value pairs to insert
|
|||
* @return Database_Result Query result
|
|||
*/
|
|||
public function insert($table = '', $set = NULL)
|
|||
{
|
|||
if ( ! is_null($set))
|
|||
{
|
|||
$this->set($set);
|
|||
}
|
|||
if ($this->set == NULL)
|
|||
throw new Kohana_Database_Exception('database.must_use_set');
|
|||
if ($table == '')
|
|||
{
|
|||
if ( ! isset($this->from[0]))
|
|||
throw new Kohana_Database_Exception('database.must_use_table');
|
|||
$table = $this->from[0];
|
|||
}
|
|||
// If caching is enabled, clear the cache before inserting
|
|||
($this->config['cache'] === TRUE) and $this->clear_cache();
|
|||
$sql = $this->driver->insert($this->config['table_prefix'].$table, array_keys($this->set), array_values($this->set));
|
|||
$this->reset_write();
|
|||
return $this->query($sql);
|
|||
}
|
|||
/**
|
|||
* Adds an "IN" condition to the where clause
|
|||
*
|
|||
* @param string Name of the column being examined
|
|||
* @param mixed An array or string to match against
|
|||
* @param bool Generate a NOT IN clause instead
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function in($field, $values, $not = FALSE)
|
|||
{
|
|||
if (is_array($values))
|
|||
{
|
|||
$escaped_values = array();
|
|||
foreach ($values as $v)
|
|||
{
|
|||
if (is_numeric($v))
|
|||
{
|
|||
$escaped_values[] = $v;
|
|||
}
|
|||
else
|
|||
{
|
|||
$escaped_values[] = "'".$this->driver->escape_str($v)."'";
|
|||
}
|
|||
}
|
|||
$values = implode(",", $escaped_values);
|
|||
}
|
|||
$where = $this->driver->escape_column(((strpos($field,'.') !== FALSE) ? $this->config['table_prefix'] : ''). $field).' '.($not === TRUE ? 'NOT ' : '').'IN ('.$values.')';
|
|||
$this->where[] = $this->driver->where($where, '', 'AND ', count($this->where), -1);
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Adds a "NOT IN" condition to the where clause
|
|||
*
|
|||
* @param string Name of the column being examined
|
|||
* @param mixed An array or string to match against
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function notin($field, $values)
|
|||
{
|
|||
return $this->in($field, $values, TRUE);
|
|||
}
|
|||
/**
|
|||
* Compiles a merge string and runs the query.
|
|||
*
|
|||
* @param string table name
|
|||
* @param array array of key/value pairs to merge
|
|||
* @return Database_Result Query result
|
|||
*/
|
|||
public function merge($table = '', $set = NULL)
|
|||
{
|
|||
if ( ! is_null($set))
|
|||
{
|
|||
$this->set($set);
|
|||
}
|
|||
if ($this->set == NULL)
|
|||
throw new Kohana_Database_Exception('database.must_use_set');
|
|||
if ($table == '')
|
|||
{
|
|||
if ( ! isset($this->from[0]))
|
|||
throw new Kohana_Database_Exception('database.must_use_table');
|
|||
$table = $this->from[0];
|
|||
}
|
|||
$sql = $this->driver->merge($this->config['table_prefix'].$table, array_keys($this->set), array_values($this->set));
|
|||
$this->reset_write();
|
|||
return $this->query($sql);
|
|||
}
|
|||
/**
|
|||
* Compiles an update string and runs the query.
|
|||
*
|
|||
* @param string table name
|
|||
* @param array associative array of update values
|
|||
* @param array where clause
|
|||
* @return Database_Result Query result
|
|||
*/
|
|||
public function update($table = '', $set = NULL, $where = NULL)
|
|||
{
|
|||
if ( is_array($set))
|
|||
{
|
|||
$this->set($set);
|
|||
}
|
|||
if ( ! is_null($where))
|
|||
{
|
|||
$this->where($where);
|
|||
}
|
|||
if ($this->set == FALSE)
|
|||
throw new Kohana_Database_Exception('database.must_use_set');
|
|||
if ($table == '')
|
|||
{
|
|||
if ( ! isset($this->from[0]))
|
|||
throw new Kohana_Database_Exception('database.must_use_table');
|
|||
$table = $this->from[0];
|
|||
}
|
|||
$sql = $this->driver->update($this->config['table_prefix'].$table, $this->set, $this->where);
|
|||
$this->reset_write();
|
|||
return $this->query($sql);
|
|||
}
|
|||
/**
|
|||
* Compiles a delete string and runs the query.
|
|||
*
|
|||
* @param string table name
|
|||
* @param array where clause
|
|||
* @return Database_Result Query result
|
|||
*/
|
|||
public function delete($table = '', $where = NULL)
|
|||
{
|
|||
if ($table == '')
|
|||
{
|
|||
if ( ! isset($this->from[0]))
|
|||
throw new Kohana_Database_Exception('database.must_use_table');
|
|||
$table = $this->from[0];
|
|||
}
|
|||
else
|
|||
{
|
|||
$table = $this->config['table_prefix'].$table;
|
|||
}
|
|||
if (! is_null($where))
|
|||
{
|
|||
$this->where($where);
|
|||
}
|
|||
if (count($this->where) < 1)
|
|||
throw new Kohana_Database_Exception('database.must_use_where');
|
|||
$sql = $this->driver->delete($table, $this->where);
|
|||
$this->reset_write();
|
|||
return $this->query($sql);
|
|||
}
|
|||
/**
|
|||
* Returns the last query run.
|
|||
*
|
|||
* @return string SQL
|
|||
*/
|
|||
public function last_query()
|
|||
{
|
|||
return $this->last_query;
|
|||
}
|
|||
/**
|
|||
* Count query records.
|
|||
*
|
|||
* @param string table name
|
|||
* @param array where clause
|
|||
* @return integer
|
|||
*/
|
|||
public function count_records($table = FALSE, $where = NULL)
|
|||
{
|
|||
if (count($this->from) < 1)
|
|||
{
|
|||
if ($table == FALSE)
|
|||
throw new Kohana_Database_Exception('database.must_use_table');
|
|||
$this->from($table);
|
|||
}
|
|||
if ($where !== NULL)
|
|||
{
|
|||
$this->where($where);
|
|||
}
|
|||
$query = $this->select('COUNT(*) AS '.$this->escape_column('records_found'))->get()->result(TRUE);
|
|||
return (int) $query->current()->records_found;
|
|||
}
|
|||
/**
|
|||
* Resets all private select variables.
|
|||
*
|
|||
* @return void
|
|||
*/
|
|||
protected function reset_select()
|
|||
{
|
|||
$this->select = array();
|
|||
$this->from = array();
|
|||
$this->join = array();
|
|||
$this->where = array();
|
|||
$this->orderby = array();
|
|||
$this->groupby = array();
|
|||
$this->having = array();
|
|||
$this->distinct = FALSE;
|
|||
$this->limit = FALSE;
|
|||
$this->offset = FALSE;
|
|||
}
|
|||
/**
|
|||
* Resets all private insert and update variables.
|
|||
*
|
|||
* @return void
|
|||
*/
|
|||
protected function reset_write()
|
|||
{
|
|||
$this->set = array();
|
|||
$this->from = array();
|
|||
$this->where = array();
|
|||
}
|
|||
/**
|
|||
* Lists all the tables in the current database.
|
|||
*
|
|||
* @return array
|
|||
*/
|
|||
public function list_tables()
|
|||
{
|
|||
$this->link or $this->connect();
|
|||
return $this->driver->list_tables();
|
|||
}
|
|||
/**
|
|||
* See if a table exists in the database.
|
|||
*
|
|||
* @param string table name
|
|||
* @param boolean True to attach table prefix
|
|||
* @return boolean
|
|||
*/
|
|||
public function table_exists($table_name, $prefix = TRUE)
|
|||
{
|
|||
if ($prefix)
|
|||
return in_array($this->config['table_prefix'].$table_name, $this->list_tables());
|
|||
else
|
|||
return in_array($table_name, $this->list_tables());
|
|||
}
|
|||
/**
|
|||
* Combine a SQL statement with the bind values. Used for safe queries.
|
|||
*
|
|||
* @param string query to bind to the values
|
|||
* @param array array of values to bind to the query
|
|||
* @return string
|
|||
*/
|
|||
public function compile_binds($sql, $binds)
|
|||
{
|
|||
foreach ((array) $binds as $val)
|
|||
{
|
|||
// If the SQL contains no more bind marks ("?"), we're done.
|
|||
if (($next_bind_pos = strpos($sql, '?')) === FALSE)
|
|||
break;
|
|||
// Properly escape the bind value.
|
|||
$val = $this->driver->escape($val);
|
|||
// Temporarily replace possible bind marks ("?"), in the bind value itself, with a placeholder.
|
|||
$val = str_replace('?', '{%B%}', $val);
|
|||
// Replace the first bind mark ("?") with its corresponding value.
|
|||
$sql = substr($sql, 0, $next_bind_pos).$val.substr($sql, $next_bind_pos + 1);
|
|||
}
|
|||
// Restore placeholders.
|
|||
return str_replace('{%B%}', '?', $sql);
|
|||
}
|
|||
/**
|
|||
* Get the field data for a database table, along with the field's attributes.
|
|||
*
|
|||
* @param string table name
|
|||
* @return array
|
|||
*/
|
|||
public function field_data($table = '')
|
|||
{
|
|||
$this->link or $this->connect();
|
|||
return $this->driver->field_data($this->config['table_prefix'].$table);
|
|||
}
|
|||
/**
|
|||
* Get the field data for a database table, along with the field's attributes.
|
|||
*
|
|||
* @param string table name
|
|||
* @return array
|
|||
*/
|
|||
public function list_fields($table = '')
|
|||
{
|
|||
$this->link or $this->connect();
|
|||
return $this->driver->list_fields($this->config['table_prefix'].$table);
|
|||
}
|
|||
/**
|
|||
* Escapes a value for a query.
|
|||
*
|
|||
* @param mixed value to escape
|
|||
* @return string
|
|||
*/
|
|||
public function escape($value)
|
|||
{
|
|||
return $this->driver->escape($value);
|
|||
}
|
|||
/**
|
|||
* Escapes a string for a query.
|
|||
*
|
|||
* @param string string to escape
|
|||
* @return string
|
|||
*/
|
|||
public function escape_str($str)
|
|||
{
|
|||
return $this->driver->escape_str($str);
|
|||
}
|
|||
/**
|
|||
* Escapes a table name for a query.
|
|||
*
|
|||
* @param string string to escape
|
|||
* @return string
|
|||
*/
|
|||
public function escape_table($table)
|
|||
{
|
|||
return $this->driver->escape_table($table);
|
|||
}
|
|||
/**
|
|||
* Escapes a column name for a query.
|
|||
*
|
|||
* @param string string to escape
|
|||
* @return string
|
|||
*/
|
|||
public function escape_column($table)
|
|||
{
|
|||
return $this->driver->escape_column($table);
|
|||
}
|
|||
/**
|
|||
* Returns table prefix of current configuration.
|
|||
*
|
|||
* @return string
|
|||
*/
|
|||
public function table_prefix()
|
|||
{
|
|||
return $this->config['table_prefix'];
|
|||
}
|
|||
/**
|
|||
* Clears the query cache.
|
|||
*
|
|||
* @param string|TRUE clear cache by SQL statement or TRUE for last query
|
|||
* @return Database This Database object.
|
|||
*/
|
|||
public function clear_cache($sql = NULL)
|
|||
{
|
|||
if ($sql === TRUE)
|
|||
{
|
|||
$this->driver->clear_cache($this->last_query);
|
|||
}
|
|||
elseif (is_string($sql))
|
|||
{
|
|||
$this->driver->clear_cache($sql);
|
|||
}
|
|||
else
|
|||
{
|
|||
$this->driver->clear_cache();
|
|||
}
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Pushes existing query space onto the query stack. Use push
|
|||
* and pop to prevent queries from clashing before they are
|
|||
* executed
|
|||
*
|
|||
* @return Database This Databaes object
|
|||
*/
|
|||
public function push()
|
|||
{
|
|||
array_push($this->query_history, array(
|
|||
$this->select,
|
|||
$this->from,
|
|||
$this->join,
|
|||
$this->where,
|
|||
$this->orderby,
|
|||
$this->order,
|
|||
$this->groupby,
|
|||
$this->having,
|
|||
$this->distinct,
|
|||
$this->limit,
|
|||
$this->offset
|
|||
));
|
|||
$this->reset_select();
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Pops from query stack into the current query space.
|
|||
*
|
|||
* @return Database This Databaes object
|
|||
*/
|
|||
public function pop()
|
|||
{
|
|||
if (count($this->query_history) == 0)
|
|||
{
|
|||
// No history
|
|||
return $this;
|
|||
}
|
|||
list(
|
|||
$this->select,
|
|||
$this->from,
|
|||
$this->join,
|
|||
$this->where,
|
|||
$this->orderby,
|
|||
$this->order,
|
|||
$this->groupby,
|
|||
$this->having,
|
|||
$this->distinct,
|
|||
$this->limit,
|
|||
$this->offset
|
|||
) = array_pop($this->query_history);
|
|||
return $this;
|
|||
}
|
|||
/**
|
|||
* Count the number of records in the last query, without LIMIT or OFFSET applied.
|
|||
*
|
|||
* @return integer
|
|||
*/
|
|||
public function count_last_query()
|
|||
{
|
|||
if ($sql = $this->last_query())
|
|||
{
|
|||
if (stripos($sql, 'LIMIT') !== FALSE)
|
|||
{
|
|||
// Remove LIMIT from the SQL
|
|||
$sql = preg_replace('/\sLIMIT\s+[^a-z]+/i', ' ', $sql);
|
|||
}
|
|||
if (stripos($sql, 'OFFSET') !== FALSE)
|
|||
{
|
|||
// Remove OFFSET from the SQL
|
|||
$sql = preg_replace('/\sOFFSET\s+\d+/i', '', $sql);
|
|||
}
|
|||
// Get the total rows from the last query executed
|
|||
$result = $this->query
|
|||
(
|
|||
'SELECT COUNT(*) AS '.$this->escape_column('total_rows').' '.
|
|||
'FROM ('.trim($sql).') AS '.$this->escape_table('counted_results')
|
|||
);
|
|||
// Return the total number of rows from the query
|
|||
return (int) $result->current()->total_rows;
|
|||
}
|
|||
return FALSE;
|
|||
}
|
|||
18ac9009 | Ondřej Fibich | ||
8baed187 | Michal Kliment | /**
|
|
* Sets benchmark on or off
|
|||
*
|
|||
* @author Ondřej Fibich
|
|||
18ac9009 | Ondřej Fibich | * @param boolean $is_on
|
|
8baed187 | Michal Kliment | */
|
|
public function set_benchmark($is_on)
|
|||
{
|
|||
$this->config['benchmark'] = ($is_on === TRUE);
|
|||
}
|
|||
18ac9009 | Ondřej Fibich | ||
c1bdc1c4 | Michal Kliment | /**
|
|
* Gets value of database variable. If variable not present in the database
|
|||
* NULL is returned.
|
|||
18ac9009 | Ondřej Fibich | *
|
|
c1bdc1c4 | Michal Kliment | * @author Ondřej Fibich
|
|
* @param string $name Variable name
|
|||
* @return string|null
|
|||
*/
|
|||
public function get_variable_value($name)
|
|||
{
|
|||
$result = $this->query("SHOW VARIABLES LIKE ?", $name);
|
|||
18ac9009 | Ondřej Fibich | ||
c1bdc1c4 | Michal Kliment | if ($result->count() == 1)
|
|
{
|
|||
$o = $result->current();
|
|||
18ac9009 | Ondřej Fibich | ||
c1bdc1c4 | Michal Kliment | if (isset($o->Value))
|
|
{
|
|||
return $o->Value;
|
|||
}
|
|||
}
|
|||
18ac9009 | Ondřej Fibich | ||
c1bdc1c4 | Michal Kliment | return NULL;
|
|
}
|
|||
18ac9009 | Ondřej Fibich | ||
c1bdc1c4 | Michal Kliment | /**
|
|
* Alterch character set amd collate of database to given values.
|
|||
18ac9009 | Ondřej Fibich | *
|
|
c1bdc1c4 | Michal Kliment | * @author Ondřej Fibich
|
|
* @param string $db_name Database name
|
|||
* @param string $set Character set name
|
|||
* @param string $collate Collate name
|
|||
*/
|
|||
public function alter_db_character_set($db_name, $set, $collate)
|
|||
{
|
|||
$db_name = $this->escape_table($db_name);
|
|||
18ac9009 | Ondřej Fibich | ||
c1bdc1c4 | Michal Kliment | $this->query("ALTER DATABASE $db_name DEFAULT CHARACTER SET ? COLLATE ?", array
|
|
(
|
|||
$set, $collate
|
|||
));
|
|||
}
|
|||
8baed187 | Michal Kliment | ||
18ac9009 | Ondřej Fibich | /**
|
|
* Truncate DB table name.
|
|||
*
|
|||
* @author Ondřej Fibich <fibich@freenetis.org>
|
|||
* @since 1.2
|
|||
*
|
|||
* @param string $table_name
|
|||
*/
|
|||
public function truncate($table_name)
|
|||
{
|
|||
$esc_table_name = $this->escape_table($table_name);
|
|||
$this->query("TRUNCATE TABLE $esc_table_name");
|
|||
}
|
|||
/**
|
|||
* Drop DB table name.
|
|||
*
|
|||
* @author Ondřej Fibich <fibich@freenetis.org>
|
|||
* @since 1.2
|
|||
*
|
|||
* @param string $table_name
|
|||
*/
|
|||
public function drop($table_name)
|
|||
{
|
|||
$esc_table_name = $this->escape_table($table_name);
|
|||
$this->query("DROP TABLE $esc_table_name");
|
|||
}
|
|||
/**
|
|||
* Enable/disable foreign key checks.
|
|||
*
|
|||
* @author Ondřej Fibich <fibich@freenetis.org>
|
|||
* @since 1.2.0
|
|||
*
|
|||
* @param boolean $enabled flag
|
|||
*/
|
|||
public function foreign_key_check($enabled)
|
|||
{
|
|||
$enabled_num = $enabled ? 1 : 0;
|
|||
$this->query("SET FOREIGN_KEY_CHECKS = $enabled_num");
|
|||
}
|
|||
8baed187 | Michal Kliment | } // End Database Class
|
|
/**
|
|||
* Sets the code for a Database exception.
|
|||
*/
|
|||
class Kohana_Database_Exception extends Kohana_Exception {
|
|||
protected $code = E_DATABASE_ERROR;
|
|||
8d90cc7c | Ondřej Fibich | } // End Kohana Database Exception
|