odbc_driver.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  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 ExpressionEngine Dev Team
  9. * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc.
  10. * @license http://codeigniter.com/user_guide/license.html
  11. * @link http://codeigniter.com
  12. * @since Version 1.0
  13. * @filesource
  14. */
  15. // ------------------------------------------------------------------------
  16. /**
  17. * ODBC Database Adapter Class
  18. *
  19. * Note: _DB is an extender class that the app controller
  20. * creates dynamically based on whether the active record
  21. * class is being used or not.
  22. *
  23. * @package CodeIgniter
  24. * @subpackage Drivers
  25. * @category Database
  26. * @author ExpressionEngine Dev Team
  27. * @link http://codeigniter.com/user_guide/database/
  28. */
  29. class CI_DB_odbc_driver extends CI_DB {
  30. var $dbdriver = 'odbc';
  31. // the character used to excape - not necessary for ODBC
  32. var $_escape_char = '';
  33. // clause and character used for LIKE escape sequences
  34. var $_like_escape_str = " {escape '%s'} ";
  35. var $_like_escape_chr = '!';
  36. /**
  37. * The syntax to count rows is slightly different across different
  38. * database engines, so this string appears in each driver and is
  39. * used for the count_all() and count_all_results() functions.
  40. */
  41. var $_count_string = "SELECT COUNT(*) AS ";
  42. var $_random_keyword;
  43. function __construct($params)
  44. {
  45. parent::__construct($params);
  46. $this->_random_keyword = ' RND('.time().')'; // database specific random keyword
  47. }
  48. /**
  49. * Non-persistent database connection
  50. *
  51. * @access private called by the base class
  52. * @return resource
  53. */
  54. function db_connect()
  55. {
  56. return @odbc_connect($this->hostname, $this->username, $this->password);
  57. }
  58. // --------------------------------------------------------------------
  59. /**
  60. * Persistent database connection
  61. *
  62. * @access private called by the base class
  63. * @return resource
  64. */
  65. function db_pconnect()
  66. {
  67. return @odbc_pconnect($this->hostname, $this->username, $this->password);
  68. }
  69. // --------------------------------------------------------------------
  70. /**
  71. * Reconnect
  72. *
  73. * Keep / reestablish the db connection if no queries have been
  74. * sent for a length of time exceeding the server's idle timeout
  75. *
  76. * @access public
  77. * @return void
  78. */
  79. function reconnect()
  80. {
  81. // not implemented in odbc
  82. }
  83. // --------------------------------------------------------------------
  84. /**
  85. * Select the database
  86. *
  87. * @access private called by the base class
  88. * @return resource
  89. */
  90. function db_select()
  91. {
  92. // Not needed for ODBC
  93. return TRUE;
  94. }
  95. // --------------------------------------------------------------------
  96. /**
  97. * Set client character set
  98. *
  99. * @access public
  100. * @param string
  101. * @param string
  102. * @return resource
  103. */
  104. function db_set_charset($charset, $collation)
  105. {
  106. // @todo - add support if needed
  107. return TRUE;
  108. }
  109. // --------------------------------------------------------------------
  110. /**
  111. * Version number query string
  112. *
  113. * @access public
  114. * @return string
  115. */
  116. function _version()
  117. {
  118. return "SELECT version() AS ver";
  119. }
  120. // --------------------------------------------------------------------
  121. /**
  122. * Execute the query
  123. *
  124. * @access private called by the base class
  125. * @param string an SQL query
  126. * @return resource
  127. */
  128. function _execute($sql)
  129. {
  130. $sql = $this->_prep_query($sql);
  131. return @odbc_exec($this->conn_id, $sql);
  132. }
  133. // --------------------------------------------------------------------
  134. /**
  135. * Prep the query
  136. *
  137. * If needed, each database adapter can prep the query string
  138. *
  139. * @access private called by execute()
  140. * @param string an SQL query
  141. * @return string
  142. */
  143. function _prep_query($sql)
  144. {
  145. return $sql;
  146. }
  147. // --------------------------------------------------------------------
  148. /**
  149. * Begin Transaction
  150. *
  151. * @access public
  152. * @return bool
  153. */
  154. function trans_begin($test_mode = FALSE)
  155. {
  156. if ( ! $this->trans_enabled)
  157. {
  158. return TRUE;
  159. }
  160. // When transactions are nested we only begin/commit/rollback the outermost ones
  161. if ($this->_trans_depth > 0)
  162. {
  163. return TRUE;
  164. }
  165. // Reset the transaction failure flag.
  166. // If the $test_mode flag is set to TRUE transactions will be rolled back
  167. // even if the queries produce a successful result.
  168. $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
  169. return odbc_autocommit($this->conn_id, FALSE);
  170. }
  171. // --------------------------------------------------------------------
  172. /**
  173. * Commit Transaction
  174. *
  175. * @access public
  176. * @return bool
  177. */
  178. function trans_commit()
  179. {
  180. if ( ! $this->trans_enabled)
  181. {
  182. return TRUE;
  183. }
  184. // When transactions are nested we only begin/commit/rollback the outermost ones
  185. if ($this->_trans_depth > 0)
  186. {
  187. return TRUE;
  188. }
  189. $ret = odbc_commit($this->conn_id);
  190. odbc_autocommit($this->conn_id, TRUE);
  191. return $ret;
  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. $ret = odbc_rollback($this->conn_id);
  212. odbc_autocommit($this->conn_id, TRUE);
  213. return $ret;
  214. }
  215. // --------------------------------------------------------------------
  216. /**
  217. * Escape String
  218. *
  219. * @access public
  220. * @param string
  221. * @param bool whether or not the string will be used in a LIKE condition
  222. * @return string
  223. */
  224. function escape_str($str, $like = FALSE)
  225. {
  226. if (is_array($str))
  227. {
  228. foreach ($str as $key => $val)
  229. {
  230. $str[$key] = $this->escape_str($val, $like);
  231. }
  232. return $str;
  233. }
  234. // ODBC doesn't require escaping
  235. $str = remove_invisible_characters($str);
  236. // escape LIKE condition wildcards
  237. if ($like === TRUE)
  238. {
  239. $str = str_replace( 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. }
  243. return $str;
  244. }
  245. // --------------------------------------------------------------------
  246. /**
  247. * Affected Rows
  248. *
  249. * @access public
  250. * @return integer
  251. */
  252. function affected_rows()
  253. {
  254. return @odbc_num_rows($this->conn_id);
  255. }
  256. // --------------------------------------------------------------------
  257. /**
  258. * Insert ID
  259. *
  260. * @access public
  261. * @return integer
  262. */
  263. function insert_id()
  264. {
  265. return @odbc_insert_id($this->conn_id);
  266. }
  267. // --------------------------------------------------------------------
  268. /**
  269. * "Count All" query
  270. *
  271. * Generates a platform-specific query string that counts all records in
  272. * the specified database
  273. *
  274. * @access public
  275. * @param string
  276. * @return string
  277. */
  278. function count_all($table = '')
  279. {
  280. if ($table == '')
  281. {
  282. return 0;
  283. }
  284. $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
  285. if ($query->num_rows() == 0)
  286. {
  287. return 0;
  288. }
  289. $row = $query->row();
  290. $this->_reset_select();
  291. return (int) $row->numrows;
  292. }
  293. // --------------------------------------------------------------------
  294. /**
  295. * Show table query
  296. *
  297. * Generates a platform-specific query string so that the table names can be fetched
  298. *
  299. * @access private
  300. * @param boolean
  301. * @return string
  302. */
  303. function _list_tables($prefix_limit = FALSE)
  304. {
  305. $sql = "SHOW TABLES FROM `".$this->database."`";
  306. if ($prefix_limit !== FALSE AND $this->dbprefix != '')
  307. {
  308. //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
  309. return FALSE; // not currently supported
  310. }
  311. return $sql;
  312. }
  313. // --------------------------------------------------------------------
  314. /**
  315. * Show column query
  316. *
  317. * Generates a platform-specific query string so that the column names can be fetched
  318. *
  319. * @access public
  320. * @param string the table name
  321. * @return string
  322. */
  323. function _list_columns($table = '')
  324. {
  325. return "SHOW COLUMNS FROM ".$table;
  326. }
  327. // --------------------------------------------------------------------
  328. /**
  329. * Field data query
  330. *
  331. * Generates a platform-specific query so that the column data can be retrieved
  332. *
  333. * @access public
  334. * @param string the table name
  335. * @return object
  336. */
  337. function _field_data($table)
  338. {
  339. return "SELECT TOP 1 FROM ".$table;
  340. }
  341. // --------------------------------------------------------------------
  342. /**
  343. * The error message string
  344. *
  345. * @access private
  346. * @return string
  347. */
  348. function _error_message()
  349. {
  350. return odbc_errormsg($this->conn_id);
  351. }
  352. // --------------------------------------------------------------------
  353. /**
  354. * The error message number
  355. *
  356. * @access private
  357. * @return integer
  358. */
  359. function _error_number()
  360. {
  361. return odbc_error($this->conn_id);
  362. }
  363. // --------------------------------------------------------------------
  364. /**
  365. * Escape the SQL Identifiers
  366. *
  367. * This function escapes column and table names
  368. *
  369. * @access private
  370. * @param string
  371. * @return string
  372. */
  373. function _escape_identifiers($item)
  374. {
  375. if ($this->_escape_char == '')
  376. {
  377. return $item;
  378. }
  379. foreach ($this->_reserved_identifiers as $id)
  380. {
  381. if (strpos($item, '.'.$id) !== FALSE)
  382. {
  383. $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
  384. // remove duplicates if the user already included the escape
  385. return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
  386. }
  387. }
  388. if (strpos($item, '.') !== FALSE)
  389. {
  390. $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
  391. }
  392. else
  393. {
  394. $str = $this->_escape_char.$item.$this->_escape_char;
  395. }
  396. // remove duplicates if the user already included the escape
  397. return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
  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 ".$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, $orderby = array(), $limit = FALSE)
  449. {
  450. foreach ($values as $key => $val)
  451. {
  452. $valstr[] = $key." = ".$val;
  453. }
  454. $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
  455. $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
  456. $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
  457. $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
  458. $sql .= $orderby.$limit;
  459. return $sql;
  460. }
  461. // --------------------------------------------------------------------
  462. /**
  463. * Truncate statement
  464. *
  465. * Generates a platform-specific truncate string from the supplied data
  466. * If the database does not support the truncate() command
  467. * This function maps to "DELETE FROM table"
  468. *
  469. * @access public
  470. * @param string the table name
  471. * @return string
  472. */
  473. function _truncate($table)
  474. {
  475. return $this->_delete($table);
  476. }
  477. // --------------------------------------------------------------------
  478. /**
  479. * Delete statement
  480. *
  481. * Generates a platform-specific delete string from the supplied data
  482. *
  483. * @access public
  484. * @param string the table name
  485. * @param array the where clause
  486. * @param string the limit clause
  487. * @return string
  488. */
  489. function _delete($table, $where = array(), $like = array(), $limit = FALSE)
  490. {
  491. $conditions = '';
  492. if (count($where) > 0 OR count($like) > 0)
  493. {
  494. $conditions = "\nWHERE ";
  495. $conditions .= implode("\n", $this->ar_where);
  496. if (count($where) > 0 && count($like) > 0)
  497. {
  498. $conditions .= " AND ";
  499. }
  500. $conditions .= implode("\n", $like);
  501. }
  502. $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
  503. return "DELETE FROM ".$table.$conditions.$limit;
  504. }
  505. // --------------------------------------------------------------------
  506. /**
  507. * Limit string
  508. *
  509. * Generates a platform-specific LIMIT clause
  510. *
  511. * @access public
  512. * @param string the sql query string
  513. * @param integer the number of rows to limit the query to
  514. * @param integer the offset value
  515. * @return string
  516. */
  517. function _limit($sql, $limit, $offset)
  518. {
  519. // Does ODBC doesn't use the LIMIT clause?
  520. return $sql;
  521. }
  522. // --------------------------------------------------------------------
  523. /**
  524. * Close DB Connection
  525. *
  526. * @access public
  527. * @param resource
  528. * @return void
  529. */
  530. function _close($conn_id)
  531. {
  532. @odbc_close($conn_id);
  533. }
  534. }
  535. /* End of file odbc_driver.php */
  536. /* Location: ./system/database/drivers/odbc/odbc_driver.php */