Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Active Record parallel queries

Lev-Zabudko edited this page · 24 revisions
Clone this wiki locally

Category:Core | Category:Core::Database | Category:Core::Community

This is a replacement of the system/database/DB_active_rec.php file, allowing you to use several CI Active Record threads at the same time without overlapping. See the relevant forum thread.

Sample code:

$this->db->set_identifier('my_first_query');
$this->db->from('blabla');
$this->db->where('blibli');

$this->db->set_identifier('my_second_query');
$this->db->from('tatata');
$this->db->where('tititi');

$this->db->set_identifier('my_first_query');
$first_query = $this->db->get();

$this->db->set_identifier('my_second_query');
$second_query = $this->db->get();

It's fully backward compatible, and you could use it also this way (adding two lines around the code to protect from other AR calls):

$this->db->set_identifier("my unique string that I won't use twice unless it's really clean");
$query = $this->db->getwhere('a_table', array('id' => $id));
$result = $query->first_row();
$this->db->set_identifier('default');

Some apps (like Rapyd in dataset.php around line 253) tweak some AR variables without using the public functions. You'll have to hack them if you want to use the new DB_active_rec.php. For example in Rapyd, the lines

// ...
$this->db->ar_limit = FALSE;
// ...
$this->db->ar_select = array('COUNT(*) AS totalrows');  
// ...
$this->db->ar_orderby = array();
// ...
$this->db->ar_order = FALSE;

becomes

// ...
$this->db->ar_limit['default'] = FALSE;
// ...
$this->db->ar_select['default'] = array('COUNT(*) AS totalrows');  
// ...
$this->db->ar_orderby['default'] = array();
// ...
$this->db->ar_order['default'] = FALSE;

Here is a piece of the code of this new file.

<?php
/**
 * Active Record Class
 *
 * This is the platform-independent base Active Record implementation class.
 *
 * Changes by Christophe Gragnic on 2007/06/14 are:
 *         vars now arrays of old vars
 *         added var $ar_identifier and its setter
 *         everywhere you had $this->ar_somevar, you now have
 *         $this->ar_somevar[$this->ar_identifier]
 *
 * Those changes allow us to use Active Record parallel queries.
 * The "identifier" is a simple string (default:'default').
 * Backward compatible, set_identifier('some_identifier') is optional.
 *
 * Sample code:
 * $this->db->set_identifier('my_first_query');
 * $this->db->from('blabla');
 * $this->db->where('blibli');
 *
 * $this->db->set_identifier('my_second_query');
 * $this->db->from('tatata');
 * $this->db->where('tititi');
 *
 * $this->db->set_identifier('my_first_query');
 * $first_query = $this->db->get();
 *
 * $this->db->set_identifier('my_second_query');
 * $second_query = $this->db->get();
 *
 * @package        CodeIgniter
 * @subpackage    Drivers
 * @category    Database
 * @author        Rick Ellis
 * @author        Christophe Gragnic (grahack) for the identifier stuff only
 * @link        http://www.codeigniter.com/user_guide/database/
 */
class CI_DB_active_record extends CI_DB_driver {

    var $ar_identifier = 'default';

    var $ar_select    = array('default' => array());
    var $ar_distinct  = array('default' => FALSE);
    var $ar_from      = array('default' => array());
    var $ar_join      = array('default' => array());
    var $ar_where     = array('default' => array());
    var $ar_like      = array('default' => array());
    var $ar_groupby   = array('default' => array());
    var $ar_having    = array('default' => array());
    var $ar_limit     = array('default' => FALSE);
    var $ar_offset    = array('default' => FALSE);
    var $ar_order     = array('default' => FALSE);
    var $ar_orderby   = array('default' => array());
    var $ar_set       = array('default' => array());

    /**
     * Set_identifier
     *
     * Chooses the channel to use
     *
     * @access    public
     * @param    string
     * @return    object
     */
    function set_identifier($identifier = 'default')
    {
        if ( ! is_string($identifier))
        {
            $identifier = 'default';
        }

        $this->ar_identifier = $identifier;

        // we have to init the values only if it is a new key
        // let's check on the first array
        if ( ! array_key_exists($identifier, $this->ar_select))
        {
            $this->ar_select        [$identifier] = array();
            $this->ar_distinct      [$identifier] = FALSE;
            $this->ar_from          [$identifier] = array();
            $this->ar_join          [$identifier] = array();
            $this->ar_where         [$identifier] = array();
            $this->ar_like          [$identifier] = array();
            $this->ar_groupby       [$identifier] = array();
            $this->ar_having        [$identifier] = array();
            $this->ar_limit         [$identifier] = FALSE;
            $this->ar_offset        [$identifier] = FALSE;
            $this->ar_order         [$identifier] = FALSE;
            $this->ar_orderby       [$identifier] = array();
            $this->ar_set           [$identifier] = array();
        }
        return $this;
    }

Download

File:DB_active_rec.zip

version 1.7.2 edited by Afro Radio Head Loved this added feature, so I had to update it File:DB_active_rec_v1.7.2.zip

updated by LevZabudko - modified this file for 2.1.3 version.

Here is the new source. Hope this helps smbdy:

don't forget to change (seems it's a Codeigniter bug in line 712 in 2.1.3) in _delete function in all db_driver files like database/driver/mysql/mysql_driver.php to:

$conditions .= implode("\n", $where);

or delete function will not work.

Main code:

<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');
/**
 * CodeIgniter
 *
 * An open source application development framework for PHP 5.1.6 or newer
 *
 * @package     CodeIgniter
 * @author      ExpressionEngine Dev Team, Lev Zabudko
 * @copyright   Copyright (c) 2008 - 2011, EllisLab, Inc.
 * @license     http://codeigniter.com/user_guide/license.html, AS IS
 * @link        http://codeigniter.com, https://www.facebook.com/LevZabudko
 * @since       Version 1.0u
 * @filesource
 */
// ------------------------------------------------------------------------

/**
 * Active Record Class
 *
 * This is the platform-independent base Active Record implementation class.
 *
 * @package     CodeIgniter
 * @subpackage  Drivers
 * @category    Database
 * @author      ExpressionEngine Dev Team
 * @link        http://codeigniter.com/user_guide/database/
 */
class CI_DB_active_record extends CI_DB_driver
{

    var $ar_identifier = 'default';
    var $ar_select = array('default' => array());
    var $ar_distinct = array('default' => FALSE);
    var $ar_from = array('default' => array());
    var $ar_join = array('default' => array());
    var $ar_where = array('default' => array());
    var $ar_like = array('default' => array());
    var $ar_groupby = array('default' => array());
    var $ar_having = array('default' => array());
    var $ar_keys = array('default' => array());
    var $ar_limit = array('default' => FALSE);
    var $ar_offset = array('default' => FALSE);
    var $ar_order = array('default' => FALSE);
    var $ar_orderby = array('default' => array());
    var $ar_set = array('default' => array());
    var $ar_wherein = array('default' => array());
    var $ar_aliased_tables = array('default' => array());
    var $ar_store_array = array('default' => array());
    var $ar_no_escape =  array('default' => array());
    // Active Record Caching variables
    var $ar_caching = FALSE;
    var $ar_cache_exists = array();
    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_orderby = array();
    var $ar_cache_set = array();
    var $ar_cache_no_escape = array();

    /**
     * Set_identifier
     *
     * Chooses the channel to use
     *
     * @access    public
     * @param    string
     * @return    object
     */
    function set_identifier($identifier = 'default')
    {
        if (!is_string($identifier))
        {
            $identifier = 'default';
        }

        $this->ar_identifier = $identifier;
        // we have to init the values only if it is a new key
        // let's check on the first array
        if (!array_key_exists($identifier, $this->ar_select))
        {
            $this->ar_select [$identifier] = array();
            $this->ar_distinct [$identifier] = FALSE;
            $this->ar_from [$identifier] = array();
            $this->ar_join [$identifier] = array();
            $this->ar_where [$identifier] = array();
            $this->ar_like [$identifier] = array();
            $this->ar_groupby [$identifier] = array();
            $this->ar_having [$identifier] = array();
            $this->ar_limit [$identifier] = FALSE;
            $this->ar_offset [$identifier] = FALSE;
            $this->ar_order [$identifier] = FALSE;
            $this->ar_orderby [$identifier] = array();
            $this->ar_set [$identifier] = array();
            $this->ar_keys [$identifier] = array();
            $this->ar_wherein [$identifier] = array();
            $this->ar_aliased_tables [$identifier] = array();
            $this->ar_store_array [$identifier] = array();
        }
        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Select
     *
     * Generates the SELECT portion of the query
     *
     * @param   string
     * @return  object
     */
    public function select($select = '*', $escape = NULL)
    {
        if (is_string($select))
        {
            $select = explode(',', $select);
        }

        foreach ($select as $val)
        {
            $val = trim($val);

            if ($val != '')
            {
                $this->ar_select[$this->ar_identifier][] = $val;
                $this->ar_no_escape[$this->ar_identifier][] = $escape;

                if ($this->ar_caching === TRUE)
                {
                    $this->ar_cache_select[] = $val;
                    $this->ar_cache_exists[] = 'select';
                    $this->ar_cache_no_escape[] = $escape;
                }
            }
        }
        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Select Max
     *
     * Generates a SELECT MAX(field) portion of a query
     *
     * @param   string  the field
     * @param   string  an alias
     * @return  object
     */
    public function select_max($select = '', $alias = '')
    {
        return $this->_max_min_avg_sum($select, $alias, 'MAX');
    }

    // --------------------------------------------------------------------

    /**
     * Select Min
     *
     * Generates a SELECT MIN(field) portion of a query
     *
     * @param   string  the field
     * @param   string  an alias
     * @return  object
     */
    public function select_min($select = '', $alias = '')
    {
        return $this->_max_min_avg_sum($select, $alias, 'MIN');
    }

    // --------------------------------------------------------------------

    /**
     * Select Average
     *
     * Generates a SELECT AVG(field) portion of a query
     *
     * @param   string  the field
     * @param   string  an alias
     * @return  object
     */
    public function select_avg($select = '', $alias = '')
    {
        return $this->_max_min_avg_sum($select, $alias, 'AVG');
    }

    // --------------------------------------------------------------------

    /**
     * Select Sum
     *
     * Generates a SELECT SUM(field) portion of a query
     *
     * @param   string  the field
     * @param   string  an alias
     * @return  object
     */
    public function select_sum($select = '', $alias = '')
    {
        return $this->_max_min_avg_sum($select, $alias, 'SUM');
    }

    // --------------------------------------------------------------------

    /**
     * Processing Function for the four functions above:
     *
     *  select_max()
     *  select_min()
     *  select_avg()
     *  select_sum()
     *
     * @param   string  the field
     * @param   string  an alias
     * @return  object
     */
    protected function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX')
    {
        if (!is_string($select) OR $select == '')
        {
            $this->display_error('db_invalid_query');
        }

        $type = strtoupper($type);

        if (!in_array($type, array('MAX', 'MIN', 'AVG', 'SUM')))
        {
            show_error('Invalid function type: ' . $type);
        }

        if ($alias == '')
        {
            $alias = $this->_create_alias_from_table(trim($select));
        }

        $sql = $type . '(' . $this->_protect_identifiers(trim($select)) . ') AS ' . $alias;

        $this->ar_select[$this->ar_identifier][] = $sql;

        if ($this->ar_caching === TRUE)
        {
            $this->ar_cache_select[] = $sql;
            $this->ar_cache_exists[] = 'select';
        }

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Determines the alias name based on the table
     *
     * @param   string
     * @return  string
     */
    protected function _create_alias_from_table($item)
    {
        if (strpos($item, '.') !== FALSE)
        {
            return end(explode('.', $item));
        }

        return $item;
    }

    // --------------------------------------------------------------------

    /**
     * DISTINCT
     *
     * Sets a flag which tells the query string compiler to add DISTINCT
     *
     * @param   bool
     * @return  object
     */
    public function distinct($val = TRUE)
    {
        $this->ar_distinct[$this->ar_identifier] = (is_bool($val)) ? $val : TRUE;
        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * From
     *
     * Generates the FROM portion of the query
     *
     * @param   mixed   can be a string or array
     * @return  object
     */
    public function from($from)
    {
        foreach ((array) $from as $val)
        {
            if (strpos($val, ',') !== FALSE)
            {
                foreach (explode(',', $val) as $v)
                {
                    $v = trim($v);
                    $this->_track_aliases($v);

                    $this->ar_from[$this->ar_identifier][] = $this->_protect_identifiers($v, TRUE, NULL, FALSE);

                    if ($this->ar_caching === TRUE)
                    {
                        $this->ar_cache_from[] = $this->_protect_identifiers($v, TRUE, NULL, FALSE);
                        $this->ar_cache_exists[] = 'from';
                    }
                }
            } else
            {
                $val = trim($val);

                // Extract any aliases that might exist.  We use this information
                // in the _protect_identifiers to know whether to add a table prefix
                $this->_track_aliases($val);

                $this->ar_from[$this->ar_identifier][] = $this->_protect_identifiers($val, TRUE, NULL, FALSE);

                if ($this->ar_caching === TRUE)
                {
                    $this->ar_cache_from[] = $this->_protect_identifiers($val, TRUE, NULL, FALSE);
                    $this->ar_cache_exists[] = 'from';
                }
            }
        }

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Join
     *
     * Generates the JOIN portion of the query
     *
     * @param   string
     * @param   string  the join condition
     * @param   string  the type of join
     * @return  object
     */
    public function join($table, $cond, $type = '')
    {
        if ($type != '')
        {
            $type = strtoupper(trim($type));

            if (!in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER')))
            {
                $type = '';
            } else
            {
                $type .= ' ';
            }
        }

        // Extract any aliases that might exist.  We use this information
        // in the _protect_identifiers to know whether to add a table prefix
        $this->_track_aliases($table);

        // Strip apart the condition and protect the identifiers
        if (preg_match('/([\w\.]+)([\W\s]+)(.+)/', $cond, $match))
        {
            $match[1] = $this->_protect_identifiers($match[1]);
            $match[3] = $this->_protect_identifiers($match[3]);

            $cond = $match[1] . $match[2] . $match[3];
        }

        // Assemble the JOIN statement
        $join = $type . 'JOIN ' . $this->_protect_identifiers($table, TRUE, NULL, FALSE) . ' ON ' . $cond;

        $this->ar_join[$this->ar_identifier][] = $join;
        if ($this->ar_caching === TRUE)
        {
            $this->ar_cache_join[] = $join;
            $this->ar_cache_exists[] = 'join';
        }

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Where
     *
     * Generates the WHERE portion of the query. Separates
     * multiple calls with AND
     *
     * @param   mixed
     * @param   mixed
     * @return  object
     */
    public function where($key, $value = NULL, $escape = TRUE)
    {
        return $this->_where($key, $value, 'AND ', $escape);
    }

    // --------------------------------------------------------------------

    /**
     * OR Where
     *
     * Generates the WHERE portion of the query. Separates
     * multiple calls with OR
     *
     * @param   mixed
     * @param   mixed
     * @return  object
     */
    public function or_where($key, $value = NULL, $escape = TRUE)
    {
        return $this->_where($key, $value, 'OR ', $escape);
    }

    // --------------------------------------------------------------------

    /**
     * Where
     *
     * Called by where() or or_where()
     *
     * @param   mixed
     * @param   mixed
     * @param   string
     * @return  object
     */
    protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
    {

        if (!is_array($key))
        {
            $key = array($key => $value);
        }

        // If the escape value was not set will will base it on the global setting
        if (!is_bool($escape))
        {
            $escape = $this->_protect_identifiers;
        }

        foreach ($key as $k => $v)
        {
            $prefix = (count($this->ar_where[$this->ar_identifier]) == 0 AND count($this->ar_cache_where) == 0) ? '' : $type;

            if (is_null($v) && !$this->_has_operator($k))
            {
                // value appears not to have been set, assign the test to IS NULL
                $k .= ' IS NULL';
            }

            if (!is_null($v))
            {
                if ($escape === TRUE)
                {
                    $k = $this->_protect_identifiers($k, FALSE, $escape);

                    $v = ' ' . $this->escape($v);
                }

                if (!$this->_has_operator($k))
                {
                    $k .= ' = ';
                }
            } else
            {
                $k = $this->_protect_identifiers($k, FALSE, $escape);
            }

            $this->ar_where[$this->ar_identifier][] = $prefix . $k . $v;

            if ($this->ar_caching === TRUE)
            {
                $this->ar_cache_where[] = $prefix . $k . $v;
                $this->ar_cache_exists[] = 'where';
            }
        }
        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Where_in
     *
     * Generates a WHERE field IN ('item', 'item') SQL query joined with
     * AND if appropriate
     *
     * @param   string  The field to search
     * @param   array   The values searched on
     * @return  object
     */
    public function where_in($key = NULL, $values = NULL)
    {
        return $this->_where_in($key, $values);
    }

    // --------------------------------------------------------------------

    /**
     * Where_in_or
     *
     * Generates a WHERE field IN ('item', 'item') SQL query joined with
     * OR if appropriate
     *
     * @param   string  The field to search
     * @param   array   The values searched on
     * @return  object
     */
    public function or_where_in($key = NULL, $values = NULL)
    {
        return $this->_where_in($key, $values, FALSE, 'OR ');
    }

    // --------------------------------------------------------------------

    /**
     * Where_not_in
     *
     * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
     * with AND if appropriate
     *
     * @param   string  The field to search
     * @param   array   The values searched on
     * @return  object
     */
    public function where_not_in($key = NULL, $values = NULL)
    {
        return $this->_where_in($key, $values, TRUE);
    }

    // --------------------------------------------------------------------

    /**
     * Where_not_in_or
     *
     * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
     * with OR if appropriate
     *
     * @param   string  The field to search
     * @param   array   The values searched on
     * @return  object
     */
    public function or_where_not_in($key = NULL, $values = NULL)
    {
        return $this->_where_in($key, $values, TRUE, 'OR ');
    }

    // --------------------------------------------------------------------

    /**
     * Where_in
     *
     * Called by where_in, where_in_or, where_not_in, where_not_in_or
     *
     * @param   string  The field to search
     * @param   array   The values searched on
     * @param   boolean If the statement would be IN or NOT IN
     * @param   string
     * @return  object
     */
    protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ')
    {
        if ($key === NULL OR $values === NULL)
        {
            return;
        }

        if (!is_array($values))
        {
            $values = array($values);
        }

        $not = ($not) ? ' NOT' : '';

        foreach ($values as $value)
        {
            $this->ar_wherein[$this->ar_identifier][] = $this->escape($value);
        }

        $prefix = (count($this->ar_where[$this->ar_identifier]) == 0) ? '' : $type;

        $where_in = $prefix . $this->_protect_identifiers($key) . $not . " IN (" . implode(", ", $this->ar_wherein[$this->ar_identifier]) . ") ";

        $this->ar_where[$this->ar_identifier][] = $where_in;
        if ($this->ar_caching === TRUE)
        {
            $this->ar_cache_where[] = $where_in;
            $this->ar_cache_exists[] = 'where';
        }

        // reset the array for multiple calls
        $this->ar_wherein[$this->ar_identifier] = array();
        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Like
     *
     * Generates a %LIKE% portion of the query. Separates
     * multiple calls with AND
     *
     * @param   mixed
     * @param   mixed
     * @return  object
     */
    public function like($field, $match = '', $side = 'both')
    {
        return $this->_like($field, $match, 'AND ', $side);
    }

    // --------------------------------------------------------------------

    /**
     * Not Like
     *
     * Generates a NOT LIKE portion of the query. Separates
     * multiple calls with AND
     *
     * @param   mixed
     * @param   mixed
     * @return  object
     */
    public function not_like($field, $match = '', $side = 'both')
    {
        return $this->_like($field, $match, 'AND ', $side, 'NOT');
    }

    // --------------------------------------------------------------------

    /**
     * OR Like
     *
     * Generates a %LIKE% portion of the query. Separates
     * multiple calls with OR
     *
     * @param   mixed
     * @param   mixed
     * @return  object
     */
    public function or_like($field, $match = '', $side = 'both')
    {
        return $this->_like($field, $match, 'OR ', $side);
    }

    // --------------------------------------------------------------------

    /**
     * OR Not Like
     *
     * Generates a NOT LIKE portion of the query. Separates
     * multiple calls with OR
     *
     * @param   mixed
     * @param   mixed
     * @return  object
     */
    public function or_not_like($field, $match = '', $side = 'both')
    {
        return $this->_like($field, $match, 'OR ', $side, 'NOT');
    }

    // --------------------------------------------------------------------

    /**
     * Like
     *
     * Called by like() or orlike()
     *
     * @param   mixed
     * @param   mixed
     * @param   string
     * @return  object
     */
    protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '')
    {
        if (!is_array($field))
        {
            $field = array($field => $match);
        }

        foreach ($field as $k => $v)
        {
            $k = $this->_protect_identifiers($k);

            $prefix = (count($this->ar_like[$this->ar_identifier]) == 0) ? '' : $type;

            $v = $this->escape_like_str($v);

            if ($side == 'none')
            {
                $like_statement = $prefix . " $k $not LIKE '{$v}'";
            } elseif ($side == 'before')
            {
                $like_statement = $prefix . " $k $not LIKE '%{$v}'";
            } elseif ($side == 'after')
            {
                $like_statement = $prefix . " $k $not LIKE '{$v}%'";
            } else
            {
                $like_statement = $prefix . " $k $not LIKE '%{$v}%'";
            }

            // some platforms require an escape sequence definition for LIKE wildcards
            if ($this->_like_escape_str != '')
            {
                $like_statement = $like_statement . sprintf($this->_like_escape_str, $this->_like_escape_chr);
            }

            $this->ar_like[$this->ar_identifier][] = $like_statement;
            if ($this->ar_caching === TRUE)
            {
                $this->ar_cache_like[] = $like_statement;
                $this->ar_cache_exists[] = 'like';
            }
        }
        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * GROUP BY
     *
     * @param   string
     * @return  object
     */
    public function group_by($by)
    {
        if (is_string($by))
        {
            $by = explode(',', $by);
        }

        foreach ($by as $val)
        {
            $val = trim($val);

            if ($val != '')
            {
                $this->ar_groupby[$this->ar_identifier][] = $this->_protect_identifiers($val);

                if ($this->ar_caching === TRUE)
                {
                    $this->ar_cache_groupby[] = $this->_protect_identifiers($val);
                    $this->ar_cache_exists[] = 'groupby';
                }
            }
        }
        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Sets the HAVING value
     *
     * Separates multiple calls with AND
     *
     * @param   string
     * @param   string
     * @return  object
     */
    public function having($key, $value = '', $escape = TRUE)
    {
        return $this->_having($key, $value, 'AND ', $escape);
    }

    // --------------------------------------------------------------------

    /**
     * Sets the OR HAVING value
     *
     * Separates multiple calls with OR
     *
     * @param   string
     * @param   string
     * @return  object
     */
    public function or_having($key, $value = '', $escape = TRUE)
    {
        return $this->_having($key, $value, 'OR ', $escape);
    }

    // --------------------------------------------------------------------

    /**
     * Sets the HAVING values
     *
     * Called by having() or or_having()
     *
     * @param   string
     * @param   string
     * @return  object
     */
    protected function _having($key, $value = '', $type = 'AND ', $escape = TRUE)
    {
        if (!is_array($key))
        {
            $key = array($key => $value);
        }

        foreach ($key as $k => $v)
        {
            $prefix = (count($this->ar_having[$this->ar_identifier]) == 0) ? '' : $type;

            if ($escape === TRUE)
            {
                $k = $this->_protect_identifiers($k);
            }

            if (!$this->_has_operator($k))
            {
                $k .= ' = ';
            }

            if ($v != '')
            {
                $v = ' ' . $this->escape($v);
            }

            $this->ar_having[$this->ar_identifier][] = $prefix . $k . $v;
            if ($this->ar_caching === TRUE)
            {
                $this->ar_cache_having[] = $prefix . $k . $v;
                $this->ar_cache_exists[] = 'having';
            }
        }

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Sets the ORDER BY value
     *
     * @param   string
     * @param   string  direction: asc or desc
     * @return  object
     */
    public function order_by($orderby, $direction = '')
    {
        if (strtolower($direction) == 'random')
        {
            $orderby = ''; // Random results want or don't need a field name
            $direction = $this->_random_keyword;
        } elseif (trim($direction) != '')
        {
            $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' ' . $direction : ' ASC';
        }


        if (strpos($orderby, ',') !== FALSE)
        {
            $temp = array();
            foreach (explode(',', $orderby) as $part)
            {
                $part = trim($part);
                if (!in_array($part, $this->ar_aliased_tables))
                {
                    $part = $this->_protect_identifiers(trim($part));
                }

                $temp[] = $part;
            }

            $orderby = implode(', ', $temp);
        } else if ($direction != $this->_random_keyword)
        {
            $orderby = $this->_protect_identifiers($orderby);
        }

        $orderby_statement = $orderby . $direction;

        $this->ar_orderby[$this->ar_identifier][] = $orderby_statement;
        if ($this->ar_caching === TRUE)
        {
            $this->ar_cache_orderby[] = $orderby_statement;
            $this->ar_cache_exists[] = 'orderby';
        }

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Sets the LIMIT value
     *
     * @param   integer the limit value
     * @param   integer the offset value
     * @return  object
     */
    public function limit($value, $offset = '')
    {
        $this->ar_limit[$this->ar_identifier] = (int) $value;

        if ($offset != '')
        {
            $this->ar_offset[$this->ar_identifier] = (int) $offset;
        }

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Sets the OFFSET value
     *
     * @param   integer the offset value
     * @return  object
     */
    public function offset($offset)
    {
        $this->ar_offset[$this->ar_identifier] = $offset;
        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * The "set" function.  Allows key/value pairs to be set for inserting or updating
     *
     * @param   mixed
     * @param   string
     * @param   boolean
     * @return  object
     */
    public function set($key, $value = '', $escape = TRUE)
    {
        $key = $this->_object_to_array($key);

        if (!is_array($key))
        {
            $key = array($key => $value);
        }

        foreach ($key as $k => $v)
        {
            if ($escape === FALSE)
            {
                $this->ar_set[$this->ar_identifier][$this->_protect_identifiers($k)] = $v;
            } else
            {
                $this->ar_set[$this->ar_identifier][$this->_protect_identifiers($k, FALSE, TRUE)] = $this->escape($v);
            }
        }

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Get
     *
     * Compiles the select statement based on the other functions called
     * and runs the query
     *
     * @param   string  the table
     * @param   string  the limit clause
     * @param   string  the offset clause
     * @return  object
     */
    public function get($table = '', $limit = null, $offset = null)
    {
        if ($table != '')
        {
            $this->_track_aliases($table);
            $this->from($table);
        }

        if (!is_null($limit))
        {
            $this->limit($limit, $offset);
        }

        $sql = $this->_compile_select();

        $result = $this->query($sql);
        $this->_reset_select();
        return $result;
    }

    /**
     * "Count All Results" query
     *
     * Generates a platform-specific query string that counts all records
     * returned by an Active Record query.
     *
     * @param   string
     * @return  string
     */
    public function count_all_results($table = '')
    {
        if ($table != '')
        {
            $this->_track_aliases($table);
            $this->from($table);
        }

        $sql = $this->_compile_select($this->_count_string . $this->_protect_identifiers('numrows'));

        $query = $this->query($sql);
        $this->_reset_select();

        if ($query->num_rows() == 0)
        {
            return 0;
        }

        $row = $query->row();
        return (int) $row->numrows;
    }

    // --------------------------------------------------------------------

    /**
     * Get_Where
     *
     * Allows the where clause, limit and offset to be added directly
     *
     * @param   string  the where clause
     * @param   string  the limit clause
     * @param   string  the offset clause
     * @return  object
     */
    public function get_where($table = '', $where = null, $limit = null, $offset = null)
    {
        if ($table != '')
        {
            $this->from($table);
        }

        if (!is_null($where))
        {
            $this->where($where);
        }

        if (!is_null($limit))
        {
            $this->limit($limit, $offset);
        }

        $sql = $this->_compile_select();

        $result = $this->query($sql);
        $this->_reset_select();
        return $result;
    }

    // --------------------------------------------------------------------

    /**
     * Insert_Batch
     *
     * Compiles batch insert strings and runs the queries
     *
     * @param   string  the table to retrieve the results from
     * @param   array   an associative array of insert values
     * @return  object
     */
    public function insert_batch($table = '', $set = NULL)
    {
        if (!is_null($set))
        {
            $this->set_insert_batch($set);
        }

        if (count($this->ar_set[$this->ar_identifier]) == 0)
        {
            if ($this->db_debug)
            {
                //No valid data array.  Folds in cases where keys and values did not match up
                return $this->display_error('db_must_use_set');
            }
            return FALSE;
        }

        if ($table == '')
        {
            if (!isset($this->ar_from[$this->ar_identifier][0]))
            {
                if ($this->db_debug)
                {
                    return $this->display_error('db_must_set_table');
                }
                return FALSE;
            }

            $table = $this->ar_from[$this->ar_identifier][0];
        }

        // Batch this baby
        for ($i = 0, $total = count($this->ar_set[$this->ar_identifier]); $i < $total; $i = $i + 100)
        {

            $sql = $this->_insert_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_keys[$this->ar_identifier], array_slice($this->ar_set[$this->ar_identifier], $i, 100));

            //echo $sql;

            $this->query($sql);
        }

        $this->_reset_write();


        return TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * The "set_insert_batch" function.  Allows key/value pairs to be set for batch inserts
     *
     * @param   mixed
     * @param   string
     * @param   boolean
     * @return  object
     */
    public function set_insert_batch($key, $value = '', $escape = TRUE)
    {
        $key = $this->_object_to_array_batch($key);

        if (!is_array($key))
        {
            $key = array($key => $value);
        }

        $keys = array_keys(current($key));
        sort($keys);

        foreach ($key as $row)
        {
            if (count(array_diff($keys, array_keys($row))) > 0 OR count(array_diff(array_keys($row), $keys)) > 0)
            {
                // batch function above returns an error on an empty array
                $this->ar_set[$this->ar_identifier][] = array();
                return;
            }

            ksort($row); // puts $row in the same order as our keys

            if ($escape === FALSE)
            {
                $this->ar_set[$this->ar_identifier][] = '(' . implode(',', $row) . ')';
            } else
            {
                $clean = array();

                foreach ($row as $value)
                {
                    $clean[] = $this->escape($value);
                }

                $this->ar_set[$this->ar_identifier][] = '(' . implode(',', $clean) . ')';
            }
        }

        foreach ($keys as $k)
        {
            $this->ar_keys[$this->ar_identifier][] = $this->_protect_identifiers($k);
        }

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Insert
     *
     * Compiles an insert string and runs the query
     *
     * @param   string  the table to insert data into
     * @param   array   an associative array of insert values
     * @return  object
     */
    function insert($table = '', $set = NULL)
    {
        if (!is_null($set))
        {
            $this->set($set);
        }

        if (count($this->ar_set[$this->ar_identifier]) == 0)
        {
            if ($this->db_debug)
            {
                return $this->display_error('db_must_use_set');
            }
            return FALSE;
        }

        if ($table == '')
        {
            if (!isset($this->ar_from[$this->ar_identifier][0]))
            {
                if ($this->db_debug)
                {
                    return $this->display_error('db_must_set_table');
                }
                return FALSE;
            }

            $table = $this->ar_from[$this->ar_identifier][0];
        }

        $sql = $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set[$this->ar_identifier]), array_values($this->ar_set[$this->ar_identifier]));

        $this->_reset_write();
        return $this->query($sql);
    }

    // --------------------------------------------------------------------

    /**
     * Replace
     *
     * Compiles an replace into string and runs the query
     *
     * @param   string  the table to replace data into
     * @param   array   an associative array of insert values
     * @return  object
     */
    public function replace($table = '', $set = NULL)
    {
        if (!is_null($set))
        {
            $this->set($set);
        }

        if (count($this->ar_set[$this->ar_identifier]) == 0)
        {
            if ($this->db_debug)
            {
                return $this->display_error('db_must_use_set');
            }
            return FALSE;
        }

        if ($table == '')
        {
            if (!isset($this->ar_from[$this->ar_identifier][0]))
            {
                if ($this->db_debug)
                {
                    return $this->display_error('db_must_set_table');
                }
                return FALSE;
            }

            $table = $this->ar_from[$this->ar_identifier][0];
        }

        $sql = $this->_replace($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set[$this->ar_identifier]), array_values($this->ar_set[$this->ar_identifier]));

        $this->_reset_write();
        return $this->query($sql);
    }

    // --------------------------------------------------------------------

    /**
     * Update
     *
     * Compiles an update string and runs the query
     *
     * @param   string  the table to retrieve the results from
     * @param   array   an associative array of update values
     * @param   mixed   the where clause
     * @return  object
     */
    public function update($table = '', $set = NULL, $where = NULL, $limit = NULL)
    {
        // Combine any cached components with the current statements
        $this->_merge_cache();

        if (!is_null($set))
        {
            $this->set($set);
        }

        if (count($this->ar_set[$this->ar_identifier]) == 0)
        {
            if ($this->db_debug)
            {
                return $this->display_error('db_must_use_set');
            }
            return FALSE;
        }

        if ($table == '')
        {
            if (!isset($this->ar_from[$this->ar_identifier][0]))
            {
                if ($this->db_debug)
                {
                    return $this->display_error('db_must_set_table');
                }
                return FALSE;
            }

            $table = $this->ar_from[$this->ar_identifier][0];
        }

        if ($where != NULL)
        {
            $this->where($where);
        }

        if ($limit != NULL)
        {
            $this->limit($limit);
        }

        $sql = $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_set[$this->ar_identifier], $this->ar_where[$this->ar_identifier], $this->ar_orderby[$this->ar_identifier], $this->ar_limit[$this->ar_identifier]);

        $this->_reset_write();
        return $this->query($sql);
    }

    // --------------------------------------------------------------------

    /**
     * Update_Batch
     *
     * Compiles an update string and runs the query
     *
     * @param   string  the table to retrieve the results from
     * @param   array   an associative array of update values
     * @param   string  the where key
     * @return  object
     */
    public function update_batch($table = '', $set = NULL, $index = NULL)
    {
        // Combine any cached components with the current statements
        $this->_merge_cache();

        if (is_null($index))
        {
            if ($this->db_debug)
            {
                return $this->display_error('db_must_use_index');
            }

            return FALSE;
        }

        if (!is_null($set))
        {
            $this->set_update_batch($set, $index);
        }

        if (count($this->ar_set[$this->ar_identifier]) == 0)
        {
            if ($this->db_debug)
            {
                return $this->display_error('db_must_use_set');
            }

            return FALSE;
        }

        if ($table == '')
        {
            if (!isset($this->ar_from[$this->ar_identifier][0]))
            {
                if ($this->db_debug)
                {
                    return $this->display_error('db_must_set_table');
                }
                return FALSE;
            }

            $table = $this->ar_from[$this->ar_identifier][0];
        }

        // Batch this baby
        for ($i = 0, $total = count($this->ar_set[$this->ar_identifier]); $i < $total; $i = $i + 100)
        {
            $sql = $this->_update_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->ar_set[$this->ar_identifier], $i, 100), $this->_protect_identifiers($index), $this->ar_where[$this->ar_identifier]);

            $this->query($sql);
        }

        $this->_reset_write();
    }

    // --------------------------------------------------------------------

    /**
     * The "set_update_batch" function.  Allows key/value pairs to be set for batch updating
     *
     * @param   array
     * @param   string
     * @param   boolean
     * @return  object
     */
    public function set_update_batch($key, $index = '', $escape = TRUE)
    {
        $key = $this->_object_to_array_batch($key);

        if (!is_array($key))
        {
            // @todo error
        }

        foreach ($key as $k => $v)
        {
            $index_set = FALSE;
            $clean = array();

            foreach ($v as $k2 => $v2)
            {
                if ($k2 == $index)
                {
                    $index_set = TRUE;
                } else
                {
                    $not[] = $k . '-' . $v;
                }

                if ($escape === FALSE)
                {
                    $clean[$this->_protect_identifiers($k2)] = $v2;
                } else
                {
                    $clean[$this->_protect_identifiers($k2)] = $this->escape($v2);
                }
            }

            if ($index_set == FALSE)
            {
                return $this->display_error('db_batch_missing_index');
            }

            $this->ar_set[$this->ar_identifier][] = $clean;
        }

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * Empty Table
     *
     * Compiles a delete string and runs "DELETE FROM table"
     *
     * @param   string  the table to empty
     * @return  object
     */
    public function empty_table($table = '')
    {
        if ($table == '')
        {
            if (!isset($this->ar_from[$this->ar_identifier][0]))
            {
                if ($this->db_debug)
                {
                    return $this->display_error('db_must_set_table');
                }
                return FALSE;
            }

            $table = $this->ar_from[$this->ar_identifier][0];
        } else
        {
            $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
        }

        $sql = $this->_delete($table);

        $this->_reset_write();

        return $this->query($sql);
    }

    // --------------------------------------------------------------------

    /**
     * Truncate
     *
     * Compiles a truncate string and runs the query
     * If the database does not support the truncate() command
     * This function maps to "DELETE FROM table"
     *
     * @param   string  the table to truncate
     * @return  object
     */
    public function truncate($table = '')
    {
        if ($table == '')
        {
            if (!isset($this->ar_from[$this->ar_identifier][0]))
            {
                if ($this->db_debug)
                {
                    return $this->display_error('db_must_set_table');
                }
                return FALSE;
            }

            $table = $this->ar_from[$this->ar_identifier][0];
        } else
        {
            $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
        }

        $sql = $this->_truncate($table);

        $this->_reset_write();

        return $this->query($sql);
    }

    // --------------------------------------------------------------------

    /**
     * Delete
     *
     * Compiles a delete string and runs the query
     *
     * @param   mixed   the table(s) to delete from. String or array
     * @param   mixed   the where clause
     * @param   mixed   the limit clause
     * @param   boolean
     * @return  object
     */
    public function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE)
    {
        // Combine any cached components with the current statements
        $this->_merge_cache();

        if ($table == '')
        {
            if (!isset($this->ar_from[$this->ar_identifier][0]))
            {
                if ($this->db_debug)
                {
                    return $this->display_error('db_must_set_table');
                }
                return FALSE;
            }

            $table = $this->ar_from[$this->ar_identifier][0];
        } elseif (is_array($table))
        {
            foreach ($table as $single_table)
            {
                $this->delete($single_table, $where, $limit, FALSE);
            }

            $this->_reset_write();
            return;
        } else
        {
            $table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
        }

        if ($where != '')
        {
            $this->where($where);
        }

        if ($limit != NULL)
        {
            $this->limit($limit);
        }

        if (count($this->ar_where[$this->ar_identifier]) == 0 && count($this->ar_wherein[$this->ar_identifier]) == 0 && count($this->ar_like[$this->ar_identifier]) == 0)
        {
            if ($this->db_debug)
            {
                return $this->display_error('db_del_must_use_where');
            }

            return FALSE;
        }
        $sql = $this->_delete($table, $this->ar_where[$this->ar_identifier], $this->ar_like[$this->ar_identifier], $this->ar_limit[$this->ar_identifier]);

        if ($reset_data)
        {
            $this->_reset_write();
        }

        return $this->query($sql);
    }

    // --------------------------------------------------------------------

    /**
     * DB Prefix
     *
     * Prepends a database prefix if one exists in configuration
     *
     * @param   string  the table
     * @return  string
     */
    public function dbprefix($table = '')
    {
        if ($table == '')
        {
            $this->display_error('db_table_name_required');
        }

        return $this->dbprefix . $table;
    }

    // --------------------------------------------------------------------

    /**
     * Set DB Prefix
     *
     * Set's the DB Prefix to something new without needing to reconnect
     *
     * @param   string  the prefix
     * @return  string
     */
    public function set_dbprefix($prefix = '')
    {
        return $this->dbprefix = $prefix;
    }

    // --------------------------------------------------------------------

    /**
     * Track Aliases
     *
     * Used to track SQL statements written with aliased tables.
     *
     * @param   string  The table to inspect
     * @return  string
     */
    protected function _track_aliases($table)
    {
        if (is_array($table))
        {
            foreach ($table as $t)
            {
                $this->_track_aliases($t);
            }
            return;
        }

        // Does the string contain a comma?  If so, we need to separate
        // the string into discreet statements
        if (strpos($table, ',') !== FALSE)
        {
            return $this->_track_aliases(explode(',', $table));
        }

        // if a table alias is used we can recognize it by a space
        if (strpos($table, " ") !== FALSE)
        {
            // if the alias is written with the AS keyword, remove it
            $table = preg_replace('/\s+AS\s+/i', ' ', $table);

            // Grab the alias
            $table = trim(strrchr($table, " "));

            // Store the alias, if it doesn't already exist
            if (!in_array($table, $this->ar_aliased_tables[$this->ar_identifier]))
            {
                $this->ar_aliased_tables[$this->ar_identifier][] = $table;
            }
        }
    }

    // --------------------------------------------------------------------

    /**
     * Compile the SELECT statement
     *
     * Generates a query string based on which functions were used.
     * Should not be called directly.  The get() function calls it.
     *
     * @return  string
     */
    protected function _compile_select($select_override = FALSE)
    {
        // Combine any cached components with the current statements
        $this->_merge_cache();

        // ----------------------------------------------------------------
        // Write the "select" portion of the query

        if ($select_override !== FALSE)
        {
            $sql = $select_override;
        } else
        {
            $sql = (!$this->ar_distinct[$this->ar_identifier]) ? 'SELECT ' : 'SELECT DISTINCT ';

            if (count($this->ar_select[$this->ar_identifier]) == 0)
            {
                $sql .= '*';
            } else
            {
                // Cycle through the "select" portion of the query and prep each column name.
                // The reason we protect identifiers here rather then in the select() function
                // is because until the user calls the from() function we don't know if there are aliases
                foreach ($this->ar_select[$this->ar_identifier] as $key => $val)
                {
                    $no_escape = isset($this->ar_no_escape[$this->ar_identifier][$key]) ? $this->ar_no_escape[$this->ar_identifier][$key] : NULL;
                    $this->ar_select[$this->ar_identifier][$key] = $this->_protect_identifiers($val, FALSE, $no_escape);
                }

                $sql .= implode(', ', $this->ar_select[$this->ar_identifier]);
            }
        }

        // ----------------------------------------------------------------
        // Write the "FROM" portion of the query

        if (count($this->ar_from[$this->ar_identifier]) > 0)
        {
            $sql .= "\nFROM ";

            $sql .= $this->_from_tables($this->ar_from[$this->ar_identifier]);
        }

        // ----------------------------------------------------------------
        // Write the "JOIN" portion of the query

        if (count($this->ar_join[$this->ar_identifier]) > 0)
        {
            $sql .= "\n";

            $sql .= implode("\n", $this->ar_join[$this->ar_identifier]);
        }

        // ----------------------------------------------------------------
        // Write the "WHERE" portion of the query

        if (count($this->ar_where[$this->ar_identifier]) > 0 OR count($this->ar_like[$this->ar_identifier]) > 0)
        {
            $sql .= "\nWHERE ";
        }

        $sql .= implode("\n", $this->ar_where[$this->ar_identifier]);

        // ----------------------------------------------------------------
        // Write the "LIKE" portion of the query

        if (count($this->ar_like[$this->ar_identifier]) > 0)
        {
            if (count($this->ar_where[$this->ar_identifier]) > 0)
            {
                $sql .= "\nAND ";
            }

            $sql .= implode("\n", $this->ar_like[$this->ar_identifier]);
        }

        // ----------------------------------------------------------------
        // Write the "GROUP BY" portion of the query

        if (count($this->ar_groupby[$this->ar_identifier]) > 0)
        {
            $sql .= "\nGROUP BY ";

            $sql .= implode(', ', $this->ar_groupby[$this->ar_identifier]);
        }

        // ----------------------------------------------------------------
        // Write the "HAVING" portion of the query

        if (count($this->ar_having[$this->ar_identifier]) > 0)
        {
            $sql .= "\nHAVING ";
            $sql .= implode("\n", $this->ar_having[$this->ar_identifier]);
        }

        // ----------------------------------------------------------------
        // Write the "ORDER BY" portion of the query

        if (count($this->ar_orderby[$this->ar_identifier]) > 0)
        {
            $sql .= "\nORDER BY ";
            $sql .= implode(', ', $this->ar_orderby[$this->ar_identifier]);

            if ($this->ar_order[$this->ar_identifier] !== FALSE)
            {
                $sql .= ($this->ar_order[$this->ar_identifier] == 'desc') ? ' DESC' : ' ASC';
            }
        }

        // ----------------------------------------------------------------
        // Write the "LIMIT" portion of the query

        if (is_numeric($this->ar_limit[$this->ar_identifier]))
        {
            $sql .= "\n";
            $sql = $this->_limit($sql, $this->ar_limit[$this->ar_identifier], $this->ar_offset[$this->ar_identifier]);
        }

        return $sql;
    }

    // --------------------------------------------------------------------

    /**
     * Object to Array
     *
     * Takes an object as input and converts the class variables to array key/vals
     *
     * @param   object
     * @return  array
     */
    public function _object_to_array($object)
    {
        if (!is_object($object))
        {
            return $object;
        }

        $array = array();
        foreach (get_object_vars($object) as $key => $val)
        {
            // There are some built in keys we need to ignore for this conversion
            if (!is_object($val) && !is_array($val) && $key != '_parent_name')
            {
                $array[$key] = $val;
            }
        }

        return $array;
    }

    // --------------------------------------------------------------------

    /**
     * Object to Array
     *
     * Takes an object as input and converts the class variables to array key/vals
     *
     * @param   object
     * @return  array
     */
    public function _object_to_array_batch($object)
    {
        if (!is_object($object))
        {
            return $object;
        }

        $array = array();
        $out = get_object_vars($object);
        $fields = array_keys($out);

        foreach ($fields as $val)
        {
            // There are some built in keys we need to ignore for this conversion
            if ($val != '_parent_name')
            {

                $i = 0;
                foreach ($out[$val] as $data)
                {
                    $array[$i][$val] = $data;
                    $i++;
                }
            }
        }

        return $array;
    }

    // --------------------------------------------------------------------

    /**
     * Start Cache
     *
     * Starts AR caching
     *
     * @return  void
     */
    public function start_cache()
    {
        $this->ar_caching = TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Stop Cache
     *
     * Stops AR caching
     *
     * @return  void
     */
    public function stop_cache()
    {
        $this->ar_caching = FALSE;
    }

    // --------------------------------------------------------------------

    /**
     * Flush Cache
     *
     * Empties the AR cache
     *
     * @access  public
     * @return  void
     */
    public function flush_cache()
    {
        $this->_reset_run(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(),
            'ar_cache_exists' => array(),
            'ar_cache_no_escape' => array()
        ));
    }

    // --------------------------------------------------------------------

    /**
     * Merge Cache
     *
     * When called, this function merges any cached AR arrays with
     * locally called ones.
     *
     * @return  void
     */
    protected function _merge_cache()
    {
        if (count($this->ar_cache_exists) == 0)
        {
            return;
        }

        foreach ($this->ar_cache_exists as $val)
        {
            $ar_variable = 'ar_' . $val;
            $ar_cache_var = 'ar_cache_' . $val;

            if (count($this->$ar_cache_var) == 0)
            {
                continue;
            }

            $this->$ar_variable = array_unique(array_merge($this->$ar_cache_var, $this->$ar_variable));
        }

        // If we are "protecting identifiers" we need to examine the "from"
        // portion of the query to determine if there are any aliases
        if ($this->_protect_identifiers === TRUE AND count($this->ar_cache_from) > 0)
        {
            $this->_track_aliases($this->ar_from[$this->ar_identifier]);
        }

        $this->ar_no_escape[$this->ar_identifier] = $this->ar_cache_no_escape;
    }

    // --------------------------------------------------------------------

    /**
     * Resets the active record values.  Called by the get() function
     *
     * @param   array   An array of fields to reset
     * @return  void
     */
    protected 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
     *
     * @return  void
     */
    protected function _reset_select()
    {
        $ar_reset_items = array(
            'ar_select' => array($this->ar_identifier => array()),
            'ar_from' => array($this->ar_identifier => array()),
            'ar_join' => array($this->ar_identifier => array()),
            'ar_where' => array($this->ar_identifier => array()),
            'ar_like' => array($this->ar_identifier => array()),
            'ar_groupby' => array($this->ar_identifier => array()),
            'ar_having' => array($this->ar_identifier => array()),
            'ar_orderby' => array($this->ar_identifier => array()),
            'ar_wherein' => array($this->ar_identifier => array()),
            'ar_aliased_tables' => array($this->ar_identifier => array()),
            'ar_no_escape' => array($this->ar_identifier => array()),
            'ar_distinct' => array($this->ar_identifier => FALSE),
            'ar_limit' => array($this->ar_identifier => FALSE),
            'ar_offset' => array($this->ar_identifier => FALSE),
            'ar_order' => array($this->ar_identifier => FALSE),
        );

        foreach ($this->ar_select as $ident => $val)
        {
            if ($ident != $this->ar_identifier)
            {
                $ar_reset_items['ar_select'][$ident] = $this->ar_select[$ident];
                $ar_reset_items['ar_from'][$ident] = $this->ar_from[$ident];
                $ar_reset_items['ar_join'][$ident] = $this->ar_join[$ident];
                $ar_reset_items['ar_where'][$ident] = $this->ar_where[$ident];
                $ar_reset_items['ar_like'][$ident] = $this->ar_like[$ident];
                $ar_reset_items['ar_groupby'][$ident] = $this->ar_groupby[$ident];
                $ar_reset_items['ar_having'][$ident] = $this->ar_having[$ident];
                $ar_reset_items['ar_orderby'][$ident] = $this->ar_orderby[$ident];
                $ar_reset_items['ar_wherein'][$ident] = $this->ar_wherein[$ident];
                $ar_reset_items['ar_aliased_tables'][$ident] = $this->ar_aliased_tables[$ident];
                $ar_reset_items['ar_no_escape'][$ident] = $this->ar_no_escape[$ident];
                $ar_reset_items['ar_distinct'][$ident] = $this->ar_distinct[$ident];
                $ar_reset_items['ar_limit'][$ident] = $this->ar_limit[$ident];
                $ar_reset_items['ar_offset'][$ident] = $this->ar_offset[$ident];
                $ar_reset_items['ar_order'][$ident] = $this->ar_order[$ident];
            }

        }

        $this->_reset_run($ar_reset_items);
    }

    // --------------------------------------------------------------------

    /**
     * Resets the active record "write" values.
     *
     * Called by the insert() update() insert_batch() update_batch() and delete() functions
     *
     * @return  void
     */
    protected function _reset_write()
    {
        $ar_reset_items = array(
            'ar_set' => array($this->ar_identifier => array()),
            'ar_from' => array($this->ar_identifier => array()),
            'ar_where' => array($this->ar_identifier => array()),
            'ar_like' => array($this->ar_identifier => array()),
            'ar_orderby' => array($this->ar_identifier => array()),
            'ar_keys' => array($this->ar_identifier => array()),
            'ar_limit' => array($this->ar_identifier => FALSE),
            'ar_order' => array($this->ar_identifier => FALSE)
        );

        $this->_reset_run($ar_reset_items);
    }
}

/* End of file DB_active_rec.php */
/* Location: ./system/database/DB_active_rec.php */
Something went wrong with that request. Please try again.