postgre_driver.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  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. * Postgre 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_postgre_driver extends CI_DB {
  31. var $dbdriver = 'postgre';
  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 = ' RANDOM()'; // database specific random keyword
  43. /**
  44. * Connection String
  45. *
  46. * @access private
  47. * @return string
  48. */
  49. function _connect_string()
  50. {
  51. $components = array(
  52. 'hostname' => 'host',
  53. 'port' => 'port',
  54. 'database' => 'dbname',
  55. 'username' => 'user',
  56. 'password' => 'password'
  57. );
  58. $connect_string = "";
  59. foreach ($components as $key => $val)
  60. {
  61. if (isset($this->$key) && $this->$key != '')
  62. {
  63. $connect_string .= " $val=".$this->$key;
  64. }
  65. }
  66. return trim($connect_string);
  67. }
  68. // --------------------------------------------------------------------
  69. /**
  70. * Non-persistent database connection
  71. *
  72. * @access private called by the base class
  73. * @return resource
  74. */
  75. function db_connect()
  76. {
  77. return @pg_connect($this->_connect_string());
  78. }
  79. // --------------------------------------------------------------------
  80. /**
  81. * Persistent database connection
  82. *
  83. * @access private called by the base class
  84. * @return resource
  85. */
  86. function db_pconnect()
  87. {
  88. return @pg_pconnect($this->_connect_string());
  89. }
  90. // --------------------------------------------------------------------
  91. /**
  92. * Reconnect
  93. *
  94. * Keep / reestablish the db connection if no queries have been
  95. * sent for a length of time exceeding the server's idle timeout
  96. *
  97. * @access public
  98. * @return void
  99. */
  100. function reconnect()
  101. {
  102. if (pg_ping($this->conn_id) === FALSE)
  103. {
  104. $this->conn_id = FALSE;
  105. }
  106. }
  107. // --------------------------------------------------------------------
  108. /**
  109. * Select the database
  110. *
  111. * @access private called by the base class
  112. * @return resource
  113. */
  114. function db_select()
  115. {
  116. // Not needed for Postgre so we'll return TRUE
  117. return TRUE;
  118. }
  119. // --------------------------------------------------------------------
  120. /**
  121. * Set client character set
  122. *
  123. * @access public
  124. * @param string
  125. * @param string
  126. * @return resource
  127. */
  128. function db_set_charset($charset, $collation)
  129. {
  130. // @todo - add support if needed
  131. return TRUE;
  132. }
  133. // --------------------------------------------------------------------
  134. /**
  135. * Version number query string
  136. *
  137. * @access public
  138. * @return string
  139. */
  140. function _version()
  141. {
  142. return "SELECT version() AS ver";
  143. }
  144. // --------------------------------------------------------------------
  145. /**
  146. * Execute the query
  147. *
  148. * @access private called by the base class
  149. * @param string an SQL query
  150. * @return resource
  151. */
  152. function _execute($sql)
  153. {
  154. $sql = $this->_prep_query($sql);
  155. return @pg_query($this->conn_id, $sql);
  156. }
  157. // --------------------------------------------------------------------
  158. /**
  159. * Prep the query
  160. *
  161. * If needed, each database adapter can prep the query string
  162. *
  163. * @access private called by execute()
  164. * @param string an SQL query
  165. * @return string
  166. */
  167. function _prep_query($sql)
  168. {
  169. return $sql;
  170. }
  171. // --------------------------------------------------------------------
  172. /**
  173. * Begin Transaction
  174. *
  175. * @access public
  176. * @return bool
  177. */
  178. function trans_begin($test_mode = FALSE)
  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. // Reset the transaction failure flag.
  190. // If the $test_mode flag is set to TRUE transactions will be rolled back
  191. // even if the queries produce a successful result.
  192. $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
  193. return @pg_exec($this->conn_id, "begin");
  194. }
  195. // --------------------------------------------------------------------
  196. /**
  197. * Commit Transaction
  198. *
  199. * @access public
  200. * @return bool
  201. */
  202. function trans_commit()
  203. {
  204. if ( ! $this->trans_enabled)
  205. {
  206. return TRUE;
  207. }
  208. // When transactions are nested we only begin/commit/rollback the outermost ones
  209. if ($this->_trans_depth > 0)
  210. {
  211. return TRUE;
  212. }
  213. return @pg_exec($this->conn_id, "commit");
  214. }
  215. // --------------------------------------------------------------------
  216. /**
  217. * Rollback Transaction
  218. *
  219. * @access public
  220. * @return bool
  221. */
  222. function trans_rollback()
  223. {
  224. if ( ! $this->trans_enabled)
  225. {
  226. return TRUE;
  227. }
  228. // When transactions are nested we only begin/commit/rollback the outermost ones
  229. if ($this->_trans_depth > 0)
  230. {
  231. return TRUE;
  232. }
  233. return @pg_exec($this->conn_id, "rollback");
  234. }
  235. // --------------------------------------------------------------------
  236. /**
  237. * Escape String
  238. *
  239. * @access public
  240. * @param string
  241. * @param bool whether or not the string will be used in a LIKE condition
  242. * @return string
  243. */
  244. function escape_str($str, $like = FALSE)
  245. {
  246. if (is_array($str))
  247. {
  248. foreach ($str as $key => $val)
  249. {
  250. $str[$key] = $this->escape_str($val, $like);
  251. }
  252. return $str;
  253. }
  254. $str = pg_escape_string($str);
  255. // escape LIKE condition wildcards
  256. if ($like === TRUE)
  257. {
  258. $str = str_replace( array('%', '_', $this->_like_escape_chr),
  259. array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
  260. $str);
  261. }
  262. return $str;
  263. }
  264. // --------------------------------------------------------------------
  265. /**
  266. * Affected Rows
  267. *
  268. * @access public
  269. * @return integer
  270. */
  271. function affected_rows()
  272. {
  273. return @pg_affected_rows($this->result_id);
  274. }
  275. // --------------------------------------------------------------------
  276. /**
  277. * Insert ID
  278. *
  279. * @access public
  280. * @return integer
  281. */
  282. function insert_id()
  283. {
  284. $v = $this->_version();
  285. $v = $v['server'];
  286. $table = func_num_args() > 0 ? func_get_arg(0) : NULL;
  287. $column = func_num_args() > 1 ? func_get_arg(1) : NULL;
  288. if ($table == NULL && $v >= '8.1')
  289. {
  290. $sql='SELECT LASTVAL() as ins_id';
  291. }
  292. elseif ($table != NULL && $column != NULL && $v >= '8.0')
  293. {
  294. $sql = sprintf("SELECT pg_get_serial_sequence('%s','%s') as seq", $table, $column);
  295. $query = $this->query($sql);
  296. $row = $query->row();
  297. $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $row->seq);
  298. }
  299. elseif ($table != NULL)
  300. {
  301. // seq_name passed in table parameter
  302. $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $table);
  303. }
  304. else
  305. {
  306. return pg_last_oid($this->result_id);
  307. }
  308. $query = $this->query($sql);
  309. $row = $query->row();
  310. return $row->ins_id;
  311. }
  312. // --------------------------------------------------------------------
  313. /**
  314. * "Count All" query
  315. *
  316. * Generates a platform-specific query string that counts all records in
  317. * the specified database
  318. *
  319. * @access public
  320. * @param string
  321. * @return string
  322. */
  323. function count_all($table = '')
  324. {
  325. if ($table == '')
  326. {
  327. return 0;
  328. }
  329. $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
  330. if ($query->num_rows() == 0)
  331. {
  332. return 0;
  333. }
  334. $row = $query->row();
  335. $this->_reset_select();
  336. return (int) $row->numrows;
  337. }
  338. // --------------------------------------------------------------------
  339. /**
  340. * Show table query
  341. *
  342. * Generates a platform-specific query string so that the table names can be fetched
  343. *
  344. * @access private
  345. * @param boolean
  346. * @return string
  347. */
  348. function _list_tables($prefix_limit = FALSE)
  349. {
  350. $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'";
  351. if ($prefix_limit !== FALSE AND $this->dbprefix != '')
  352. {
  353. $sql .= " AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr);
  354. }
  355. return $sql;
  356. }
  357. // --------------------------------------------------------------------
  358. /**
  359. * Show column query
  360. *
  361. * Generates a platform-specific query string so that the column names can be fetched
  362. *
  363. * @access public
  364. * @param string the table name
  365. * @return string
  366. */
  367. function _list_columns($table = '')
  368. {
  369. return "SELECT column_name FROM information_schema.columns WHERE table_name ='".$table."'";
  370. }
  371. // --------------------------------------------------------------------
  372. /**
  373. * Field data query
  374. *
  375. * Generates a platform-specific query so that the column data can be retrieved
  376. *
  377. * @access public
  378. * @param string the table name
  379. * @return object
  380. */
  381. function _field_data($table)
  382. {
  383. return "SELECT * FROM ".$table." LIMIT 1";
  384. }
  385. // --------------------------------------------------------------------
  386. /**
  387. * The error message string
  388. *
  389. * @access private
  390. * @return string
  391. */
  392. function _error_message()
  393. {
  394. return pg_last_error($this->conn_id);
  395. }
  396. // --------------------------------------------------------------------
  397. /**
  398. * The error message number
  399. *
  400. * @access private
  401. * @return integer
  402. */
  403. function _error_number()
  404. {
  405. return '';
  406. }
  407. // --------------------------------------------------------------------
  408. /**
  409. * Escape the SQL Identifiers
  410. *
  411. * This function escapes column and table names
  412. *
  413. * @access private
  414. * @param string
  415. * @return string
  416. */
  417. function _escape_identifiers($item)
  418. {
  419. if ($this->_escape_char == '')
  420. {
  421. return $item;
  422. }
  423. foreach ($this->_reserved_identifiers as $id)
  424. {
  425. if (strpos($item, '.'.$id) !== FALSE)
  426. {
  427. $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
  428. // remove duplicates if the user already included the escape
  429. return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
  430. }
  431. }
  432. if (strpos($item, '.') !== FALSE)
  433. {
  434. $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
  435. }
  436. else
  437. {
  438. $str = $this->_escape_char.$item.$this->_escape_char;
  439. }
  440. // remove duplicates if the user already included the escape
  441. return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
  442. }
  443. // --------------------------------------------------------------------
  444. /**
  445. * From Tables
  446. *
  447. * This function implicitly groups FROM tables so there is no confusion
  448. * about operator precedence in harmony with SQL standards
  449. *
  450. * @access public
  451. * @param type
  452. * @return type
  453. */
  454. function _from_tables($tables)
  455. {
  456. if ( ! is_array($tables))
  457. {
  458. $tables = array($tables);
  459. }
  460. return implode(', ', $tables);
  461. }
  462. // --------------------------------------------------------------------
  463. /**
  464. * Insert statement
  465. *
  466. * Generates a platform-specific insert string from the supplied data
  467. *
  468. * @access public
  469. * @param string the table name
  470. * @param array the insert keys
  471. * @param array the insert values
  472. * @return string
  473. */
  474. function _insert($table, $keys, $values)
  475. {
  476. return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
  477. }
  478. // --------------------------------------------------------------------
  479. /**
  480. * Insert_batch statement
  481. *
  482. * Generates a platform-specific insert string from the supplied data
  483. *
  484. * @access public
  485. * @param string the table name
  486. * @param array the insert keys
  487. * @param array the insert values
  488. * @return string
  489. */
  490. function _insert_batch($table, $keys, $values)
  491. {
  492. return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values);
  493. }
  494. // --------------------------------------------------------------------
  495. /**
  496. * Update statement
  497. *
  498. * Generates a platform-specific update string from the supplied data
  499. *
  500. * @access public
  501. * @param string the table name
  502. * @param array the update data
  503. * @param array the where clause
  504. * @param array the orderby clause
  505. * @param array the limit clause
  506. * @return string
  507. */
  508. function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
  509. {
  510. foreach ($values as $key => $val)
  511. {
  512. $valstr[] = $key." = ".$val;
  513. }
  514. $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
  515. $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
  516. $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
  517. $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
  518. $sql .= $orderby.$limit;
  519. return $sql;
  520. }
  521. // --------------------------------------------------------------------
  522. /**
  523. * Truncate statement
  524. *
  525. * Generates a platform-specific truncate string from the supplied data
  526. * If the database does not support the truncate() command
  527. * This function maps to "DELETE FROM table"
  528. *
  529. * @access public
  530. * @param string the table name
  531. * @return string
  532. */
  533. function _truncate($table)
  534. {
  535. return "TRUNCATE ".$table;
  536. }
  537. // --------------------------------------------------------------------
  538. /**
  539. * Delete statement
  540. *
  541. * Generates a platform-specific delete string from the supplied data
  542. *
  543. * @access public
  544. * @param string the table name
  545. * @param array the where clause
  546. * @param string the limit clause
  547. * @return string
  548. */
  549. function _delete($table, $where = array(), $like = array(), $limit = FALSE)
  550. {
  551. $conditions = '';
  552. if (count($where) > 0 OR count($like) > 0)
  553. {
  554. $conditions = "\nWHERE ";
  555. $conditions .= implode("\n", $this->ar_where);
  556. if (count($where) > 0 && count($like) > 0)
  557. {
  558. $conditions .= " AND ";
  559. }
  560. $conditions .= implode("\n", $like);
  561. }
  562. $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
  563. return "DELETE FROM ".$table.$conditions.$limit;
  564. }
  565. // --------------------------------------------------------------------
  566. /**
  567. * Limit string
  568. *
  569. * Generates a platform-specific LIMIT clause
  570. *
  571. * @access public
  572. * @param string the sql query string
  573. * @param integer the number of rows to limit the query to
  574. * @param integer the offset value
  575. * @return string
  576. */
  577. function _limit($sql, $limit, $offset)
  578. {
  579. $sql .= "LIMIT ".$limit;
  580. if ($offset > 0)
  581. {
  582. $sql .= " OFFSET ".$offset;
  583. }
  584. return $sql;
  585. }
  586. // --------------------------------------------------------------------
  587. /**
  588. * Close DB Connection
  589. *
  590. * @access public
  591. * @param resource
  592. * @return void
  593. */
  594. function _close($conn_id)
  595. {
  596. @pg_close($conn_id);
  597. }
  598. }
  599. /* End of file postgre_driver.php */
  600. /* Location: ./system/database/drivers/postgre/postgre_driver.php */