blob: 32f1a59d6f7c9ef908670d9592926deb3ac4f6a9 [file] [log] [blame]
Andrey Andreev0e8968a2012-01-26 02:04:37 +02001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Alex Bilbie84445d02011-03-10 16:43:39 +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
Alex Bilbie84445d02011-03-10 16:43:39 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
Andrey Andreev0e8968a2012-01-26 02:04:37 +02008 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05009 * Licensed under the Open Software License version 3.0
Andrey Andreev0e8968a2012-01-26 02:04:37 +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 *
Alex Bilbie84445d02011-03-10 16:43:39 +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)
Alex Bilbie84445d02011-03-10 16:43:39 +000023 * @link http://codeigniter.com
Andrey Andreevbf940582012-06-10 07:05:05 +030024 * @since Version 2.0.3
Alex Bilbie84445d02011-03-10 16:43:39 +000025 * @filesource
26 */
27
Alex Bilbie84445d02011-03-10 16:43:39 +000028/**
Alex Bilbie01ab0042011-03-18 19:24:30 +000029 * SQLSRV Database Adapter Class
Alex Bilbie84445d02011-03-10 16:43:39 +000030 *
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
Alex Bilbie84445d02011-03-10 16:43:39 +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
Alex Bilbie84445d02011-03-10 16:43:39 +000039 * @link http://codeigniter.com/user_guide/database/
40 */
Alex Bilbie01ab0042011-03-18 19:24:30 +000041class CI_DB_sqlsrv_driver extends CI_DB {
Alex Bilbie84445d02011-03-10 16:43:39 +000042
Andrey Andreev0e8968a2012-01-26 02:04:37 +020043 public $dbdriver = 'sqlsrv';
Alex Bilbie84445d02011-03-10 16:43:39 +000044
45 // The character used for escaping
Andrey Andreev082ee2b2012-06-08 15:26:34 +030046 protected $_escape_char = '"';
Alex Bilbie84445d02011-03-10 16:43:39 +000047
Andrey Andreev0e8968a2012-01-26 02:04:37 +020048 protected $_random_keyword = ' NEWID()';
Alex Bilbie84445d02011-03-10 16:43:39 +000049
Andrey Andreev082ee2b2012-06-08 15:26:34 +030050 // SQLSRV-specific properties
51 protected $_quoted_identifier = TRUE;
52
Alex Bilbie84445d02011-03-10 16:43:39 +000053 /**
54 * Non-persistent database connection
55 *
Andrey Andreev5fd3ae82012-10-24 14:55:35 +030056 * @param bool $pooling = FALSE
Alex Bilbie84445d02011-03-10 16:43:39 +000057 * @return resource
58 */
Andrey Andreeve6297342012-03-20 16:25:07 +020059 public function db_connect($pooling = FALSE)
Alex Bilbie84445d02011-03-10 16:43:39 +000060 {
Andrey Andreev2f8bf9b2012-10-12 20:37:52 +030061 $charset = in_array(strtolower($this->char_set), array('utf-8', 'utf8'), TRUE)
62 ? 'UTF-8' : SQLSRV_ENC_CHAR;
Alex Bilbie3a43c7a2011-03-18 19:48:04 +000063
64 $connection = array(
Andrey Andreev0e8968a2012-01-26 02:04:37 +020065 'UID' => empty($this->username) ? '' : $this->username,
66 'PWD' => empty($this->password) ? '' : $this->password,
67 'Database' => $this->database,
Andrey Andreev2f8bf9b2012-10-12 20:37:52 +030068 'ConnectionPooling' => ($pooling === TRUE) ? 1 : 0,
69 'CharacterSet' => $charset,
70 'Encrypt' => ($this->encrypt === TRUE) ? 1 : 0,
Andrey Andreev0e8968a2012-01-26 02:04:37 +020071 'ReturnDatesAsStrings' => 1
Alex Bilbie3a43c7a2011-03-18 19:48:04 +000072 );
Andrey Andreev0e8968a2012-01-26 02:04:37 +020073
74 // If the username and password are both empty, assume this is a
Alex Bilbie3a43c7a2011-03-18 19:48:04 +000075 // 'Windows Authentication Mode' connection.
Andrey Andreev0e8968a2012-01-26 02:04:37 +020076 if (empty($connection['UID']) && empty($connection['PWD']))
77 {
Alex Bilbie3a43c7a2011-03-18 19:48:04 +000078 unset($connection['UID'], $connection['PWD']);
Alex Bilbie84445d02011-03-10 16:43:39 +000079 }
80
Andrey Andreevfac37612012-07-02 14:56:20 +030081 $this->conn_id = sqlsrv_connect($this->hostname, $connection);
Andrey Andreev082ee2b2012-06-08 15:26:34 +030082
83 // Determine how identifiers are escaped
84 $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
85 $query = $query->row_array();
Andrey Andreev70c72c92012-06-25 00:04:51 +030086 $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi'];
Andrey Andreev082ee2b2012-06-08 15:26:34 +030087 $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
88
Andrey Andreevfac37612012-07-02 14:56:20 +030089 return $this->conn_id;
Alex Bilbie84445d02011-03-10 16:43:39 +000090 }
91
92 // --------------------------------------------------------------------
93
94 /**
95 * Persistent database connection
96 *
Alex Bilbie84445d02011-03-10 16:43:39 +000097 * @return resource
98 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +020099 public function db_pconnect()
Alex Bilbie84445d02011-03-10 16:43:39 +0000100 {
Kyle Farris37e351f2011-09-07 11:14:46 -0300101 return $this->db_connect(TRUE);
Alex Bilbie84445d02011-03-10 16:43:39 +0000102 }
103
104 // --------------------------------------------------------------------
105
106 /**
Alex Bilbie84445d02011-03-10 16:43:39 +0000107 * Select the database
108 *
Andrey Andreev11454e02012-02-22 16:05:47 +0200109 * @param string database name
110 * @return bool
Alex Bilbie84445d02011-03-10 16:43:39 +0000111 */
Andrey Andreev11454e02012-02-22 16:05:47 +0200112 public function db_select($database = '')
Alex Bilbie84445d02011-03-10 16:43:39 +0000113 {
Andrey Andreev024ba2d2012-02-24 11:40:36 +0200114 if ($database === '')
115 {
116 $database = $this->database;
117 }
118
119 if ($this->_execute('USE '.$database))
120 {
121 $this->database = $database;
122 return TRUE;
123 }
124
125 return FALSE;
Alex Bilbie84445d02011-03-10 16:43:39 +0000126 }
127
128 // --------------------------------------------------------------------
129
130 /**
Alex Bilbie84445d02011-03-10 16:43:39 +0000131 * Execute the query
132 *
Alex Bilbie84445d02011-03-10 16:43:39 +0000133 * @param string an SQL query
134 * @return resource
135 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200136 protected function _execute($sql)
Alex Bilbie84445d02011-03-10 16:43:39 +0000137 {
Andrey Andreevb2f60332012-07-03 14:45:00 +0300138 return ($this->is_write_type($sql) && stripos($sql, 'INSERT') === FALSE)
Andrey Andreev846acc72012-05-24 23:27:46 +0300139 ? sqlsrv_query($this->conn_id, $sql)
140 : sqlsrv_query($this->conn_id, $sql, NULL, array('Scrollable' => SQLSRV_CURSOR_STATIC));
Alex Bilbie84445d02011-03-10 16:43:39 +0000141 }
142
143 // --------------------------------------------------------------------
144
145 /**
146 * Begin Transaction
147 *
Andrey Andreev5fd3ae82012-10-24 14:55:35 +0300148 * @param bool $test_mode = FALSE
Alex Bilbie84445d02011-03-10 16:43:39 +0000149 * @return bool
150 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200151 public function trans_begin($test_mode = FALSE)
Alex Bilbie84445d02011-03-10 16:43:39 +0000152 {
Alex Bilbie84445d02011-03-10 16:43:39 +0000153 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200154 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Alex Bilbie84445d02011-03-10 16:43:39 +0000155 {
156 return TRUE;
157 }
158
159 // Reset the transaction failure flag.
160 // If the $test_mode flag is set to TRUE transactions will be rolled back
161 // even if the queries produce a successful result.
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200162 $this->_trans_failure = ($test_mode === TRUE);
Alex Bilbie84445d02011-03-10 16:43:39 +0000163
Alex Bilbie3a43c7a2011-03-18 19:48:04 +0000164 return sqlsrv_begin_transaction($this->conn_id);
Alex Bilbie84445d02011-03-10 16:43:39 +0000165 }
166
167 // --------------------------------------------------------------------
168
169 /**
170 * Commit Transaction
171 *
Alex Bilbie84445d02011-03-10 16:43:39 +0000172 * @return bool
173 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200174 public function trans_commit()
Alex Bilbie84445d02011-03-10 16:43:39 +0000175 {
Alex Bilbie84445d02011-03-10 16:43:39 +0000176 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200177 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Alex Bilbie84445d02011-03-10 16:43:39 +0000178 {
179 return TRUE;
180 }
181
Alex Bilbie3a43c7a2011-03-18 19:48:04 +0000182 return sqlsrv_commit($this->conn_id);
Alex Bilbie84445d02011-03-10 16:43:39 +0000183 }
184
185 // --------------------------------------------------------------------
186
187 /**
188 * Rollback Transaction
189 *
Alex Bilbie84445d02011-03-10 16:43:39 +0000190 * @return bool
191 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200192 public function trans_rollback()
Alex Bilbie84445d02011-03-10 16:43:39 +0000193 {
Alex Bilbie84445d02011-03-10 16:43:39 +0000194 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200195 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Alex Bilbie84445d02011-03-10 16:43:39 +0000196 {
197 return TRUE;
198 }
199
Alex Bilbie3a43c7a2011-03-18 19:48:04 +0000200 return sqlsrv_rollback($this->conn_id);
Alex Bilbie84445d02011-03-10 16:43:39 +0000201 }
202
203 // --------------------------------------------------------------------
204
205 /**
206 * Escape String
207 *
Alex Bilbie84445d02011-03-10 16:43:39 +0000208 * @param string
209 * @param bool whether or not the string will be used in a LIKE condition
210 * @return string
211 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200212 public function escape_str($str, $like = FALSE)
Alex Bilbie84445d02011-03-10 16:43:39 +0000213 {
Alex Bilbie84445d02011-03-10 16:43:39 +0000214 // Escape single quotes
Alex Bilbie3a43c7a2011-03-18 19:48:04 +0000215 return str_replace("'", "''", $str);
Alex Bilbie84445d02011-03-10 16:43:39 +0000216 }
217
218 // --------------------------------------------------------------------
219
220 /**
221 * Affected Rows
222 *
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200223 * @return int
Alex Bilbie84445d02011-03-10 16:43:39 +0000224 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200225 public function affected_rows()
Alex Bilbie84445d02011-03-10 16:43:39 +0000226 {
Andrey Andreevede49ba2012-07-23 16:06:36 +0300227 return sqlsrv_rows_affected($this->result_id);
Alex Bilbie84445d02011-03-10 16:43:39 +0000228 }
229
230 // --------------------------------------------------------------------
231
232 /**
Andrey Andreeve6297342012-03-20 16:25:07 +0200233 * Insert ID
234 *
235 * Returns the last id created in the Identity column.
236 *
237 * @return string
238 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200239 public function insert_id()
Alex Bilbie84445d02011-03-10 16:43:39 +0000240 {
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200241 $query = $this->query('SELECT @@IDENTITY AS insert_id');
242 $query = $query->row();
243 return $query->insert_id;
Alex Bilbie84445d02011-03-10 16:43:39 +0000244 }
245
246 // --------------------------------------------------------------------
247
248 /**
Andrey Andreev08856b82012-03-03 03:19:28 +0200249 * Database version number
250 *
251 * @return string
252 */
253 public function version()
Alex Bilbie84445d02011-03-10 16:43:39 +0000254 {
Andrey Andreev08856b82012-03-03 03:19:28 +0200255 if (isset($this->data_cache['version']))
256 {
257 return $this->data_cache['version'];
258 }
259
260 if (($info = sqlsrv_server_info($this->conn_id)) === FALSE)
261 {
262 return FALSE;
263 }
264
265 return $this->data_cache['version'] = $info['SQLServerVersion'];
Alex Bilbie84445d02011-03-10 16:43:39 +0000266 }
267
268 // --------------------------------------------------------------------
269
270 /**
Alex Bilbie84445d02011-03-10 16:43:39 +0000271 * List table query
272 *
273 * Generates a platform-specific query string so that the table names can be fetched
274 *
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200275 * @param bool
Alex Bilbie84445d02011-03-10 16:43:39 +0000276 * @return string
277 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200278 protected function _list_tables($prefix_limit = FALSE)
Alex Bilbie84445d02011-03-10 16:43:39 +0000279 {
Andrey Andreev70c72c92012-06-25 00:04:51 +0300280 $sql = 'SELECT '.$this->escape_identifiers('name')
281 .' FROM '.$this->escape_identifiers('sysobjects')
282 .' WHERE '.$this->escape_identifiers('type')." = 'U'";
283
284 if ($prefix_limit === TRUE && $this->dbprefix !== '')
285 {
286 $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' "
287 .sprintf($this->_escape_like_str, $this->_escape_like_chr);
288 }
289
290 return $sql.' ORDER BY '.$this->escape_identifiers('name');
Alex Bilbie84445d02011-03-10 16:43:39 +0000291 }
292
293 // --------------------------------------------------------------------
294
295 /**
296 * List column query
297 *
298 * Generates a platform-specific query string so that the column names can be fetched
299 *
Alex Bilbie84445d02011-03-10 16:43:39 +0000300 * @param string the table name
301 * @return string
302 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200303 protected function _list_columns($table = '')
Alex Bilbie84445d02011-03-10 16:43:39 +0000304 {
Andrey Andreeve6297342012-03-20 16:25:07 +0200305 return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$table."'";
Alex Bilbie84445d02011-03-10 16:43:39 +0000306 }
307
308 // --------------------------------------------------------------------
309
310 /**
311 * Field data query
312 *
313 * Generates a platform-specific query so that the column data can be retrieved
314 *
Alex Bilbie84445d02011-03-10 16:43:39 +0000315 * @param string the table name
Andrey Andreeve6297342012-03-20 16:25:07 +0200316 * @return string
Alex Bilbie84445d02011-03-10 16:43:39 +0000317 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200318 protected function _field_data($table)
Alex Bilbie84445d02011-03-10 16:43:39 +0000319 {
Andrey Andreev70c72c92012-06-25 00:04:51 +0300320 return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table);
Alex Bilbie84445d02011-03-10 16:43:39 +0000321 }
322
323 // --------------------------------------------------------------------
324
325 /**
Andrey Andreev4be5de12012-03-02 15:45:41 +0200326 * Error
Alex Bilbie84445d02011-03-10 16:43:39 +0000327 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200328 * Returns an array containing code and message of the last
329 * database error that has occured.
Alex Bilbie84445d02011-03-10 16:43:39 +0000330 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200331 * @return array
Alex Bilbie84445d02011-03-10 16:43:39 +0000332 */
Andrey Andreev4be5de12012-03-02 15:45:41 +0200333 public function error()
Alex Bilbie84445d02011-03-10 16:43:39 +0000334 {
Andrey Andreev4be5de12012-03-02 15:45:41 +0200335 $error = array('code' => '00000', 'message' => '');
336 $sqlsrv_errors = sqlsrv_errors(SQLSRV_ERR_ERRORS);
337
338 if ( ! is_array($sqlsrv_errors))
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200339 {
Andrey Andreev4be5de12012-03-02 15:45:41 +0200340 return $error;
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200341 }
342
Andrey Andreev4be5de12012-03-02 15:45:41 +0200343 $sqlsrv_error = array_shift($sqlsrv_errors);
344 if (isset($sqlsrv_error['SQLSTATE']))
345 {
346 $error['code'] = isset($sqlsrv_error['code']) ? $sqlsrv_error['SQLSTATE'].'/'.$sqlsrv_error['code'] : $sqlsrv_error['SQLSTATE'];
347 }
348 elseif (isset($sqlsrv_error['code']))
349 {
350 $error['code'] = $sqlsrv_error['code'];
351 }
352
353 if (isset($sqlsrv_error['message']))
354 {
355 $error['message'] = $sqlsrv_error['message'];
356 }
357
358 return $error;
Alex Bilbie84445d02011-03-10 16:43:39 +0000359 }
360
361 // --------------------------------------------------------------------
362
363 /**
Alex Bilbie84445d02011-03-10 16:43:39 +0000364 * Update statement
365 *
366 * Generates a platform-specific update string from the supplied data
367 *
Alex Bilbie84445d02011-03-10 16:43:39 +0000368 * @param string the table name
369 * @param array the update data
Alex Bilbie84445d02011-03-10 16:43:39 +0000370 * @return string
371 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300372 protected function _update($table, $values)
Alex Bilbie84445d02011-03-10 16:43:39 +0000373 {
Andrey Andreevb0478652012-07-18 15:34:46 +0300374 $this->qb_limit = FALSE;
375 $this->qb_orderby = array();
376 return parent::_update($table, $values);
Alex Bilbie84445d02011-03-10 16:43:39 +0000377 }
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200378
Alex Bilbie84445d02011-03-10 16:43:39 +0000379 // --------------------------------------------------------------------
380
381 /**
382 * Truncate statement
383 *
384 * Generates a platform-specific truncate string from the supplied data
Andrey Andreev6d83cde2012-04-05 16:20:50 +0300385 *
386 * If the database does not support the truncate() command,
387 * then this method maps to 'DELETE FROM table'
Alex Bilbie84445d02011-03-10 16:43:39 +0000388 *
Alex Bilbie84445d02011-03-10 16:43:39 +0000389 * @param string the table name
390 * @return string
391 */
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200392 protected function _truncate($table)
Alex Bilbie84445d02011-03-10 16:43:39 +0000393 {
Andrey Andreev6d83cde2012-04-05 16:20:50 +0300394 return 'TRUNCATE TABLE '.$table;
Alex Bilbie84445d02011-03-10 16:43:39 +0000395 }
396
397 // --------------------------------------------------------------------
398
399 /**
400 * Delete statement
401 *
402 * Generates a platform-specific delete string from the supplied data
403 *
Alex Bilbie84445d02011-03-10 16:43:39 +0000404 * @param string the table name
Alex Bilbie84445d02011-03-10 16:43:39 +0000405 * @return string
406 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300407 protected function _delete($table)
Alex Bilbie84445d02011-03-10 16:43:39 +0000408 {
Andrey Andreevb0478652012-07-18 15:34:46 +0300409 if ($this->qb_limit)
410 {
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300411 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 +0300412 }
Andrey Andreev5c0e9fe2012-04-09 12:28:11 +0300413
Andrey Andreevb0478652012-07-18 15:34:46 +0300414 return parent::_delete($table);
Alex Bilbie84445d02011-03-10 16:43:39 +0000415 }
416
417 // --------------------------------------------------------------------
418
419 /**
420 * Limit string
421 *
422 * Generates a platform-specific LIMIT clause
423 *
Alex Bilbie84445d02011-03-10 16:43:39 +0000424 * @param string the sql query string
Alex Bilbie84445d02011-03-10 16:43:39 +0000425 * @return string
426 */
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300427 protected function _limit($sql)
Alex Bilbie84445d02011-03-10 16:43:39 +0000428 {
Andrey Andreevd25c5892012-06-08 16:23:01 +0300429 // As of SQL Server 2012 (11.0.*) OFFSET is supported
Andrey Andreev71379ca2012-06-11 16:12:43 +0300430 if (version_compare($this->version(), '11', '>='))
431 {
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300432 return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY';
Andrey Andreev71379ca2012-06-11 16:12:43 +0300433 }
434
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300435 $limit = $this->qb_offset + $this->qb_limit;
Andrey Andreev71379ca2012-06-11 16:12:43 +0300436
437 // An ORDER BY clause is required for ROW_NUMBER() to work
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300438 if ($this->qb_offset && ! empty($this->qb_orderby))
Andrey Andreev71379ca2012-06-11 16:12:43 +0300439 {
Andrey Andreev2d486232012-07-19 14:46:51 +0300440 $orderby = $this->_compile_order_by();
Andrey Andreev71379ca2012-06-11 16:12:43 +0300441
442 // We have to strip the ORDER BY clause
Andrey Andreev2d486232012-07-19 14:46:51 +0300443 $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
Andrey Andreev71379ca2012-06-11 16:12:43 +0300444
Andrey Andreev44514542012-10-23 15:35:09 +0300445 // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
446 if (count($this->qb_select) === 0)
447 {
448 $select = '*'; // Inevitable
449 }
450 else
451 {
452 // Use only field names and their aliases, everything else is out of our scope.
453 $select = array();
454 $field_regexp = ($this->_quoted_identifier)
455 ? '("[^\"]+")' : '(\[[^\]]+\])';
456 for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
457 {
458 $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
459 ? $m[1] : $this->qb_select[$i];
460 }
461 $select = implode(', ', $select);
462 }
463
464 return 'SELECT '.$select." FROM (\n\n"
Andrey Andreev2d486232012-07-19 14:46:51 +0300465 .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 +0300466 ."\n\n) ".$this->escape_identifiers('CI_subquery')
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300467 ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
Andrey Andreev71379ca2012-06-11 16:12:43 +0300468 }
469
470 return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
Alex Bilbie84445d02011-03-10 16:43:39 +0000471 }
472
473 // --------------------------------------------------------------------
474
475 /**
476 * Close DB Connection
477 *
Alex Bilbie84445d02011-03-10 16:43:39 +0000478 * @return void
479 */
Andrey Andreev79922c02012-05-23 12:27:17 +0300480 protected function _close()
Alex Bilbie84445d02011-03-10 16:43:39 +0000481 {
Andrey Andreev79922c02012-05-23 12:27:17 +0300482 @sqlsrv_close($this->conn_id);
Alex Bilbie84445d02011-03-10 16:43:39 +0000483 }
484
485}
486
Andrey Andreev0e8968a2012-01-26 02:04:37 +0200487/* End of file sqlsrv_driver.php */
Andrey Andreev79922c02012-05-23 12:27:17 +0300488/* Location: ./system/database/drivers/sqlsrv/sqlsrv_driver.php */