blob: bd83c5459da3e79be6365dad04a61e32fd34cad7 [file] [log] [blame]
Andrey Andreevc5536aa2012-11-01 17:33:58 +02001<?php
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
3 * CodeIgniter
4 *
Phil Sturgeon07c1ac82012-03-09 17:03:37 +00005 * An open source application development framework for PHP 5.2.4 or newer
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
Andrey Andreev4da24f82012-01-25 21:54:23 +02008 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05009 * Licensed under the Open Software License version 3.0
Andrey Andreev4da24f82012-01-25 21:54:23 +020010 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -050011 * This source file is subject to the Open Software License (OSL 3.0) that is
12 * bundled with this package in the files license.txt / license.rst. It is
13 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
Derek Allard2067d1a2008-11-13 22:59:24 +000019 * @package CodeIgniter
Derek Jonesf4a4bd82011-10-20 12:18:42 -050020 * @author EllisLab Dev Team
Greg Aker0defe5d2012-01-01 18:46:41 -060021 * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
Derek Jonesf4a4bd82011-10-20 12:18:42 -050022 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
Derek Allard2067d1a2008-11-13 22:59:24 +000023 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @filesource
26 */
Andrey Andreevc5536aa2012-11-01 17:33:58 +020027defined('BASEPATH') OR exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +000028
Derek Allard2067d1a2008-11-13 22:59:24 +000029/**
30 * MS SQL Database Adapter Class
31 *
32 * Note: _DB is an extender class that the app controller
Jamie Rumbelow7efad202012-02-19 12:37:00 +000033 * creates dynamically based on whether the query builder
Derek Allard2067d1a2008-11-13 22:59:24 +000034 * class is being used or not.
35 *
36 * @package CodeIgniter
37 * @subpackage Drivers
38 * @category Database
Derek Jonesf4a4bd82011-10-20 12:18:42 -050039 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000040 * @link http://codeigniter.com/user_guide/database/
41 */
42class CI_DB_mssql_driver extends CI_DB {
43
Andrey Andreev4da24f82012-01-25 21:54:23 +020044 public $dbdriver = 'mssql';
Barry Mienydd671972010-10-04 16:33:58 +020045
Derek Allard2067d1a2008-11-13 22:59:24 +000046 // The character used for escaping
Andrey Andreev082ee2b2012-06-08 15:26:34 +030047 protected $_escape_char = '"';
Derek Jonese4ed5832009-02-20 21:44:59 +000048
Andrey Andreevdd7242b2012-01-26 00:43:38 +020049 protected $_random_keyword = ' NEWID()';
Derek Allard2067d1a2008-11-13 22:59:24 +000050
Andrey Andreev082ee2b2012-06-08 15:26:34 +030051 // MSSQL-specific properties
52 protected $_quoted_identifier = TRUE;
53
Andrey Andreev5fd3ae82012-10-24 14:55:35 +030054 /**
Andrey Andreev082ee2b2012-06-08 15:26:34 +030055 * Constructor
56 *
57 * Appends the port number to the hostname, if needed.
58 *
Andrey Andreev5fd3ae82012-10-24 14:55:35 +030059 * @param array $params
Andrey Andreev082ee2b2012-06-08 15:26:34 +030060 * @return void
61 */
Andrey Andreevbd601d32012-02-12 21:16:51 +020062 public function __construct($params)
63 {
64 parent::__construct($params);
65
Andrey Andreev2cb262f2012-03-28 13:45:04 +030066 if ( ! empty($this->port))
Andrey Andreevbd601d32012-02-12 21:16:51 +020067 {
68 $this->hostname .= (DIRECTORY_SEPARATOR === '\\' ? ',' : ':').$this->port;
69 }
70 }
71
Andrey Andreev082ee2b2012-06-08 15:26:34 +030072 // --------------------------------------------------------------------
73
Derek Allard2067d1a2008-11-13 22:59:24 +000074 /**
75 * Non-persistent database connection
76 *
Andrey Andreevfac37612012-07-02 14:56:20 +030077 * @param bool
Derek Allard2067d1a2008-11-13 22:59:24 +000078 * @return resource
Barry Mienydd671972010-10-04 16:33:58 +020079 */
Andrey Andreevfac37612012-07-02 14:56:20 +030080 public function db_connect($persistent = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +000081 {
Andrey Andreevfac37612012-07-02 14:56:20 +030082 $this->conn_id = ($persistent)
83 ? @mssql_pconnect($this->hostname, $this->username, $this->password)
84 : @mssql_connect($this->hostname, $this->username, $this->password);
85
86 if ( ! $this->conn_id)
87 {
88 return FALSE;
89 }
90
91 // Determine how identifiers are escaped
92 $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
93 $query = $query->row_array();
94 $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi'];
95 $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
96
97 return $this->conn_id;
Derek Allard2067d1a2008-11-13 22:59:24 +000098 }
Barry Mienydd671972010-10-04 16:33:58 +020099
Derek Allard2067d1a2008-11-13 22:59:24 +0000100 // --------------------------------------------------------------------
101
102 /**
103 * Persistent database connection
104 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000105 * @return resource
Barry Mienydd671972010-10-04 16:33:58 +0200106 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200107 public function db_pconnect()
Derek Allard2067d1a2008-11-13 22:59:24 +0000108 {
Andrey Andreevfac37612012-07-02 14:56:20 +0300109 return $this->db_connect(TRUE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000110 }
Barry Mienydd671972010-10-04 16:33:58 +0200111
Derek Allard2067d1a2008-11-13 22:59:24 +0000112 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200113
Derek Jones87cbafc2009-02-27 16:29:59 +0000114 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000115 * Select the database
116 *
Andrey Andreev11454e02012-02-22 16:05:47 +0200117 * @param string database name
Andrey Andreev4da24f82012-01-25 21:54:23 +0200118 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200119 */
Andrey Andreev11454e02012-02-22 16:05:47 +0200120 public function db_select($database = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000121 {
Andrey Andreev024ba2d2012-02-24 11:40:36 +0200122 if ($database === '')
123 {
124 $database = $this->database;
125 }
126
Derek Allard2067d1a2008-11-13 22:59:24 +0000127 // Note: The brackets are required in the event that the DB name
128 // contains reserved characters
Andrey Andreev082ee2b2012-06-08 15:26:34 +0300129 if (@mssql_select_db($this->escape_identifiers($database), $this->conn_id))
Andrey Andreev024ba2d2012-02-24 11:40:36 +0200130 {
131 $this->database = $database;
132 return TRUE;
133 }
134
135 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000136 }
137
138 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200139
Derek Allard2067d1a2008-11-13 22:59:24 +0000140 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000141 * Execute the query
142 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000143 * @param string an SQL query
Andrey Andreev4da24f82012-01-25 21:54:23 +0200144 * @return mixed resource if rows are returned, bool otherwise
Barry Mienydd671972010-10-04 16:33:58 +0200145 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200146 protected function _execute($sql)
Derek Allard2067d1a2008-11-13 22:59:24 +0000147 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000148 return @mssql_query($sql, $this->conn_id);
Derek Allard2067d1a2008-11-13 22:59:24 +0000149 }
150
151 // --------------------------------------------------------------------
152
153 /**
154 * Begin Transaction
155 *
Andrey Andreev5fd3ae82012-10-24 14:55:35 +0300156 * @param bool $test_mode = FALSE
Barry Mienydd671972010-10-04 16:33:58 +0200157 * @return bool
158 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200159 public function trans_begin($test_mode = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000160 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000161 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev4da24f82012-01-25 21:54:23 +0200162 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000163 {
164 return TRUE;
165 }
166
167 // Reset the transaction failure flag.
168 // If the $test_mode flag is set to TRUE transactions will be rolled back
169 // even if the queries produce a successful result.
Andrey Andreev4da24f82012-01-25 21:54:23 +0200170 $this->_trans_failure = ($test_mode === TRUE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000171
Andrey Andreev4da24f82012-01-25 21:54:23 +0200172 return $this->simple_query('BEGIN TRAN');
Derek Allard2067d1a2008-11-13 22:59:24 +0000173 }
174
175 // --------------------------------------------------------------------
176
177 /**
178 * Commit Transaction
179 *
Barry Mienydd671972010-10-04 16:33:58 +0200180 * @return bool
181 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200182 public function trans_commit()
Derek Allard2067d1a2008-11-13 22:59:24 +0000183 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000184 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev4da24f82012-01-25 21:54:23 +0200185 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000186 {
187 return TRUE;
188 }
189
Andrey Andreev4da24f82012-01-25 21:54:23 +0200190 return $this->simple_query('COMMIT TRAN');
Derek Allard2067d1a2008-11-13 22:59:24 +0000191 }
192
193 // --------------------------------------------------------------------
194
195 /**
196 * Rollback Transaction
197 *
Barry Mienydd671972010-10-04 16:33:58 +0200198 * @return bool
199 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200200 public function trans_rollback()
Derek Allard2067d1a2008-11-13 22:59:24 +0000201 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000202 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev4da24f82012-01-25 21:54:23 +0200203 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000204 {
205 return TRUE;
206 }
207
Andrey Andreev4da24f82012-01-25 21:54:23 +0200208 return $this->simple_query('ROLLBACK TRAN');
Derek Allard2067d1a2008-11-13 22:59:24 +0000209 }
Barry Mienydd671972010-10-04 16:33:58 +0200210
Derek Allard2067d1a2008-11-13 22:59:24 +0000211 // --------------------------------------------------------------------
212
213 /**
214 * Escape String
215 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000216 * @param string
Derek Jonese4ed5832009-02-20 21:44:59 +0000217 * @param bool whether or not the string will be used in a LIKE condition
Derek Allard2067d1a2008-11-13 22:59:24 +0000218 * @return string
219 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200220 public function escape_str($str, $like = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000221 {
Derek Jonese4ed5832009-02-20 21:44:59 +0000222 if (is_array($str))
223 {
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500224 foreach ($str as $key => $val)
Barry Mienydd671972010-10-04 16:33:58 +0200225 {
Derek Jonese4ed5832009-02-20 21:44:59 +0000226 $str[$key] = $this->escape_str($val, $like);
Barry Mienydd671972010-10-04 16:33:58 +0200227 }
228
229 return $str;
230 }
231
Derek Allard2067d1a2008-11-13 22:59:24 +0000232 // Escape single quotes
Greg Aker757dda62010-04-14 19:06:19 -0500233 $str = str_replace("'", "''", remove_invisible_characters($str));
Barry Mienydd671972010-10-04 16:33:58 +0200234
Derek Jonese4ed5832009-02-20 21:44:59 +0000235 // escape LIKE condition wildcards
236 if ($like === TRUE)
237 {
Andrey Andreev4da24f82012-01-25 21:54:23 +0200238 return str_replace(
Phil Sturgeon36b0c942011-04-02 12:16:41 +0100239 array($this->_like_escape_chr, '%', '_'),
240 array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
241 $str
242 );
Derek Jonese4ed5832009-02-20 21:44:59 +0000243 }
Barry Mienydd671972010-10-04 16:33:58 +0200244
Derek Jonese4ed5832009-02-20 21:44:59 +0000245 return $str;
Derek Allard2067d1a2008-11-13 22:59:24 +0000246 }
Barry Mienydd671972010-10-04 16:33:58 +0200247
Derek Allard2067d1a2008-11-13 22:59:24 +0000248 // --------------------------------------------------------------------
249
250 /**
251 * Affected Rows
252 *
Andrey Andreev4da24f82012-01-25 21:54:23 +0200253 * @return int
Derek Allard2067d1a2008-11-13 22:59:24 +0000254 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200255 public function affected_rows()
Derek Allard2067d1a2008-11-13 22:59:24 +0000256 {
257 return @mssql_rows_affected($this->conn_id);
258 }
Barry Mienydd671972010-10-04 16:33:58 +0200259
Derek Allard2067d1a2008-11-13 22:59:24 +0000260 // --------------------------------------------------------------------
261
262 /**
Andrey Andreev1f619a82012-03-20 16:03:04 +0200263 * Insert ID
264 *
265 * Returns the last id created in the Identity column.
266 *
267 * @return string
268 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200269 public function insert_id()
Derek Allard2067d1a2008-11-13 22:59:24 +0000270 {
Andrey Andreev70c72c92012-06-25 00:04:51 +0300271 $query = version_compare($this->version(), '8', '>=')
Andrey Andreev4da24f82012-01-25 21:54:23 +0200272 ? 'SELECT SCOPE_IDENTITY() AS last_id'
273 : 'SELECT @@IDENTITY AS last_id';
274
Andrey Andreevb7a47a72012-01-26 02:13:33 +0200275 $query = $this->query($query);
276 $query = $query->row();
277 return $query->last_id;
Derek Allard2067d1a2008-11-13 22:59:24 +0000278 }
279
280 // --------------------------------------------------------------------
281
282 /**
Andrey Andreev1f619a82012-03-20 16:03:04 +0200283 * Version number query string
284 *
285 * @return string
286 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200287 protected function _version()
Derek Allard2067d1a2008-11-13 22:59:24 +0000288 {
Andrey Andreev4da24f82012-01-25 21:54:23 +0200289 return 'SELECT @@VERSION AS ver';
Derek Allard2067d1a2008-11-13 22:59:24 +0000290 }
291
292 // --------------------------------------------------------------------
293
294 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000295 * List table query
296 *
297 * Generates a platform-specific query string so that the table names can be fetched
298 *
Andrey Andreev4da24f82012-01-25 21:54:23 +0200299 * @param bool
Derek Allard2067d1a2008-11-13 22:59:24 +0000300 * @return string
301 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200302 protected function _list_tables($prefix_limit = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000303 {
Andrey Andreev70c72c92012-06-25 00:04:51 +0300304 $sql = 'SELECT '.$this->escape_identifiers('name')
305 .' FROM '.$this->escape_identifiers('sysobjects')
306 .' WHERE '.$this->escape_identifiers('type')." = 'U'";
Barry Mienydd671972010-10-04 16:33:58 +0200307
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100308 if ($prefix_limit !== FALSE AND $this->dbprefix !== '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000309 {
Andrey Andreev70c72c92012-06-25 00:04:51 +0300310 $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' "
311 .sprintf($this->_like_escape_str, $this->_like_escape_chr);
Derek Allard2067d1a2008-11-13 22:59:24 +0000312 }
Barry Mienydd671972010-10-04 16:33:58 +0200313
Andrey Andreev70c72c92012-06-25 00:04:51 +0300314 return $sql.' ORDER BY '.$this->escape_identifiers('name');
Derek Allard2067d1a2008-11-13 22:59:24 +0000315 }
316
317 // --------------------------------------------------------------------
318
319 /**
320 * List column query
321 *
322 * Generates a platform-specific query string so that the column names can be fetched
323 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000324 * @param string the table name
325 * @return string
326 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200327 protected function _list_columns($table = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000328 {
Barry Mienydd671972010-10-04 16:33:58 +0200329 return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$table."'";
Derek Allard2067d1a2008-11-13 22:59:24 +0000330 }
331
332 // --------------------------------------------------------------------
333
334 /**
335 * Field data query
336 *
337 * Generates a platform-specific query so that the column data can be retrieved
338 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000339 * @param string the table name
Andrey Andreev4da24f82012-01-25 21:54:23 +0200340 * @return string
Derek Allard2067d1a2008-11-13 22:59:24 +0000341 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200342 protected function _field_data($table)
Derek Allard2067d1a2008-11-13 22:59:24 +0000343 {
Andrey Andreev70c72c92012-06-25 00:04:51 +0300344 return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
Derek Allard2067d1a2008-11-13 22:59:24 +0000345 }
346
347 // --------------------------------------------------------------------
348
349 /**
Andrey Andreev4be5de12012-03-02 15:45:41 +0200350 * Error
Derek Allard2067d1a2008-11-13 22:59:24 +0000351 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200352 * Returns an array containing code and message of the last
353 * database error that has occured.
Derek Allard2067d1a2008-11-13 22:59:24 +0000354 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200355 * @return array
Derek Allard2067d1a2008-11-13 22:59:24 +0000356 */
Andrey Andreev4be5de12012-03-02 15:45:41 +0200357 public function error()
Derek Allard2067d1a2008-11-13 22:59:24 +0000358 {
Andrey Andreev4be5de12012-03-02 15:45:41 +0200359 $query = $this->query('SELECT @@ERROR AS code');
360 $query = $query->row();
361 return array('code' => $query->code, 'message' => mssql_get_last_message());
Derek Allard2067d1a2008-11-13 22:59:24 +0000362 }
363
364 // --------------------------------------------------------------------
365
366 /**
Andrey Andreev00541ae2012-04-09 11:43:10 +0300367 * Update statement
368 *
369 * Generates a platform-specific update string from the supplied data
370 *
371 * @param string the table name
372 * @param array the update data
Andrey Andreev00541ae2012-04-09 11:43:10 +0300373 * @return string
374 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300375 protected function _update($table, $values)
Andrey Andreev00541ae2012-04-09 11:43:10 +0300376 {
Andrey Andreevb0478652012-07-18 15:34:46 +0300377 $this->qb_limit = FALSE;
378 $this->qb_orderby = array();
379 return parent::_update($table, $values);
Andrey Andreev00541ae2012-04-09 11:43:10 +0300380 }
381
382 // --------------------------------------------------------------------
383
384 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000385 * Truncate statement
386 *
387 * Generates a platform-specific truncate string from the supplied data
Andrey Andreev6d83cde2012-04-05 16:20:50 +0300388 *
389 * If the database does not support the truncate() command,
390 * then this method maps to 'DELETE FROM table'
Derek Allard2067d1a2008-11-13 22:59:24 +0000391 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000392 * @param string the table name
393 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200394 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200395 protected function _truncate($table)
Derek Allard2067d1a2008-11-13 22:59:24 +0000396 {
Andrey Andreev6d83cde2012-04-05 16:20:50 +0300397 return 'TRUNCATE TABLE '.$table;
Derek Allard2067d1a2008-11-13 22:59:24 +0000398 }
Barry Mienydd671972010-10-04 16:33:58 +0200399
Derek Allard2067d1a2008-11-13 22:59:24 +0000400 // --------------------------------------------------------------------
401
402 /**
403 * Delete statement
404 *
405 * Generates a platform-specific delete string from the supplied data
406 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000407 * @param string the table name
Derek Allard2067d1a2008-11-13 22:59:24 +0000408 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200409 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300410 protected function _delete($table)
Derek Allard2067d1a2008-11-13 22:59:24 +0000411 {
Andrey Andreevb0478652012-07-18 15:34:46 +0300412 if ($this->qb_limit)
413 {
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300414 return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
Andrey Andreevb0478652012-07-18 15:34:46 +0300415 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000416
Andrey Andreevb0478652012-07-18 15:34:46 +0300417 return parent::_delete($table);
Derek Allard2067d1a2008-11-13 22:59:24 +0000418 }
419
420 // --------------------------------------------------------------------
421
422 /**
423 * Limit string
424 *
425 * Generates a platform-specific LIMIT clause
426 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000427 * @param string the sql query string
Derek Allard2067d1a2008-11-13 22:59:24 +0000428 * @return string
429 */
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300430 protected function _limit($sql)
Derek Allard2067d1a2008-11-13 22:59:24 +0000431 {
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300432 $limit = $this->qb_offset + $this->qb_limit;
Andrey Andreev71379ca2012-06-11 16:12:43 +0300433
434 // As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported,
435 // however an ORDER BY clause is required for it to work
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300436 if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby))
Andrey Andreev71379ca2012-06-11 16:12:43 +0300437 {
Andrey Andreev2d486232012-07-19 14:46:51 +0300438 $orderby = $this->_compile_order_by();
Andrey Andreev71379ca2012-06-11 16:12:43 +0300439
440 // We have to strip the ORDER BY clause
Andrey Andreev2d486232012-07-19 14:46:51 +0300441 $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
Andrey Andreev71379ca2012-06-11 16:12:43 +0300442
Andrey Andreev44514542012-10-23 15:35:09 +0300443 // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
444 if (count($this->qb_select) === 0)
445 {
446 $select = '*'; // Inevitable
447 }
448 else
449 {
450 // Use only field names and their aliases, everything else is out of our scope.
451 $select = array();
452 $field_regexp = ($this->_quoted_identifier)
453 ? '("[^\"]+")' : '(\[[^\]]+\])';
454 for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
455 {
456 $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
457 ? $m[1] : $this->qb_select[$i];
458 }
459 $select = implode(', ', $select);
460 }
461
462 return 'SELECT '.$select." FROM (\n\n"
Andrey Andreev2d486232012-07-19 14:46:51 +0300463 .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
Andrey Andreev44514542012-10-23 15:35:09 +0300464 ."\n\n) ".$this->escape_identifiers('CI_subquery')
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300465 ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
Andrey Andreev71379ca2012-06-11 16:12:43 +0300466 }
467
468 return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
Derek Allard2067d1a2008-11-13 22:59:24 +0000469 }
470
471 // --------------------------------------------------------------------
472
473 /**
474 * Close DB Connection
475 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000476 * @return void
477 */
Andrey Andreev79922c02012-05-23 12:27:17 +0300478 protected function _close()
Derek Allard2067d1a2008-11-13 22:59:24 +0000479 {
Andrey Andreev79922c02012-05-23 12:27:17 +0300480 @mssql_close($this->conn_id);
Barry Mienydd671972010-10-04 16:33:58 +0200481 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000482
483}
484
Derek Allard2067d1a2008-11-13 22:59:24 +0000485/* End of file mssql_driver.php */
Andrey Andreev79922c02012-05-23 12:27:17 +0300486/* Location: ./system/database/drivers/mssql/mssql_driver.php */