Added KH 3.3.0

This commit is contained in:
Deon George
2013-03-19 14:39:17 +11:00
parent 715f7efe9b
commit 2e134ea609
1283 changed files with 145138 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Database exceptions.
*
* @package Kohana/Database
* @category Exceptions
* @author Kohana Team
* @copyright (c) 2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_Exception extends Kohana_Exception {}

View File

@@ -0,0 +1,138 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Database expressions can be used to add unescaped SQL fragments to a
* [Database_Query_Builder] object.
*
* For example, you can use an expression to generate a column alias:
*
* // SELECT CONCAT(first_name, last_name) AS full_name
* $query = DB::select(array(DB::expr('CONCAT(first_name, last_name)'), 'full_name')));
*
* More examples are available on the [Query Builder](database/query/builder#database-expressions) page
*
* @package Kohana/Database
* @category Base
* @author Kohana Team
* @copyright (c) 2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_Expression {
// Unquoted parameters
protected $_parameters;
// Raw expression string
protected $_value;
/**
* Sets the expression string.
*
* $expression = new Database_Expression('COUNT(users.id)');
*
* @param string $value raw SQL expression string
* @param array $parameters unquoted parameter values
* @return void
*/
public function __construct($value, $parameters = array())
{
// Set the expression string
$this->_value = $value;
$this->_parameters = $parameters;
}
/**
* Bind a variable to a parameter.
*
* @param string $param parameter key to replace
* @param mixed $var variable to use
* @return $this
*/
public function bind($param, & $var)
{
$this->_parameters[$param] =& $var;
return $this;
}
/**
* Set the value of a parameter.
*
* @param string $param parameter key to replace
* @param mixed $value value to use
* @return $this
*/
public function param($param, $value)
{
$this->_parameters[$param] = $value;
return $this;
}
/**
* Add multiple parameter values.
*
* @param array $params list of parameter values
* @return $this
*/
public function parameters(array $params)
{
$this->_parameters = $params + $this->_parameters;
return $this;
}
/**
* Get the expression value as a string.
*
* $sql = $expression->value();
*
* @return string
*/
public function value()
{
return (string) $this->_value;
}
/**
* Return the value of the expression as a string.
*
* echo $expression;
*
* @return string
* @uses Database_Expression::value
*/
public function __toString()
{
return $this->value();
}
/**
* Compile the SQL expression and return it. Replaces any parameters with
* their given values.
*
* @param mixed Database instance or name of instance
* @return string
*/
public function compile($db = NULL)
{
if ( ! is_object($db))
{
// Get the database instance
$db = Database::instance($db);
}
$value = $this->value();
if ( ! empty($this->_parameters))
{
// Quote all of the parameter values
$params = array_map(array($db, 'quote'), $this->_parameters);
// Replace the values in the expression
$value = strtr($value, $params);
}
return $value;
}
} // End Database_Expression

View File

@@ -0,0 +1,443 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* MySQL database connection.
*
* @package Kohana/Database
* @category Drivers
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_MySQL extends Database {
// Database in use by each connection
protected static $_current_databases = array();
// Use SET NAMES to set the character set
protected static $_set_names;
// Identifier for this connection within the PHP driver
protected $_connection_id;
// MySQL uses a backtick for identifiers
protected $_identifier = '`';
public function connect()
{
if ($this->_connection)
return;
if (Database_MySQL::$_set_names === NULL)
{
// Determine if we can use mysql_set_charset(), which is only
// available on PHP 5.2.3+ when compiled against MySQL 5.0+
Database_MySQL::$_set_names = ! function_exists('mysql_set_charset');
}
// Extract the connection parameters, adding required variabels
extract($this->_config['connection'] + array(
'database' => '',
'hostname' => '',
'username' => '',
'password' => '',
'persistent' => FALSE,
));
// Prevent this information from showing up in traces
unset($this->_config['connection']['username'], $this->_config['connection']['password']);
try
{
if ($persistent)
{
// Create a persistent connection
$this->_connection = mysql_pconnect($hostname, $username, $password);
}
else
{
// Create a connection and force it to be a new link
$this->_connection = mysql_connect($hostname, $username, $password, TRUE);
}
}
catch (Exception $e)
{
// No connection exists
$this->_connection = NULL;
throw new Database_Exception(':error',
array(':error' => $e->getMessage()),
$e->getCode());
}
// \xFF is a better delimiter, but the PHP driver uses underscore
$this->_connection_id = sha1($hostname.'_'.$username.'_'.$password);
$this->_select_db($database);
if ( ! empty($this->_config['charset']))
{
// Set the character set
$this->set_charset($this->_config['charset']);
}
if ( ! empty($this->_config['connection']['variables']))
{
// Set session variables
$variables = array();
foreach ($this->_config['connection']['variables'] as $var => $val)
{
$variables[] = 'SESSION '.$var.' = '.$this->quote($val);
}
mysql_query('SET '.implode(', ', $variables), $this->_connection);
}
}
/**
* Select the database
*
* @param string $database Database
* @return void
*/
protected function _select_db($database)
{
if ( ! mysql_select_db($database, $this->_connection))
{
// Unable to select database
throw new Database_Exception(':error',
array(':error' => mysql_error($this->_connection)),
mysql_errno($this->_connection));
}
Database_MySQL::$_current_databases[$this->_connection_id] = $database;
}
public function disconnect()
{
try
{
// Database is assumed disconnected
$status = TRUE;
if (is_resource($this->_connection))
{
if ($status = mysql_close($this->_connection))
{
// Clear the connection
$this->_connection = NULL;
// Clear the instance
parent::disconnect();
}
}
}
catch (Exception $e)
{
// Database is probably not disconnected
$status = ! is_resource($this->_connection);
}
return $status;
}
public function set_charset($charset)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if (Database_MySQL::$_set_names === TRUE)
{
// PHP is compiled against MySQL 4.x
$status = (bool) mysql_query('SET NAMES '.$this->quote($charset), $this->_connection);
}
else
{
// PHP is compiled against MySQL 5.x
$status = mysql_set_charset($charset, $this->_connection);
}
if ($status === FALSE)
{
throw new Database_Exception(':error',
array(':error' => mysql_error($this->_connection)),
mysql_errno($this->_connection));
}
}
public function query($type, $sql, $as_object = FALSE, array $params = NULL)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if (Kohana::$profiling)
{
// Benchmark this query for the current instance
$benchmark = Profiler::start("Database ({$this->_instance})", $sql);
}
if ( ! empty($this->_config['connection']['persistent']) AND $this->_config['connection']['database'] !== Database_MySQL::$_current_databases[$this->_connection_id])
{
// Select database on persistent connections
$this->_select_db($this->_config['connection']['database']);
}
// Execute the query
if (($result = mysql_query($sql, $this->_connection)) === FALSE)
{
if (isset($benchmark))
{
// This benchmark is worthless
Profiler::delete($benchmark);
}
throw new Database_Exception(':error [ :query ]',
array(':error' => mysql_error($this->_connection), ':query' => $sql),
mysql_errno($this->_connection));
}
if (isset($benchmark))
{
Profiler::stop($benchmark);
}
// Set the last query
$this->last_query = $sql;
if ($type === Database::SELECT)
{
// Return an iterator of results
return new Database_MySQL_Result($result, $sql, $as_object, $params);
}
elseif ($type === Database::INSERT)
{
// Return a list of insert id and rows created
return array(
mysql_insert_id($this->_connection),
mysql_affected_rows($this->_connection),
);
}
else
{
// Return the number of rows affected
return mysql_affected_rows($this->_connection);
}
}
public function datatype($type)
{
static $types = array
(
'blob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '65535'),
'bool' => array('type' => 'bool'),
'bigint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '18446744073709551615'),
'datetime' => array('type' => 'string'),
'decimal unsigned' => array('type' => 'float', 'exact' => TRUE, 'min' => '0'),
'double' => array('type' => 'float'),
'double precision unsigned' => array('type' => 'float', 'min' => '0'),
'double unsigned' => array('type' => 'float', 'min' => '0'),
'enum' => array('type' => 'string'),
'fixed' => array('type' => 'float', 'exact' => TRUE),
'fixed unsigned' => array('type' => 'float', 'exact' => TRUE, 'min' => '0'),
'float unsigned' => array('type' => 'float', 'min' => '0'),
'int unsigned' => array('type' => 'int', 'min' => '0', 'max' => '4294967295'),
'integer unsigned' => array('type' => 'int', 'min' => '0', 'max' => '4294967295'),
'longblob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '4294967295'),
'longtext' => array('type' => 'string', 'character_maximum_length' => '4294967295'),
'mediumblob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '16777215'),
'mediumint' => array('type' => 'int', 'min' => '-8388608', 'max' => '8388607'),
'mediumint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '16777215'),
'mediumtext' => array('type' => 'string', 'character_maximum_length' => '16777215'),
'national varchar' => array('type' => 'string'),
'numeric unsigned' => array('type' => 'float', 'exact' => TRUE, 'min' => '0'),
'nvarchar' => array('type' => 'string'),
'point' => array('type' => 'string', 'binary' => TRUE),
'real unsigned' => array('type' => 'float', 'min' => '0'),
'set' => array('type' => 'string'),
'smallint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '65535'),
'text' => array('type' => 'string', 'character_maximum_length' => '65535'),
'tinyblob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '255'),
'tinyint' => array('type' => 'int', 'min' => '-128', 'max' => '127'),
'tinyint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '255'),
'tinytext' => array('type' => 'string', 'character_maximum_length' => '255'),
'year' => array('type' => 'string'),
);
$type = str_replace(' zerofill', '', $type);
if (isset($types[$type]))
return $types[$type];
return parent::datatype($type);
}
/**
* Start a SQL transaction
*
* @link http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
*
* @param string $mode Isolation level
* @return boolean
*/
public function begin($mode = NULL)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if ($mode AND ! mysql_query("SET TRANSACTION ISOLATION LEVEL $mode", $this->_connection))
{
throw new Database_Exception(':error',
array(':error' => mysql_error($this->_connection)),
mysql_errno($this->_connection));
}
return (bool) mysql_query('START TRANSACTION', $this->_connection);
}
/**
* Commit a SQL transaction
*
* @return boolean
*/
public function commit()
{
// Make sure the database is connected
$this->_connection or $this->connect();
return (bool) mysql_query('COMMIT', $this->_connection);
}
/**
* Rollback a SQL transaction
*
* @return boolean
*/
public function rollback()
{
// Make sure the database is connected
$this->_connection or $this->connect();
return (bool) mysql_query('ROLLBACK', $this->_connection);
}
public function list_tables($like = NULL)
{
if (is_string($like))
{
// Search for table names
$result = $this->query(Database::SELECT, 'SHOW TABLES LIKE '.$this->quote($like), FALSE);
}
else
{
// Find all table names
$result = $this->query(Database::SELECT, 'SHOW TABLES', FALSE);
}
$tables = array();
foreach ($result as $row)
{
$tables[] = reset($row);
}
return $tables;
}
public function list_columns($table, $like = NULL, $add_prefix = TRUE)
{
// Quote the table name
$table = ($add_prefix === TRUE) ? $this->quote_table($table) : $table;
if (is_string($like))
{
// Search for column names
$result = $this->query(Database::SELECT, 'SHOW FULL COLUMNS FROM '.$table.' LIKE '.$this->quote($like), FALSE);
}
else
{
// Find all column names
$result = $this->query(Database::SELECT, 'SHOW FULL COLUMNS FROM '.$table, FALSE);
}
$count = 0;
$columns = array();
foreach ($result as $row)
{
list($type, $length) = $this->_parse_type($row['Type']);
$column = $this->datatype($type);
$column['column_name'] = $row['Field'];
$column['column_default'] = $row['Default'];
$column['data_type'] = $type;
$column['is_nullable'] = ($row['Null'] == 'YES');
$column['ordinal_position'] = ++$count;
switch ($column['type'])
{
case 'float':
if (isset($length))
{
list($column['numeric_precision'], $column['numeric_scale']) = explode(',', $length);
}
break;
case 'int':
if (isset($length))
{
// MySQL attribute
$column['display'] = $length;
}
break;
case 'string':
switch ($column['data_type'])
{
case 'binary':
case 'varbinary':
$column['character_maximum_length'] = $length;
break;
case 'char':
case 'varchar':
$column['character_maximum_length'] = $length;
case 'text':
case 'tinytext':
case 'mediumtext':
case 'longtext':
$column['collation_name'] = $row['Collation'];
break;
case 'enum':
case 'set':
$column['collation_name'] = $row['Collation'];
$column['options'] = explode('\',\'', substr($length, 1, -1));
break;
}
break;
}
// MySQL attributes
$column['comment'] = $row['Comment'];
$column['extra'] = $row['Extra'];
$column['key'] = $row['Key'];
$column['privileges'] = $row['Privileges'];
$columns[$row['Field']] = $column;
}
return $columns;
}
public function escape($value)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if (($value = mysql_real_escape_string( (string) $value, $this->_connection)) === FALSE)
{
throw new Database_Exception(':error',
array(':error' => mysql_error($this->_connection)),
mysql_errno($this->_connection));
}
// SQL standard is to use single-quotes for all values
return "'$value'";
}
} // End Database_MySQL

View File

@@ -0,0 +1,71 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* MySQL database result. See [Results](/database/results) for usage and examples.
*
* @package Kohana/Database
* @category Query/Result
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_MySQL_Result extends Database_Result {
protected $_internal_row = 0;
public function __construct($result, $sql, $as_object = FALSE, array $params = NULL)
{
parent::__construct($result, $sql, $as_object, $params);
// Find the number of rows in the result
$this->_total_rows = mysql_num_rows($result);
}
public function __destruct()
{
if (is_resource($this->_result))
{
mysql_free_result($this->_result);
}
}
public function seek($offset)
{
if ($this->offsetExists($offset) AND mysql_data_seek($this->_result, $offset))
{
// Set the current row to the offset
$this->_current_row = $this->_internal_row = $offset;
return TRUE;
}
else
{
return FALSE;
}
}
public function current()
{
if ($this->_current_row !== $this->_internal_row AND ! $this->seek($this->_current_row))
return NULL;
// Increment internal row for optimization assuming rows are fetched in order
$this->_internal_row++;
if ($this->_as_object === TRUE)
{
// Return an stdClass
return mysql_fetch_object($this->_result);
}
elseif (is_string($this->_as_object))
{
// Return an object of given class name
return mysql_fetch_object($this->_result, $this->_as_object, $this->_object_params);
}
else
{
// Return an array of the row
return mysql_fetch_assoc($this->_result);
}
}
} // End Database_MySQL_Result_Select

View File

@@ -0,0 +1,247 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* PDO database connection.
*
* @package Kohana/Database
* @category Drivers
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_PDO extends Database {
// PDO uses no quoting for identifiers
protected $_identifier = '';
public function __construct($name, array $config)
{
parent::__construct($name, $config);
if (isset($this->_config['identifier']))
{
// Allow the identifier to be overloaded per-connection
$this->_identifier = (string) $this->_config['identifier'];
}
}
public function connect()
{
if ($this->_connection)
return;
// Extract the connection parameters, adding required variabels
extract($this->_config['connection'] + array(
'dsn' => '',
'username' => NULL,
'password' => NULL,
'persistent' => FALSE,
));
// Clear the connection parameters for security
unset($this->_config['connection']);
// Force PDO to use exceptions for all errors
$options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
if ( ! empty($persistent))
{
// Make the connection persistent
$options[PDO::ATTR_PERSISTENT] = TRUE;
}
try
{
// Create a new PDO connection
$this->_connection = new PDO($dsn, $username, $password, $options);
}
catch (PDOException $e)
{
throw new Database_Exception(':error',
array(':error' => $e->getMessage()),
$e->getCode());
}
}
/**
* Create or redefine a SQL aggregate function.
*
* [!!] Works only with SQLite
*
* @link http://php.net/manual/function.pdo-sqlitecreateaggregate
*
* @param string $name Name of the SQL function to be created or redefined
* @param callback $step Called for each row of a result set
* @param callback $final Called after all rows of a result set have been processed
* @param integer $arguments Number of arguments that the SQL function takes
*
* @return boolean
*/
public function create_aggregate($name, $step, $final, $arguments = -1)
{
$this->_connection or $this->connect();
return $this->_connection->sqliteCreateAggregate(
$name, $step, $final, $arguments
);
}
/**
* Create or redefine a SQL function.
*
* [!!] Works only with SQLite
*
* @link http://php.net/manual/function.pdo-sqlitecreatefunction
*
* @param string $name Name of the SQL function to be created or redefined
* @param callback $callback Callback which implements the SQL function
* @param integer $arguments Number of arguments that the SQL function takes
*
* @return boolean
*/
public function create_function($name, $callback, $arguments = -1)
{
$this->_connection or $this->connect();
return $this->_connection->sqliteCreateFunction(
$name, $callback, $arguments
);
}
public function disconnect()
{
// Destroy the PDO object
$this->_connection = NULL;
return parent::disconnect();
}
public function set_charset($charset)
{
// Make sure the database is connected
$this->_connection OR $this->connect();
// This SQL-92 syntax is not supported by all drivers
$this->_connection->exec('SET NAMES '.$this->quote($charset));
}
public function query($type, $sql, $as_object = FALSE, array $params = NULL)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if (Kohana::$profiling)
{
// Benchmark this query for the current instance
$benchmark = Profiler::start("Database ({$this->_instance})", $sql);
}
try
{
$result = $this->_connection->query($sql);
}
catch (Exception $e)
{
if (isset($benchmark))
{
// This benchmark is worthless
Profiler::delete($benchmark);
}
// Convert the exception in a database exception
throw new Database_Exception(':error [ :query ]',
array(
':error' => $e->getMessage(),
':query' => $sql
),
$e->getCode());
}
if (isset($benchmark))
{
Profiler::stop($benchmark);
}
// Set the last query
$this->last_query = $sql;
if ($type === Database::SELECT)
{
// Convert the result into an array, as PDOStatement::rowCount is not reliable
if ($as_object === FALSE)
{
$result->setFetchMode(PDO::FETCH_ASSOC);
}
elseif (is_string($as_object))
{
$result->setFetchMode(PDO::FETCH_CLASS, $as_object, $params);
}
else
{
$result->setFetchMode(PDO::FETCH_CLASS, 'stdClass');
}
$result = $result->fetchAll();
// Return an iterator of results
return new Database_Result_Cached($result, $sql, $as_object, $params);
}
elseif ($type === Database::INSERT)
{
// Return a list of insert id and rows created
return array(
$this->_connection->lastInsertId(),
$result->rowCount(),
);
}
else
{
// Return the number of rows affected
return $result->rowCount();
}
}
public function begin($mode = NULL)
{
// Make sure the database is connected
$this->_connection or $this->connect();
return $this->_connection->beginTransaction();
}
public function commit()
{
// Make sure the database is connected
$this->_connection or $this->connect();
return $this->_connection->commit();
}
public function rollback()
{
// Make sure the database is connected
$this->_connection or $this->connect();
return $this->_connection->rollBack();
}
public function list_tables($like = NULL)
{
throw new Kohana_Exception('Database method :method is not supported by :class',
array(':method' => __FUNCTION__, ':class' => __CLASS__));
}
public function list_columns($table, $like = NULL, $add_prefix = TRUE)
{
throw new Kohana_Exception('Database method :method is not supported by :class',
array(':method' => __FUNCTION__, ':class' => __CLASS__));
}
public function escape($value)
{
// Make sure the database is connected
$this->_connection or $this->connect();
return $this->_connection->quote($value);
}
} // End Database_PDO

View File

@@ -0,0 +1,262 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Database query wrapper. See [Parameterized Statements](database/query/parameterized) for usage and examples.
*
* @package Kohana/Database
* @category Query
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_Query {
// Query type
protected $_type;
// Execute the query during a cache hit
protected $_force_execute = FALSE;
// Cache lifetime
protected $_lifetime = NULL;
// SQL statement
protected $_sql;
// Quoted query parameters
protected $_parameters = array();
// Return results as associative arrays or objects
protected $_as_object = FALSE;
// Parameters for __construct when using object results
protected $_object_params = array();
/**
* Creates a new SQL query of the specified type.
*
* @param integer $type query type: Database::SELECT, Database::INSERT, etc
* @param string $sql query string
* @return void
*/
public function __construct($type, $sql)
{
$this->_type = $type;
$this->_sql = $sql;
}
/**
* Return the SQL query string.
*
* @return string
*/
public function __toString()
{
try
{
// Return the SQL string
return $this->compile(Database::instance());
}
catch (Exception $e)
{
return Kohana_Exception::text($e);
}
}
/**
* Get the type of the query.
*
* @return integer
*/
public function type()
{
return $this->_type;
}
/**
* Enables the query to be cached for a specified amount of time.
*
* @param integer $lifetime number of seconds to cache, 0 deletes it from the cache
* @param boolean whether or not to execute the query during a cache hit
* @return $this
* @uses Kohana::$cache_life
*/
public function cached($lifetime = NULL, $force = FALSE)
{
if ($lifetime === NULL)
{
// Use the global setting
$lifetime = Kohana::$cache_life;
}
$this->_force_execute = $force;
$this->_lifetime = $lifetime;
return $this;
}
/**
* Returns results as associative arrays
*
* @return $this
*/
public function as_assoc()
{
$this->_as_object = FALSE;
$this->_object_params = array();
return $this;
}
/**
* Returns results as objects
*
* @param string $class classname or TRUE for stdClass
* @param array $params
* @return $this
*/
public function as_object($class = TRUE, array $params = NULL)
{
$this->_as_object = $class;
if ($params)
{
// Add object parameters
$this->_object_params = $params;
}
return $this;
}
/**
* Set the value of a parameter in the query.
*
* @param string $param parameter key to replace
* @param mixed $value value to use
* @return $this
*/
public function param($param, $value)
{
// Add or overload a new parameter
$this->_parameters[$param] = $value;
return $this;
}
/**
* Bind a variable to a parameter in the query.
*
* @param string $param parameter key to replace
* @param mixed $var variable to use
* @return $this
*/
public function bind($param, & $var)
{
// Bind a value to a variable
$this->_parameters[$param] =& $var;
return $this;
}
/**
* Add multiple parameters to the query.
*
* @param array $params list of parameters
* @return $this
*/
public function parameters(array $params)
{
// Merge the new parameters in
$this->_parameters = $params + $this->_parameters;
return $this;
}
/**
* Compile the SQL query and return it. Replaces any parameters with their
* given values.
*
* @param mixed $db Database instance or name of instance
* @return string
*/
public function compile($db = NULL)
{
if ( ! is_object($db))
{
// Get the database instance
$db = Database::instance($db);
}
// Import the SQL locally
$sql = $this->_sql;
if ( ! empty($this->_parameters))
{
// Quote all of the values
$values = array_map(array($db, 'quote'), $this->_parameters);
// Replace the values in the SQL
$sql = strtr($sql, $values);
}
return $sql;
}
/**
* Execute the current query on the given database.
*
* @param mixed $db Database instance or name of instance
* @param string result object classname, TRUE for stdClass or FALSE for array
* @param array result object constructor arguments
* @return object Database_Result for SELECT queries
* @return mixed the insert id for INSERT queries
* @return integer number of affected rows for all other queries
*/
public function execute($db = NULL, $as_object = NULL, $object_params = NULL)
{
if ( ! is_object($db))
{
// Get the database instance
$db = Database::instance($db);
}
if ($as_object === NULL)
{
$as_object = $this->_as_object;
}
if ($object_params === NULL)
{
$object_params = $this->_object_params;
}
// Compile the SQL query
$sql = $this->compile($db);
if ($this->_lifetime !== NULL AND $this->_type === Database::SELECT)
{
// Set the cache key based on the database instance name and SQL
$cache_key = 'Database::query("'.$db.'", "'.$sql.'")';
// Read the cache first to delete a possible hit with lifetime <= 0
if (($result = Kohana::cache($cache_key, NULL, $this->_lifetime)) !== NULL
AND ! $this->_force_execute)
{
// Return a cached result
return new Database_Result_Cached($result, $sql, $as_object, $object_params);
}
}
// Execute the query
$result = $db->query($this->_type, $sql, $as_object, $object_params);
if (isset($cache_key) AND $this->_lifetime > 0)
{
// Cache the result array
Kohana::cache($cache_key, $result->as_array(), $this->_lifetime);
}
return $result;
}
} // End Database_Query

View File

@@ -0,0 +1,248 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Database query builder. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
abstract class Kohana_Database_Query_Builder extends Database_Query {
/**
* Compiles an array of JOIN statements into an SQL partial.
*
* @param object $db Database instance
* @param array $joins join statements
* @return string
*/
protected function _compile_join(Database $db, array $joins)
{
$statements = array();
foreach ($joins as $join)
{
// Compile each of the join statements
$statements[] = $join->compile($db);
}
return implode(' ', $statements);
}
/**
* Compiles an array of conditions into an SQL partial. Used for WHERE
* and HAVING.
*
* @param object $db Database instance
* @param array $conditions condition statements
* @return string
*/
protected function _compile_conditions(Database $db, array $conditions)
{
$last_condition = NULL;
$sql = '';
foreach ($conditions as $group)
{
// Process groups of conditions
foreach ($group as $logic => $condition)
{
if ($condition === '(')
{
if ( ! empty($sql) AND $last_condition !== '(')
{
// Include logic operator
$sql .= ' '.$logic.' ';
}
$sql .= '(';
}
elseif ($condition === ')')
{
$sql .= ')';
}
else
{
if ( ! empty($sql) AND $last_condition !== '(')
{
// Add the logic operator
$sql .= ' '.$logic.' ';
}
// Split the condition
list($column, $op, $value) = $condition;
if ($value === NULL)
{
if ($op === '=')
{
// Convert "val = NULL" to "val IS NULL"
$op = 'IS';
}
elseif ($op === '!=')
{
// Convert "val != NULL" to "valu IS NOT NULL"
$op = 'IS NOT';
}
}
// Database operators are always uppercase
$op = strtoupper($op);
if ($op === 'BETWEEN' AND is_array($value))
{
// BETWEEN always has exactly two arguments
list($min, $max) = $value;
if ((is_string($min) AND array_key_exists($min, $this->_parameters)) === FALSE)
{
// Quote the value, it is not a parameter
$min = $db->quote($min);
}
if ((is_string($max) AND array_key_exists($max, $this->_parameters)) === FALSE)
{
// Quote the value, it is not a parameter
$max = $db->quote($max);
}
// Quote the min and max value
$value = $min.' AND '.$max;
}
elseif ((is_string($value) AND array_key_exists($value, $this->_parameters)) === FALSE)
{
// Quote the value, it is not a parameter
$value = $db->quote($value);
}
if ($column)
{
if (is_array($column))
{
// Use the column name
$column = $db->quote_identifier(reset($column));
}
else
{
// Apply proper quoting to the column
$column = $db->quote_column($column);
}
}
// Append the statement to the query
$sql .= trim($column.' '.$op.' '.$value);
}
$last_condition = $condition;
}
}
return $sql;
}
/**
* Compiles an array of set values into an SQL partial. Used for UPDATE.
*
* @param object $db Database instance
* @param array $values updated values
* @return string
*/
protected function _compile_set(Database $db, array $values)
{
$set = array();
foreach ($values as $group)
{
// Split the set
list ($column, $value) = $group;
// Quote the column name
$column = $db->quote_column($column);
if ((is_string($value) AND array_key_exists($value, $this->_parameters)) === FALSE)
{
// Quote the value, it is not a parameter
$value = $db->quote($value);
}
$set[$column] = $column.' = '.$value;
}
return implode(', ', $set);
}
/**
* Compiles an array of GROUP BY columns into an SQL partial.
*
* @param object $db Database instance
* @param array $columns
* @return string
*/
protected function _compile_group_by(Database $db, array $columns)
{
$group = array();
foreach ($columns as $column)
{
if (is_array($column))
{
// Use the column alias
$column = $db->quote_identifier(end($column));
}
else
{
// Apply proper quoting to the column
$column = $db->quote_column($column);
}
$group[] = $column;
}
return 'GROUP BY '.implode(', ', $group);
}
/**
* Compiles an array of ORDER BY statements into an SQL partial.
*
* @param object $db Database instance
* @param array $columns sorting columns
* @return string
*/
protected function _compile_order_by(Database $db, array $columns)
{
$sort = array();
foreach ($columns as $group)
{
list ($column, $direction) = $group;
if (is_array($column))
{
// Use the column alias
$column = $db->quote_identifier(end($column));
}
else
{
// Apply proper quoting to the column
$column = $db->quote_column($column);
}
if ($direction)
{
// Make the direction uppercase
$direction = ' '.strtoupper($direction);
}
$sort[] = $column.$direction;
}
return 'ORDER BY '.implode(', ', $sort);
}
/**
* Reset the current builder status.
*
* @return $this
*/
abstract public function reset();
} // End Database_Query_Builder

View File

@@ -0,0 +1,99 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Database query builder for DELETE statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_Query_Builder_Delete extends Database_Query_Builder_Where {
// DELETE FROM ...
protected $_table;
/**
* Set the table for a delete.
*
* @param mixed $table table name or array($table, $alias) or object
* @return void
*/
public function __construct($table = NULL)
{
if ($table)
{
// Set the inital table name
$this->_table = $table;
}
// Start the query with no SQL
return parent::__construct(Database::DELETE, '');
}
/**
* Sets the table to delete from.
*
* @param mixed $table table name or array($table, $alias) or object
* @return $this
*/
public function table($table)
{
$this->_table = $table;
return $this;
}
/**
* Compile the SQL query and return it.
*
* @param mixed $db Database instance or name of instance
* @return string
*/
public function compile($db = NULL)
{
if ( ! is_object($db))
{
// Get the database instance
$db = Database::instance($db);
}
// Start a deletion query
$query = 'DELETE FROM '.$db->quote_table($this->_table);
if ( ! empty($this->_where))
{
// Add deletion conditions
$query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
}
if ( ! empty($this->_order_by))
{
// Add sorting
$query .= ' '.$this->_compile_order_by($db, $this->_order_by);
}
if ($this->_limit !== NULL)
{
// Add limiting
$query .= ' LIMIT '.$this->_limit;
}
$this->_sql = $query;
return parent::compile($db);
}
public function reset()
{
$this->_table = NULL;
$this->_where = array();
$this->_parameters = array();
$this->_sql = NULL;
return $this;
}
} // End Database_Query_Builder_Delete

View File

@@ -0,0 +1,181 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Database query builder for INSERT statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_Query_Builder_Insert extends Database_Query_Builder {
// INSERT INTO ...
protected $_table;
// (...)
protected $_columns = array();
// VALUES (...)
protected $_values = array();
/**
* Set the table and columns for an insert.
*
* @param mixed $table table name or array($table, $alias) or object
* @param array $columns column names
* @return void
*/
public function __construct($table = NULL, array $columns = NULL)
{
if ($table)
{
// Set the inital table name
$this->_table = $table;
}
if ($columns)
{
// Set the column names
$this->_columns = $columns;
}
// Start the query with no SQL
return parent::__construct(Database::INSERT, '');
}
/**
* Sets the table to insert into.
*
* @param mixed $table table name or array($table, $alias) or object
* @return $this
*/
public function table($table)
{
$this->_table = $table;
return $this;
}
/**
* Set the columns that will be inserted.
*
* @param array $columns column names
* @return $this
*/
public function columns(array $columns)
{
$this->_columns = $columns;
return $this;
}
/**
* Adds or overwrites values. Multiple value sets can be added.
*
* @param array $values values list
* @param ...
* @return $this
*/
public function values(array $values)
{
if ( ! is_array($this->_values))
{
throw new Kohana_Exception('INSERT INTO ... SELECT statements cannot be combined with INSERT INTO ... VALUES');
}
// Get all of the passed values
$values = func_get_args();
$this->_values = array_merge($this->_values, $values);
return $this;
}
/**
* Use a sub-query to for the inserted values.
*
* @param object $query Database_Query of SELECT type
* @return $this
*/
public function select(Database_Query $query)
{
if ($query->type() !== Database::SELECT)
{
throw new Kohana_Exception('Only SELECT queries can be combined with INSERT queries');
}
$this->_values = $query;
return $this;
}
/**
* Compile the SQL query and return it.
*
* @param mixed $db Database instance or name of instance
* @return string
*/
public function compile($db = NULL)
{
if ( ! is_object($db))
{
// Get the database instance
$db = Database::instance($db);
}
// Start an insertion query
$query = 'INSERT INTO '.$db->quote_table($this->_table);
// Add the column names
$query .= ' ('.implode(', ', array_map(array($db, 'quote_column'), $this->_columns)).') ';
if (is_array($this->_values))
{
// Callback for quoting values
$quote = array($db, 'quote');
$groups = array();
foreach ($this->_values as $group)
{
foreach ($group as $offset => $value)
{
if ((is_string($value) AND array_key_exists($value, $this->_parameters)) === FALSE)
{
// Quote the value, it is not a parameter
$group[$offset] = $db->quote($value);
}
}
$groups[] = '('.implode(', ', $group).')';
}
// Add the values
$query .= 'VALUES '.implode(', ', $groups);
}
else
{
// Add the sub-query
$query .= (string) $this->_values;
}
$this->_sql = $query;
return parent::compile($db);;
}
public function reset()
{
$this->_table = NULL;
$this->_columns =
$this->_values = array();
$this->_parameters = array();
$this->_sql = NULL;
return $this;
}
} // End Database_Query_Builder_Insert

View File

@@ -0,0 +1,149 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Database query builder for JOIN statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_Query_Builder_Join extends Database_Query_Builder {
// Type of JOIN
protected $_type;
// JOIN ...
protected $_table;
// ON ...
protected $_on = array();
// USING ...
protected $_using = array();
/**
* Creates a new JOIN statement for a table. Optionally, the type of JOIN
* can be specified as the second parameter.
*
* @param mixed $table column name or array($column, $alias) or object
* @param string $type type of JOIN: INNER, RIGHT, LEFT, etc
* @return void
*/
public function __construct($table, $type = NULL)
{
// Set the table to JOIN on
$this->_table = $table;
if ($type !== NULL)
{
// Set the JOIN type
$this->_type = (string) $type;
}
}
/**
* Adds a new condition for joining.
*
* @param mixed $c1 column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $c2 column name or array($column, $alias) or object
* @return $this
*/
public function on($c1, $op, $c2)
{
if ( ! empty($this->_using))
{
throw new Kohana_Exception('JOIN ... ON ... cannot be combined with JOIN ... USING ...');
}
$this->_on[] = array($c1, $op, $c2);
return $this;
}
/**
* Adds a new condition for joining.
*
* @param string $columns column name
* @return $this
*/
public function using($columns)
{
if ( ! empty($this->_on))
{
throw new Kohana_Exception('JOIN ... ON ... cannot be combined with JOIN ... USING ...');
}
$columns = func_get_args();
$this->_using = array_merge($this->_using, $columns);
return $this;
}
/**
* Compile the SQL partial for a JOIN statement and return it.
*
* @param mixed $db Database instance or name of instance
* @return string
*/
public function compile($db = NULL)
{
if ( ! is_object($db))
{
// Get the database instance
$db = Database::instance($db);
}
if ($this->_type)
{
$sql = strtoupper($this->_type).' JOIN';
}
else
{
$sql = 'JOIN';
}
// Quote the table name that is being joined
$sql .= ' '.$db->quote_table($this->_table);
if ( ! empty($this->_using))
{
// Quote and concat the columns
$sql .= ' USING ('.implode(', ', array_map(array($db, 'quote_column'), $this->_using)).')';
}
else
{
$conditions = array();
foreach ($this->_on as $condition)
{
// Split the condition
list($c1, $op, $c2) = $condition;
if ($op)
{
// Make the operator uppercase and spaced
$op = ' '.strtoupper($op);
}
// Quote each of the columns used for the condition
$conditions[] = $db->quote_column($c1).$op.' '.$db->quote_column($c2);
}
// Concat the conditions "... AND ..."
$sql .= ' ON ('.implode(' AND ', $conditions).')';
}
return $sql;
}
public function reset()
{
$this->_type =
$this->_table = NULL;
$this->_on = array();
}
} // End Database_Query_Builder_Join

View File

@@ -0,0 +1,446 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Database query builder for SELECT statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where {
// SELECT ...
protected $_select = array();
// DISTINCT
protected $_distinct = FALSE;
// FROM ...
protected $_from = array();
// JOIN ...
protected $_join = array();
// GROUP BY ...
protected $_group_by = array();
// HAVING ...
protected $_having = array();
// OFFSET ...
protected $_offset = NULL;
// UNION ...
protected $_union = array();
// The last JOIN statement created
protected $_last_join;
/**
* Sets the initial columns to select from.
*
* @param array $columns column list
* @return void
*/
public function __construct(array $columns = NULL)
{
if ( ! empty($columns))
{
// Set the initial columns
$this->_select = $columns;
}
// Start the query with no actual SQL statement
parent::__construct(Database::SELECT, '');
}
/**
* Enables or disables selecting only unique columns using "SELECT DISTINCT"
*
* @param boolean $value enable or disable distinct columns
* @return $this
*/
public function distinct($value)
{
$this->_distinct = (bool) $value;
return $this;
}
/**
* Choose the columns to select from.
*
* @param mixed $columns column name or array($column, $alias) or object
* @return $this
*/
public function select($columns = NULL)
{
$columns = func_get_args();
$this->_select = array_merge($this->_select, $columns);
return $this;
}
/**
* Choose the columns to select from, using an array.
*
* @param array $columns list of column names or aliases
* @return $this
*/
public function select_array(array $columns)
{
$this->_select = array_merge($this->_select, $columns);
return $this;
}
/**
* Choose the tables to select "FROM ..."
*
* @param mixed $table table name or array($table, $alias) or object
* @return $this
*/
public function from($tables)
{
$tables = func_get_args();
$this->_from = array_merge($this->_from, $tables);
return $this;
}
/**
* Adds addition tables to "JOIN ...".
*
* @param mixed $table column name or array($column, $alias) or object
* @param string $type join type (LEFT, RIGHT, INNER, etc)
* @return $this
*/
public function join($table, $type = NULL)
{
$this->_join[] = $this->_last_join = new Database_Query_Builder_Join($table, $type);
return $this;
}
/**
* Adds "ON ..." conditions for the last created JOIN statement.
*
* @param mixed $c1 column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $c2 column name or array($column, $alias) or object
* @return $this
*/
public function on($c1, $op, $c2)
{
$this->_last_join->on($c1, $op, $c2);
return $this;
}
/**
* Adds "USING ..." conditions for the last created JOIN statement.
*
* @param string $columns column name
* @return $this
*/
public function using($columns)
{
$columns = func_get_args();
call_user_func_array(array($this->_last_join, 'using'), $columns);
return $this;
}
/**
* Creates a "GROUP BY ..." filter.
*
* @param mixed $columns column name or array($column, $alias) or object
* @return $this
*/
public function group_by($columns)
{
$columns = func_get_args();
$this->_group_by = array_merge($this->_group_by, $columns);
return $this;
}
/**
* Alias of and_having()
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $value column value
* @return $this
*/
public function having($column, $op, $value = NULL)
{
return $this->and_having($column, $op, $value);
}
/**
* Creates a new "AND HAVING" condition for the query.
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $value column value
* @return $this
*/
public function and_having($column, $op, $value = NULL)
{
$this->_having[] = array('AND' => array($column, $op, $value));
return $this;
}
/**
* Creates a new "OR HAVING" condition for the query.
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $value column value
* @return $this
*/
public function or_having($column, $op, $value = NULL)
{
$this->_having[] = array('OR' => array($column, $op, $value));
return $this;
}
/**
* Alias of and_having_open()
*
* @return $this
*/
public function having_open()
{
return $this->and_having_open();
}
/**
* Opens a new "AND HAVING (...)" grouping.
*
* @return $this
*/
public function and_having_open()
{
$this->_having[] = array('AND' => '(');
return $this;
}
/**
* Opens a new "OR HAVING (...)" grouping.
*
* @return $this
*/
public function or_having_open()
{
$this->_having[] = array('OR' => '(');
return $this;
}
/**
* Closes an open "AND HAVING (...)" grouping.
*
* @return $this
*/
public function having_close()
{
return $this->and_having_close();
}
/**
* Closes an open "AND HAVING (...)" grouping.
*
* @return $this
*/
public function and_having_close()
{
$this->_having[] = array('AND' => ')');
return $this;
}
/**
* Closes an open "OR HAVING (...)" grouping.
*
* @return $this
*/
public function or_having_close()
{
$this->_having[] = array('OR' => ')');
return $this;
}
/**
* Adds an other UNION clause.
*
* @param mixed $select if string, it must be the name of a table. Else
* must be an instance of Database_Query_Builder_Select
* @param boolean $all decides if it's an UNION or UNION ALL clause
* @return $this
*/
public function union($select, $all = TRUE)
{
if (is_string($select))
{
$select = DB::select()->from($select);
}
if ( ! $select instanceof Database_Query_Builder_Select)
throw new Kohana_Exception('first parameter must be a string or an instance of Database_Query_Builder_Select');
$this->_union []= array('select' => $select, 'all' => $all);
return $this;
}
/**
* Start returning results after "OFFSET ..."
*
* @param integer $number starting result number or NULL to reset
* @return $this
*/
public function offset($number)
{
$this->_offset = $number;
return $this;
}
/**
* Compile the SQL query and return it.
*
* @param mixed $db Database instance or name of instance
* @return string
*/
public function compile($db = NULL)
{
if ( ! is_object($db))
{
// Get the database instance
$db = Database::instance($db);
}
// Callback to quote columns
$quote_column = array($db, 'quote_column');
// Callback to quote tables
$quote_table = array($db, 'quote_table');
// Start a selection query
$query = 'SELECT ';
if ($this->_distinct === TRUE)
{
// Select only unique results
$query .= 'DISTINCT ';
}
if (empty($this->_select))
{
// Select all columns
$query .= '*';
}
else
{
// Select all columns
$query .= implode(', ', array_unique(array_map($quote_column, $this->_select)));
}
if ( ! empty($this->_from))
{
// Set tables to select from
$query .= ' FROM '.implode(', ', array_unique(array_map($quote_table, $this->_from)));
}
if ( ! empty($this->_join))
{
// Add tables to join
$query .= ' '.$this->_compile_join($db, $this->_join);
}
if ( ! empty($this->_where))
{
// Add selection conditions
$query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
}
if ( ! empty($this->_group_by))
{
// Add grouping
$query .= ' '.$this->_compile_group_by($db, $this->_group_by);
}
if ( ! empty($this->_having))
{
// Add filtering conditions
$query .= ' HAVING '.$this->_compile_conditions($db, $this->_having);
}
if ( ! empty($this->_order_by))
{
// Add sorting
$query .= ' '.$this->_compile_order_by($db, $this->_order_by);
}
if ($this->_limit !== NULL)
{
// Add limiting
$query .= ' LIMIT '.$this->_limit;
}
if ($this->_offset !== NULL)
{
// Add offsets
$query .= ' OFFSET '.$this->_offset;
}
if ( ! empty($this->_union))
{
foreach ($this->_union as $u) {
$query .= ' UNION ';
if ($u['all'] === TRUE)
{
$query .= 'ALL ';
}
$query .= $u['select']->compile($db);
}
}
$this->_sql = $query;
return parent::compile($db);
}
public function reset()
{
$this->_select =
$this->_from =
$this->_join =
$this->_where =
$this->_group_by =
$this->_having =
$this->_order_by =
$this->_union = array();
$this->_distinct = FALSE;
$this->_limit =
$this->_offset =
$this->_last_join = NULL;
$this->_parameters = array();
$this->_sql = NULL;
return $this;
}
} // End Database_Query_Select

View File

@@ -0,0 +1,140 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Database query builder for UPDATE statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_Query_Builder_Update extends Database_Query_Builder_Where {
// UPDATE ...
protected $_table;
// SET ...
protected $_set = array();
/**
* Set the table for a update.
*
* @param mixed $table table name or array($table, $alias) or object
* @return void
*/
public function __construct($table = NULL)
{
if ($table)
{
// Set the inital table name
$this->_table = $table;
}
// Start the query with no SQL
return parent::__construct(Database::UPDATE, '');
}
/**
* Sets the table to update.
*
* @param mixed $table table name or array($table, $alias) or object
* @return $this
*/
public function table($table)
{
$this->_table = $table;
return $this;
}
/**
* Set the values to update with an associative array.
*
* @param array $pairs associative (column => value) list
* @return $this
*/
public function set(array $pairs)
{
foreach ($pairs as $column => $value)
{
$this->_set[] = array($column, $value);
}
return $this;
}
/**
* Set the value of a single column.
*
* @param mixed $column table name or array($table, $alias) or object
* @param mixed $value column value
* @return $this
*/
public function value($column, $value)
{
$this->_set[] = array($column, $value);
return $this;
}
/**
* Compile the SQL query and return it.
*
* @param mixed $db Database instance or name of instance
* @return string
*/
public function compile($db = NULL)
{
if ( ! is_object($db))
{
// Get the database instance
$db = Database::instance($db);
}
// Start an update query
$query = 'UPDATE '.$db->quote_table($this->_table);
// Add the columns to update
$query .= ' SET '.$this->_compile_set($db, $this->_set);
if ( ! empty($this->_where))
{
// Add selection conditions
$query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
}
if ( ! empty($this->_order_by))
{
// Add sorting
$query .= ' '.$this->_compile_order_by($db, $this->_order_by);
}
if ($this->_limit !== NULL)
{
// Add limiting
$query .= ' LIMIT '.$this->_limit;
}
$this->_sql = $query;
return parent::compile($db);
}
public function reset()
{
$this->_table = NULL;
$this->_set =
$this->_where = array();
$this->_limit = NULL;
$this->_parameters = array();
$this->_sql = NULL;
return $this;
}
} // End Database_Query_Builder_Update

View File

@@ -0,0 +1,180 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Database query builder for WHERE statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
abstract class Kohana_Database_Query_Builder_Where extends Database_Query_Builder {
// WHERE ...
protected $_where = array();
// ORDER BY ...
protected $_order_by = array();
// LIMIT ...
protected $_limit = NULL;
/**
* Alias of and_where()
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $value column value
* @return $this
*/
public function where($column, $op, $value)
{
return $this->and_where($column, $op, $value);
}
/**
* Creates a new "AND WHERE" condition for the query.
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $value column value
* @return $this
*/
public function and_where($column, $op, $value)
{
$this->_where[] = array('AND' => array($column, $op, $value));
return $this;
}
/**
* Creates a new "OR WHERE" condition for the query.
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $value column value
* @return $this
*/
public function or_where($column, $op, $value)
{
$this->_where[] = array('OR' => array($column, $op, $value));
return $this;
}
/**
* Alias of and_where_open()
*
* @return $this
*/
public function where_open()
{
return $this->and_where_open();
}
/**
* Opens a new "AND WHERE (...)" grouping.
*
* @return $this
*/
public function and_where_open()
{
$this->_where[] = array('AND' => '(');
return $this;
}
/**
* Opens a new "OR WHERE (...)" grouping.
*
* @return $this
*/
public function or_where_open()
{
$this->_where[] = array('OR' => '(');
return $this;
}
/**
* Closes an open "WHERE (...)" grouping.
*
* @return $this
*/
public function where_close()
{
return $this->and_where_close();
}
/**
* Closes an open "WHERE (...)" grouping or removes the grouping when it is
* empty.
*
* @return $this
*/
public function where_close_empty()
{
$group = end($this->_where);
if ($group AND reset($group) === '(')
{
array_pop($this->_where);
return $this;
}
return $this->where_close();
}
/**
* Closes an open "WHERE (...)" grouping.
*
* @return $this
*/
public function and_where_close()
{
$this->_where[] = array('AND' => ')');
return $this;
}
/**
* Closes an open "WHERE (...)" grouping.
*
* @return $this
*/
public function or_where_close()
{
$this->_where[] = array('OR' => ')');
return $this;
}
/**
* Applies sorting with "ORDER BY ..."
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $direction direction of sorting
* @return $this
*/
public function order_by($column, $direction = NULL)
{
$this->_order_by[] = array($column, $direction);
return $this;
}
/**
* Return up to "LIMIT ..." results
*
* @param integer $number maximum results to return or NULL to reset
* @return $this
*/
public function limit($number)
{
$this->_limit = $number;
return $this;
}
} // End Database_Query_Builder_Where

View File

@@ -0,0 +1,338 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Database result wrapper. See [Results](/database/results) for usage and examples.
*
* @package Kohana/Database
* @category Query/Result
* @author Kohana Team
* @copyright (c) 2008-2009 Kohana Team
* @license http://kohanaphp.com/license
*/
abstract class Kohana_Database_Result implements Countable, Iterator, SeekableIterator, ArrayAccess {
// Executed SQL for this result
protected $_query;
// Raw result resource
protected $_result;
// Total number of rows and current row
protected $_total_rows = 0;
protected $_current_row = 0;
// Return rows as an object or associative array
protected $_as_object;
// Parameters for __construct when using object results
protected $_object_params = NULL;
/**
* Sets the total number of rows and stores the result locally.
*
* @param mixed $result query result
* @param string $sql SQL query
* @param mixed $as_object
* @param array $params
* @return void
*/
public function __construct($result, $sql, $as_object = FALSE, array $params = NULL)
{
// Store the result locally
$this->_result = $result;
// Store the SQL locally
$this->_query = $sql;
if (is_object($as_object))
{
// Get the object class name
$as_object = get_class($as_object);
}
// Results as objects or associative arrays
$this->_as_object = $as_object;
if ($params)
{
// Object constructor params
$this->_object_params = $params;
}
}
/**
* Result destruction cleans up all open result sets.
*
* @return void
*/
abstract public function __destruct();
/**
* Get a cached database result from the current result iterator.
*
* $cachable = serialize($result->cached());
*
* @return Database_Result_Cached
* @since 3.0.5
*/
public function cached()
{
return new Database_Result_Cached($this->as_array(), $this->_query, $this->_as_object);
}
/**
* Return all of the rows in the result as an array.
*
* // Indexed array of all rows
* $rows = $result->as_array();
*
* // Associative array of rows by "id"
* $rows = $result->as_array('id');
*
* // Associative array of rows, "id" => "name"
* $rows = $result->as_array('id', 'name');
*
* @param string $key column for associative keys
* @param string $value column for values
* @return array
*/
public function as_array($key = NULL, $value = NULL)
{
$results = array();
if ($key === NULL AND $value === NULL)
{
// Indexed rows
foreach ($this as $row)
{
$results[] = $row;
}
}
elseif ($key === NULL)
{
// Indexed columns
if ($this->_as_object)
{
foreach ($this as $row)
{
$results[] = $row->$value;
}
}
else
{
foreach ($this as $row)
{
$results[] = $row[$value];
}
}
}
elseif ($value === NULL)
{
// Associative rows
if ($this->_as_object)
{
foreach ($this as $row)
{
$results[$row->$key] = $row;
}
}
else
{
foreach ($this as $row)
{
$results[$row[$key]] = $row;
}
}
}
else
{
// Associative columns
if ($this->_as_object)
{
foreach ($this as $row)
{
$results[$row->$key] = $row->$value;
}
}
else
{
foreach ($this as $row)
{
$results[$row[$key]] = $row[$value];
}
}
}
$this->rewind();
return $results;
}
/**
* Return the named column from the current row.
*
* // Get the "id" value
* $id = $result->get('id');
*
* @param string $name column to get
* @param mixed $default default value if the column does not exist
* @return mixed
*/
public function get($name, $default = NULL)
{
$row = $this->current();
if ($this->_as_object)
{
if (isset($row->$name))
return $row->$name;
}
else
{
if (isset($row[$name]))
return $row[$name];
}
return $default;
}
/**
* Implements [Countable::count], returns the total number of rows.
*
* echo count($result);
*
* @return integer
*/
public function count()
{
return $this->_total_rows;
}
/**
* Implements [ArrayAccess::offsetExists], determines if row exists.
*
* if (isset($result[10]))
* {
* // Row 10 exists
* }
*
* @param int $offset
* @return boolean
*/
public function offsetExists($offset)
{
return ($offset >= 0 AND $offset < $this->_total_rows);
}
/**
* Implements [ArrayAccess::offsetGet], gets a given row.
*
* $row = $result[10];
*
* @param int $offset
* @return mixed
*/
public function offsetGet($offset)
{
if ( ! $this->seek($offset))
return NULL;
return $this->current();
}
/**
* Implements [ArrayAccess::offsetSet], throws an error.
*
* [!!] You cannot modify a database result.
*
* @param int $offset
* @param mixed $value
* @return void
* @throws Kohana_Exception
*/
final public function offsetSet($offset, $value)
{
throw new Kohana_Exception('Database results are read-only');
}
/**
* Implements [ArrayAccess::offsetUnset], throws an error.
*
* [!!] You cannot modify a database result.
*
* @param int $offset
* @return void
* @throws Kohana_Exception
*/
final public function offsetUnset($offset)
{
throw new Kohana_Exception('Database results are read-only');
}
/**
* Implements [Iterator::key], returns the current row number.
*
* echo key($result);
*
* @return integer
*/
public function key()
{
return $this->_current_row;
}
/**
* Implements [Iterator::next], moves to the next row.
*
* next($result);
*
* @return $this
*/
public function next()
{
++$this->_current_row;
return $this;
}
/**
* Implements [Iterator::prev], moves to the previous row.
*
* prev($result);
*
* @return $this
*/
public function prev()
{
--$this->_current_row;
return $this;
}
/**
* Implements [Iterator::rewind], sets the current row to zero.
*
* rewind($result);
*
* @return $this
*/
public function rewind()
{
$this->_current_row = 0;
return $this;
}
/**
* Implements [Iterator::valid], checks if the current row exists.
*
* [!!] This method is only used internally.
*
* @return boolean
*/
public function valid()
{
return $this->offsetExists($this->_current_row);
}
} // End Database_Result

View File

@@ -0,0 +1,51 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Object used for caching the results of select queries. See [Results](/database/results#select-cached) for usage and examples.
*
* @package Kohana/Database
* @category Query/Result
* @author Kohana Team
* @copyright (c) 2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Database_Result_Cached extends Database_Result {
public function __construct(array $result, $sql, $as_object = NULL)
{
parent::__construct($result, $sql, $as_object);
// Find the number of rows in the result
$this->_total_rows = count($result);
}
public function __destruct()
{
// Cached results do not use resources
}
public function cached()
{
return $this;
}
public function seek($offset)
{
if ($this->offsetExists($offset))
{
$this->_current_row = $offset;
return TRUE;
}
else
{
return FALSE;
}
}
public function current()
{
// Return an array of the row
return $this->valid() ? $this->_result[$this->_current_row] : NULL;
}
} // End Database_Result_Cached