mysqli_driver.php

Go to the documentation of this file.
00001 <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
00002 /**
00003  * CodeIgniter
00004  *
00005  * An open source application development framework for PHP 4.3.2 or newer
00006  *
00007  * @package             CodeIgniter
00008  * @author              ExpressionEngine Dev Team
00009  * @copyright   Copyright (c) 2006, EllisLab, Inc.
00010  * @license             http://codeigniter.com/user_guide/license.html
00011  * @link                http://codeigniter.com
00012  * @since               Version 1.0
00013  * @filesource
00014  */
00015 
00016 // ------------------------------------------------------------------------
00017 
00018 /**
00019  * MySQLi Database Adapter Class - MySQLi only works with PHP 5
00020  *
00021  * Note: _DB is an extender class that the app controller
00022  * creates dynamically based on whether the active record
00023  * class is being used or not.
00024  *
00025  * @package             CodeIgniter
00026  * @subpackage  Drivers
00027  * @category    Database
00028  * @author              ExpressionEngine Dev Team
00029  * @link                http://codeigniter.com/user_guide/database/
00030  */
00031 class CI_DB_mysqli_driver extends CI_DB {
00032 
00033         /**
00034          * The syntax to count rows is slightly different across different
00035          * database engines, so this string appears in each driver and is
00036          * used for the count_all() and count_all_results() functions.
00037          */
00038         var $_count_string = "SELECT COUNT(*) AS ";
00039         var $_random_keyword = ' RAND()'; // database specific random keyword
00040 
00041         /**
00042          * Whether to use the MySQL "delete hack" which allows the number
00043          * of affected rows to be shown. Uses a preg_replace when enabled,
00044          * adding a bit more processing to all queries.
00045          */     
00046         var $delete_hack = TRUE;
00047 
00048         // --------------------------------------------------------------------
00049 
00050         /**
00051          * Non-persistent database connection
00052          *
00053          * @access      private called by the base class
00054          * @return      resource
00055          */     
00056         function db_connect()
00057         {
00058                 return @mysqli_connect($this->hostname, $this->username, $this->password);
00059         }
00060 
00061         // --------------------------------------------------------------------
00062 
00063         /**
00064          * Persistent database connection
00065          *
00066          * @access      private called by the base class
00067          * @return      resource
00068          */     
00069         function db_pconnect()
00070         {
00071                 return $this->db_connect();
00072         }
00073         
00074         // --------------------------------------------------------------------
00075 
00076         /**
00077          * Select the database
00078          *
00079          * @access      private called by the base class
00080          * @return      resource
00081          */     
00082         function db_select()
00083         {
00084                 return @mysqli_select_db($this->conn_id, $this->database);
00085         }
00086 
00087         // --------------------------------------------------------------------
00088 
00089         /**
00090          * Set client character set
00091          *
00092          * @access      public
00093          * @param       string
00094          * @param       string
00095          * @return      resource
00096          */
00097         function db_set_charset($charset, $collation)
00098         {
00099                 return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'");
00100         }
00101 
00102         // --------------------------------------------------------------------
00103         
00104         /**
00105          * Version number query string
00106          *
00107          * @access      public
00108          * @return      string
00109          */
00110         function _version()
00111         {
00112                 return "SELECT version() AS ver";
00113         }
00114 
00115         // --------------------------------------------------------------------
00116 
00117         /**
00118          * Execute the query
00119          *
00120          * @access      private called by the base class
00121          * @param       string  an SQL query
00122          * @return      resource
00123          */     
00124         function _execute($sql)
00125         {
00126                 $sql = $this->_prep_query($sql);        
00127                 $result = @mysqli_query($this->conn_id, $sql);
00128                 return $result;
00129         }
00130         
00131         // --------------------------------------------------------------------
00132 
00133         /**
00134          * Prep the query
00135          *
00136          * If needed, each database adapter can prep the query string
00137          *
00138          * @access      private called by execute()
00139          * @param       string  an SQL query
00140          * @return      string
00141          */     
00142         function _prep_query($sql)
00143         {
00144                 // "DELETE FROM TABLE" returns 0 affected rows This hack modifies
00145                 // the query so that it returns the number of affected rows
00146                 if ($this->delete_hack === TRUE)
00147                 {
00148                         if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql))
00149                         {
00150                                 $sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $sql);
00151                         }
00152                 }
00153                 
00154                 return $sql;
00155         }
00156 
00157         // --------------------------------------------------------------------
00158 
00159         /**
00160          * Begin Transaction
00161          *
00162          * @access      public
00163          * @return      bool            
00164          */     
00165         function trans_begin($test_mode = FALSE)
00166         {
00167                 if ( ! $this->trans_enabled)
00168                 {
00169                         return TRUE;
00170                 }
00171                 
00172                 // When transactions are nested we only begin/commit/rollback the outermost ones
00173                 if ($this->_trans_depth > 0)
00174                 {
00175                         return TRUE;
00176                 }
00177 
00178                 // Reset the transaction failure flag.
00179                 // If the $test_mode flag is set to TRUE transactions will be rolled back
00180                 // even if the queries produce a successful result.
00181                 $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
00182 
00183                 $this->simple_query('SET AUTOCOMMIT=0');
00184                 $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
00185                 return TRUE;
00186         }
00187 
00188         // --------------------------------------------------------------------
00189 
00190         /**
00191          * Commit Transaction
00192          *
00193          * @access      public
00194          * @return      bool            
00195          */     
00196         function trans_commit()
00197         {
00198                 if ( ! $this->trans_enabled)
00199                 {
00200                         return TRUE;
00201                 }
00202 
00203                 // When transactions are nested we only begin/commit/rollback the outermost ones
00204                 if ($this->_trans_depth > 0)
00205                 {
00206                         return TRUE;
00207                 }
00208 
00209                 $this->simple_query('COMMIT');
00210                 $this->simple_query('SET AUTOCOMMIT=1');
00211                 return TRUE;
00212         }
00213 
00214         // --------------------------------------------------------------------
00215 
00216         /**
00217          * Rollback Transaction
00218          *
00219          * @access      public
00220          * @return      bool            
00221          */     
00222         function trans_rollback()
00223         {
00224                 if ( ! $this->trans_enabled)
00225                 {
00226                         return TRUE;
00227                 }
00228 
00229                 // When transactions are nested we only begin/commit/rollback the outermost ones
00230                 if ($this->_trans_depth > 0)
00231                 {
00232                         return TRUE;
00233                 }
00234 
00235                 $this->simple_query('ROLLBACK');
00236                 $this->simple_query('SET AUTOCOMMIT=1');
00237                 return TRUE;
00238         }
00239 
00240         // --------------------------------------------------------------------
00241 
00242         /**
00243          * Escape String
00244          *
00245          * @access      public
00246          * @param       string
00247          * @return      string
00248          */
00249         function escape_str($str)       
00250         {
00251                 if (function_exists('mysqli_real_escape_string') AND is_object($this->conn_id))
00252                 {
00253                         return mysqli_real_escape_string($this->conn_id, $str);
00254                 }
00255                 elseif (function_exists('mysql_escape_string'))
00256                 {
00257                         return mysql_escape_string($str);
00258                 }
00259                 else
00260                 {
00261                         return addslashes($str);
00262                 }
00263         }
00264                 
00265         // --------------------------------------------------------------------
00266 
00267         /**
00268          * Affected Rows
00269          *
00270          * @access      public
00271          * @return      integer
00272          */
00273         function affected_rows()
00274         {
00275                 return @mysqli_affected_rows($this->conn_id);
00276         }
00277         
00278         // --------------------------------------------------------------------
00279 
00280         /**
00281          * Insert ID
00282          *
00283          * @access      public
00284          * @return      integer
00285          */
00286         function insert_id()
00287         {
00288                 return @mysqli_insert_id($this->conn_id);
00289         }
00290 
00291         // --------------------------------------------------------------------
00292 
00293         /**
00294          * "Count All" query
00295          *
00296          * Generates a platform-specific query string that counts all records in
00297          * the specified database
00298          *
00299          * @access      public
00300          * @param       string
00301          * @return      string
00302          */
00303         function count_all($table = '')
00304         {
00305                 if ($table == '')
00306                         return '0';
00307         
00308                 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows'). " FROM " . $this->_protect_identifiers($this->dbprefix.$table));
00309                 
00310                 if ($query->num_rows() == 0)
00311                         return '0';
00312 
00313                 $row = $query->row();
00314                 return $row->numrows;
00315         }
00316 
00317         // --------------------------------------------------------------------
00318 
00319         /**
00320          * List table query
00321          *
00322          * Generates a platform-specific query string so that the table names can be fetched
00323          *
00324          * @access      private
00325          * @param       boolean
00326          * @return      string
00327          */
00328         function _list_tables($prefix_limit = FALSE)
00329         {
00330                 $sql = "SHOW TABLES FROM `".$this->database."`";        
00331                 
00332                 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
00333                 {
00334                         $sql .= " LIKE '".$this->dbprefix."%'";
00335                 }
00336                 
00337                 return $sql;
00338         }
00339 
00340         // --------------------------------------------------------------------
00341 
00342         /**
00343          * Show column query
00344          *
00345          * Generates a platform-specific query string so that the column names can be fetched
00346          *
00347          * @access      public
00348          * @param       string  the table name
00349          * @return      string
00350          */
00351         function _list_columns($table = '')
00352         {
00353                 return "SHOW COLUMNS FROM ".$this->_escape_table($table);
00354         }
00355 
00356         // --------------------------------------------------------------------
00357 
00358         /**
00359          * Field data query
00360          *
00361          * Generates a platform-specific query so that the column data can be retrieved
00362          *
00363          * @access      public
00364          * @param       string  the table name
00365          * @return      object
00366          */
00367         function _field_data($table)
00368         {
00369                 return "SELECT * FROM ".$this->_escape_table($table)." LIMIT 1";
00370         }
00371 
00372         // --------------------------------------------------------------------
00373 
00374         /**
00375          * The error message string
00376          *
00377          * @access      private
00378          * @return      string
00379          */
00380         function _error_message()
00381         {
00382                 return mysqli_error($this->conn_id);
00383         }
00384         
00385         // --------------------------------------------------------------------
00386 
00387         /**
00388          * The error message number
00389          *
00390          * @access      private
00391          * @return      integer
00392          */
00393         function _error_number()
00394         {
00395                 return mysqli_errno($this->conn_id);
00396         }
00397         
00398         // --------------------------------------------------------------------
00399 
00400         /**
00401          * Escape Table Name
00402          *
00403          * This function adds backticks if the table name has a period
00404          * in it. Some DBs will get cranky unless periods are escaped
00405          *
00406          * @access      private
00407          * @param       string  the table name
00408          * @return      string
00409          */
00410         function _escape_table($table)
00411         {
00412                 if (strpos($table, '.') !== FALSE)
00413                 {
00414                         $table = '`' . str_replace('.', '`.`', $table) . '`';
00415                 }
00416                 
00417                 return $table;
00418         }
00419                 
00420         // --------------------------------------------------------------------
00421 
00422         /**
00423          * Protect Identifiers
00424          *
00425          * This function adds backticks if appropriate based on db type
00426          *
00427          * @access      private
00428          * @param       mixed   the item to escape
00429          * @param       boolean only affect the first word
00430          * @return      mixed   the item with backticks
00431          */
00432         function _protect_identifiers($item, $first_word_only = FALSE)
00433         {
00434                 if (is_array($item))
00435                 {
00436                         $escaped_array = array();
00437 
00438                         foreach($item as $k=>$v)
00439                         {
00440                                 $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v, $first_word_only);
00441                         }
00442 
00443                         return $escaped_array;
00444                 }       
00445 
00446                 // This function may get "item1 item2" as a string, and so
00447                 // we may need "`item1` `item2`" and not "`item1 item2`"
00448                 if (ctype_alnum($item) === FALSE)
00449                 {
00450                         if (strpos($item, '.') !== FALSE)
00451                         {
00452                                 $aliased_tables = implode(".",$this->ar_aliased_tables).'.';
00453                                 $table_name =  substr($item, 0, strpos($item, '.')+1);
00454                                 $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item;
00455                         }
00456 
00457                         // This function may get "field >= 1", and need it to return "`field` >= 1"
00458                         $lbound = ($first_word_only === TRUE) ? '' : '|\s|\(';
00459 
00460                         $item = preg_replace('/(^'.$lbound.')([\w\d\-\_]+?)(\s|\)|$)/iS', '$1`$2`$3', $item);
00461                 }
00462                 else
00463                 {
00464                         return "`{$item}`";
00465                 }
00466 
00467                 $exceptions = array('AS', '/', '-', '%', '+', '*', 'OR', 'IS');
00468                 
00469                 foreach ($exceptions as $exception)
00470                 {
00471                 
00472                         if (stristr($item, " `{$exception}` ") !== FALSE)
00473                         {
00474                                 $item = preg_replace('/ `('.preg_quote($exception).')` /i', ' $1 ', $item);
00475                         }
00476                 }
00477                 return $item;
00478         }
00479                         
00480         // --------------------------------------------------------------------
00481 
00482         /**
00483          * From Tables
00484          *
00485          * This function implicitly groups FROM tables so there is no confusion
00486          * about operator precedence in harmony with SQL standards
00487          *
00488          * @access      public
00489          * @param       type
00490          * @return      type
00491          */
00492         function _from_tables($tables)
00493         {
00494                 if ( ! is_array($tables))
00495                 {
00496                         $tables = array($tables);
00497                 }
00498                 
00499                 return '('.implode(', ', $tables).')';
00500         }
00501 
00502         // --------------------------------------------------------------------
00503         
00504         /**
00505          * Insert statement
00506          *
00507          * Generates a platform-specific insert string from the supplied data
00508          *
00509          * @access      public
00510          * @param       string  the table name
00511          * @param       array   the insert keys
00512          * @param       array   the insert values
00513          * @return      string
00514          */
00515         function _insert($table, $keys, $values)
00516         {       
00517                 return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
00518         }
00519         
00520         // --------------------------------------------------------------------
00521 
00522         /**
00523          * Update statement
00524          *
00525          * Generates a platform-specific update string from the supplied data
00526          *
00527          * @access      public
00528          * @param       string  the table name
00529          * @param       array   the update data
00530          * @param       array   the where clause
00531          * @param       array   the orderby clause
00532          * @param       array   the limit clause
00533          * @return      string
00534          */
00535         function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
00536         {
00537                 foreach($values as $key => $val)
00538                 {
00539                         $valstr[] = $key." = ".$val;
00540                 }
00541                 
00542                 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
00543                 
00544                 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
00545         
00546                 $sql = "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr);
00547                 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
00548                 $sql .= $orderby.$limit;
00549                 
00550                 return $sql;
00551         }
00552 
00553         
00554         // --------------------------------------------------------------------
00555 
00556         /**
00557          * Truncate statement
00558          *
00559          * Generates a platform-specific truncate string from the supplied data
00560          * If the database does not support the truncate() command
00561          * This function maps to "DELETE FROM table"
00562          *
00563          * @access      public
00564          * @param       string  the table name
00565          * @return      string
00566          */     
00567         function _truncate($table)
00568         {
00569                 return "TRUNCATE ".$this->_escape_table($table);
00570         }
00571         
00572         // --------------------------------------------------------------------
00573 
00574         /**
00575          * Delete statement
00576          *
00577          * Generates a platform-specific delete string from the supplied data
00578          *
00579          * @access      public
00580          * @param       string  the table name
00581          * @param       array   the where clause
00582          * @param       string  the limit clause
00583          * @return      string
00584          */     
00585         function _delete($table, $where = array(), $like = array(), $limit = FALSE)
00586         {
00587                 $conditions = '';
00588 
00589                 if (count($where) > 0 OR count($like) > 0)
00590                 {
00591                         $conditions = "\nWHERE ";
00592                         $conditions .= implode("\n", $this->ar_where);
00593 
00594                         if (count($where) > 0 && count($like) > 0)
00595                         {
00596                                 $conditions .= " AND ";
00597                         }
00598                         $conditions .= implode("\n", $like);
00599                 }
00600 
00601                 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
00602         
00603                 return "DELETE FROM ".$table.$conditions.$limit;
00604         }
00605 
00606         // --------------------------------------------------------------------
00607 
00608         /**
00609          * Limit string
00610          *
00611          * Generates a platform-specific LIMIT clause
00612          *
00613          * @access      public
00614          * @param       string  the sql query string
00615          * @param       integer the number of rows to limit the query to
00616          * @param       integer the offset value
00617          * @return      string
00618          */
00619         function _limit($sql, $limit, $offset)
00620         {       
00621                 $sql .= "LIMIT ".$limit;
00622         
00623                 if ($offset > 0)
00624                 {
00625                         $sql .= " OFFSET ".$offset;
00626                 }
00627                 
00628                 return $sql;
00629         }
00630 
00631         // --------------------------------------------------------------------
00632 
00633         /**
00634          * Close DB Connection
00635          *
00636          * @access      public
00637          * @param       resource
00638          * @return      void
00639          */
00640         function _close($conn_id)
00641         {
00642                 @mysqli_close($conn_id);
00643         }
00644 
00645 
00646 }
00647 
00648 
00649 /* End of file mysqli_driver.php */
00650 /* Location: ./system/database/drivers/mysqli/mysqli_driver.php */