blob: 2063dad904b3d58d175e525dea042b01e4f41f83 [file] [log] [blame]
Andrey Andreev4da24f82012-01-25 21:54:23 +02001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
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 */
27
Derek Allard2067d1a2008-11-13 22:59:24 +000028/**
29 * MS SQL Database Adapter Class
30 *
31 * Note: _DB is an extender class that the app controller
Jamie Rumbelow7efad202012-02-19 12:37:00 +000032 * creates dynamically based on whether the query builder
Derek Allard2067d1a2008-11-13 22:59:24 +000033 * class is being used or not.
34 *
35 * @package CodeIgniter
36 * @subpackage Drivers
37 * @category Database
Derek Jonesf4a4bd82011-10-20 12:18:42 -050038 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000039 * @link http://codeigniter.com/user_guide/database/
40 */
41class CI_DB_mssql_driver extends CI_DB {
42
Andrey Andreev4da24f82012-01-25 21:54:23 +020043 public $dbdriver = 'mssql';
Barry Mienydd671972010-10-04 16:33:58 +020044
Derek Allard2067d1a2008-11-13 22:59:24 +000045 // The character used for escaping
Andrey Andreev082ee2b2012-06-08 15:26:34 +030046 protected $_escape_char = '"';
Derek Jonese4ed5832009-02-20 21:44:59 +000047
Andrey Andreevdd7242b2012-01-26 00:43:38 +020048 protected $_random_keyword = ' NEWID()';
Derek Allard2067d1a2008-11-13 22:59:24 +000049
Andrey Andreev082ee2b2012-06-08 15:26:34 +030050 // MSSQL-specific properties
51 protected $_quoted_identifier = TRUE;
52
Andrey Andreev5fd3ae82012-10-24 14:55:35 +030053 /**
Andrey Andreev082ee2b2012-06-08 15:26:34 +030054 * Constructor
55 *
56 * Appends the port number to the hostname, if needed.
57 *
Andrey Andreev5fd3ae82012-10-24 14:55:35 +030058 * @param array $params
Andrey Andreev082ee2b2012-06-08 15:26:34 +030059 * @return void
60 */
Andrey Andreevbd601d32012-02-12 21:16:51 +020061 public function __construct($params)
62 {
63 parent::__construct($params);
64
Andrey Andreev2cb262f2012-03-28 13:45:04 +030065 if ( ! empty($this->port))
Andrey Andreevbd601d32012-02-12 21:16:51 +020066 {
67 $this->hostname .= (DIRECTORY_SEPARATOR === '\\' ? ',' : ':').$this->port;
68 }
69 }
70
Andrey Andreev082ee2b2012-06-08 15:26:34 +030071 // --------------------------------------------------------------------
72
Derek Allard2067d1a2008-11-13 22:59:24 +000073 /**
74 * Non-persistent database connection
75 *
Andrey Andreevfac37612012-07-02 14:56:20 +030076 * @param bool
Derek Allard2067d1a2008-11-13 22:59:24 +000077 * @return resource
Barry Mienydd671972010-10-04 16:33:58 +020078 */
Andrey Andreevfac37612012-07-02 14:56:20 +030079 public function db_connect($persistent = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +000080 {
Andrey Andreevfac37612012-07-02 14:56:20 +030081 $this->conn_id = ($persistent)
82 ? @mssql_pconnect($this->hostname, $this->username, $this->password)
83 : @mssql_connect($this->hostname, $this->username, $this->password);
84
85 if ( ! $this->conn_id)
86 {
87 return FALSE;
88 }
89
90 // Determine how identifiers are escaped
91 $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
92 $query = $query->row_array();
93 $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi'];
94 $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
95
96 return $this->conn_id;
Derek Allard2067d1a2008-11-13 22:59:24 +000097 }
Barry Mienydd671972010-10-04 16:33:58 +020098
Derek Allard2067d1a2008-11-13 22:59:24 +000099 // --------------------------------------------------------------------
100
101 /**
102 * Persistent database connection
103 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000104 * @return resource
Barry Mienydd671972010-10-04 16:33:58 +0200105 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200106 public function db_pconnect()
Derek Allard2067d1a2008-11-13 22:59:24 +0000107 {
Andrey Andreevfac37612012-07-02 14:56:20 +0300108 return $this->db_connect(TRUE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000109 }
Barry Mienydd671972010-10-04 16:33:58 +0200110
Derek Allard2067d1a2008-11-13 22:59:24 +0000111 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200112
Derek Jones87cbafc2009-02-27 16:29:59 +0000113 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000114 * Select the database
115 *
Andrey Andreev11454e02012-02-22 16:05:47 +0200116 * @param string database name
Andrey Andreev4da24f82012-01-25 21:54:23 +0200117 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200118 */
Andrey Andreev11454e02012-02-22 16:05:47 +0200119 public function db_select($database = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000120 {
Andrey Andreev024ba2d2012-02-24 11:40:36 +0200121 if ($database === '')
122 {
123 $database = $this->database;
124 }
125
Derek Allard2067d1a2008-11-13 22:59:24 +0000126 // Note: The brackets are required in the event that the DB name
127 // contains reserved characters
Andrey Andreev082ee2b2012-06-08 15:26:34 +0300128 if (@mssql_select_db($this->escape_identifiers($database), $this->conn_id))
Andrey Andreev024ba2d2012-02-24 11:40:36 +0200129 {
130 $this->database = $database;
131 return TRUE;
132 }
133
134 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000135 }
136
137 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200138
Derek Allard2067d1a2008-11-13 22:59:24 +0000139 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000140 * Execute the query
141 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000142 * @param string an SQL query
Andrey Andreev4da24f82012-01-25 21:54:23 +0200143 * @return mixed resource if rows are returned, bool otherwise
Barry Mienydd671972010-10-04 16:33:58 +0200144 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200145 protected function _execute($sql)
Derek Allard2067d1a2008-11-13 22:59:24 +0000146 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000147 return @mssql_query($sql, $this->conn_id);
Derek Allard2067d1a2008-11-13 22:59:24 +0000148 }
149
150 // --------------------------------------------------------------------
151
152 /**
153 * Begin Transaction
154 *
Andrey Andreev5fd3ae82012-10-24 14:55:35 +0300155 * @param bool $test_mode = FALSE
Barry Mienydd671972010-10-04 16:33:58 +0200156 * @return bool
157 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200158 public function trans_begin($test_mode = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000159 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000160 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev4da24f82012-01-25 21:54:23 +0200161 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000162 {
163 return TRUE;
164 }
165
166 // Reset the transaction failure flag.
167 // If the $test_mode flag is set to TRUE transactions will be rolled back
168 // even if the queries produce a successful result.
Andrey Andreev4da24f82012-01-25 21:54:23 +0200169 $this->_trans_failure = ($test_mode === TRUE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000170
Andrey Andreev4da24f82012-01-25 21:54:23 +0200171 return $this->simple_query('BEGIN TRAN');
Derek Allard2067d1a2008-11-13 22:59:24 +0000172 }
173
174 // --------------------------------------------------------------------
175
176 /**
177 * Commit Transaction
178 *
Barry Mienydd671972010-10-04 16:33:58 +0200179 * @return bool
180 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200181 public function trans_commit()
Derek Allard2067d1a2008-11-13 22:59:24 +0000182 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000183 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev4da24f82012-01-25 21:54:23 +0200184 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000185 {
186 return TRUE;
187 }
188
Andrey Andreev4da24f82012-01-25 21:54:23 +0200189 return $this->simple_query('COMMIT TRAN');
Derek Allard2067d1a2008-11-13 22:59:24 +0000190 }
191
192 // --------------------------------------------------------------------
193
194 /**
195 * Rollback Transaction
196 *
Barry Mienydd671972010-10-04 16:33:58 +0200197 * @return bool
198 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200199 public function trans_rollback()
Derek Allard2067d1a2008-11-13 22:59:24 +0000200 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000201 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev4da24f82012-01-25 21:54:23 +0200202 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000203 {
204 return TRUE;
205 }
206
Andrey Andreev4da24f82012-01-25 21:54:23 +0200207 return $this->simple_query('ROLLBACK TRAN');
Derek Allard2067d1a2008-11-13 22:59:24 +0000208 }
Barry Mienydd671972010-10-04 16:33:58 +0200209
Derek Allard2067d1a2008-11-13 22:59:24 +0000210 // --------------------------------------------------------------------
211
212 /**
213 * Escape String
214 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000215 * @param string
Derek Jonese4ed5832009-02-20 21:44:59 +0000216 * @param bool whether or not the string will be used in a LIKE condition
Derek Allard2067d1a2008-11-13 22:59:24 +0000217 * @return string
218 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200219 public function escape_str($str, $like = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000220 {
Derek Jonese4ed5832009-02-20 21:44:59 +0000221 if (is_array($str))
222 {
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500223 foreach ($str as $key => $val)
Barry Mienydd671972010-10-04 16:33:58 +0200224 {
Derek Jonese4ed5832009-02-20 21:44:59 +0000225 $str[$key] = $this->escape_str($val, $like);
Barry Mienydd671972010-10-04 16:33:58 +0200226 }
227
228 return $str;
229 }
230
Derek Allard2067d1a2008-11-13 22:59:24 +0000231 // Escape single quotes
Greg Aker757dda62010-04-14 19:06:19 -0500232 $str = str_replace("'", "''", remove_invisible_characters($str));
Barry Mienydd671972010-10-04 16:33:58 +0200233
Derek Jonese4ed5832009-02-20 21:44:59 +0000234 // escape LIKE condition wildcards
235 if ($like === TRUE)
236 {
Andrey Andreev4da24f82012-01-25 21:54:23 +0200237 return str_replace(
Phil Sturgeon36b0c942011-04-02 12:16:41 +0100238 array($this->_like_escape_chr, '%', '_'),
239 array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
240 $str
241 );
Derek Jonese4ed5832009-02-20 21:44:59 +0000242 }
Barry Mienydd671972010-10-04 16:33:58 +0200243
Derek Jonese4ed5832009-02-20 21:44:59 +0000244 return $str;
Derek Allard2067d1a2008-11-13 22:59:24 +0000245 }
Barry Mienydd671972010-10-04 16:33:58 +0200246
Derek Allard2067d1a2008-11-13 22:59:24 +0000247 // --------------------------------------------------------------------
248
249 /**
250 * Affected Rows
251 *
Andrey Andreev4da24f82012-01-25 21:54:23 +0200252 * @return int
Derek Allard2067d1a2008-11-13 22:59:24 +0000253 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200254 public function affected_rows()
Derek Allard2067d1a2008-11-13 22:59:24 +0000255 {
256 return @mssql_rows_affected($this->conn_id);
257 }
Barry Mienydd671972010-10-04 16:33:58 +0200258
Derek Allard2067d1a2008-11-13 22:59:24 +0000259 // --------------------------------------------------------------------
260
261 /**
Andrey Andreev1f619a82012-03-20 16:03:04 +0200262 * Insert ID
263 *
264 * Returns the last id created in the Identity column.
265 *
266 * @return string
267 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200268 public function insert_id()
Derek Allard2067d1a2008-11-13 22:59:24 +0000269 {
Andrey Andreev70c72c92012-06-25 00:04:51 +0300270 $query = version_compare($this->version(), '8', '>=')
Andrey Andreev4da24f82012-01-25 21:54:23 +0200271 ? 'SELECT SCOPE_IDENTITY() AS last_id'
272 : 'SELECT @@IDENTITY AS last_id';
273
Andrey Andreevb7a47a72012-01-26 02:13:33 +0200274 $query = $this->query($query);
275 $query = $query->row();
276 return $query->last_id;
Derek Allard2067d1a2008-11-13 22:59:24 +0000277 }
278
279 // --------------------------------------------------------------------
280
281 /**
Andrey Andreev1f619a82012-03-20 16:03:04 +0200282 * Version number query string
283 *
284 * @return string
285 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200286 protected function _version()
Derek Allard2067d1a2008-11-13 22:59:24 +0000287 {
Andrey Andreev4da24f82012-01-25 21:54:23 +0200288 return 'SELECT @@VERSION AS ver';
Derek Allard2067d1a2008-11-13 22:59:24 +0000289 }
290
291 // --------------------------------------------------------------------
292
293 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000294 * List table query
295 *
296 * Generates a platform-specific query string so that the table names can be fetched
297 *
Andrey Andreev4da24f82012-01-25 21:54:23 +0200298 * @param bool
Derek Allard2067d1a2008-11-13 22:59:24 +0000299 * @return string
300 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200301 protected function _list_tables($prefix_limit = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000302 {
Andrey Andreev70c72c92012-06-25 00:04:51 +0300303 $sql = 'SELECT '.$this->escape_identifiers('name')
304 .' FROM '.$this->escape_identifiers('sysobjects')
305 .' WHERE '.$this->escape_identifiers('type')." = 'U'";
Barry Mienydd671972010-10-04 16:33:58 +0200306
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100307 if ($prefix_limit !== FALSE AND $this->dbprefix !== '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000308 {
Andrey Andreev70c72c92012-06-25 00:04:51 +0300309 $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' "
310 .sprintf($this->_like_escape_str, $this->_like_escape_chr);
Derek Allard2067d1a2008-11-13 22:59:24 +0000311 }
Barry Mienydd671972010-10-04 16:33:58 +0200312
Andrey Andreev70c72c92012-06-25 00:04:51 +0300313 return $sql.' ORDER BY '.$this->escape_identifiers('name');
Derek Allard2067d1a2008-11-13 22:59:24 +0000314 }
315
316 // --------------------------------------------------------------------
317
318 /**
319 * List column query
320 *
321 * Generates a platform-specific query string so that the column names can be fetched
322 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000323 * @param string the table name
324 * @return string
325 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200326 protected function _list_columns($table = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000327 {
Barry Mienydd671972010-10-04 16:33:58 +0200328 return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$table."'";
Derek Allard2067d1a2008-11-13 22:59:24 +0000329 }
330
331 // --------------------------------------------------------------------
332
333 /**
334 * Field data query
335 *
336 * Generates a platform-specific query so that the column data can be retrieved
337 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000338 * @param string the table name
Andrey Andreev4da24f82012-01-25 21:54:23 +0200339 * @return string
Derek Allard2067d1a2008-11-13 22:59:24 +0000340 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200341 protected function _field_data($table)
Derek Allard2067d1a2008-11-13 22:59:24 +0000342 {
Andrey Andreev70c72c92012-06-25 00:04:51 +0300343 return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
Derek Allard2067d1a2008-11-13 22:59:24 +0000344 }
345
346 // --------------------------------------------------------------------
347
348 /**
Andrey Andreev4be5de12012-03-02 15:45:41 +0200349 * Error
Derek Allard2067d1a2008-11-13 22:59:24 +0000350 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200351 * Returns an array containing code and message of the last
352 * database error that has occured.
Derek Allard2067d1a2008-11-13 22:59:24 +0000353 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200354 * @return array
Derek Allard2067d1a2008-11-13 22:59:24 +0000355 */
Andrey Andreev4be5de12012-03-02 15:45:41 +0200356 public function error()
Derek Allard2067d1a2008-11-13 22:59:24 +0000357 {
Andrey Andreev4be5de12012-03-02 15:45:41 +0200358 $query = $this->query('SELECT @@ERROR AS code');
359 $query = $query->row();
360 return array('code' => $query->code, 'message' => mssql_get_last_message());
Derek Allard2067d1a2008-11-13 22:59:24 +0000361 }
362
363 // --------------------------------------------------------------------
364
365 /**
Andrey Andreev00541ae2012-04-09 11:43:10 +0300366 * Update statement
367 *
368 * Generates a platform-specific update string from the supplied data
369 *
370 * @param string the table name
371 * @param array the update data
Andrey Andreev00541ae2012-04-09 11:43:10 +0300372 * @return string
373 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300374 protected function _update($table, $values)
Andrey Andreev00541ae2012-04-09 11:43:10 +0300375 {
Andrey Andreevb0478652012-07-18 15:34:46 +0300376 $this->qb_limit = FALSE;
377 $this->qb_orderby = array();
378 return parent::_update($table, $values);
Andrey Andreev00541ae2012-04-09 11:43:10 +0300379 }
380
381 // --------------------------------------------------------------------
382
383 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000384 * Truncate statement
385 *
386 * Generates a platform-specific truncate string from the supplied data
Andrey Andreev6d83cde2012-04-05 16:20:50 +0300387 *
388 * If the database does not support the truncate() command,
389 * then this method maps to 'DELETE FROM table'
Derek Allard2067d1a2008-11-13 22:59:24 +0000390 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000391 * @param string the table name
392 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200393 */
Andrey Andreev4da24f82012-01-25 21:54:23 +0200394 protected function _truncate($table)
Derek Allard2067d1a2008-11-13 22:59:24 +0000395 {
Andrey Andreev6d83cde2012-04-05 16:20:50 +0300396 return 'TRUNCATE TABLE '.$table;
Derek Allard2067d1a2008-11-13 22:59:24 +0000397 }
Barry Mienydd671972010-10-04 16:33:58 +0200398
Derek Allard2067d1a2008-11-13 22:59:24 +0000399 // --------------------------------------------------------------------
400
401 /**
402 * Delete statement
403 *
404 * Generates a platform-specific delete string from the supplied data
405 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000406 * @param string the table name
Derek Allard2067d1a2008-11-13 22:59:24 +0000407 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200408 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300409 protected function _delete($table)
Derek Allard2067d1a2008-11-13 22:59:24 +0000410 {
Andrey Andreevb0478652012-07-18 15:34:46 +0300411 if ($this->qb_limit)
412 {
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300413 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 +0300414 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000415
Andrey Andreevb0478652012-07-18 15:34:46 +0300416 return parent::_delete($table);
Derek Allard2067d1a2008-11-13 22:59:24 +0000417 }
418
419 // --------------------------------------------------------------------
420
421 /**
422 * Limit string
423 *
424 * Generates a platform-specific LIMIT clause
425 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000426 * @param string the sql query string
Derek Allard2067d1a2008-11-13 22:59:24 +0000427 * @return string
428 */
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300429 protected function _limit($sql)
Derek Allard2067d1a2008-11-13 22:59:24 +0000430 {
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300431 $limit = $this->qb_offset + $this->qb_limit;
Andrey Andreev71379ca2012-06-11 16:12:43 +0300432
433 // As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported,
434 // however an ORDER BY clause is required for it to work
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300435 if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby))
Andrey Andreev71379ca2012-06-11 16:12:43 +0300436 {
Andrey Andreev2d486232012-07-19 14:46:51 +0300437 $orderby = $this->_compile_order_by();
Andrey Andreev71379ca2012-06-11 16:12:43 +0300438
439 // We have to strip the ORDER BY clause
Andrey Andreev2d486232012-07-19 14:46:51 +0300440 $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
Andrey Andreev71379ca2012-06-11 16:12:43 +0300441
Andrey Andreev44514542012-10-23 15:35:09 +0300442 // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
443 if (count($this->qb_select) === 0)
444 {
445 $select = '*'; // Inevitable
446 }
447 else
448 {
449 // Use only field names and their aliases, everything else is out of our scope.
450 $select = array();
451 $field_regexp = ($this->_quoted_identifier)
452 ? '("[^\"]+")' : '(\[[^\]]+\])';
453 for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
454 {
455 $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
456 ? $m[1] : $this->qb_select[$i];
457 }
458 $select = implode(', ', $select);
459 }
460
461 return 'SELECT '.$select." FROM (\n\n"
Andrey Andreev2d486232012-07-19 14:46:51 +0300462 .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 +0300463 ."\n\n) ".$this->escape_identifiers('CI_subquery')
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300464 ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
Andrey Andreev71379ca2012-06-11 16:12:43 +0300465 }
466
467 return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
Derek Allard2067d1a2008-11-13 22:59:24 +0000468 }
469
470 // --------------------------------------------------------------------
471
472 /**
473 * Close DB Connection
474 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000475 * @return void
476 */
Andrey Andreev79922c02012-05-23 12:27:17 +0300477 protected function _close()
Derek Allard2067d1a2008-11-13 22:59:24 +0000478 {
Andrey Andreev79922c02012-05-23 12:27:17 +0300479 @mssql_close($this->conn_id);
Barry Mienydd671972010-10-04 16:33:58 +0200480 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000481
482}
483
Derek Allard2067d1a2008-11-13 22:59:24 +0000484/* End of file mssql_driver.php */
Andrey Andreev79922c02012-05-23 12:27:17 +0300485/* Location: ./system/database/drivers/mssql/mssql_driver.php */