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