From d064f81dd8b0e95eb2fe87b7cfb3147bc9262e94 Mon Sep 17 00:00:00 2001 From: Matt Button Date: Tue, 29 Mar 2011 03:08:18 +0100 Subject: [PATCH 01/21] Adding config reader/writer --- classes/config/database.php | 9 +++ classes/config/database/reader.php | 15 ++++ classes/config/database/writer.php | 15 ++++ classes/kohana/config/database.php | 98 ++--------------------- classes/kohana/config/database/reader.php | 53 ++++++++++++ classes/kohana/config/database/writer.php | 45 +++++++++++ 6 files changed, 145 insertions(+), 90 deletions(-) create mode 100644 classes/config/database/reader.php create mode 100644 classes/config/database/writer.php create mode 100644 classes/kohana/config/database/reader.php create mode 100644 classes/kohana/config/database/writer.php diff --git a/classes/config/database.php b/classes/config/database.php index 776a801..bca215a 100644 --- a/classes/config/database.php +++ b/classes/config/database.php @@ -1,3 +1,12 @@ _database_instance = $config['instance']; - } - - if (isset($config['table'])) - { - $this->_database_table = $config['table']; - } - - parent::__construct(); - } - - /** - * Query the configuration table for all values for this group and - * unserialize each of the values. - * - * @param string group name - * @param array configuration array - * @return $this clone of the current object - */ - public function load($group, array $config = NULL) - { - if ($config === NULL AND $group !== 'database') - { - // Load all of the configuration values for this group - $query = DB::select('config_key', 'config_value') - ->from($this->_database_table) - ->where('group_name', '=', $group) - ->execute($this->_database_instance); - - if (count($query) > 0) - { - // Unserialize the configuration values - $config = array_map('unserialize', $query->as_array('config_key', 'config_value')); - } - } - - return parent::load($group, $config); - } - - /** - * Overload setting offsets to insert or update the database values as - * changes occur. - * - * @param string array key - * @param mixed new value - * @return mixed - */ - public function offsetSet($key, $value) - { - if ( ! $this->offsetExists($key)) - { - // Insert a new value - DB::insert($this->_database_table, array('group_name', 'config_key', 'config_value')) - ->values(array($this->_configuration_group, $key, serialize($value))) - ->execute($this->_database_instance); - } - elseif ($this->offsetGet($key) !== $value) - { - // Update the value - DB::update($this->_database_table) - ->value('config_value', serialize($value)) - ->where('group_name', '=', $this->_configuration_group) - ->where('config_key', '=', $key) - ->execute($this->_database_instance); - } - - return parent::offsetSet($key, $value); - } - -} // End Kohana_Config_Database +class Kohana_Config_Database extends Config_Database_Writer +{ + +} diff --git a/classes/kohana/config/database/reader.php b/classes/kohana/config/database/reader.php new file mode 100644 index 0000000..27f47c1 --- /dev/null +++ b/classes/kohana/config/database/reader.php @@ -0,0 +1,53 @@ +_db_instance = $config['instance']; + } + + if (isset($config['table_name'])) + { + $this->_table_name = $config['table_name']; + } + } + + /** + * Tries to load the specificed configuration group + * + * Returns FALSE if group does not exist or an array if it does + * + * @param string $group Configuration group + * @return boolean|array + */ + public function load($group) + { + $query = DB::select('config_key', 'config_value') + ->from($this->_table_name) + ->where('group_name', '=', $group) + ->execute($this->_db_instance); + + return count($query) ? array_map('unserialize', $query->as_array('config_key', 'config_value')) : FALSE; + } +} diff --git a/classes/kohana/config/database/writer.php b/classes/kohana/config/database/writer.php new file mode 100644 index 0000000..7a15fe1 --- /dev/null +++ b/classes/kohana/config/database/writer.php @@ -0,0 +1,45 @@ +_table_name) + ->value('config_value', $config) + ->where('group_name', '=', $group) + ->where('config_key', '=', $key) + ->execute($this->_db_instance); + + // If this config option DNX + if ($query === 0) + { + DB::insert($this->_table_name, array('group_name', 'config_key', 'config_value')) + ->values(array($group, $key, $config)) + ->execute($this->_db_instance); + } + + return TRUE; + } +} From ca7056f5cd0c7a011057b0cb6bcbfbd8869fa8f9 Mon Sep 17 00:00:00 2001 From: Matt Button Date: Tue, 29 Mar 2011 14:13:31 +0100 Subject: [PATCH 02/21] Changing the config writer to use REPLACE INTO as it's more reliable --- classes/config/database/reader.php | 4 ++-- classes/kohana/config/database/writer.php | 18 ++++++------------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/classes/config/database/reader.php b/classes/config/database/reader.php index 8aa800b..af9892e 100644 --- a/classes/config/database/reader.php +++ b/classes/config/database/reader.php @@ -6,8 +6,8 @@ * @package Kohana/Database * @category Configuration * @author Kohana Team - * @copyright (c) 2009 Kohana Team - * @license http://kohanaphp.com/license + * @copyright (c) 2011 Kohana Team + * @license http://kohanaframework.org/license */ class Config_Database_Reader extends Kohana_Config_Database_Reader { diff --git a/classes/kohana/config/database/writer.php b/classes/kohana/config/database/writer.php index 7a15fe1..fc8af45 100644 --- a/classes/kohana/config/database/writer.php +++ b/classes/kohana/config/database/writer.php @@ -26,20 +26,14 @@ public function write($group, $key, $config) { $config = serialize($config); - $query = DB::update($this->_table_name) - ->value('config_value', $config) - ->where('group_name', '=', $group) - ->where('config_key', '=', $key) + $query = DB::query(Database::INSERT, 'REPLACE INTO `'.$this->_table_name.'`(`group_name`, `config_key`, `config_value`) VALUES(:group_name, :config_key, :config_value)') + ->parameters(array( + ':group_name' => $group, + ':config_key' => $key, + ':config_value' => $config + )) ->execute($this->_db_instance); - // If this config option DNX - if ($query === 0) - { - DB::insert($this->_table_name, array('group_name', 'config_key', 'config_value')) - ->values(array($group, $key, $config)) - ->execute($this->_db_instance); - } - return TRUE; } } From 27d8ba4e9517a39338fcf2935340ec351bbe0d77 Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Tue, 3 May 2011 08:42:18 -0500 Subject: [PATCH 03/21] Revert "Enabling order_by(NULL, ...) to do ordering without columns, fixes #3485" This reverts commit db74dd6eb579bc0ed2098f44235241439afecada. --- classes/kohana/database/query/builder.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/classes/kohana/database/query/builder.php b/classes/kohana/database/query/builder.php index 67c1024..99a0d9a 100644 --- a/classes/kohana/database/query/builder.php +++ b/classes/kohana/database/query/builder.php @@ -180,16 +180,10 @@ protected function _compile_order_by(Database $db, array $columns) if ($direction) { // Make the direction uppercase - $direction = strtoupper($direction); + $direction = ' '.strtoupper($direction); } - if ($column) - { - // Quote the column, if it has a value - $column = $db->quote_identifier($column); - } - - $sort[] = trim($column.' '.$direction); + $sort[] = $db->quote_identifier($column).$direction; } return 'ORDER BY '.implode(', ', $sort); From cc21f54423fbf0920f1c4759a70d4867d8d049eb Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Thu, 9 Jun 2011 10:32:36 -0500 Subject: [PATCH 04/21] Fix bad merge 4acfcdbdc47135e8e8161135bd012289c4045136. Refs #3485 --- classes/kohana/database/query/builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/kohana/database/query/builder.php b/classes/kohana/database/query/builder.php index d0975f7..270e316 100644 --- a/classes/kohana/database/query/builder.php +++ b/classes/kohana/database/query/builder.php @@ -183,7 +183,7 @@ protected function _compile_order_by(Database $db, array $columns) $direction = ' '.strtoupper($direction); } - $sort[] = $db->quote_identifier($column).$direction; + $sort[] = $db->quote_column($column).$direction; } return 'ORDER BY '.implode(', ', $sort); From f7ce165c8eaacabaa455675239656d08dfa86d70 Mon Sep 17 00:00:00 2001 From: Matt Button Date: Sun, 26 Jun 2011 23:32:42 +0100 Subject: [PATCH 05/21] Updating for new config system --- classes/kohana/database.php | 2 +- guide/database/examples.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/classes/kohana/database.php b/classes/kohana/database.php index d84420a..4b694e3 100644 --- a/classes/kohana/database.php +++ b/classes/kohana/database.php @@ -62,7 +62,7 @@ public static function instance($name = NULL, array $config = NULL) if ($config === NULL) { // Load the configuration for this database - $config = Kohana::config('database')->$name; + $config = Kohana::$config->load('database')->$name; } if ( ! isset($config['type'])) diff --git a/guide/database/examples.md b/guide/database/examples.md index 4849823..4587ddc 100644 --- a/guide/database/examples.md +++ b/guide/database/examples.md @@ -28,7 +28,7 @@ In this example, we loop through an array of whitelisted input fields and for ea $count = $pagination_query->select('COUNT("*") AS mycount')->execute()->get('mycount'); //pass the total item count to Pagination - $config = Kohana::config('pagination'); + $config = Kohana::$config->load('pagination'); $pagination = Pagination::factory(array( 'total_items' => $count, 'current_page' => array('source' => 'route', 'key' => 'page'), From 92b2fe4c674f78d085e2d1e63132ee20c5c6376b Mon Sep 17 00:00:00 2001 From: Matt Button Date: Mon, 27 Jun 2011 21:09:39 +0100 Subject: [PATCH 06/21] Few more updates for config system --- classes/kohana/config/database.php | 2 +- classes/kohana/config/database/reader.php | 2 +- classes/kohana/config/database/writer.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/kohana/config/database.php b/classes/kohana/config/database.php index bce019d..abb73eb 100644 --- a/classes/kohana/config/database.php +++ b/classes/kohana/config/database.php @@ -9,7 +9,7 @@ * @copyright (c) 2011 Kohana Team * @license http://kohanaframework.org/license */ -class Kohana_Config_Database extends Config_Database_Writer +class Kohana_Config_Database extends Kohana_Config_Database_Writer { } diff --git a/classes/kohana/config/database/reader.php b/classes/kohana/config/database/reader.php index 27f47c1..5a5a9a7 100644 --- a/classes/kohana/config/database/reader.php +++ b/classes/kohana/config/database/reader.php @@ -9,7 +9,7 @@ * @copyright (c) 2011 Kohana Team * @license http://kohanaframework.org/license */ -class Kohana_Config_Database_Reader implements Config_Reader +class Kohana_Config_Database_Reader implements Kohana_Config_Reader { protected $_db_instance = 'default'; diff --git a/classes/kohana/config/database/writer.php b/classes/kohana/config/database/writer.php index fc8af45..18cad65 100644 --- a/classes/kohana/config/database/writer.php +++ b/classes/kohana/config/database/writer.php @@ -9,7 +9,7 @@ * @copyright (c) 2007-2011 Kohana Team * @license http://kohanaframework.org/license */ -class Kohana_Config_Database_Writer extends Config_Database_Reader implements Config_Writer +class Kohana_Config_Database_Writer extends Config_Database_Reader implements Kohana_Config_Writer { /** * Writes the passed config for $group From a05913fbd14b6f8cdf3d5e414d5dde880479dd3d Mon Sep 17 00:00:00 2001 From: Matt Button Date: Mon, 27 Jun 2011 21:32:45 +0100 Subject: [PATCH 07/21] Making the db config code more portable --- classes/kohana/config/database/writer.php | 85 +++++++++++++++++++++-- 1 file changed, 78 insertions(+), 7 deletions(-) diff --git a/classes/kohana/config/database/writer.php b/classes/kohana/config/database/writer.php index 18cad65..c739e5b 100644 --- a/classes/kohana/config/database/writer.php +++ b/classes/kohana/config/database/writer.php @@ -11,6 +11,28 @@ */ class Kohana_Config_Database_Writer extends Config_Database_Reader implements Kohana_Config_Writer { + protected $_loaded_keys = array(); + + /** + * Tries to load the specificed configuration group + * + * Returns FALSE if group does not exist or an array if it does + * + * @param string $group Configuration group + * @return boolean|array + */ + public function load($group) + { + $config = parent::load($group); + + if ($config !== FALSE) + { + $this->_loaded_keys[$group] = array_combine(array_keys($config), array_keys($config)); + } + + return $config; + } + /** * Writes the passed config for $group * @@ -26,14 +48,63 @@ public function write($group, $key, $config) { $config = serialize($config); - $query = DB::query(Database::INSERT, 'REPLACE INTO `'.$this->_table_name.'`(`group_name`, `config_key`, `config_value`) VALUES(:group_name, :config_key, :config_value)') - ->parameters(array( - ':group_name' => $group, - ':config_key' => $key, - ':config_value' => $config - )) - ->execute($this->_db_instance); + // Check to see if we've loaded the config from the table already + if (isset($this->_loaded_keys[$group][$key])) + { + $this->_update($group, $key, $config); + } + else + { + // Attempt to run an insert query + // This may fail if the config key already exists in the table + // and we don't know about it + try + { + $this->_insert($group, $key, $config); + } + catch (Database_Exception $e) + { + // Attempt to run an update instead + $this->_update($group, $key, $config); + } + } return TRUE; } + + /** + * Insert the config values into the table + * + * @param string $group The config group + * @param string $key The config key to write to + * @param array $config The serialized configuration to write + * @return boolean + */ + protected function _insert($group, $key, $config) + { + DB::insert($this->_table_name, array('group_name', 'config_key', 'config_value')) + ->values(array($group, $key, $config)) + ->execute($this->_db_instance); + + return $this; + } + + /** + * Update the config values in the table + * + * @param string $group The config group + * @param string $key The config key to write to + * @param array $config The serialized configuration to write + * @return boolean + */ + protected function _update($group, $key, $config) + { + DB::update($this->_table_name) + ->set('config_value', $config) + ->where('group_name'. $group) + ->where('config_key', $key) + ->execute($this->_db_instance); + + return $this; + } } From e8c004b4f34ceab44489d2058af0496e49add410 Mon Sep 17 00:00:00 2001 From: Matt Button Date: Mon, 27 Jun 2011 21:37:02 +0100 Subject: [PATCH 08/21] Fixing typo in config writer --- classes/kohana/config/database/writer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/kohana/config/database/writer.php b/classes/kohana/config/database/writer.php index c739e5b..a601d67 100644 --- a/classes/kohana/config/database/writer.php +++ b/classes/kohana/config/database/writer.php @@ -101,7 +101,7 @@ protected function _update($group, $key, $config) { DB::update($this->_table_name) ->set('config_value', $config) - ->where('group_name'. $group) + ->where('group_name', $group) ->where('config_key', $key) ->execute($this->_db_instance); From caf914acd27986974dc8bd1550c43abcbbd8b5b6 Mon Sep 17 00:00:00 2001 From: Matt Button Date: Mon, 27 Jun 2011 21:41:46 +0100 Subject: [PATCH 09/21] Fixing some embarrassing typos in config writer --- classes/kohana/config/database/writer.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/kohana/config/database/writer.php b/classes/kohana/config/database/writer.php index a601d67..52d9dd9 100644 --- a/classes/kohana/config/database/writer.php +++ b/classes/kohana/config/database/writer.php @@ -100,9 +100,9 @@ protected function _insert($group, $key, $config) protected function _update($group, $key, $config) { DB::update($this->_table_name) - ->set('config_value', $config) - ->where('group_name', $group) - ->where('config_key', $key) + ->set(array('config_value' => $config)) + ->where('group_name', '=', $group) + ->where('config_key', '=', $key) ->execute($this->_db_instance); return $this; From 052ba522b0998009e083b1eb9776831bf61ee0a3 Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Sat, 2 Jul 2011 09:20:15 -0500 Subject: [PATCH 10/21] MySQL: Allow session variables to be set via config. Fixes #3329 --- classes/kohana/database/mysql.php | 12 ++++++++++++ config/database.php | 1 + 2 files changed, 13 insertions(+) diff --git a/classes/kohana/database/mysql.php b/classes/kohana/database/mysql.php index 4fdbf01..dced2c6 100644 --- a/classes/kohana/database/mysql.php +++ b/classes/kohana/database/mysql.php @@ -79,6 +79,18 @@ public function connect() // Set the character set $this->set_charset($this->_config['charset']); } + + if ( ! empty($this->_config['connection']['variables'])) + { + // Set session variables + foreach ($this->_config['connection']['variables'] as $variable => $value) + { + mysql_query( + 'SET SESSION '.$variable.' = '.$this->quote($value), + $this->_connection + ); + } + } } /** diff --git a/config/database.php b/config/database.php index 69cb827..627af81 100644 --- a/config/database.php +++ b/config/database.php @@ -14,6 +14,7 @@ * string username database username * string password database password * boolean persistent use persistent connections? + * array variables system variables as "key => value" pairs * * Ports and sockets may be appended to the hostname. */ From 9212c28dc12570deb0a51b74ffcc9b90c27e490a Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Sat, 2 Jul 2011 11:11:12 -0500 Subject: [PATCH 11/21] Add parameter to force execution of a cached query. Fixes #2760 Also, a non-positive lifetime no longer saves results to the cache. --- classes/kohana/database/query.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/classes/kohana/database/query.php b/classes/kohana/database/query.php index 96db093..75530cb 100644 --- a/classes/kohana/database/query.php +++ b/classes/kohana/database/query.php @@ -13,6 +13,9 @@ class Kohana_Database_Query { // Query type protected $_type; + // Execute the query during a cache hit + protected $_force_execute = FALSE; + // Cache lifetime protected $_lifetime = NULL; @@ -72,11 +75,12 @@ public function type() /** * Enables the query to be cached for a specified amount of time. * - * @param integer number of seconds to cache + * @param integer 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) + public function cached($lifetime = NULL, $force = FALSE) { if ($lifetime === NULL) { @@ -84,6 +88,7 @@ public function cached($lifetime = NULL) $lifetime = Kohana::$cache_life; } + $this->_force_execute = $force; $this->_lifetime = $lifetime; return $this; @@ -214,7 +219,9 @@ public function execute($db = NULL) // Set the cache key based on the database instance name and SQL $cache_key = 'Database::query("'.$db.'", "'.$sql.'")'; - if ($result = Kohana::cache($cache_key, NULL, $this->_lifetime)) + // Read the cache first to delete a possible hit with lifetime <= 0 + if ($result = Kohana::cache($cache_key, NULL, $this->_lifetime) + AND ! $this->_force_execute) { // Return a cached result return new Database_Result_Cached($result, $sql, $this->_as_object, $this->_object_params); @@ -224,7 +231,7 @@ public function execute($db = NULL) // Execute the query $result = $db->query($this->_type, $sql, $this->_as_object, $this->_object_params); - if (isset($cache_key)) + if (isset($cache_key) AND $this->_lifetime > 0) { // Cache the result array Kohana::cache($cache_key, $result->as_array(), $this->_lifetime); From 453b7f356427393748ecb310b542267e48a89a55 Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Sun, 3 Jul 2011 08:59:42 -0500 Subject: [PATCH 12/21] SQLite: Allow user-defined functions. Fixes #3502 These methods will move to Database_PDO_SQLite in the future. --- classes/kohana/database/pdo.php | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/classes/kohana/database/pdo.php b/classes/kohana/database/pdo.php index 4f631b6..c4ec050 100644 --- a/classes/kohana/database/pdo.php +++ b/classes/kohana/database/pdo.php @@ -68,6 +68,51 @@ public function connect() } } + /** + * 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 From e303e81ac3aa4a23e92aec5c218f12aaef1ffce7 Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Sun, 3 Jul 2011 09:12:40 -0500 Subject: [PATCH 13/21] Allow LIMIT and OFFSET to be reset. Fixes #3735 --- classes/kohana/database/query/builder/select.php | 5 ++--- classes/kohana/database/query/builder/where.php | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/classes/kohana/database/query/builder/select.php b/classes/kohana/database/query/builder/select.php index 4c45624..c4c9c59 100644 --- a/classes/kohana/database/query/builder/select.php +++ b/classes/kohana/database/query/builder/select.php @@ -308,12 +308,12 @@ public function union($select, $all = TRUE) /** * Start returning results after "OFFSET ..." * - * @param integer starting result number + * @param integer starting result number or NULL to reset * @return $this */ public function offset($number) { - $this->_offset = (int) $number; + $this->_offset = $number; return $this; } @@ -442,4 +442,3 @@ public function reset() } } // End Database_Query_Select - diff --git a/classes/kohana/database/query/builder/where.php b/classes/kohana/database/query/builder/where.php index aeece75..292e01a 100644 --- a/classes/kohana/database/query/builder/where.php +++ b/classes/kohana/database/query/builder/where.php @@ -147,12 +147,12 @@ public function order_by($column, $direction = NULL) /** * Return up to "LIMIT ..." results * - * @param integer maximum results to return + * @param integer maximum results to return or NULL to reset * @return $this */ public function limit($number) { - $this->_limit = (int) $number; + $this->_limit = $number; return $this; } From f8abadbcf3a3a7c3f22b6f6e13ba1a4973346f9c Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Sun, 3 Jul 2011 09:40:55 -0500 Subject: [PATCH 14/21] Allow object results to be chosen during execute(). Fixes #3227 --- classes/kohana/database/query.php | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/classes/kohana/database/query.php b/classes/kohana/database/query.php index 75530cb..26b53a2 100644 --- a/classes/kohana/database/query.php +++ b/classes/kohana/database/query.php @@ -199,11 +199,14 @@ public function compile(Database $db) * Execute the current query on the given database. * * @param mixed 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) + public function execute($db = NULL, $as_object = NULL, $object_params = NULL) { if ( ! is_object($db)) { @@ -211,6 +214,16 @@ public function execute($db = NULL) $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); @@ -224,12 +237,12 @@ public function execute($db = NULL) AND ! $this->_force_execute) { // Return a cached result - return new Database_Result_Cached($result, $sql, $this->_as_object, $this->_object_params); + return new Database_Result_Cached($result, $sql, $as_object, $object_params); } } // Execute the query - $result = $db->query($this->_type, $sql, $this->_as_object, $this->_object_params); + $result = $db->query($this->_type, $sql, $as_object, $object_params); if (isset($cache_key) AND $this->_lifetime > 0) { From f2ff54585629a87b961b30eacd05d65fd5a059ac Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Mon, 4 Jul 2011 08:47:24 -0500 Subject: [PATCH 15/21] Allow Expression to have parameters. Fixes #3429 --- classes/kohana/database.php | 30 ++++++---- classes/kohana/database/expression.php | 78 +++++++++++++++++++++++++- classes/kohana/db.php | 5 +- 3 files changed, 100 insertions(+), 13 deletions(-) diff --git a/classes/kohana/database.php b/classes/kohana/database.php index 4b694e3..b7b7acf 100644 --- a/classes/kohana/database.php +++ b/classes/kohana/database.php @@ -416,7 +416,7 @@ public function table_prefix() * $db->quote('fred'); // 'fred' * * Objects passed to this function will be converted to strings. - * [Database_Expression] objects will use the value of the expression. + * [Database_Expression] objects will be compiled. * [Database_Query] objects will be compiled and converted to a sub-query. * All other objects will be converted using the `__toString` method. * @@ -447,8 +447,8 @@ public function quote($value) } elseif ($value instanceof Database_Expression) { - // Use a raw expression - return $value->value(); + // Compile the expression + return $value->compile($this); } else { @@ -483,6 +483,11 @@ public function quote($value) * // The value of "column" will be quoted * $column = $db->quote_column('COUNT("column")'); * + * Objects passed to this function will be converted to strings. + * [Database_Expression] objects will be compiled. + * [Database_Query] objects will be compiled and converted to a sub-query. + * All other objects will be converted using the `__toString` method. + * * @param mixed column name or array(column, alias) * @return string * @uses Database::quote_identifier @@ -502,8 +507,8 @@ public function quote_column($column) } elseif ($column instanceof Database_Expression) { - // Use a raw expression - $column = $column->value(); + // Compile the expression + $column = $column->compile($this); } else { @@ -562,6 +567,11 @@ public function quote_column($column) * * $table = $db->quote_table($table); * + * Objects passed to this function will be converted to strings. + * [Database_Expression] objects will be compiled. + * [Database_Query] objects will be compiled and converted to a sub-query. + * All other objects will be converted using the `__toString` method. + * * @param mixed table name or array(table, alias) * @return string * @uses Database::quote_identifier @@ -581,8 +591,8 @@ public function quote_table($table) } elseif ($table instanceof Database_Expression) { - // Use a raw expression - $table = $table->value(); + // Compile the expression + $table = $table->compile($this); } else { @@ -630,7 +640,7 @@ public function quote_table($table) * Quote a database identifier * * Objects passed to this function will be converted to strings. - * [Database_Expression] objects will use the value of the expression. + * [Database_Expression] objects will be compiled. * [Database_Query] objects will be compiled and converted to a sub-query. * All other objects will be converted using the `__toString` method. * @@ -651,8 +661,8 @@ public function quote_identifier($value) } elseif ($value instanceof Database_Expression) { - // Use a raw expression - $value = $value->value(); + // Compile the expression + $value = $value->compile($this); } else { diff --git a/classes/kohana/database/expression.php b/classes/kohana/database/expression.php index 90b8100..b61b85a 100644 --- a/classes/kohana/database/expression.php +++ b/classes/kohana/database/expression.php @@ -18,6 +18,9 @@ */ class Kohana_Database_Expression { + // Unquoted parameters + protected $_parameters; + // Raw expression string protected $_value; @@ -26,12 +29,56 @@ class Kohana_Database_Expression { * * $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) + 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; } /** @@ -59,4 +106,33 @@ 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 diff --git a/classes/kohana/db.php b/classes/kohana/db.php index b6e513f..7b04130 100644 --- a/classes/kohana/db.php +++ b/classes/kohana/db.php @@ -129,11 +129,12 @@ public static function delete($table = NULL) * $users = ORM::factory('user')->where(DB::expr("BINARY `hash`"), '=', $hash)->find(); * * @param string expression + * @param array parameters * @return Database_Expression */ - public static function expr($string) + public static function expr($string, $parameters = array()) { - return new Database_Expression($string); + return new Database_Expression($string, $parameters); } } // End DB From e353340975ac21c5b7ffb2a25f31a052b03fce0f Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Mon, 4 Jul 2011 11:13:06 -0500 Subject: [PATCH 16/21] Handle cached empty results in Query::execute(). Fixes #4032 --- classes/kohana/database/query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/kohana/database/query.php b/classes/kohana/database/query.php index 3567b15..7c8f8af 100644 --- a/classes/kohana/database/query.php +++ b/classes/kohana/database/query.php @@ -214,7 +214,7 @@ public function execute($db = NULL) // Set the cache key based on the database instance name and SQL $cache_key = 'Database::query("'.$db.'", "'.$sql.'")'; - if ($result = Kohana::cache($cache_key, NULL, $this->_lifetime)) + if (($result = Kohana::cache($cache_key, NULL, $this->_lifetime)) !== NULL) { // Return a cached result return new Database_Result_Cached($result, $sql, $this->_as_object, $this->_object_params); From f7433b1cf5ebe8378e57572f1360103395066ed7 Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Mon, 4 Jul 2011 11:24:44 -0500 Subject: [PATCH 17/21] Use message and code from the generated exception. Fixes #3608 --- classes/kohana/database/mysql.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/kohana/database/mysql.php b/classes/kohana/database/mysql.php index f5f0df8..2855a47 100644 --- a/classes/kohana/database/mysql.php +++ b/classes/kohana/database/mysql.php @@ -59,14 +59,14 @@ public function connect() $this->_connection = mysql_connect($hostname, $username, $password, TRUE); } } - catch (ErrorException $e) + catch (Exception $e) { // No connection exists $this->_connection = NULL; throw new Database_Exception(':error', - array(':error' => mysql_error()), - mysql_errno()); + array(':error' => $e->getMessage()), + $e->getCode()); } // \xFF is a better delimiter, but the PHP driver uses underscore From 9ef34f4db2d5e47eb2303735a6eea39e9975b502 Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Mon, 4 Jul 2011 13:16:22 -0500 Subject: [PATCH 18/21] Use column aliases in WHERE, GROUP BY, HAVING and ORDER BY clauses. Fixes #4057 --- classes/kohana/database/query/builder.php | 55 ++++++++++++++++++- .../kohana/database/query/builder/select.php | 4 +- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/classes/kohana/database/query/builder.php b/classes/kohana/database/query/builder.php index 270e316..4437df2 100644 --- a/classes/kohana/database/query/builder.php +++ b/classes/kohana/database/query/builder.php @@ -118,8 +118,16 @@ protected function _compile_conditions(Database $db, array $conditions) if ($column) { - // Apply proper quoting to the column - $column = $db->quote_column($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); + } } // Append the statement to the query @@ -163,6 +171,36 @@ protected function _compile_set(Database $db, array $values) return implode(', ', $set); } + /** + * Compiles an array of GROUP BY columns into an SQL partial. + * + * @param object 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. * @@ -177,13 +215,24 @@ protected function _compile_order_by(Database $db, array $columns) { 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[] = $db->quote_column($column).$direction; + $sort[] = $column.$direction; } return 'ORDER BY '.implode(', ', $sort); diff --git a/classes/kohana/database/query/builder/select.php b/classes/kohana/database/query/builder/select.php index 4c45624..30e0513 100644 --- a/classes/kohana/database/query/builder/select.php +++ b/classes/kohana/database/query/builder/select.php @@ -372,8 +372,8 @@ public function compile(Database $db) if ( ! empty($this->_group_by)) { - // Add sorting - $query .= ' GROUP BY '.implode(', ', array_map($quote_column, $this->_group_by)); + // Add grouping + $query .= ' '.$this->_compile_group_by($db, $this->_group_by); } if ( ! empty($this->_having)) From 70dbbc0b395eeb5b1fe09539968c778aca32a0ff Mon Sep 17 00:00:00 2001 From: Kiall Mac Innes Date: Tue, 5 Jul 2011 07:36:01 +0100 Subject: [PATCH 19/21] Add support for session restarting - refs #3100 --- classes/kohana/session/database.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/classes/kohana/session/database.php b/classes/kohana/session/database.php index 1a381cd..c219a00 100644 --- a/classes/kohana/session/database.php +++ b/classes/kohana/session/database.php @@ -176,6 +176,16 @@ protected function _write() return TRUE; } + /** + * @return bool + */ + protected function _restart() + { + $this->_regenerate(); + + return TRUE; + } + protected function _destroy() { if ($this->_update_id === NULL) From 10474ec0d25fead87a7a4e7367675f839b9eecb3 Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Mon, 11 Jul 2011 22:34:19 -0500 Subject: [PATCH 20/21] Column aliases cannot be used in WHERE and HAVING conditions. Fixes #4057 --- classes/kohana/database/query/builder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classes/kohana/database/query/builder.php b/classes/kohana/database/query/builder.php index 4437df2..d41b23a 100644 --- a/classes/kohana/database/query/builder.php +++ b/classes/kohana/database/query/builder.php @@ -120,8 +120,8 @@ protected function _compile_conditions(Database $db, array $conditions) { if (is_array($column)) { - // Use the column alias - $column = $db->quote_identifier(end($column)); + // Use the column name + $column = $db->quote_identifier(reset($column)); } else { From f0944e8586ef2f8230042d822a3781c4835c3a75 Mon Sep 17 00:00:00 2001 From: Chris Bandy Date: Mon, 11 Jul 2011 23:02:28 -0500 Subject: [PATCH 21/21] MySQL: Set session variables in a single statement. Fixes #4103 --- classes/kohana/database/mysql.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/classes/kohana/database/mysql.php b/classes/kohana/database/mysql.php index 2c8719e..f80e923 100644 --- a/classes/kohana/database/mysql.php +++ b/classes/kohana/database/mysql.php @@ -83,13 +83,14 @@ public function connect() if ( ! empty($this->_config['connection']['variables'])) { // Set session variables - foreach ($this->_config['connection']['variables'] as $variable => $value) + $variables = array(); + + foreach ($this->_config['connection']['variables'] as $var => $val) { - mysql_query( - 'SET SESSION '.$variable.' = '.$this->quote($value), - $this->_connection - ); + $variables[] = 'SESSION '.$var.' = '.$this->quote($val); } + + mysql_query('SET '.implode(', ', $variables), $this->_connection); } }