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