From 9b3e7b5f2d4ec4feae793ef90454506addbb19e1 Mon Sep 17 00:00:00 2001 From: Derek Allard Date: Mon, 4 Feb 2008 23:20:34 +0000 Subject: Added and documented Active Record caching. Made AR fully database-prefix aware --- system/database/DB_active_rec.php | 313 ++++++++++++++++++--- system/database/drivers/mssql/mssql_driver.php | 7 + system/database/drivers/mysql/mysql_driver.php | 7 + system/database/drivers/mysqli/mysqli_driver.php | 7 + system/database/drivers/oci8/oci8_driver.php | 7 + system/database/drivers/odbc/odbc_driver.php | 7 + system/database/drivers/postgre/postgre_driver.php | 9 +- system/database/drivers/sqlite/sqlite_driver.php | 7 + 8 files changed, 322 insertions(+), 42 deletions(-) (limited to 'system/database') diff --git a/system/database/DB_active_rec.php b/system/database/DB_active_rec.php index e93b99e3d..b3bf02a8b 100644 --- a/system/database/DB_active_rec.php +++ b/system/database/DB_active_rec.php @@ -43,6 +43,23 @@ class CI_DB_active_record extends CI_DB_driver { var $ar_set = array(); var $ar_wherein = array(); var $ar_aliased_tables = array(); + var $ar_store_array = array(); + + // Active Record Caching variables + var $ar_caching = FALSE; + var $ar_cache_select = array(); + var $ar_cache_from = array(); + var $ar_cache_join = array(); + var $ar_cache_where = array(); + var $ar_cache_like = array(); + var $ar_cache_groupby = array(); + var $ar_cache_having = array(); + var $ar_cache_limit = FALSE; + var $ar_cache_offset = FALSE; + var $ar_cache_order = FALSE; + var $ar_cache_orderby = array(); + var $ar_cache_set = array(); + /** * DB Prefix @@ -87,12 +104,23 @@ class CI_DB_active_record extends CI_DB_driver { if ($val != '*' && $protect_identifiers !== FALSE) { - $val = $this->_protect_identifiers($val); + if (strpos($val, '.') !== FALSE) + { + $val = $this->dbprefix.$val; + } + else + { + $val = $this->_protect_identifiers($val); + } } if ($val != '') { $this->ar_select[] = $val; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_select[] = $val; + } } } return $this; @@ -122,6 +150,10 @@ class CI_DB_active_record extends CI_DB_driver { $sql = 'MAX('.$this->_protect_identifiers(trim($select)).') AS '.$this->_protect_identifiers(trim($alias)); $this->ar_select[] = $sql; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_select[] = $sql; + } return $this; } @@ -150,7 +182,11 @@ class CI_DB_active_record extends CI_DB_driver { $sql = 'MIN('.$this->_protect_identifiers(trim($select)).') AS '.$this->_protect_identifiers(trim($alias)); $this->ar_select[] = $sql; - + if ($this->ar_caching === TRUE) + { + $this->ar_cache_select[] = $sql; + } + return $this; } @@ -178,7 +214,11 @@ class CI_DB_active_record extends CI_DB_driver { $sql = 'AVG('.$this->_protect_identifiers(trim($select)).') AS '.$this->_protect_identifiers(trim($alias)); $this->ar_select[] = $sql; - + if ($this->ar_caching === TRUE) + { + $this->ar_cache_select[] = $sql; + } + return $this; } @@ -206,7 +246,11 @@ class CI_DB_active_record extends CI_DB_driver { $sql = 'SUM('.$this->_protect_identifiers(trim($select)).') AS '.$this->_protect_identifiers(trim($alias)); $this->ar_select[] = $sql; - + if ($this->ar_caching === TRUE) + { + $this->ar_cache_select[] = $sql; + } + return $this; } @@ -243,6 +287,10 @@ class CI_DB_active_record extends CI_DB_driver { foreach ((array)$from as $val) { $this->ar_from[] = $this->_protect_identifiers($this->_track_aliases($val)); + if ($this->ar_caching === TRUE) + { + $this->ar_cache_from[] = $this->_protect_identifiers($val); + } } return $this; @@ -289,7 +337,14 @@ class CI_DB_active_record extends CI_DB_driver { $cond = preg_replace('|([\w\.]+)([\W\s]+)(.+)|', $this->dbprefix . "$1$2" . $this->dbprefix . "$3", $cond); } - $this->ar_join[] = $type.'JOIN '.$this->_protect_identifiers($this->dbprefix.$table, TRUE).' ON '.$cond; + $join = $type.'JOIN '.$this->_protect_identifiers($this->dbprefix.$table, TRUE).' ON '.$cond; + + $this->ar_join[] = $join; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_join[] = $join; + } + return $this; } @@ -360,7 +415,7 @@ class CI_DB_active_record extends CI_DB_driver { { $key = array($key => $value); } - + foreach ($key as $k => $v) { $prefix = (count($this->ar_where) == 0) ? '' : $type; @@ -393,10 +448,18 @@ class CI_DB_active_record extends CI_DB_driver { } $v = ' '.$this->escape($v); - } - + else + { + $k = $this->_protect_identifiers($k, TRUE); + } + $this->ar_where[] = $prefix.$k.$v; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_where[] = $prefix.$k.$v; + } + } return $this; } @@ -507,7 +570,13 @@ class CI_DB_active_record extends CI_DB_driver { $prefix = (count($this->ar_where) == 0) ? '' : $type; - $this->ar_where[] = $prefix . $this->_protect_identifiers($key) . $not . " IN (" . implode(", ", $this->ar_wherein) . ") "; + $where_in = $prefix . $this->_protect_identifiers($key) . $not . " IN (" . implode(", ", $this->ar_wherein) . ") "; + + $this->ar_where[] = $where_in; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_where[] = $where_in; + } // reset the array for multiple calls $this->ar_wherein = array(); @@ -629,16 +698,23 @@ class CI_DB_active_record extends CI_DB_driver { if ($side == 'before') { - $this->ar_like[] = $prefix." $k $not LIKE '%{$v}'"; + $like_statement = $prefix." $k $not LIKE '%{$v}'"; } elseif ($side == 'after') { - $this->ar_like[] = $prefix." $k $not LIKE '{$v}%'"; + $like_statement = $prefix." $k $not LIKE '{$v}%'"; } else { - $this->ar_like[] = $prefix." $k $not LIKE '%{$v}%'"; + $like_statement = $prefix." $k $not LIKE '%{$v}%'"; } + + $this->ar_like[] = $like_statement; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_like[] = $like_statement; + } + } return $this; } @@ -664,7 +740,13 @@ class CI_DB_active_record extends CI_DB_driver { $val = trim($val); if ($val != '') + { $this->ar_groupby[] = $this->_protect_identifiers($val); + if ($this->ar_caching === TRUE) + { + $this->ar_cache_groupby[] = $this->_protect_identifiers($val); + } + } } return $this; } @@ -724,6 +806,7 @@ class CI_DB_active_record extends CI_DB_driver { * * @access private * @param string + * @param string * @return object */ @@ -737,14 +820,20 @@ class CI_DB_active_record extends CI_DB_driver { foreach ($key as $k => $v) { $prefix = (count($this->ar_having) == 0) ? '' : $type; + $k = $this->_protect_identifiers($k); if ($v != '') { - $v = ' '.$this->escape($v); + $v = ' '.$this->escape_str($v); } $this->ar_having[] = $prefix.$k.$v; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_having[] = $prefix.$k.$v; + } } + return $this; } @@ -770,7 +859,14 @@ class CI_DB_active_record extends CI_DB_driver { $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC'; } - $this->ar_orderby[] = $this->_protect_identifiers($orderby, TRUE).$direction; + $orderby_statement = $this->_protect_identifiers($orderby, TRUE).$direction; + + $this->ar_orderby[] = $orderby_statement; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_orderby[] = $orderby_statement; + } + return $this; } @@ -799,9 +895,19 @@ class CI_DB_active_record extends CI_DB_driver { function limit($value, $offset = '') { $this->ar_limit = $value; - + if ($this->ar_caching === TRUE) + { + $this->ar_cache_limit[] = $value; + } + if ($offset != '') + { $this->ar_offset = $offset; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_offset[] = $offset; + } + } return $this; } @@ -815,9 +921,14 @@ class CI_DB_active_record extends CI_DB_driver { * @param integer the offset value * @return object */ - function offset($value) + function offset($offset) { - $this->ar_offset = $value; + $this->ar_offset = $offset; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_offset[] = $offset; + } + return $this; } @@ -846,12 +957,19 @@ class CI_DB_active_record extends CI_DB_driver { if ($escape === FALSE) { $this->ar_set[$this->_protect_identifiers($k)] = $v; + if ($this->ar_caching === TRUE) + { + $this->ar_cache_offset[$this->_protect_identifiers($k)] = $v; + } } else { $this->ar_set[$this->_protect_identifiers($k)] = $this->escape($v); + if ($this->ar_caching === TRUE) + { + $this->ar_cache_offset[$this->_protect_identifiers($k)] = $this->escape($v); + } } - } return $this; @@ -1331,6 +1449,11 @@ class CI_DB_active_record extends CI_DB_driver { */ function _compile_select($select_override = FALSE) { + if ($this->ar_caching === TRUE) + { + $this->_merge_cache(); + } + $sql = ( ! $this->ar_distinct) ? 'SELECT ' : 'SELECT DISTINCT '; $sql .= (count($this->ar_select) == 0) ? '*' : implode(', ', $this->ar_select); @@ -1455,6 +1578,107 @@ class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- + /** + * Start Cache + * + * Starts AR caching + * + * @access public + * @return void + */ + function start_cache() + { + $this->ar_caching = TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Stop Cache + * + * Stops AR caching + * + * @access public + * @return void + */ + function stop_cache() + { + $this->ar_caching = FALSE; + } + + + // -------------------------------------------------------------------- + + /** + * Flush Cache + * + * Empties the AR cache + * + * @access public + * @return void + */ + function flush_cache() + { + $ar_reset_items = array( + 'ar_cache_select' => array(), + 'ar_cache_from' => array(), + 'ar_cache_join' => array(), + 'ar_cache_where' => array(), + 'ar_cache_like' => array(), + 'ar_cache_groupby' => array(), + 'ar_cache_having' =>array(), + 'ar_cache_orderby' => array(), + 'ar_cache_set' => array() + ); + + $this->_reset_run($ar_reset_items); + } + + // -------------------------------------------------------------------- + + /** + * Merge Cache + * + * When called, this function merges any cached AR arrays with + * locally called ones. + * + * @access private + * @return void + */ + function _merge_cache() + { + $ar_items = array('select', 'from', 'join', 'where', 'like', 'groupby', 'having', 'orderby', 'set'); + + foreach ($ar_items as $ar_item) + { + $ar_cache_item = 'ar_cache_'.$ar_item; + $ar_item = 'ar_'.$ar_item; + $this->$ar_item = array_unique(array_merge($this->$ar_item, $this->$ar_cache_item)); + } + } + + // -------------------------------------------------------------------- + + /** + * Resets the active record values. Called by the get() function + * + * @access private + * @param array An array of fields to reset + * @return void + */ + function _reset_run($ar_reset_items) + { + foreach ($ar_reset_items as $item => $default_value) + { + if (!in_array($item, $this->ar_store_array)) + { + $this->$item = $default_value; + } + } + } + + // -------------------------------------------------------------------- + /** * Resets the active record values. Called by the get() function * @@ -1463,20 +1687,24 @@ class CI_DB_active_record extends CI_DB_driver { */ function _reset_select() { - $this->ar_select = array(); - $this->ar_distinct = FALSE; - $this->ar_from = array(); - $this->ar_join = array(); - $this->ar_where = array(); - $this->ar_like = array(); - $this->ar_groupby = array(); - $this->ar_having = array(); - $this->ar_limit = FALSE; - $this->ar_offset = FALSE; - $this->ar_order = FALSE; - $this->ar_orderby = array(); - $this->ar_wherein = array(); - $this->ar_aliased_tables = array(); + $ar_reset_items = array( + 'ar_select' => array(), + 'ar_from' => array(), + 'ar_join' => array(), + 'ar_where' => array(), + 'ar_like' => array(), + 'ar_groupby' => array(), + 'ar_having' => array(), + 'ar_orderby' => array(), + 'ar_wherein' => array(), + 'ar_aliased_tables' => array(), + 'ar_distinct' => FALSE, + 'ar_limit' => FALSE, + 'ar_offset' => FALSE, + 'ar_order' => FALSE, + ); + + $this->_reset_run($ar_reset_items); } // -------------------------------------------------------------------- @@ -1490,16 +1718,19 @@ class CI_DB_active_record extends CI_DB_driver { * @return void */ function _reset_write() - { - $this->ar_set = array(); - $this->ar_from = array(); - $this->ar_where = array(); - $this->ar_like = array(); - $this->ar_limit = FALSE; - $this->ar_order = FALSE; - $this->ar_orderby = array(); + { + $ar_reset_items = array( + 'ar_set' => array(), + 'ar_from' => array(), + 'ar_where' => array(), + 'ar_like' => array(), + 'ar_orderby' => array(), + 'ar_limit' => FALSE, + 'ar_order' => FALSE + ); + + $this->_reset_run($ar_reset_items); } } - ?> \ No newline at end of file diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php index ad747d4ad..ecd404b52 100644 --- a/system/database/drivers/mssql/mssql_driver.php +++ b/system/database/drivers/mssql/mssql_driver.php @@ -433,6 +433,13 @@ class CI_DB_mssql_driver extends CI_DB { function _protect_identifiers($item, $affect_spaces = TRUE, $first_word_only = FALSE) { // MSSQL doesn't use backticks + if (strpos($item, '.') !== FALSE) + { + $aliased_tables = implode(".",$this->ar_aliased_tables).'.'; + $table_name = substr($item, 0, strpos($item, '.')+1); + $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item; + } + return $item; } diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php index f00257250..a5082d1b3 100644 --- a/system/database/drivers/mysql/mysql_driver.php +++ b/system/database/drivers/mysql/mysql_driver.php @@ -454,6 +454,13 @@ class CI_DB_mysql_driver extends CI_DB { // we may need "`item1` `item2`" and not "`item1 item2`" if (ctype_alnum($item) === FALSE) { + if (strpos($item, '.') !== FALSE) + { + $aliased_tables = implode(".",$this->ar_aliased_tables).'.'; + $table_name = substr($item, 0, strpos($item, '.')+1); + $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item; + } + // This function may get "field >= 1", and need it to return "`field` >= 1" $lbound = ($first_word_only === TRUE) ? '' : '|\s|\('; diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php index b2e97f927..9e7cc0c9f 100644 --- a/system/database/drivers/mysqli/mysqli_driver.php +++ b/system/database/drivers/mysqli/mysqli_driver.php @@ -448,6 +448,13 @@ class CI_DB_mysqli_driver extends CI_DB { // we may need "`item1` `item2`" and not "`item1 item2`" if (ctype_alnum($item) === FALSE) { + if (strpos($item, '.') !== FALSE) + { + $aliased_tables = implode(".",$this->ar_aliased_tables).'.'; + $table_name = substr($item, 0, strpos($item, '.')+1); + $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item; + } + // This function may get "field >= 1", and need it to return "`field` >= 1" $lbound = ($first_word_only === TRUE) ? '' : '|\s|\('; diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php index ddc0fba99..aa2aeca42 100644 --- a/system/database/drivers/oci8/oci8_driver.php +++ b/system/database/drivers/oci8/oci8_driver.php @@ -559,6 +559,13 @@ class CI_DB_oci8_driver extends CI_DB { // we may need "`item1` `item2`" and not "`item1 item2`" if (ctype_alnum($item) === FALSE) { + if (strpos($item, '.') !== FALSE) + { + $aliased_tables = implode(".",$this->ar_aliased_tables).'.'; + $table_name = substr($item, 0, strpos($item, '.')+1); + $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item; + } + // This function may get "field >= 1", and need it to return "`field` >= 1" $lbound = ($first_word_only === TRUE) ? '' : '|\s|\('; diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php index 03c0e6a86..88fff4365 100644 --- a/system/database/drivers/odbc/odbc_driver.php +++ b/system/database/drivers/odbc/odbc_driver.php @@ -424,6 +424,13 @@ class CI_DB_odbc_driver extends CI_DB { // we may need "`item1` `item2`" and not "`item1 item2`" if (ctype_alnum($item) === FALSE) { + if (strpos($item, '.') !== FALSE) + { + $aliased_tables = implode(".",$this->ar_aliased_tables).'.'; + $table_name = substr($item, 0, strpos($item, '.')+1); + $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item; + } + // This function may get "field >= 1", and need it to return "`field` >= 1" $lbound = ($first_word_only === TRUE) ? '' : '|\s|\('; diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php index e72981348..ae8bd86eb 100644 --- a/system/database/drivers/postgre/postgre_driver.php +++ b/system/database/drivers/postgre/postgre_driver.php @@ -444,6 +444,13 @@ class CI_DB_postgre_driver extends CI_DB { // we may need ""item1" "item2"" and not ""item1 item2"" if (ctype_alnum($item) === FALSE) { + if (strpos($item, '.') !== FALSE) + { + $aliased_tables = implode(".",$this->ar_aliased_tables).'.'; + $table_name = substr($item, 0, strpos($item, '.')+1); + $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item; + } + // This function may get "field >= 1", and need it to return ""field" >= 1" $lbound = ($first_word_only === TRUE) ? '' : '|\s|\('; @@ -486,7 +493,7 @@ class CI_DB_postgre_driver extends CI_DB { $tables = array($tables); } - return implode(', ', $tables); + return '('.implode(', ', $tables).')'; } // -------------------------------------------------------------------- diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php index 38febca29..dad5eeedf 100644 --- a/system/database/drivers/sqlite/sqlite_driver.php +++ b/system/database/drivers/sqlite/sqlite_driver.php @@ -440,6 +440,13 @@ class CI_DB_sqlite_driver extends CI_DB { // we may need "`item1` `item2`" and not "`item1 item2`" if (ctype_alnum($item) === FALSE) { + if (strpos($item, '.') !== FALSE) + { + $aliased_tables = implode(".",$this->ar_aliased_tables).'.'; + $table_name = substr($item, 0, strpos($item, '.')+1); + $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item; + } + // This function may get "field >= 1", and need it to return "`field` >= 1" $lbound = ($first_word_only === TRUE) ? '' : '|\s|\('; -- cgit v1.2.3-24-g4f1b