oci8_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) 2008, 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  * oci8 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 
00032 /**
00033  * oci8 Database Adapter Class
00034  *
00035  * This is a modification of the DB_driver class to
00036  * permit access to oracle databases
00037  *
00038  * NOTE: this uses the PHP 4 oci methods
00039  *
00040  * @author        Kelly McArdle
00041  *
00042  */
00043 
00044 class CI_DB_oci8_driver extends CI_DB {
00045 
00046         var $dbdriver = 'oci8';
00047         
00048         // The character used for excaping
00049         var $_escape_char = '"';
00050 
00051         /**
00052          * The syntax to count rows is slightly different across different
00053          * database engines, so this string appears in each driver and is
00054          * used for the count_all() and count_all_results() functions.
00055          */
00056         var $_count_string = "SELECT COUNT(1) AS ";
00057         var $_random_keyword = ' ASC'; // not currently supported
00058 
00059         // Set "auto commit" by default
00060         var $_commit = OCI_COMMIT_ON_SUCCESS;
00061 
00062         // need to track statement id and cursor id
00063         var $stmt_id;
00064         var $curs_id;
00065 
00066         // if we use a limit, we will add a field that will
00067         // throw off num_fields later
00068         var $limit_used;
00069 
00070         /**
00071          * Non-persistent database connection
00072          *
00073          * @access  private called by the base class
00074          * @return  resource
00075          */
00076         function db_connect()
00077         {
00078                 return @ocilogon($this->username, $this->password, $this->hostname);
00079         }
00080 
00081         // --------------------------------------------------------------------
00082 
00083         /**
00084          * Persistent database connection
00085          *
00086          * @access  private called by the base class
00087          * @return  resource
00088          */
00089         function db_pconnect()
00090         {
00091                 return @ociplogon($this->username, $this->password, $this->hostname);
00092         }
00093 
00094         // --------------------------------------------------------------------
00095 
00096         /**
00097          * Select the database
00098          *
00099          * @access  private called by the base class
00100          * @return  resource
00101          */
00102         function db_select()
00103         {
00104                 return TRUE;
00105         }
00106 
00107         // --------------------------------------------------------------------
00108 
00109         /**
00110          * Set client character set
00111          *
00112          * @access      public
00113          * @param       string
00114          * @param       string
00115          * @return      resource
00116          */
00117         function db_set_charset($charset, $collation)
00118         {
00119                 // @todo - add support if needed
00120                 return TRUE;
00121         }
00122 
00123         // --------------------------------------------------------------------
00124         
00125         /**
00126          * Version number query string
00127          *
00128          * @access  public
00129          * @return  string
00130          */
00131         function _version()
00132         {
00133                 return ociserverversion($this->conn_id);
00134         }
00135 
00136         // --------------------------------------------------------------------
00137 
00138         /**
00139          * Execute the query
00140          *
00141          * @access  private called by the base class
00142          * @param   string  an SQL query
00143          * @return  resource
00144          */
00145         function _execute($sql)
00146         {
00147                 // oracle must parse the query before it is run. All of the actions with
00148                 // the query are based on the statement id returned by ociparse
00149                 $this->stmt_id = FALSE;
00150                 $this->_set_stmt_id($sql);
00151                 ocisetprefetch($this->stmt_id, 1000);
00152                 return @ociexecute($this->stmt_id, $this->_commit);
00153         }
00154 
00155         /**
00156          * Generate a statement ID
00157          *
00158          * @access  private
00159          * @param   string  an SQL query
00160          * @return  none
00161          */
00162         function _set_stmt_id($sql)
00163         {
00164                 if ( ! is_resource($this->stmt_id))
00165                 {
00166                         $this->stmt_id = ociparse($this->conn_id, $this->_prep_query($sql));
00167                 }
00168         }
00169 
00170         // --------------------------------------------------------------------
00171 
00172         /**
00173          * Prep the query
00174          *
00175          * If needed, each database adapter can prep the query string
00176          *
00177          * @access  private called by execute()
00178          * @param   string  an SQL query
00179          * @return  string
00180          */
00181         function _prep_query($sql)
00182         {
00183                 return $sql;
00184         }
00185 
00186         // --------------------------------------------------------------------
00187 
00188         /**
00189          * getCursor.  Returns a cursor from the datbase
00190          *
00191          * @access  public
00192          * @return  cursor id
00193          */
00194         function get_cursor()
00195         {
00196                 $this->curs_id = ocinewcursor($this->conn_id);
00197                 return $this->curs_id;
00198         }
00199 
00200         // --------------------------------------------------------------------
00201 
00202         /**
00203          * Stored Procedure.  Executes a stored procedure
00204          *
00205          * @access  public
00206          * @param   package      package stored procedure is in
00207          * @param   procedure   stored procedure to execute
00208          * @param   params        array of parameters
00209          * @return  array
00210          *
00211          * params array keys
00212          *
00213          * KEY    OPTIONAL      NOTES
00214          * name         no              the name of the parameter should be in :<param_name> format
00215          * value        no              the value of the parameter.  If this is an OUT or IN OUT parameter,
00216          *                                      this should be a reference to a variable
00217          * type         yes             the type of the parameter
00218          * length       yes             the max size of the parameter
00219          */
00220         function stored_procedure($package, $procedure, $params)
00221         {
00222                 if ($package == '' OR $procedure == '' OR ! is_array($params))
00223                 {
00224                         if ($this->db_debug)
00225                         {
00226                                 log_message('error', 'Invalid query: '.$package.'.'.$procedure);
00227                                 return $this->display_error('db_invalid_query');
00228                         }
00229                         return FALSE;
00230                 }
00231                 
00232                 // build the query string
00233                 $sql = "begin $package.$procedure(";
00234 
00235                 $have_cursor = FALSE;
00236                 foreach($params as $param)
00237                 {
00238                         $sql .= $param['name'] . ",";
00239                         
00240                         if (array_key_exists('type', $param) && ($param['type'] == OCI_B_CURSOR))
00241                         {
00242                                 $have_cursor = TRUE;
00243                         }
00244                 }
00245                 $sql = trim($sql, ",") . "); end;";
00246                                 
00247                 $this->stmt_id = FALSE;
00248                 $this->_set_stmt_id($sql);
00249                 $this->_bind_params($params);
00250                 $this->query($sql, FALSE, $have_cursor);
00251         }
00252         
00253         // --------------------------------------------------------------------
00254 
00255         /**
00256          * Bind parameters
00257          *
00258          * @access  private
00259          * @return  none
00260          */
00261         function _bind_params($params)
00262         {
00263                 if ( ! is_array($params) OR ! is_resource($this->stmt_id))
00264                 {
00265                         return;
00266                 }
00267                 
00268                 foreach ($params as $param)
00269                 {
00270                         foreach (array('name', 'value', 'type', 'length') as $val)
00271                         {
00272                                 if ( ! isset($param[$val]))
00273                                 {
00274                                         $param[$val] = '';
00275                                 }
00276                         }
00277 
00278                         ocibindbyname($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']);
00279                 }
00280         }
00281 
00282         // --------------------------------------------------------------------
00283 
00284         /**
00285          * Begin Transaction
00286          *
00287          * @access      public
00288          * @return      bool            
00289          */     
00290         function trans_begin($test_mode = FALSE)
00291         {
00292                 if ( ! $this->trans_enabled)
00293                 {
00294                         return TRUE;
00295                 }
00296                 
00297                 // When transactions are nested we only begin/commit/rollback the outermost ones
00298                 if ($this->_trans_depth > 0)
00299                 {
00300                         return TRUE;
00301                 }
00302                 
00303                 // Reset the transaction failure flag.
00304                 // If the $test_mode flag is set to TRUE transactions will be rolled back
00305                 // even if the queries produce a successful result.
00306                 $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
00307                 
00308                 $this->_commit = OCI_DEFAULT;
00309                 return TRUE;
00310         }
00311 
00312         // --------------------------------------------------------------------
00313 
00314         /**
00315          * Commit Transaction
00316          *
00317          * @access      public
00318          * @return      bool            
00319          */     
00320         function trans_commit()
00321         {
00322                 if ( ! $this->trans_enabled)
00323                 {
00324                         return TRUE;
00325                 }
00326 
00327                 // When transactions are nested we only begin/commit/rollback the outermost ones
00328                 if ($this->_trans_depth > 0)
00329                 {
00330                         return TRUE;
00331                 }
00332 
00333                 $ret = OCIcommit($this->conn_id);
00334                 $this->_commit = OCI_COMMIT_ON_SUCCESS;
00335                 return $ret;
00336         }
00337 
00338         // --------------------------------------------------------------------
00339 
00340         /**
00341          * Rollback Transaction
00342          *
00343          * @access      public
00344          * @return      bool            
00345          */     
00346         function trans_rollback()
00347         {
00348                 if ( ! $this->trans_enabled)
00349                 {
00350                         return TRUE;
00351                 }
00352 
00353                 // When transactions are nested we only begin/commit/rollback the outermost ones
00354                 if ($this->_trans_depth > 0)
00355                 {
00356                         return TRUE;
00357                 }
00358 
00359                 $ret = OCIrollback($this->conn_id);
00360                 $this->_commit = OCI_COMMIT_ON_SUCCESS;
00361                 return $ret;
00362         }
00363 
00364         // --------------------------------------------------------------------
00365 
00366         /**
00367          * Escape String
00368          *
00369          * @access  public
00370          * @param   string
00371          * @return  string
00372          */
00373         function escape_str($str)
00374         {
00375                 // Access the CI object
00376                 $CI =& get_instance();
00377 
00378                 return $CI->_remove_invisible_characters($str);
00379         }
00380 
00381         // --------------------------------------------------------------------
00382 
00383         /**
00384          * Affected Rows
00385          *
00386          * @access  public
00387          * @return  integer
00388          */
00389         function affected_rows()
00390         {
00391                 return @ocirowcount($this->stmt_id);
00392         }
00393 
00394         // --------------------------------------------------------------------
00395 
00396         /**
00397          * Insert ID
00398          *
00399          * @access  public
00400          * @return  integer
00401          */
00402         function insert_id()
00403         {
00404                 // not supported in oracle
00405                 return $this->display_error('db_unsupported_function');
00406         }
00407 
00408         // --------------------------------------------------------------------
00409 
00410         /**
00411          * "Count All" query
00412          *
00413          * Generates a platform-specific query string that counts all records in
00414          * the specified database
00415          *
00416          * @access  public
00417          * @param   string
00418          * @return  string
00419          */
00420         function count_all($table = '')
00421         {
00422                 if ($table == '')
00423                         return '0';
00424 
00425                 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows'). " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
00426 
00427                 if ($query == FALSE)
00428                         {
00429                         return 0;
00430                         }
00431 
00432                 $row = $query->row();
00433                 return $row->NUMROWS;
00434         }
00435 
00436         // --------------------------------------------------------------------
00437 
00438         /**
00439          * Show table query
00440          *
00441          * Generates a platform-specific query string so that the table names can be fetched
00442          *
00443          * @access  private
00444          * @param       boolean
00445          * @return  string
00446          */
00447         function _list_tables($prefix_limit = FALSE)
00448         {
00449                 $sql = "SELECT TABLE_NAME FROM ALL_TABLES";
00450 
00451                 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
00452                 {
00453                         $sql .= " WHERE TABLE_NAME LIKE '".$this->dbprefix."%'";
00454                 }
00455                 
00456                 return $sql;
00457         }
00458 
00459         // --------------------------------------------------------------------
00460 
00461         /**
00462          * Show column query
00463          *
00464          * Generates a platform-specific query string so that the column names can be fetched
00465          *
00466          * @access  public
00467          * @param   string  the table name
00468          * @return  string
00469          */
00470         function _list_columns($table = '')
00471         {
00472                 return "SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = '$table'";
00473         }
00474 
00475         // --------------------------------------------------------------------
00476 
00477         /**
00478          * Field data query
00479          *
00480          * Generates a platform-specific query so that the column data can be retrieved
00481          *
00482          * @access  public
00483          * @param   string  the table name
00484          * @return  object
00485          */
00486         function _field_data($table)
00487         {
00488                 return "SELECT * FROM ".$table." where rownum = 1";
00489         }
00490 
00491         // --------------------------------------------------------------------
00492 
00493         /**
00494          * The error message string
00495          *
00496          * @access  private
00497          * @return  string
00498          */
00499         function _error_message()
00500         {
00501                 $error = ocierror($this->conn_id);
00502                 return $error['message'];
00503         }
00504 
00505         // --------------------------------------------------------------------
00506 
00507         /**
00508          * The error message number
00509          *
00510          * @access  private
00511          * @return  integer
00512          */
00513         function _error_number()
00514         {
00515                 $error = ocierror($this->conn_id);
00516                 return $error['code'];
00517         }
00518         
00519         // --------------------------------------------------------------------
00520 
00521         /**
00522          * Escape the SQL Identifiers
00523          *
00524          * This function escapes column and table names
00525          *
00526          * @access      private
00527          * @param       string
00528          * @return      string
00529          */
00530         function _escape_identifiers($item)
00531         {
00532                 if ($this->_escape_char == '')
00533                 {
00534                         return $item;
00535                 }
00536         
00537                 if (strpos($item, '.') !== FALSE)
00538                 {
00539                         $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;                    
00540                 }
00541                 else
00542                 {
00543                         $str = $this->_escape_char.$item.$this->_escape_char;
00544                 }
00545                 
00546                 // remove duplicates if the user already included the escape
00547                 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
00548         }
00549         
00550         // --------------------------------------------------------------------
00551 
00552         /**
00553          * From Tables
00554          *
00555          * This function implicitly groups FROM tables so there is no confusion
00556          * about operator precedence in harmony with SQL standards
00557          *
00558          * @access      public
00559          * @param       type
00560          * @return      type
00561          */
00562         function _from_tables($tables)
00563         {
00564                 if ( ! is_array($tables))
00565                 {
00566                         $tables = array($tables);
00567                 }
00568                 
00569                 return implode(', ', $tables);
00570         }
00571 
00572         // --------------------------------------------------------------------
00573         
00574         /**
00575          * Insert statement
00576          *
00577          * Generates a platform-specific insert string from the supplied data
00578          *
00579          * @access  public
00580          * @param   string  the table name
00581          * @param   array   the insert keys
00582          * @param   array   the insert values
00583          * @return  string
00584          */
00585         function _insert($table, $keys, $values)
00586         {
00587         return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
00588         }
00589 
00590         // --------------------------------------------------------------------
00591 
00592         /**
00593          * Update statement
00594          *
00595          * Generates a platform-specific update string from the supplied data
00596          *
00597          * @access      public
00598          * @param       string  the table name
00599          * @param       array   the update data
00600          * @param       array   the where clause
00601          * @param       array   the orderby clause
00602          * @param       array   the limit clause
00603          * @return      string
00604          */
00605         function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
00606         {
00607                 foreach($values as $key => $val)
00608                 {
00609                         $valstr[] = $key." = ".$val;
00610                 }
00611                 
00612                 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
00613                 
00614                 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
00615         
00616                 $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
00617 
00618                 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
00619 
00620                 $sql .= $orderby.$limit;
00621                 
00622                 return $sql;
00623         }
00624 
00625         // --------------------------------------------------------------------
00626 
00627         /**
00628          * Truncate statement
00629          *
00630          * Generates a platform-specific truncate string from the supplied data
00631          * If the database does not support the truncate() command
00632          * This function maps to "DELETE FROM table"
00633          *
00634          * @access      public
00635          * @param       string  the table name
00636          * @return      string
00637          */     
00638         function _truncate($table)
00639         {
00640                 return "TRUNCATE TABLE ".$table;
00641         }
00642         
00643         // --------------------------------------------------------------------
00644 
00645         /**
00646          * Delete statement
00647          *
00648          * Generates a platform-specific delete string from the supplied data
00649          *
00650          * @access      public
00651          * @param       string  the table name
00652          * @param       array   the where clause
00653          * @param       string  the limit clause
00654          * @return      string
00655          */     
00656         function _delete($table, $where = array(), $like = array(), $limit = FALSE)
00657         {
00658                 $conditions = '';
00659 
00660                 if (count($where) > 0 OR count($like) > 0)
00661                 {
00662                         $conditions = "\nWHERE ";
00663                         $conditions .= implode("\n", $this->ar_where);
00664 
00665                         if (count($where) > 0 && count($like) > 0)
00666                         {
00667                                 $conditions .= " AND ";
00668                         }
00669                         $conditions .= implode("\n", $like);
00670                 }
00671 
00672                 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
00673         
00674                 return "DELETE FROM ".$table.$conditions.$limit;
00675         }
00676 
00677         // --------------------------------------------------------------------
00678 
00679         /**
00680          * Limit string
00681          *
00682          * Generates a platform-specific LIMIT clause
00683          *
00684          * @access  public
00685          * @param   string  the sql query string
00686          * @param   integer the number of rows to limit the query to
00687          * @param   integer the offset value
00688          * @return  string
00689          */
00690         function _limit($sql, $limit, $offset)
00691         {
00692                 $limit = $offset + $limit;
00693                 $newsql = "SELECT * FROM (select inner_query.*, rownum rnum FROM ($sql) inner_query WHERE rownum < $limit)";
00694 
00695                 if ($offset != 0)
00696                 {
00697                         $newsql .= " WHERE rnum >= $offset";
00698                 }
00699 
00700                 // remember that we used limits
00701                 $this->limit_used = TRUE;
00702 
00703                 return $newsql;
00704         }       
00705 
00706         // --------------------------------------------------------------------
00707 
00708         /**
00709          * Close DB Connection
00710          *
00711          * @access  public
00712          * @param   resource
00713          * @return  void
00714          */
00715         function _close($conn_id)
00716         {
00717                 @ocilogoff($conn_id);
00718         }
00719 
00720 
00721 }
00722 
00723 
00724 
00725 /* End of file oci8_driver.php */
00726 /* Location: ./system/database/drivers/oci8/oci8_driver.php */