Advertisement
Guest User

Untitled

a guest
Jul 24th, 2017
629
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 39.70 KB | None | 0 0
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3.  * CodeIgniter
  4.  *
  5.  * An open source application development framework for PHP 5.2.4 or newer
  6.  *
  7.  * NOTICE OF LICENSE
  8.  *
  9.  * Licensed under the Open Software License version 3.0
  10.  *
  11.  * This source file is subject to the Open Software License (OSL 3.0) that is
  12.  * bundled with this package in the files license.txt / license.rst.  It is
  13.  * also available through the world wide web at this URL:
  14.  * http://opensource.org/licenses/OSL-3.0
  15.  * If you did not receive a copy of the license and are unable to obtain it
  16.  * through the world wide web, please send an email to
  17.  * licensing@ellislab.com so we can send you a copy immediately.
  18.  *
  19.  * @package     CodeIgniter
  20.  * @author      EllisLab Dev Team
  21.  * @copyright   Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  22.  * @license     http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  23.  * @link        http://codeigniter.com
  24.  * @since       Version 1.0
  25.  * @filesource
  26.  */
  27.  
  28. /**
  29.  * Database Driver Class
  30.  *
  31.  * This is the platform-independent base DB implementation class.
  32.  * This class will not be called directly. Rather, the adapter
  33.  * class for the specific database will extend and instantiate it.
  34.  *
  35.  * @package     CodeIgniter
  36.  * @subpackage  Drivers
  37.  * @category    Database
  38.  * @author      EllisLab Dev Team
  39.  * @link        http://codeigniter.com/user_guide/database/
  40.  */
  41. abstract class CI_DB_driver {
  42.  
  43.     public $dsn;
  44.     public $username;
  45.     public $password;
  46.     public $hostname;
  47.     public $database;
  48.     public $dbdriver        = 'mysqli';
  49.     public $subdriver;
  50.     public $dbprefix        = '';
  51.     public $char_set        = 'utf8';
  52.     public $dbcollat        = 'utf8_general_ci';
  53.     public $autoinit        = TRUE; // Whether to automatically initialize the DB
  54.     public $compress        = TRUE;
  55.     public $swap_pre        = '';
  56.     public $port            = '';
  57.     public $pconnect        = FALSE;
  58.     public $conn_id         = FALSE;
  59.     public $result_id       = FALSE;
  60.     public $db_debug        = FALSE;
  61.     public $benchmark       = 0;
  62.     public $query_count     = 0;
  63.     public $bind_marker     = '?';
  64.     public $save_queries        = TRUE;
  65.     public $queries         = array();
  66.     public $query_times     = array();
  67.     public $data_cache      = array();
  68.  
  69.     public $trans_enabled       = TRUE;
  70.     public $trans_strict        = TRUE;
  71.     protected $_trans_depth     = 0;
  72.     protected $_trans_status    = TRUE; // Used with transactions to determine if a rollback should occur
  73.  
  74.     public $cache_on        = FALSE;
  75.     public $cachedir        = '';
  76.     public $cache_autodel       = FALSE;
  77.     public $CACHE; // The cache class object
  78.  
  79.     protected $_protect_identifiers     = TRUE;
  80.     protected $_reserved_identifiers    = array('*'); // Identifiers that should NOT be escaped
  81.  
  82.     // clause and character used for LIKE escape sequences
  83.     protected $_like_escape_str = " ESCAPE '%s' ";
  84.     protected $_like_escape_chr = '!';
  85.  
  86.     /**
  87.      * The syntax to count rows is slightly different across different
  88.      * database engines, so this string appears in each driver and is
  89.      * used for the count_all() and count_all_results() functions.
  90.      */
  91.     protected $_count_string = 'SELECT COUNT(*) AS ';
  92.  
  93.     /**
  94.      * Constructor
  95.      *
  96.      * @param   array
  97.      * @return  void
  98.      */
  99.     public function __construct($params)
  100.     {
  101.         if (is_array($params))
  102.         {
  103.             foreach ($params as $key => $val)
  104.             {
  105.                 $this->$key = $val;
  106.             }
  107.         }
  108.  
  109.         log_message('debug', 'Database Driver Class Initialized');
  110.     }
  111.  
  112.     // --------------------------------------------------------------------
  113.  
  114.     /**
  115.      * Initialize Database Settings
  116.      *
  117.      * @return  bool
  118.      */
  119.     public function initialize()
  120.     {
  121.         /* If an established connection is available, then there's
  122.          * no need to connect and select the database.
  123.          *
  124.          * Depending on the database driver, conn_id can be either
  125.          * boolean TRUE, a resource or an object.
  126.          */
  127.         if ($this->conn_id)
  128.         {
  129.             return TRUE;
  130.         }
  131.  
  132.         // ----------------------------------------------------------------
  133.  
  134.         // Connect to the database and set the connection ID
  135.         $this->conn_id = ($this->pconnect === FALSE) ? $this->db_connect() : $this->db_pconnect();
  136.  
  137.         // No connection resource? Check if there is a failover else throw an error
  138.         if ( ! $this->conn_id)
  139.         {
  140.             // Check if there is a failover set
  141.             if ( ! empty($this->failover) && is_array($this->failover))
  142.             {
  143.                 // Go over all the failovers
  144.                 foreach ($this->failover as $failover)
  145.                 {
  146.                     // Replace the current settings with those of the failover
  147.                     foreach ($failover as $key => $val)
  148.                     {
  149.                         $this->$key = $val;
  150.                     }
  151.  
  152.                     // Try to connect
  153.                     $this->conn_id = ($this->pconnect === FALSE) ? $this->db_connect() : $this->db_pconnect();
  154.  
  155.                     // If a connection is made break the foreach loop
  156.                     if ($this->conn_id)
  157.                     {
  158.                         break;
  159.                     }
  160.                 }
  161.             }
  162.  
  163.             // We still don't have a connection?
  164.             if ( ! $this->conn_id)
  165.             {
  166.                 log_message('error', 'Unable to connect to the database');
  167.  
  168.                 if ($this->db_debug)
  169.                 {
  170.                     $this->display_error('db_unable_to_connect');
  171.                 }
  172.                 return FALSE;
  173.             }
  174.         }
  175.  
  176.         // ----------------------------------------------------------------
  177.  
  178.         // Select the DB... assuming a database name is specified in the config file
  179.         if ($this->database !== '' && ! $this->db_select())
  180.         {
  181.             log_message('error', 'Unable to select database: '.$this->database);
  182.  
  183.             if ($this->db_debug)
  184.             {
  185.                 $this->display_error('db_unable_to_select', $this->database);
  186.             }
  187.             return FALSE;
  188.         }
  189.  
  190.         // Now we set the character set and that's all
  191.         return $this->db_set_charset($this->char_set);
  192.     }
  193.  
  194.     // --------------------------------------------------------------------
  195.  
  196.     /**
  197.      * Reconnect
  198.      *
  199.      * Keep / reestablish the db connection if no queries have been
  200.      * sent for a length of time exceeding the server's idle timeout.
  201.      *
  202.      * This is just a dummy method to allow drivers without such
  203.      * functionality to not declare it, while others will override it.
  204.      *
  205.      * @return      void
  206.      */
  207.     public function reconnect()
  208.     {
  209.     }
  210.  
  211.     // --------------------------------------------------------------------
  212.  
  213.     /**
  214.      * Select database
  215.      *
  216.      * This is just a dummy method to allow drivers without such
  217.      * functionality to not declare it, while others will override it.
  218.      *
  219.      * @return      bool
  220.      */
  221.     public function db_select()
  222.     {
  223.         return TRUE;
  224.     }
  225.  
  226.     // --------------------------------------------------------------------
  227.  
  228.     /**
  229.      * Set client character set
  230.      *
  231.      * @param   string
  232.      * @return  bool
  233.      */
  234.     public function db_set_charset($charset)
  235.     {
  236.         if (method_exists($this, '_db_set_charset') && ! $this->_db_set_charset($charset))
  237.         {
  238.             log_message('error', 'Unable to set database connection charset: '.$charset);
  239.  
  240.             if ($this->db_debug)
  241.             {
  242.                 $this->display_error('db_unable_to_set_charset', $charset);
  243.             }
  244.  
  245.             return FALSE;
  246.         }
  247.  
  248.         return TRUE;
  249.     }
  250.  
  251.     // --------------------------------------------------------------------
  252.  
  253.     /**
  254.      * The name of the platform in use (mysql, mssql, etc...)
  255.      *
  256.      * @return  string
  257.      */
  258.     public function platform()
  259.     {
  260.         return $this->dbdriver;
  261.     }
  262.  
  263.     // --------------------------------------------------------------------
  264.  
  265.     /**
  266.      * Database version number
  267.      *
  268.      * Returns a string containing the version of the database being used.
  269.      * Most drivers will override this method.
  270.      *
  271.      * @return  string
  272.      */
  273.     public function version()
  274.     {
  275.         if (isset($this->data_cache['version']))
  276.         {
  277.             return $this->data_cache['version'];
  278.         }
  279.  
  280.         if (FALSE === ($sql = $this->_version()))
  281.         {
  282.             return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE;
  283.         }
  284.  
  285.         $query = $this->query($sql);
  286.         $query = $query->row();
  287.         return $this->data_cache['version'] = $query->ver;
  288.     }
  289.  
  290.     // --------------------------------------------------------------------
  291.  
  292.     /**
  293.      * Version number query string
  294.      *
  295.      * @return  string
  296.      */
  297.     protected function _version()
  298.     {
  299.         return 'SELECT VERSION() AS ver';
  300.     }
  301.  
  302.     // --------------------------------------------------------------------
  303.  
  304.     /**
  305.      * Execute the query
  306.      *
  307.      * Accepts an SQL string as input and returns a result object upon
  308.      * successful execution of a "read" type query. Returns boolean TRUE
  309.      * upon successful execution of a "write" type query. Returns boolean
  310.      * FALSE upon failure, and if the $db_debug variable is set to TRUE
  311.      * will raise an error.
  312.      *
  313.      * @param   string  An SQL query string
  314.      * @param   array   An array of binding data
  315.      * @return  mixed
  316.      */
  317.     public function query($sql, $binds = FALSE, $return_object = NULL)
  318.     {
  319.         if ($sql === '')
  320.         {
  321.             log_message('error', 'Invalid query: '.$sql);
  322.  
  323.             return ($this->db_debug) ? $this->display_error('db_invalid_query') : FALSE;
  324.         }
  325.         elseif ( ! is_bool($return_object))
  326.         {
  327.             $return_object = ! $this->is_write_type($sql);
  328.         }
  329.  
  330.         // Verify table prefix and replace if necessary
  331.         if ($this->dbprefix !== '' && $this->swap_pre !== '' && $this->dbprefix !== $this->swap_pre)
  332.         {
  333.             $sql = preg_replace('/(\W)'.$this->swap_pre.'(\S+?)/', '\\1'.$this->dbprefix.'\\2', $sql);
  334.         }
  335.  
  336.         // Compile binds if needed
  337.         if ($binds !== FALSE)
  338.         {
  339.             $sql = $this->compile_binds($sql, $binds);
  340.         }
  341.  
  342.         // Is query caching enabled? If the query is a "read type"
  343.         // we will load the caching class and return the previously
  344.         // cached query if it exists
  345.         if ($this->cache_on === TRUE && $return_object === TRUE && $this->_cache_init())
  346.         {
  347.             $this->load_rdriver();
  348.             if (FALSE !== ($cache = $this->CACHE->read($sql)))
  349.             {
  350.                 return $cache;
  351.             }
  352.         }
  353.  
  354.         // Save the query for debugging
  355.         if ($this->save_queries === TRUE)
  356.         {
  357.             $this->queries[] = $sql;
  358.         }
  359.  
  360.         // Start the Query Timer
  361.         $time_start = microtime(TRUE);
  362.  
  363.         // Run the Query
  364.         if (FALSE === ($this->result_id = $this->simple_query($sql)))
  365.         {
  366.             if ($this->save_queries === TRUE)
  367.             {
  368.                 $this->query_times[] = 0;
  369.             }
  370.  
  371.             // This will trigger a rollback if transactions are being used
  372.             $this->_trans_status = FALSE;
  373.  
  374.             // Grab the error now, as we might run some additional queries before displaying the error
  375.             $error = $this->error();
  376.  
  377.             // Log errors
  378.             log_message('error', 'Query error: '.$error['message'].' - Invalid query: '.$sql);
  379.  
  380.             if ($this->db_debug)
  381.             {
  382.                 // We call this function in order to roll-back queries
  383.                 // if transactions are enabled. If we don't call this here
  384.                 // the error message will trigger an exit, causing the
  385.                 // transactions to remain in limbo.
  386.                 $this->trans_complete();
  387.  
  388.                 // Display errors
  389.                 return $this->display_error(array('Error Number: '.$error['code'], $error['message'], $sql));
  390.             }
  391.  
  392.             return FALSE;
  393.         }
  394.  
  395.         // Stop and aggregate the query time results
  396.         $time_end = microtime(TRUE);
  397.         $this->benchmark += $time_end - $time_start;
  398.  
  399.         if ($this->save_queries === TRUE)
  400.         {
  401.             $this->query_times[] = $time_end - $time_start;
  402.         }
  403.  
  404.         // Increment the query counter
  405.         $this->query_count++;
  406.  
  407.         // Will we have a result object instantiated? If not - we'll simply return TRUE
  408.         if ($return_object !== TRUE)
  409.         {
  410.             // If caching is enabled we'll auto-cleanup any existing files related to this particular URI
  411.             if ($this->cache_on === TRUE && $this->cache_autodel === TRUE && $this->_cache_init())
  412.             {
  413.                 $this->CACHE->delete();
  414.             }
  415.  
  416.             return TRUE;
  417.         }
  418.  
  419.         // Return TRUE if we don't need to create a result object
  420.         if ($return_object !== TRUE)
  421.         {
  422.             return TRUE;
  423.         }
  424.  
  425.         // Load and instantiate the result driver
  426.         $driver     = $this->load_rdriver();
  427.         $RES        = new $driver($this);
  428.  
  429.         // Is query caching enabled? If so, we'll serialize the
  430.         // result object and save it to a cache file.
  431.         if ($this->cache_on === TRUE && $this->_cache_init())
  432.         {
  433.             // We'll create a new instance of the result object
  434.             // only without the platform specific driver since
  435.             // we can't use it with cached data (the query result
  436.             // resource ID won't be any good once we've cached the
  437.             // result object, so we'll have to compile the data
  438.             // and save it)
  439.             $CR = new CI_DB_result();
  440.             $CR->result_object  = $RES->result_object();
  441.             $CR->result_array   = $RES->result_array();
  442.             $CR->num_rows       = $RES->num_rows();
  443.  
  444.             // Reset these since cached objects can not utilize resource IDs.
  445.             $CR->conn_id        = NULL;
  446.             $CR->result_id      = NULL;
  447.  
  448.             $this->CACHE->write($sql, $CR);
  449.         }
  450.  
  451.         return $RES;
  452.     }
  453.  
  454.     // --------------------------------------------------------------------
  455.  
  456.     /**
  457.      * Load the result drivers
  458.      *
  459.      * @return  string  the name of the result class
  460.      */
  461.     public function load_rdriver()
  462.     {
  463.         $driver = 'CI_DB_'.$this->dbdriver.'_result';
  464.  
  465.         if ( ! class_exists($driver))
  466.         {
  467.             include_once(BASEPATH.'database/DB_result.php');
  468.             include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result.php');
  469.         }
  470.  
  471.         return $driver;
  472.     }
  473.  
  474.     // --------------------------------------------------------------------
  475.  
  476.     /**
  477.      * Simple Query
  478.      * This is a simplified version of the query() function. Internally
  479.      * we only use it when running transaction commands since they do
  480.      * not require all the features of the main query() function.
  481.      *
  482.      * @param   string  the sql query
  483.      * @return  mixed
  484.      */
  485.     public function simple_query($sql)
  486.     {
  487.         if ( ! $this->conn_id)
  488.         {
  489.             $this->initialize();
  490.         }
  491.  
  492.         return $this->_execute($sql);
  493.     }
  494.  
  495.     // --------------------------------------------------------------------
  496.  
  497.     /**
  498.      * Disable Transactions
  499.      * This permits transactions to be disabled at run-time.
  500.      *
  501.      * @return  void
  502.      */
  503.     public function trans_off()
  504.     {
  505.         $this->trans_enabled = FALSE;
  506.     }
  507.  
  508.     // --------------------------------------------------------------------
  509.  
  510.     /**
  511.      * Enable/disable Transaction Strict Mode
  512.      * When strict mode is enabled, if you are running multiple groups of
  513.      * transactions, if one group fails all groups will be rolled back.
  514.      * If strict mode is disabled, each group is treated autonomously, meaning
  515.      * a failure of one group will not affect any others
  516.      *
  517.      * @return  void
  518.      */
  519.     public function trans_strict($mode = TRUE)
  520.     {
  521.         $this->trans_strict = is_bool($mode) ? $mode : TRUE;
  522.     }
  523.  
  524.     // --------------------------------------------------------------------
  525.  
  526.     /**
  527.      * Start Transaction
  528.      *
  529.      * @return  void
  530.      */
  531.     public function trans_start($test_mode = FALSE)
  532.     {
  533.         if ( ! $this->trans_enabled)
  534.         {
  535.             return FALSE;
  536.         }
  537.  
  538.         // When transactions are nested we only begin/commit/rollback the outermost ones
  539.         if ($this->_trans_depth > 0)
  540.         {
  541.             $this->_trans_depth += 1;
  542.             return;
  543.         }
  544.  
  545.         $this->trans_begin($test_mode);
  546.         $this->_trans_depth += 1;
  547.     }
  548.  
  549.     // --------------------------------------------------------------------
  550.  
  551.     /**
  552.      * Complete Transaction
  553.      *
  554.      * @return  bool
  555.      */
  556.     public function trans_complete()
  557.     {
  558.         if ( ! $this->trans_enabled)
  559.         {
  560.             return FALSE;
  561.         }
  562.  
  563.         // When transactions are nested we only begin/commit/rollback the outermost ones
  564.         if ($this->_trans_depth > 1)
  565.         {
  566.             $this->_trans_depth -= 1;
  567.             return TRUE;
  568.         }
  569.         else
  570.         {
  571.             $this->_trans_depth = 0;
  572.         }
  573.  
  574.         // The query() function will set this flag to FALSE in the event that a query failed
  575.         if ($this->_trans_status === FALSE)
  576.         {
  577.             $this->trans_rollback();
  578.  
  579.             // If we are NOT running in strict mode, we will reset
  580.             // the _trans_status flag so that subsequent groups of transactions
  581.             // will be permitted.
  582.             if ($this->trans_strict === FALSE)
  583.             {
  584.                 $this->_trans_status = TRUE;
  585.             }
  586.  
  587.             log_message('debug', 'DB Transaction Failure');
  588.             return FALSE;
  589.         }
  590.  
  591.         $this->trans_commit();
  592.         return TRUE;
  593.     }
  594.  
  595.     // --------------------------------------------------------------------
  596.  
  597.     /**
  598.      * Lets you retrieve the transaction flag to determine if it has failed
  599.      *
  600.      * @return  bool
  601.      */
  602.     public function trans_status()
  603.     {
  604.         return $this->_trans_status;
  605.     }
  606.  
  607.     // --------------------------------------------------------------------
  608.  
  609.     /**
  610.      * Compile Bindings
  611.      *
  612.      * @param   string  the sql statement
  613.      * @param   array   an array of bind data
  614.      * @return  string
  615.      */
  616.     public function compile_binds($sql, $binds)
  617.     {
  618.         if (empty($binds) OR empty($this->bind_marker) OR strpos($sql, $this->bind_marker) === FALSE)
  619.         {
  620.             return $sql;
  621.         }
  622.         elseif ( ! is_array($binds))
  623.         {
  624.             $binds = array($binds);
  625.             $bind_count = 1;
  626.         }
  627.         else
  628.         {
  629.             // Make sure we're using numeric keys
  630.             $binds = array_values($binds);
  631.             $bind_count = count($binds);
  632.         }
  633.  
  634.         // We'll need the marker length later
  635.         $ml = strlen($this->bind_marker);
  636.  
  637.         // Make sure not to replace a chunk inside a string that happens to match the bind marker
  638.         if ($c = preg_match_all("/'[^']*'/i", $sql, $matches))
  639.         {
  640.             $c = preg_match_all('/'.preg_quote($this->bind_marker).'/i',
  641.                 str_replace($matches[0],
  642.                     str_replace($this->bind_marker, str_repeat(' ', $ml), $matches[0]),
  643.                     $sql, $c),
  644.                 $matches, PREG_OFFSET_CAPTURE);
  645.  
  646.             // Bind values' count must match the count of markers in the query
  647.             if ($bind_count !== $c)
  648.             {
  649.                 return $sql;
  650.             }
  651.         }
  652.         elseif (($c = preg_match_all('/'.preg_quote($this->bind_marker).'/i', $sql, $matches, PREG_OFFSET_CAPTURE)) !== $bind_count)
  653.         {
  654.             return $sql;
  655.         }
  656.  
  657.         do
  658.         {
  659.             $c--;
  660.             $sql = substr_replace($sql, $this->escape($binds[$c]), $matches[0][$c][1], $ml);
  661.         }
  662.         while ($c !== 0);
  663.  
  664.         return $sql;
  665.     }
  666.  
  667.     // --------------------------------------------------------------------
  668.  
  669.     /**
  670.      * Determines if a query is a "write" type.
  671.      *
  672.      * @param   string  An SQL query string
  673.      * @return  bool
  674.      */
  675.     public function is_write_type($sql)
  676.     {
  677.         return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql);
  678.     }
  679.  
  680.     // --------------------------------------------------------------------
  681.  
  682.     /**
  683.      * Calculate the aggregate query elapsed time
  684.      *
  685.      * @param   int The number of decimal places
  686.      * @return  int
  687.      */
  688.     public function elapsed_time($decimals = 6)
  689.     {
  690.         return number_format($this->benchmark, $decimals);
  691.     }
  692.  
  693.     // --------------------------------------------------------------------
  694.  
  695.     /**
  696.      * Returns the total number of queries
  697.      *
  698.      * @return  int
  699.      */
  700.     public function total_queries()
  701.     {
  702.         return $this->query_count;
  703.     }
  704.  
  705.     // --------------------------------------------------------------------
  706.  
  707.     /**
  708.      * Returns the last query that was executed
  709.      *
  710.      * @return  string
  711.      */
  712.     public function last_query()
  713.     {
  714.         return end($this->queries);
  715.     }
  716.  
  717.     // --------------------------------------------------------------------
  718.  
  719.     /**
  720.      * "Smart" Escape String
  721.      *
  722.      * Escapes data based on type
  723.      * Sets boolean and null types
  724.      *
  725.      * @param   string
  726.      * @return  mixed
  727.      */
  728.     public function escape($str)
  729.     {
  730.         if (is_string($str) OR method_exists($str, '__toString'))
  731.         {
  732.             return "'".$this->escape_str($str)."'";
  733.         }
  734.         elseif (is_bool($str))
  735.         {
  736.             return ($str === FALSE) ? 0 : 1;
  737.         }
  738.         elseif (is_null($str))
  739.         {
  740.             return 'NULL';
  741.         }
  742.  
  743.         return $str;
  744.     }
  745.  
  746.     // --------------------------------------------------------------------
  747.  
  748.     /**
  749.      * Escape LIKE String
  750.      *
  751.      * Calls the individual driver for platform
  752.      * specific escaping for LIKE conditions
  753.      *
  754.      * @param   string
  755.      * @return  mixed
  756.      */
  757.     public function escape_like_str($str)
  758.     {
  759.         return $this->escape_str($str, TRUE);
  760.     }
  761.  
  762.     // --------------------------------------------------------------------
  763.  
  764.     /**
  765.      * Primary
  766.      *
  767.      * Retrieves the primary key. It assumes that the row in the first
  768.      * position is the primary key
  769.      *
  770.      * @param   string  the table name
  771.      * @return  string
  772.      */
  773.     public function primary($table = '')
  774.     {
  775.         $fields = $this->list_fields($table);
  776.         return is_array($fields) ? current($fields) : FALSE;
  777.     }
  778.  
  779.     // --------------------------------------------------------------------
  780.  
  781.     /**
  782.      * "Count All" query
  783.      *
  784.      * Generates a platform-specific query string that counts all records in
  785.      * the specified database
  786.      *
  787.      * @param   string
  788.      * @return  int
  789.      */
  790.     public function count_all($table = '')
  791.     {
  792.         if ($table === '')
  793.         {
  794.             return 0;
  795.         }
  796.  
  797.         $query = $this->query($this->_count_string.$this->escape_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
  798.         if ($query->num_rows() === 0)
  799.         {
  800.             return 0;
  801.         }
  802.  
  803.         $query = $query->row();
  804.         $this->_reset_select();
  805.         return (int) $query->numrows;
  806.     }
  807.  
  808.     // --------------------------------------------------------------------
  809.  
  810.     /**
  811.      * Returns an array of table names
  812.      *
  813.      * @return  array
  814.      */
  815.     public function list_tables($constrain_by_prefix = FALSE)
  816.     {
  817.         // Is there a cached result?
  818.         if (isset($this->data_cache['table_names']))
  819.         {
  820.             return $this->data_cache['table_names'];
  821.         }
  822.  
  823.         if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
  824.         {
  825.             return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE;
  826.         }
  827.  
  828.         $this->data_cache['table_names'] = array();
  829.         $query = $this->query($sql);
  830.  
  831.         foreach ($query->result_array() as $row)
  832.         {
  833.             // Do we know from which column to get the table name?
  834.             if ( ! isset($key))
  835.             {
  836.                 if (isset($row['table_name']))
  837.                 {
  838.                     $key = 'table_name';
  839.                 }
  840.                 elseif (isset($row['TABLE_NAME']))
  841.                 {
  842.                     $key = 'TABLE_NAME';
  843.                 }
  844.                 else
  845.                 {
  846.                     /* We have no other choice but to just get the first element's key.
  847.                      * Due to array_shift() accepting it's argument by reference, if
  848.                      * E_STRICT is on, this would trigger a warning. So we'll have to
  849.                      * assign it first.
  850.                      */
  851.                     $key = array_keys($row);
  852.                     $key = array_shift($key);
  853.                 }
  854.             }
  855.  
  856.             $this->data_cache['table_names'][] = $row[$key];
  857.         }
  858.  
  859.         return $this->data_cache['table_names'];
  860.     }
  861.  
  862.     // --------------------------------------------------------------------
  863.  
  864.     /**
  865.      * Determine if a particular table exists
  866.      *
  867.      * @return  bool
  868.      */
  869.     public function table_exists($table_name)
  870.     {
  871.         return in_array($this->protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables());
  872.     }
  873.  
  874.     // --------------------------------------------------------------------
  875.  
  876.     /**
  877.      * Fetch Field Names
  878.      *
  879.      * @param   string  the table name
  880.      * @return  array
  881.      */
  882.     public function list_fields($table = '')
  883.     {
  884.         // Is there a cached result?
  885.         if (isset($this->data_cache['field_names'][$table]))
  886.         {
  887.             return $this->data_cache['field_names'][$table];
  888.         }
  889.  
  890.         if ($table === '')
  891.         {
  892.             return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
  893.         }
  894.  
  895.         if (FALSE === ($sql = $this->_list_columns($table)))
  896.         {
  897.             return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE;
  898.         }
  899.  
  900.         $query = $this->query($sql);
  901.         $this->data_cache['field_names'][$table] = array();
  902.  
  903.         foreach ($query->result_array() as $row)
  904.         {
  905.             // Do we know from where to get the column's name?
  906.             if ( ! isset($key))
  907.             {
  908.                 if (isset($row['column_name']))
  909.                 {
  910.                     $key = 'column_name';
  911.                 }
  912.                 elseif (isset($row['COLUMN_NAME']))
  913.                 {
  914.                     $key = 'COLUMN_NAME';
  915.                 }
  916.                 else
  917.                 {
  918.                     /* We have no other choice but to just get the first element's key.
  919.                      * Due to array_shift() accepting it's argument by reference, if
  920.                      * E_STRICT is on, this would trigger a warning. So we'll have to
  921.                      * assign it first.
  922.                      */
  923.                     $key = array_keys($row);
  924.                     $key = array_shift($key);
  925.                 }
  926.             }
  927.  
  928.             $this->data_cache['field_names'][$table][] = $row[$key];
  929.         }
  930.  
  931.         return $this->data_cache['field_names'][$table];
  932.     }
  933.  
  934.     // --------------------------------------------------------------------
  935.  
  936.     /**
  937.      * Determine if a particular field exists
  938.      *
  939.      * @param   string
  940.      * @param   string
  941.      * @return  bool
  942.      */
  943.     public function field_exists($field_name, $table_name)
  944.     {
  945.         return in_array($field_name, $this->list_fields($table_name));
  946.     }
  947.  
  948.     // --------------------------------------------------------------------
  949.  
  950.     /**
  951.      * Returns an object with field data
  952.      *
  953.      * @param   string  the table name
  954.      * @return  object
  955.      */
  956.     public function field_data($table = '')
  957.     {
  958.         if ($table === '')
  959.         {
  960.             return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
  961.         }
  962.  
  963.         $query = $this->query($this->_field_data($this->protect_identifiers($table, TRUE, NULL, FALSE)));
  964.         return $query->field_data();
  965.     }
  966.  
  967.     // --------------------------------------------------------------------
  968.  
  969.     /**
  970.      * Escape the SQL Identifiers
  971.      *
  972.      * This function escapes column and table names
  973.      *
  974.      * @param   mixed
  975.      * @return  mixed
  976.      */
  977.     public function escape_identifiers($item)
  978.     {
  979.         if ($this->_escape_char === '' OR empty($item))
  980.         {
  981.             return $item;
  982.         }
  983.         elseif (is_array($item))
  984.         {
  985.             foreach ($item as $key => $value)
  986.             {
  987.                 $item[$key] = $this->escape_identifiers($value);
  988.             }
  989.  
  990.             return $item;
  991.         }
  992.         // Avoid breaking functions and literal values inside queries
  993.         elseif (ctype_digit($item) OR $item[0] === "'" OR ($this->_escape_char !== '"' && $item[0] === '"') OR strpos($item, '(') !== FALSE)
  994.         {
  995.             return $item;
  996.         }
  997.  
  998.         static $preg_ec = array();
  999.  
  1000.         if (empty($preg_ec))
  1001.         {
  1002.             if (is_array($this->_escape_char))
  1003.             {
  1004.                 $preg_ec = array(
  1005.                         preg_quote($this->_escape_char[0]), preg_quote($this->_escape_char[1]),
  1006.                         $this->_escape_char[0], $this->_escape_char[1]
  1007.                         );
  1008.             }
  1009.             else
  1010.             {
  1011.                 $preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char);
  1012.                 $preg_ec[2] = $preg_ec[3] = $this->_escape_char;
  1013.             }
  1014.         }
  1015.  
  1016.         foreach ($this->_reserved_identifiers as $id)
  1017.         {
  1018.             if (strpos($item, '.'.$id) !== FALSE)
  1019.             {
  1020.                 return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?\./i', $preg_ec[2].'$1'.$preg_ec[3].'.', $item);
  1021.             }
  1022.         }
  1023.  
  1024.         return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?(\.)?/i', $preg_ec[2].'$1'.$preg_ec[3].'$2', $item);
  1025.     }
  1026.  
  1027.     // --------------------------------------------------------------------
  1028.  
  1029.     /**
  1030.      * Generate an insert string
  1031.      *
  1032.      * @param   string  the table upon which the query will be performed
  1033.      * @param   array   an associative array data of key/values
  1034.      * @return  string
  1035.      */
  1036.     public function insert_string($table, $data)
  1037.     {
  1038.         $fields = $values = array();
  1039.  
  1040.         foreach ($data as $key => $val)
  1041.         {
  1042.             $fields[] = $this->escape_identifiers($key);
  1043.             $values[] = $this->escape($val);
  1044.         }
  1045.  
  1046.         return $this->_insert($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values);
  1047.     }
  1048.  
  1049.     // --------------------------------------------------------------------
  1050.  
  1051.     /**
  1052.      * Insert statement
  1053.      *
  1054.      * Generates a platform-specific insert string from the supplied data
  1055.      *
  1056.      * @param   string  the table name
  1057.      * @param   array   the insert keys
  1058.      * @param   array   the insert values
  1059.      * @return  string
  1060.      */
  1061.     protected function _insert($table, $keys, $values)
  1062.     {
  1063.         return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
  1064.     }
  1065.  
  1066.     // --------------------------------------------------------------------
  1067.  
  1068.     /**
  1069.      * Generate an update string
  1070.      *
  1071.      * @param   string  the table upon which the query will be performed
  1072.      * @param   array   an associative array data of key/values
  1073.      * @param   mixed   the "where" statement
  1074.      * @return  string
  1075.      */
  1076.     public function update_string($table, $data, $where)
  1077.     {
  1078.         if ($where === '')
  1079.         {
  1080.             return FALSE;
  1081.         }
  1082.  
  1083.         $fields = array();
  1084.         foreach ($data as $key => $val)
  1085.         {
  1086.             $fields[$this->protect_identifiers($key)] = $this->escape($val);
  1087.         }
  1088.  
  1089.         if ( ! is_array($where))
  1090.         {
  1091.             $dest = array($where);
  1092.         }
  1093.         else
  1094.         {
  1095.             $dest = array();
  1096.             foreach ($where as $key => $val)
  1097.             {
  1098.                 $prefix = (count($dest) === 0) ? '' : ' AND ';
  1099.                 $key = $this->protect_identifiers($key);
  1100.  
  1101.                 if ($val !== '')
  1102.                 {
  1103.                     if ( ! $this->_has_operator($key))
  1104.                     {
  1105.                         $key .= ' =';
  1106.                     }
  1107.  
  1108.                     $val = ' '.$this->escape($val);
  1109.                 }
  1110.  
  1111.                 $dest[] = $prefix.$key.$val;
  1112.             }
  1113.         }
  1114.  
  1115.         return $this->_update($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest);
  1116.     }
  1117.  
  1118.     // --------------------------------------------------------------------
  1119.  
  1120.     /**
  1121.      * Update statement
  1122.      *
  1123.      * Generates a platform-specific update string from the supplied data
  1124.      *
  1125.      * @param   string  the table name
  1126.      * @param   array   the update data
  1127.      * @param   array   the where clause
  1128.      * @param   array   the orderby clause
  1129.      * @param   array   the limit clause
  1130.      * @param   array   the like clause
  1131.      * @return  string
  1132.      */
  1133.     protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array())
  1134.     {
  1135.         foreach ($values as $key => $val)
  1136.         {
  1137.             $valstr[] = $key.' = '.$val;
  1138.         }
  1139.  
  1140.         $where = empty($where) ? '' : ' WHERE '.implode(' ', $where);
  1141.  
  1142.         if ( ! empty($like))
  1143.         {
  1144.             $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like);
  1145.         }
  1146.  
  1147.         return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
  1148.             .$where
  1149.             .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
  1150.             .($limit ? ' LIMIT '.$limit : '');
  1151.     }
  1152.  
  1153.     // --------------------------------------------------------------------
  1154.  
  1155.     /**
  1156.      * Tests whether the string has an SQL operator
  1157.      *
  1158.      * @param   string
  1159.      * @return  bool
  1160.      */
  1161.     protected function _has_operator($str)
  1162.     {
  1163.         return (bool) preg_match('/(\s|<|>|!|=|IS NULL|IS NOT NULL|BETWEEN)/i', trim($str));
  1164.     }
  1165.  
  1166.     // --------------------------------------------------------------------
  1167.  
  1168.     /**
  1169.      * Returns the SQL string operator
  1170.      *
  1171.      * @param   string
  1172.      * @return  string
  1173.      */
  1174.     protected function _get_operator($str)
  1175.     {
  1176.         return preg_match('/(=|!|<|>| IS NULL| IS NOT NULL| BETWEEN)/i', $str, $match)
  1177.             ? $match[1] : FALSE;
  1178.     }
  1179.  
  1180.     // --------------------------------------------------------------------
  1181.  
  1182.     /**
  1183.      * Enables a native PHP function to be run, using a platform agnostic wrapper.
  1184.      *
  1185.      * @param   string  the function name
  1186.      * @param   mixed   any parameters needed by the function
  1187.      * @return  mixed
  1188.      */
  1189.     public function call_function($function)
  1190.     {
  1191.         $driver = ($this->dbdriver === 'postgre') ? 'pg_' : $this->dbdriver.'_';
  1192.  
  1193.         if (FALSE === strpos($driver, $function))
  1194.         {
  1195.             $function = $driver.$function;
  1196.         }
  1197.  
  1198.         if ( ! function_exists($function))
  1199.         {
  1200.             return ($this->db_debug) ? $this->display_error('db_unsupported_function') : FALSE;
  1201.         }
  1202.  
  1203.         return (func_num_args() > 1)
  1204.             ? call_user_func_array($function, array_splice(func_get_args(), 1))
  1205.             : call_user_func($function);
  1206.     }
  1207.  
  1208.     // --------------------------------------------------------------------
  1209.  
  1210.     /**
  1211.      * Set Cache Directory Path
  1212.      *
  1213.      * @param   string  the path to the cache directory
  1214.      * @return  void
  1215.      */
  1216.     public function cache_set_path($path = '')
  1217.     {
  1218.         $this->cachedir = $path;
  1219.     }
  1220.  
  1221.     // --------------------------------------------------------------------
  1222.  
  1223.     /**
  1224.      * Enable Query Caching
  1225.      *
  1226.      * @return  bool    cache_on value
  1227.      */
  1228.     public function cache_on()
  1229.     {
  1230.         return $this->cache_on = TRUE;
  1231.     }
  1232.  
  1233.     // --------------------------------------------------------------------
  1234.  
  1235.     /**
  1236.      * Disable Query Caching
  1237.      *
  1238.      * @return  bool    cache_on value
  1239.      */
  1240.     public function cache_off()
  1241.     {
  1242.         return $this->cache_on = FALSE;
  1243.     }
  1244.  
  1245.     // --------------------------------------------------------------------
  1246.  
  1247.     /**
  1248.      * Delete the cache files associated with a particular URI
  1249.      *
  1250.      * @return  bool
  1251.      */
  1252.     public function cache_delete($segment_one = '', $segment_two = '')
  1253.     {
  1254.         return ($this->_cache_init())
  1255.             ? $this->CACHE->delete($segment_one, $segment_two)
  1256.             : FALSE;
  1257.     }
  1258.  
  1259.     // --------------------------------------------------------------------
  1260.  
  1261.     /**
  1262.      * Delete All cache files
  1263.      *
  1264.      * @return  bool
  1265.      */
  1266.     public function cache_delete_all()
  1267.     {
  1268.         return ($this->_cache_init())
  1269.             ? $this->CACHE->delete_all()
  1270.             : FALSE;
  1271.     }
  1272.  
  1273.     // --------------------------------------------------------------------
  1274.  
  1275.     /**
  1276.      * Initialize the Cache Class
  1277.      *
  1278.      * @return  bool
  1279.      */
  1280.     protected function _cache_init()
  1281.     {
  1282.         if (class_exists('CI_DB_Cache'))
  1283.         {
  1284.             if (is_object($this->CACHE))
  1285.             {
  1286.                 return TRUE;
  1287.             }
  1288.         }
  1289.         elseif ( ! @include_once(BASEPATH.'database/DB_cache.php'))
  1290.         {
  1291.             return $this->cache_off();
  1292.         }
  1293.  
  1294.         $this->CACHE = new CI_DB_Cache($this); // pass db object to support multiple db connections and returned db objects
  1295.         return TRUE;
  1296.     }
  1297.  
  1298.     // --------------------------------------------------------------------
  1299.  
  1300.     /**
  1301.      * Close DB Connection
  1302.      *
  1303.      * @return  void
  1304.      */
  1305.     public function close()
  1306.     {
  1307.         if ($this->conn_id)
  1308.         {
  1309.             $this->_close();
  1310.             $this->conn_id = FALSE;
  1311.         }
  1312.     }
  1313.  
  1314.     // --------------------------------------------------------------------
  1315.  
  1316.     /**
  1317.      * Close DB Connection
  1318.      *
  1319.      * This method would be overriden by most of the drivers.
  1320.      *
  1321.      * @return  void
  1322.      */
  1323.     protected function _close()
  1324.     {
  1325.         $this->conn_id = FALSE;
  1326.     }
  1327.  
  1328.     // --------------------------------------------------------------------
  1329.  
  1330.     /**
  1331.      * Display an error message
  1332.      *
  1333.      * @param   string  the error message
  1334.      * @param   string  any "swap" values
  1335.      * @param   bool    whether to localize the message
  1336.      * @return  string  sends the application/error_db.php template
  1337.      */
  1338.     public function display_error($error = '', $swap = '', $native = FALSE)
  1339.     {
  1340.         $LANG =& load_class('Lang', 'core');
  1341.         $LANG->load('db');
  1342.  
  1343.         $heading = $LANG->line('db_error_heading');
  1344.  
  1345.         if ($native === TRUE)
  1346.         {
  1347.             $message = (array) $error;
  1348.         }
  1349.         else
  1350.         {
  1351.             $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
  1352.         }
  1353.  
  1354.         // Find the most likely culprit of the error by going through
  1355.         // the backtrace until the source file is no longer in the
  1356.         // database folder.
  1357.         $trace = debug_backtrace();
  1358.         foreach ($trace as $call)
  1359.         {
  1360.             if (isset($call['file'], $call['class']) && strpos($call['file'], BASEPATH.'database') === FALSE && strpos($call['class'], 'Loader') !== FALSE)
  1361.             {
  1362.                 // Found it - use a relative path for safety
  1363.                 $message[] = 'Filename: '.str_replace(array(APPPATH, BASEPATH), '', $call['file']);
  1364.                 $message[] = 'Line Number: '.$call['line'];
  1365.                 break;
  1366.             }
  1367.         }
  1368.  
  1369.         $error =& load_class('Exceptions', 'core');
  1370.         echo $error->show_error($heading, $message, 'error_db');
  1371.         exit;
  1372.     }
  1373.  
  1374.     // --------------------------------------------------------------------
  1375.  
  1376.     /**
  1377.      * Protect Identifiers
  1378.      *
  1379.      * This function is used extensively by the Query Builder class, and by
  1380.      * a couple functions in this class.
  1381.      * It takes a column or table name (optionally with an alias) and inserts
  1382.      * the table prefix onto it. Some logic is necessary in order to deal with
  1383.      * column names that include the path. Consider a query like this:
  1384.      *
  1385.      * SELECT * FROM hostname.database.table.column AS c FROM hostname.database.table
  1386.      *
  1387.      * Or a query with aliasing:
  1388.      *
  1389.      * SELECT m.member_id, m.member_name FROM members AS m
  1390.      *
  1391.      * Since the column name can include up to four segments (host, DB, table, column)
  1392.      * or also have an alias prefix, we need to do a bit of work to figure this out and
  1393.      * insert the table prefix (if it exists) in the proper position, and escape only
  1394.      * the correct identifiers.
  1395.      *
  1396.      * @param   string
  1397.      * @param   bool
  1398.      * @param   mixed
  1399.      * @param   bool
  1400.      * @return  string
  1401.      */
  1402.     public function protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE)
  1403.     {
  1404.         if ( ! is_bool($protect_identifiers))
  1405.         {
  1406.             $protect_identifiers = $this->_protect_identifiers;
  1407.         }
  1408.  
  1409.         if (is_array($item))
  1410.         {
  1411.             $escaped_array = array();
  1412.             foreach ($item as $k => $v)
  1413.             {
  1414.                 $escaped_array[$this->protect_identifiers($k)] = $this->protect_identifiers($v, $prefix_single, $protect_identifiers, $field_exists);
  1415.             }
  1416.  
  1417.             return $escaped_array;
  1418.         }
  1419.  
  1420.         // This is basically a bug fix for queries that use MAX, MIN, etc.
  1421.         // If a parenthesis is found we know that we do not need to
  1422.         // escape the data or add a prefix. There's probably a more graceful
  1423.         // way to deal with this, but I'm not thinking of it -- Rick
  1424.         if (strpos($item, '(') !== FALSE)
  1425.         {
  1426.             return $item;
  1427.         }
  1428.  
  1429.         // Convert tabs or multiple spaces into single spaces
  1430.         $item = preg_replace('/\s+/', ' ', $item);
  1431.  
  1432.         // If the item has an alias declaration we remove it and set it aside.
  1433.         // Note: strripos() is used in order to support spaces in table names
  1434.         if ($offset = strripos($item, ' AS '))
  1435.         {
  1436.             $alias = ($protect_identifiers)
  1437.                     ? substr($item, $offset, 4).$this->escape_identifiers(substr($item, $offset + 4))
  1438.                     : substr($item, $offset);
  1439.             $item = substr($item, 0, $offset);
  1440.         }
  1441.         elseif ($offset = strrpos($item, ' '))
  1442.         {
  1443.             $alias = ($protect_identifiers)
  1444.                     ? ' '.$this->escape_identifiers(substr($item, $offset + 1))
  1445.                     : substr($item, $offset);
  1446.             $item = substr($item, 0, $offset);
  1447.         }
  1448.         else
  1449.         {
  1450.             $alias = '';
  1451.         }
  1452.  
  1453.         // Break the string apart if it contains periods, then insert the table prefix
  1454.         // in the correct location, assuming the period doesn't indicate that we're dealing
  1455.         // with an alias. While we're at it, we will escape the components
  1456.         if (strpos($item, '.') !== FALSE)
  1457.         {
  1458.             $parts  = explode('.', $item);
  1459.  
  1460.             // Does the first segment of the exploded item match
  1461.             // one of the aliases previously identified? If so,
  1462.             // we have nothing more to do other than escape the item
  1463.             if (in_array($parts[0], $this->qb_aliased_tables))
  1464.             {
  1465.                 if ($protect_identifiers === TRUE)
  1466.                 {
  1467.                     foreach ($parts as $key => $val)
  1468.                     {
  1469.                         if ( ! in_array($val, $this->_reserved_identifiers))
  1470.                         {
  1471.                             $parts[$key] = $this->escape_identifiers($val);
  1472.                         }
  1473.                     }
  1474.  
  1475.                     $item = implode('.', $parts);
  1476.                 }
  1477.  
  1478.                 return $item.$alias;
  1479.             }
  1480.  
  1481.             // Is there a table prefix defined in the config file? If not, no need to do anything
  1482.             if ($this->dbprefix !== '')
  1483.             {
  1484.                 // We now add the table prefix based on some logic.
  1485.                 // Do we have 4 segments (hostname.database.table.column)?
  1486.                 // If so, we add the table prefix to the column name in the 3rd segment.
  1487.                 if (isset($parts[3]))
  1488.                 {
  1489.                     $i = 2;
  1490.                 }
  1491.                 // Do we have 3 segments (database.table.column)?
  1492.                 // If so, we add the table prefix to the column name in 2nd position
  1493.                 elseif (isset($parts[2]))
  1494.                 {
  1495.                     $i = 1;
  1496.                 }
  1497.                 // Do we have 2 segments (table.column)?
  1498.                 // If so, we add the table prefix to the column name in 1st segment
  1499.                 else
  1500.                 {
  1501.                     $i = 0;
  1502.                 }
  1503.  
  1504.                 // This flag is set when the supplied $item does not contain a field name.
  1505.                 // This can happen when this function is being called from a JOIN.
  1506.                 if ($field_exists === FALSE)
  1507.                 {
  1508.                     $i++;
  1509.                 }
  1510.  
  1511.                 // Verify table prefix and replace if necessary
  1512.                 if ($this->swap_pre !== '' && strpos($parts[$i], $this->swap_pre) === 0)
  1513.                 {
  1514.                     $parts[$i] = preg_replace('/^'.$this->swap_pre.'(\S+?)/', $this->dbprefix.'\\1', $parts[$i]);
  1515.                 }
  1516.                 // We only add the table prefix if it does not already exist
  1517.                 elseif (strpos($parts[$i], $this->dbprefix) !== 0)
  1518.                 {
  1519.                     $parts[$i] = $this->dbprefix.$parts[$i];
  1520.                 }
  1521.  
  1522.                 // Put the parts back together
  1523.                 $item = implode('.', $parts);
  1524.             }
  1525.  
  1526.             if ($protect_identifiers === TRUE)
  1527.             {
  1528.                 $item = $this->escape_identifiers($item);
  1529.             }
  1530.  
  1531.             return $item.$alias;
  1532.         }
  1533.  
  1534.         // Is there a table prefix? If not, no need to insert it
  1535.         if ($this->dbprefix !== '')
  1536.         {
  1537.             // Verify table prefix and replace if necessary
  1538.             if ($this->swap_pre !== '' && strpos($item, $this->swap_pre) === 0)
  1539.             {
  1540.                 $item = preg_replace('/^'.$this->swap_pre.'(\S+?)/', $this->dbprefix.'\\1', $item);
  1541.             }
  1542.             // Do we prefix an item with no segments?
  1543.             elseif ($prefix_single === TRUE && strpos($item, $this->dbprefix) !== 0)
  1544.             {
  1545.                 $item = $this->dbprefix.$item;
  1546.             }
  1547.         }
  1548.  
  1549.         if ($protect_identifiers === TRUE && ! in_array($item, $this->_reserved_identifiers))
  1550.         {
  1551.             $item = $this->escape_identifiers($item);
  1552.         }
  1553.  
  1554.         return $item.$alias;
  1555.     }
  1556.  
  1557.     // --------------------------------------------------------------------
  1558.  
  1559.     /**
  1560.      * Dummy method that allows Query Builder class to be disabled
  1561.      * and keep count_all() working.
  1562.      *
  1563.      * @return  void
  1564.      */
  1565.     protected function _reset_select()
  1566.     {
  1567.     }
  1568.  
  1569. }
  1570.  
  1571. /* End of file DB_driver.php */
  1572. /* Location: ./system/database/DB_driver.php */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement