sqlsrv_driver.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP 5.1.6 or newer
  6. *
  7. * @package CodeIgniter
  8. * @author EllisLab Dev Team
  9. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc.
  10. * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
  11. * @license http://codeigniter.com/user_guide/license.html
  12. * @link http://codeigniter.com
  13. * @since Version 1.0
  14. * @filesource
  15. */
  16. // ------------------------------------------------------------------------
  17. /**
  18. * SQLSRV Database Adapter Class
  19. *
  20. * Note: _DB is an extender class that the app controller
  21. * creates dynamically based on whether the active record
  22. * class is being used or not.
  23. *
  24. * @package CodeIgniter
  25. * @subpackage Drivers
  26. * @category Database
  27. * @author EllisLab Dev Team
  28. * @link http://codeigniter.com/user_guide/database/
  29. */
  30. class CI_DB_sqlsrv_driver extends CI_DB {
  31. var $dbdriver = 'sqlsrv';
  32. // The character used for escaping
  33. var $_escape_char = '';
  34. // clause and character used for LIKE escape sequences
  35. var $_like_escape_str = " ESCAPE '%s' ";
  36. var $_like_escape_chr = '!';
  37. /**
  38. * The syntax to count rows is slightly different across different
  39. * database engines, so this string appears in each driver and is
  40. * used for the count_all() and count_all_results() functions.
  41. */
  42. var $_count_string = "SELECT COUNT(*) AS ";
  43. var $_random_keyword = ' ASC'; // not currently supported
  44. /**
  45. * Non-persistent database connection
  46. *
  47. * @access private called by the base class
  48. * @return resource
  49. */
  50. function db_connect($pooling = false)
  51. {
  52. // Check for a UTF-8 charset being passed as CI's default 'utf8'.
  53. $character_set = (0 === strcasecmp('utf8', $this->char_set)) ? 'UTF-8' : $this->char_set;
  54. $connection = array(
  55. 'UID' => empty($this->username) ? '' : $this->username,
  56. 'PWD' => empty($this->password) ? '' : $this->password,
  57. 'Database' => $this->database,
  58. 'ConnectionPooling' => $pooling ? 1 : 0,
  59. 'CharacterSet' => $character_set,
  60. 'ReturnDatesAsStrings' => 1
  61. );
  62. // If the username and password are both empty, assume this is a
  63. // 'Windows Authentication Mode' connection.
  64. if(empty($connection['UID']) && empty($connection['PWD'])) {
  65. unset($connection['UID'], $connection['PWD']);
  66. }
  67. return sqlsrv_connect($this->hostname, $connection);
  68. }
  69. // --------------------------------------------------------------------
  70. /**
  71. * Persistent database connection
  72. *
  73. * @access private called by the base class
  74. * @return resource
  75. */
  76. function db_pconnect()
  77. {
  78. $this->db_connect(TRUE);
  79. }
  80. // --------------------------------------------------------------------
  81. /**
  82. * Reconnect
  83. *
  84. * Keep / reestablish the db connection if no queries have been
  85. * sent for a length of time exceeding the server's idle timeout
  86. *
  87. * @access public
  88. * @return void
  89. */
  90. function reconnect()
  91. {
  92. // not implemented in MSSQL
  93. }
  94. // --------------------------------------------------------------------
  95. /**
  96. * Select the database
  97. *
  98. * @access private called by the base class
  99. * @return resource
  100. */
  101. function db_select()
  102. {
  103. return $this->_execute('USE ' . $this->database);
  104. }
  105. // --------------------------------------------------------------------
  106. /**
  107. * Set client character set
  108. *
  109. * @access public
  110. * @param string
  111. * @param string
  112. * @return resource
  113. */
  114. function db_set_charset($charset, $collation)
  115. {
  116. // @todo - add support if needed
  117. return TRUE;
  118. }
  119. // --------------------------------------------------------------------
  120. /**
  121. * Execute the query
  122. *
  123. * @access private called by the base class
  124. * @param string an SQL query
  125. * @return resource
  126. */
  127. function _execute($sql)
  128. {
  129. $sql = $this->_prep_query($sql);
  130. return sqlsrv_query($this->conn_id, $sql, null, array(
  131. 'Scrollable' => SQLSRV_CURSOR_STATIC,
  132. 'SendStreamParamsAtExec' => true
  133. ));
  134. }
  135. // --------------------------------------------------------------------
  136. /**
  137. * Prep the query
  138. *
  139. * If needed, each database adapter can prep the query string
  140. *
  141. * @access private called by execute()
  142. * @param string an SQL query
  143. * @return string
  144. */
  145. function _prep_query($sql)
  146. {
  147. return $sql;
  148. }
  149. // --------------------------------------------------------------------
  150. /**
  151. * Begin Transaction
  152. *
  153. * @access public
  154. * @return bool
  155. */
  156. function trans_begin($test_mode = FALSE)
  157. {
  158. if ( ! $this->trans_enabled)
  159. {
  160. return TRUE;
  161. }
  162. // When transactions are nested we only begin/commit/rollback the outermost ones
  163. if ($this->_trans_depth > 0)
  164. {
  165. return TRUE;
  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.
  170. $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
  171. return sqlsrv_begin_transaction($this->conn_id);
  172. }
  173. // --------------------------------------------------------------------
  174. /**
  175. * Commit Transaction
  176. *
  177. * @access public
  178. * @return bool
  179. */
  180. function trans_commit()
  181. {
  182. if ( ! $this->trans_enabled)
  183. {
  184. return TRUE;
  185. }
  186. // When transactions are nested we only begin/commit/rollback the outermost ones
  187. if ($this->_trans_depth > 0)
  188. {
  189. return TRUE;
  190. }
  191. return sqlsrv_commit($this->conn_id);
  192. }
  193. // --------------------------------------------------------------------
  194. /**
  195. * Rollback Transaction
  196. *
  197. * @access public
  198. * @return bool
  199. */
  200. function trans_rollback()
  201. {
  202. if ( ! $this->trans_enabled)
  203. {
  204. return TRUE;
  205. }
  206. // When transactions are nested we only begin/commit/rollback the outermost ones
  207. if ($this->_trans_depth > 0)
  208. {
  209. return TRUE;
  210. }
  211. return sqlsrv_rollback($this->conn_id);
  212. }
  213. // --------------------------------------------------------------------
  214. /**
  215. * Escape String
  216. *
  217. * @access public
  218. * @param string
  219. * @param bool whether or not the string will be used in a LIKE condition
  220. * @return string
  221. */
  222. function escape_str($str, $like = FALSE)
  223. {
  224. // Escape single quotes
  225. return str_replace("'", "''", $str);
  226. }
  227. // --------------------------------------------------------------------
  228. /**
  229. * Affected Rows
  230. *
  231. * @access public
  232. * @return integer
  233. */
  234. function affected_rows()
  235. {
  236. return @sqlrv_rows_affected($this->conn_id);
  237. }
  238. // --------------------------------------------------------------------
  239. /**
  240. * Insert ID
  241. *
  242. * Returns the last id created in the Identity column.
  243. *
  244. * @access public
  245. * @return integer
  246. */
  247. function insert_id()
  248. {
  249. return $this->query('select @@IDENTITY as insert_id')->row('insert_id');
  250. }
  251. // --------------------------------------------------------------------
  252. /**
  253. * Parse major version
  254. *
  255. * Grabs the major version number from the
  256. * database server version string passed in.
  257. *
  258. * @access private
  259. * @param string $version
  260. * @return int16 major version number
  261. */
  262. function _parse_major_version($version)
  263. {
  264. preg_match('/([0-9]+)\.([0-9]+)\.([0-9]+)/', $version, $ver_info);
  265. return $ver_info[1]; // return the major version b/c that's all we're interested in.
  266. }
  267. // --------------------------------------------------------------------
  268. /**
  269. * Version number query string
  270. *
  271. * @access public
  272. * @return string
  273. */
  274. function _version()
  275. {
  276. $info = sqlsrv_server_info($this->conn_id);
  277. return sprintf("select '%s' as ver", $info['SQLServerVersion']);
  278. }
  279. // --------------------------------------------------------------------
  280. /**
  281. * "Count All" query
  282. *
  283. * Generates a platform-specific query string that counts all records in
  284. * the specified database
  285. *
  286. * @access public
  287. * @param string
  288. * @return string
  289. */
  290. function count_all($table = '')
  291. {
  292. if ($table == '')
  293. {
  294. return 0;
  295. }
  296. $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
  297. if ($query->num_rows() == 0)
  298. {
  299. return 0;
  300. }
  301. $row = $query->row();
  302. $this->_reset_select();
  303. return (int) $row->numrows;
  304. }
  305. // --------------------------------------------------------------------
  306. /**
  307. * List table query
  308. *
  309. * Generates a platform-specific query string so that the table names can be fetched
  310. *
  311. * @access private
  312. * @param boolean
  313. * @return string
  314. */
  315. function _list_tables($prefix_limit = FALSE)
  316. {
  317. return "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
  318. }
  319. // --------------------------------------------------------------------
  320. /**
  321. * List column query
  322. *
  323. * Generates a platform-specific query string so that the column names can be fetched
  324. *
  325. * @access private
  326. * @param string the table name
  327. * @return string
  328. */
  329. function _list_columns($table = '')
  330. {
  331. return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$this->_escape_table($table)."'";
  332. }
  333. // --------------------------------------------------------------------
  334. /**
  335. * Field data query
  336. *
  337. * Generates a platform-specific query so that the column data can be retrieved
  338. *
  339. * @access public
  340. * @param string the table name
  341. * @return object
  342. */
  343. function _field_data($table)
  344. {
  345. return "SELECT TOP 1 * FROM " . $this->_escape_table($table);
  346. }
  347. // --------------------------------------------------------------------
  348. /**
  349. * The error message string
  350. *
  351. * @access private
  352. * @return string
  353. */
  354. function _error_message()
  355. {
  356. $error = array_shift(sqlsrv_errors());
  357. return !empty($error['message']) ? $error['message'] : null;
  358. }
  359. // --------------------------------------------------------------------
  360. /**
  361. * The error message number
  362. *
  363. * @access private
  364. * @return integer
  365. */
  366. function _error_number()
  367. {
  368. $error = array_shift(sqlsrv_errors());
  369. return isset($error['SQLSTATE']) ? $error['SQLSTATE'] : null;
  370. }
  371. // --------------------------------------------------------------------
  372. /**
  373. * Escape Table Name
  374. *
  375. * This function adds backticks if the table name has a period
  376. * in it. Some DBs will get cranky unless periods are escaped
  377. *
  378. * @access private
  379. * @param string the table name
  380. * @return string
  381. */
  382. function _escape_table($table)
  383. {
  384. return $table;
  385. }
  386. /**
  387. * Escape the SQL Identifiers
  388. *
  389. * This function escapes column and table names
  390. *
  391. * @access private
  392. * @param string
  393. * @return string
  394. */
  395. function _escape_identifiers($item)
  396. {
  397. return $item;
  398. }
  399. // --------------------------------------------------------------------
  400. /**
  401. * From Tables
  402. *
  403. * This function implicitly groups FROM tables so there is no confusion
  404. * about operator precedence in harmony with SQL standards
  405. *
  406. * @access public
  407. * @param type
  408. * @return type
  409. */
  410. function _from_tables($tables)
  411. {
  412. if ( ! is_array($tables))
  413. {
  414. $tables = array($tables);
  415. }
  416. return implode(', ', $tables);
  417. }
  418. // --------------------------------------------------------------------
  419. /**
  420. * Insert statement
  421. *
  422. * Generates a platform-specific insert string from the supplied data
  423. *
  424. * @access public
  425. * @param string the table name
  426. * @param array the insert keys
  427. * @param array the insert values
  428. * @return string
  429. */
  430. function _insert($table, $keys, $values)
  431. {
  432. return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
  433. }
  434. // --------------------------------------------------------------------
  435. /**
  436. * Update statement
  437. *
  438. * Generates a platform-specific update string from the supplied data
  439. *
  440. * @access public
  441. * @param string the table name
  442. * @param array the update data
  443. * @param array the where clause
  444. * @param array the orderby clause
  445. * @param array the limit clause
  446. * @return string
  447. */
  448. function _update($table, $values, $where)
  449. {
  450. foreach($values as $key => $val)
  451. {
  452. $valstr[] = $key." = ".$val;
  453. }
  454. return "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr)." WHERE ".implode(" ", $where);
  455. }
  456. // --------------------------------------------------------------------
  457. /**
  458. * Truncate statement
  459. *
  460. * Generates a platform-specific truncate string from the supplied data
  461. * If the database does not support the truncate() command
  462. * This function maps to "DELETE FROM table"
  463. *
  464. * @access public
  465. * @param string the table name
  466. * @return string
  467. */
  468. function _truncate($table)
  469. {
  470. return "TRUNCATE TABLE ".$table;
  471. }
  472. // --------------------------------------------------------------------
  473. /**
  474. * Delete statement
  475. *
  476. * Generates a platform-specific delete string from the supplied data
  477. *
  478. * @access public
  479. * @param string the table name
  480. * @param array the where clause
  481. * @param string the limit clause
  482. * @return string
  483. */
  484. function _delete($table, $where)
  485. {
  486. return "DELETE FROM ".$this->_escape_table($table)." WHERE ".implode(" ", $where);
  487. }
  488. // --------------------------------------------------------------------
  489. /**
  490. * Limit string
  491. *
  492. * Generates a platform-specific LIMIT clause
  493. *
  494. * @access public
  495. * @param string the sql query string
  496. * @param integer the number of rows to limit the query to
  497. * @param integer the offset value
  498. * @return string
  499. */
  500. function _limit($sql, $limit, $offset)
  501. {
  502. $i = $limit + $offset;
  503. return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$i.' ', $sql);
  504. }
  505. // --------------------------------------------------------------------
  506. /**
  507. * Close DB Connection
  508. *
  509. * @access public
  510. * @param resource
  511. * @return void
  512. */
  513. function _close($conn_id)
  514. {
  515. @sqlsrv_close($conn_id);
  516. }
  517. }
  518. /* End of file sqlsrv_driver.php */
  519. /* Location: ./system/database/drivers/sqlsrv/sqlsrv_driver.php */