PageRenderTime 42ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/system/database/drivers/sqlsrv/sqlsrv_driver.php

https://gitlab.com/betanurlaila/UI_onlineshop
PHP | 542 lines | 222 code | 74 blank | 246 comment | 23 complexity | 69926dbbf2b55e673046a7b67be792f6 MD5 | raw file
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2016, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 2.0.3
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * SQLSRV Database Adapter Class
  41. *
  42. * Note: _DB is an extender class that the app controller
  43. * creates dynamically based on whether the query builder
  44. * class is being used or not.
  45. *
  46. * @package CodeIgniter
  47. * @subpackage Drivers
  48. * @category Database
  49. * @author EllisLab Dev Team
  50. * @link https://codeigniter.com/user_guide/database/
  51. */
  52. class CI_DB_sqlsrv_driver extends CI_DB {
  53. /**
  54. * Database driver
  55. *
  56. * @var string
  57. */
  58. public $dbdriver = 'sqlsrv';
  59. /**
  60. * Scrollable flag
  61. *
  62. * Determines what cursor type to use when executing queries.
  63. *
  64. * FALSE or SQLSRV_CURSOR_FORWARD would increase performance,
  65. * but would disable num_rows() (and possibly insert_id())
  66. *
  67. * @var mixed
  68. */
  69. public $scrollable;
  70. // --------------------------------------------------------------------
  71. /**
  72. * ORDER BY random keyword
  73. *
  74. * @var array
  75. */
  76. protected $_random_keyword = array('NEWID()', 'RAND(%d)');
  77. /**
  78. * Quoted identifier flag
  79. *
  80. * Whether to use SQL-92 standard quoted identifier
  81. * (double quotes) or brackets for identifier escaping.
  82. *
  83. * @var bool
  84. */
  85. protected $_quoted_identifier = TRUE;
  86. // --------------------------------------------------------------------
  87. /**
  88. * Class constructor
  89. *
  90. * @param array $params
  91. * @return void
  92. */
  93. public function __construct($params)
  94. {
  95. parent::__construct($params);
  96. // This is only supported as of SQLSRV 3.0
  97. if ($this->scrollable === NULL)
  98. {
  99. $this->scrollable = defined('SQLSRV_CURSOR_CLIENT_BUFFERED')
  100. ? SQLSRV_CURSOR_CLIENT_BUFFERED
  101. : FALSE;
  102. }
  103. }
  104. // --------------------------------------------------------------------
  105. /**
  106. * Database connection
  107. *
  108. * @param bool $pooling
  109. * @return resource
  110. */
  111. public function db_connect($pooling = FALSE)
  112. {
  113. $charset = in_array(strtolower($this->char_set), array('utf-8', 'utf8'), TRUE)
  114. ? 'UTF-8' : SQLSRV_ENC_CHAR;
  115. $connection = array(
  116. 'UID' => empty($this->username) ? '' : $this->username,
  117. 'PWD' => empty($this->password) ? '' : $this->password,
  118. 'Database' => $this->database,
  119. 'ConnectionPooling' => ($pooling === TRUE) ? 1 : 0,
  120. 'CharacterSet' => $charset,
  121. 'Encrypt' => ($this->encrypt === TRUE) ? 1 : 0,
  122. 'ReturnDatesAsStrings' => 1
  123. );
  124. // If the username and password are both empty, assume this is a
  125. // 'Windows Authentication Mode' connection.
  126. if (empty($connection['UID']) && empty($connection['PWD']))
  127. {
  128. unset($connection['UID'], $connection['PWD']);
  129. }
  130. if (FALSE !== ($this->conn_id = sqlsrv_connect($this->hostname, $connection)))
  131. {
  132. // Determine how identifiers are escaped
  133. $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi');
  134. $query = $query->row_array();
  135. $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi'];
  136. $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']');
  137. }
  138. return $this->conn_id;
  139. }
  140. // --------------------------------------------------------------------
  141. /**
  142. * Select the database
  143. *
  144. * @param string $database
  145. * @return bool
  146. */
  147. public function db_select($database = '')
  148. {
  149. if ($database === '')
  150. {
  151. $database = $this->database;
  152. }
  153. if ($this->_execute('USE '.$this->escape_identifiers($database)))
  154. {
  155. $this->database = $database;
  156. return TRUE;
  157. }
  158. return FALSE;
  159. }
  160. // --------------------------------------------------------------------
  161. /**
  162. * Execute the query
  163. *
  164. * @param string $sql an SQL query
  165. * @return resource
  166. */
  167. protected function _execute($sql)
  168. {
  169. return ($this->scrollable === FALSE OR $this->is_write_type($sql))
  170. ? sqlsrv_query($this->conn_id, $sql)
  171. : sqlsrv_query($this->conn_id, $sql, NULL, array('Scrollable' => $this->scrollable));
  172. }
  173. // --------------------------------------------------------------------
  174. /**
  175. * Begin Transaction
  176. *
  177. * @return bool
  178. */
  179. protected function _trans_begin()
  180. {
  181. return sqlsrv_begin_transaction($this->conn_id);
  182. }
  183. // --------------------------------------------------------------------
  184. /**
  185. * Commit Transaction
  186. *
  187. * @return bool
  188. */
  189. protected function _trans_commit()
  190. {
  191. return sqlsrv_commit($this->conn_id);
  192. }
  193. // --------------------------------------------------------------------
  194. /**
  195. * Rollback Transaction
  196. *
  197. * @return bool
  198. */
  199. protected function _trans_rollback()
  200. {
  201. return sqlsrv_rollback($this->conn_id);
  202. }
  203. // --------------------------------------------------------------------
  204. /**
  205. * Affected Rows
  206. *
  207. * @return int
  208. */
  209. public function affected_rows()
  210. {
  211. return sqlsrv_rows_affected($this->result_id);
  212. }
  213. // --------------------------------------------------------------------
  214. /**
  215. * Insert ID
  216. *
  217. * Returns the last id created in the Identity column.
  218. *
  219. * @return string
  220. */
  221. public function insert_id()
  222. {
  223. return $this->query('SELECT SCOPE_IDENTITY() AS insert_id')->row()->insert_id;
  224. }
  225. // --------------------------------------------------------------------
  226. /**
  227. * Database version number
  228. *
  229. * @return string
  230. */
  231. public function version()
  232. {
  233. if (isset($this->data_cache['version']))
  234. {
  235. return $this->data_cache['version'];
  236. }
  237. if ( ! $this->conn_id OR ($info = sqlsrv_server_info($this->conn_id)) === FALSE)
  238. {
  239. return FALSE;
  240. }
  241. return $this->data_cache['version'] = $info['SQLServerVersion'];
  242. }
  243. // --------------------------------------------------------------------
  244. /**
  245. * List table query
  246. *
  247. * Generates a platform-specific query string so that the table names can be fetched
  248. *
  249. * @param bool
  250. * @return string $prefix_limit
  251. */
  252. protected function _list_tables($prefix_limit = FALSE)
  253. {
  254. $sql = 'SELECT '.$this->escape_identifiers('name')
  255. .' FROM '.$this->escape_identifiers('sysobjects')
  256. .' WHERE '.$this->escape_identifiers('type')." = 'U'";
  257. if ($prefix_limit === TRUE && $this->dbprefix !== '')
  258. {
  259. $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' "
  260. .sprintf($this->_escape_like_str, $this->_escape_like_chr);
  261. }
  262. return $sql.' ORDER BY '.$this->escape_identifiers('name');
  263. }
  264. // --------------------------------------------------------------------
  265. /**
  266. * List column query
  267. *
  268. * Generates a platform-specific query string so that the column names can be fetched
  269. *
  270. * @param string $table
  271. * @return string
  272. */
  273. protected function _list_columns($table = '')
  274. {
  275. return 'SELECT COLUMN_NAME
  276. FROM INFORMATION_SCHEMA.Columns
  277. WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
  278. }
  279. // --------------------------------------------------------------------
  280. /**
  281. * Returns an object with field data
  282. *
  283. * @param string $table
  284. * @return array
  285. */
  286. public function field_data($table)
  287. {
  288. $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, COLUMN_DEFAULT
  289. FROM INFORMATION_SCHEMA.Columns
  290. WHERE UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
  291. if (($query = $this->query($sql)) === FALSE)
  292. {
  293. return FALSE;
  294. }
  295. $query = $query->result_object();
  296. $retval = array();
  297. for ($i = 0, $c = count($query); $i < $c; $i++)
  298. {
  299. $retval[$i] = new stdClass();
  300. $retval[$i]->name = $query[$i]->COLUMN_NAME;
  301. $retval[$i]->type = $query[$i]->DATA_TYPE;
  302. $retval[$i]->max_length = ($query[$i]->CHARACTER_MAXIMUM_LENGTH > 0) ? $query[$i]->CHARACTER_MAXIMUM_LENGTH : $query[$i]->NUMERIC_PRECISION;
  303. $retval[$i]->default = $query[$i]->COLUMN_DEFAULT;
  304. }
  305. return $retval;
  306. }
  307. // --------------------------------------------------------------------
  308. /**
  309. * Error
  310. *
  311. * Returns an array containing code and message of the last
  312. * database error that has occured.
  313. *
  314. * @return array
  315. */
  316. public function error()
  317. {
  318. $error = array('code' => '00000', 'message' => '');
  319. $sqlsrv_errors = sqlsrv_errors(SQLSRV_ERR_ERRORS);
  320. if ( ! is_array($sqlsrv_errors))
  321. {
  322. return $error;
  323. }
  324. $sqlsrv_error = array_shift($sqlsrv_errors);
  325. if (isset($sqlsrv_error['SQLSTATE']))
  326. {
  327. $error['code'] = isset($sqlsrv_error['code']) ? $sqlsrv_error['SQLSTATE'].'/'.$sqlsrv_error['code'] : $sqlsrv_error['SQLSTATE'];
  328. }
  329. elseif (isset($sqlsrv_error['code']))
  330. {
  331. $error['code'] = $sqlsrv_error['code'];
  332. }
  333. if (isset($sqlsrv_error['message']))
  334. {
  335. $error['message'] = $sqlsrv_error['message'];
  336. }
  337. return $error;
  338. }
  339. // --------------------------------------------------------------------
  340. /**
  341. * Update statement
  342. *
  343. * Generates a platform-specific update string from the supplied data
  344. *
  345. * @param string $table
  346. * @param array $values
  347. * @return string
  348. */
  349. protected function _update($table, $values)
  350. {
  351. $this->qb_limit = FALSE;
  352. $this->qb_orderby = array();
  353. return parent::_update($table, $values);
  354. }
  355. // --------------------------------------------------------------------
  356. /**
  357. * Truncate statement
  358. *
  359. * Generates a platform-specific truncate string from the supplied data
  360. *
  361. * If the database does not support the TRUNCATE statement,
  362. * then this method maps to 'DELETE FROM table'
  363. *
  364. * @param string $table
  365. * @return string
  366. */
  367. protected function _truncate($table)
  368. {
  369. return 'TRUNCATE TABLE '.$table;
  370. }
  371. // --------------------------------------------------------------------
  372. /**
  373. * Delete statement
  374. *
  375. * Generates a platform-specific delete string from the supplied data
  376. *
  377. * @param string $table
  378. * @return string
  379. */
  380. protected function _delete($table)
  381. {
  382. if ($this->qb_limit)
  383. {
  384. return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete';
  385. }
  386. return parent::_delete($table);
  387. }
  388. // --------------------------------------------------------------------
  389. /**
  390. * LIMIT
  391. *
  392. * Generates a platform-specific LIMIT clause
  393. *
  394. * @param string $sql SQL Query
  395. * @return string
  396. */
  397. protected function _limit($sql)
  398. {
  399. // As of SQL Server 2012 (11.0.*) OFFSET is supported
  400. if (version_compare($this->version(), '11', '>='))
  401. {
  402. // SQL Server OFFSET-FETCH can be used only with the ORDER BY clause
  403. empty($this->qb_orderby) && $sql .= ' ORDER BY 1';
  404. return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY';
  405. }
  406. $limit = $this->qb_offset + $this->qb_limit;
  407. // An ORDER BY clause is required for ROW_NUMBER() to work
  408. if ($this->qb_offset && ! empty($this->qb_orderby))
  409. {
  410. $orderby = $this->_compile_order_by();
  411. // We have to strip the ORDER BY clause
  412. $sql = trim(substr($sql, 0, strrpos($sql, $orderby)));
  413. // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results
  414. if (count($this->qb_select) === 0)
  415. {
  416. $select = '*'; // Inevitable
  417. }
  418. else
  419. {
  420. // Use only field names and their aliases, everything else is out of our scope.
  421. $select = array();
  422. $field_regexp = ($this->_quoted_identifier)
  423. ? '("[^\"]+")' : '(\[[^\]]+\])';
  424. for ($i = 0, $c = count($this->qb_select); $i < $c; $i++)
  425. {
  426. $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m)
  427. ? $m[1] : $this->qb_select[$i];
  428. }
  429. $select = implode(', ', $select);
  430. }
  431. return 'SELECT '.$select." FROM (\n\n"
  432. .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql)
  433. ."\n\n) ".$this->escape_identifiers('CI_subquery')
  434. ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit;
  435. }
  436. return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql);
  437. }
  438. // --------------------------------------------------------------------
  439. /**
  440. * Insert batch statement
  441. *
  442. * Generates a platform-specific insert string from the supplied data.
  443. *
  444. * @param string $table Table name
  445. * @param array $keys INSERT keys
  446. * @param array $values INSERT values
  447. * @return string|bool
  448. */
  449. protected function _insert_batch($table, $keys, $values)
  450. {
  451. // Multiple-value inserts are only supported as of SQL Server 2008
  452. if (version_compare($this->version(), '10', '>='))
  453. {
  454. return parent::_insert_batch($table, $keys, $values);
  455. }
  456. return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
  457. }
  458. // --------------------------------------------------------------------
  459. /**
  460. * Close DB Connection
  461. *
  462. * @return void
  463. */
  464. protected function _close()
  465. {
  466. sqlsrv_close($this->conn_id);
  467. }
  468. }