PageRenderTime 43ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/system/database/drivers/postgre/postgre_driver.php

https://bitbucket.org/saifshuvo/codeigniter
PHP | 636 lines | 283 code | 89 blank | 264 comment | 33 complexity | 00b31569c7f9075544a29193eb3526aa MD5 | raw file
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP 5.2.4 or newer
  6. *
  7. * NOTICE OF LICENSE
  8. *
  9. * Licensed under the Open Software License version 3.0
  10. *
  11. * 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. *
  19. * @package CodeIgniter
  20. * @author EllisLab Dev Team
  21. * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
  22. * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  23. * @link http://codeigniter.com
  24. * @since Version 1.0
  25. * @filesource
  26. */
  27. defined('BASEPATH') OR exit('No direct script access allowed');
  28. /**
  29. * Postgre Database Adapter Class
  30. *
  31. * Note: _DB is an extender class that the app controller
  32. * creates dynamically based on whether the query builder
  33. * class is being used or not.
  34. *
  35. * @package CodeIgniter
  36. * @subpackage Drivers
  37. * @category Database
  38. * @author EllisLab Dev Team
  39. * @link http://codeigniter.com/user_guide/database/
  40. */
  41. class CI_DB_postgre_driver extends CI_DB {
  42. /**
  43. * Database driver
  44. *
  45. * @var string
  46. */
  47. public $dbdriver = 'postgre';
  48. /**
  49. * Database schema
  50. *
  51. * @var string
  52. */
  53. public $schema = 'public';
  54. // --------------------------------------------------------------------
  55. /**
  56. * ORDER BY random keyword
  57. *
  58. * @var array
  59. */
  60. protected $_random_keyword = array('RANDOM()', 'RANDOM()');
  61. // --------------------------------------------------------------------
  62. /**
  63. * Class constructor
  64. *
  65. * Creates a DSN string to be used for db_connect() and db_pconnect()
  66. *
  67. * @param array $params
  68. * @return void
  69. */
  70. public function __construct($params)
  71. {
  72. parent::__construct($params);
  73. if ( ! empty($this->dsn))
  74. {
  75. return;
  76. }
  77. $this->dsn === '' OR $this->dsn = '';
  78. if (strpos($this->hostname, '/') !== FALSE)
  79. {
  80. // If UNIX sockets are used, we shouldn't set a port
  81. $this->port = '';
  82. }
  83. $this->hostname === '' OR $this->dsn = 'host='.$this->hostname.' ';
  84. if ( ! empty($this->port) && ctype_digit($this->port))
  85. {
  86. $this->dsn .= 'port='.$this->port.' ';
  87. }
  88. if ($this->username !== '')
  89. {
  90. $this->dsn .= 'user='.$this->username.' ';
  91. /* An empty password is valid!
  92. *
  93. * $db['password'] = NULL must be done in order to ignore it.
  94. */
  95. $this->password === NULL OR $this->dsn .= "password='".$this->password."' ";
  96. }
  97. $this->database === '' OR $this->dsn .= 'dbname='.$this->database.' ';
  98. /* We don't have these options as elements in our standard configuration
  99. * array, but they might be set by parse_url() if the configuration was
  100. * provided via string. Example:
  101. *
  102. * postgre://username:password@localhost:5432/database?connect_timeout=5&sslmode=1
  103. */
  104. foreach (array('connect_timeout', 'options', 'sslmode', 'service') as $key)
  105. {
  106. if (isset($this->$key) && is_string($this->key) && $this->key !== '')
  107. {
  108. $this->dsn .= $key."='".$this->key."' ";
  109. }
  110. }
  111. $this->dsn = rtrim($this->dsn);
  112. }
  113. // --------------------------------------------------------------------
  114. /**
  115. * Database connection
  116. *
  117. * @param bool $persistent
  118. * @return resource
  119. */
  120. public function db_connect($persistent = FALSE)
  121. {
  122. if ($persistent === TRUE
  123. && ($this->conn_id = @pg_pconnect($this->dsn))
  124. && pg_connection_status($this->conn_id) === PGSQL_CONNECTION_BAD
  125. && pg_ping($this->conn_id) === FALSE
  126. )
  127. {
  128. return FALSE;
  129. }
  130. else
  131. {
  132. $this->conn_id = @pg_connect($this->dsn);
  133. }
  134. if ($this->conn_id && ! empty($this->schema))
  135. {
  136. $this->simple_query('SET search_path TO '.$this->schema.',public');
  137. }
  138. return $this->conn_id;
  139. }
  140. // --------------------------------------------------------------------
  141. /**
  142. * Persistent database connection
  143. *
  144. * @return resource
  145. */
  146. public function db_pconnect()
  147. {
  148. return $this->db_connect(TRUE);
  149. }
  150. // --------------------------------------------------------------------
  151. /**
  152. * Reconnect
  153. *
  154. * Keep / reestablish the db connection if no queries have been
  155. * sent for a length of time exceeding the server's idle timeout
  156. *
  157. * @return void
  158. */
  159. public function reconnect()
  160. {
  161. if (pg_ping($this->conn_id) === FALSE)
  162. {
  163. $this->conn_id = FALSE;
  164. }
  165. }
  166. // --------------------------------------------------------------------
  167. /**
  168. * Set client character set
  169. *
  170. * @param string $charset
  171. * @return bool
  172. */
  173. protected function _db_set_charset($charset)
  174. {
  175. return (pg_set_client_encoding($this->conn_id, $charset) === 0);
  176. }
  177. // --------------------------------------------------------------------
  178. /**
  179. * Database version number
  180. *
  181. * @return string
  182. */
  183. public function version()
  184. {
  185. if (isset($this->data_cache['version']))
  186. {
  187. return $this->data_cache['version'];
  188. }
  189. elseif ( ! $this->conn_id)
  190. {
  191. $this->initialize();
  192. }
  193. if ( ! $this->conn_id OR ($pg_version = pg_version($this->conn_id)) === FALSE)
  194. {
  195. return FALSE;
  196. }
  197. /* If PHP was compiled with PostgreSQL lib versions earlier
  198. * than 7.4, pg_version() won't return the server version
  199. * and so we'll have to fall back to running a query in
  200. * order to get it.
  201. */
  202. return isset($pg_version['server'])
  203. ? $this->data_cache['version'] = $pg_version['server']
  204. : parent::version();
  205. }
  206. // --------------------------------------------------------------------
  207. /**
  208. * Execute the query
  209. *
  210. * @param string $sql an SQL query
  211. * @return resource
  212. */
  213. protected function _execute($sql)
  214. {
  215. return @pg_query($this->conn_id, $sql);
  216. }
  217. // --------------------------------------------------------------------
  218. /**
  219. * Begin Transaction
  220. *
  221. * @param bool $test_mode
  222. * @return bool
  223. */
  224. public function trans_begin($test_mode = FALSE)
  225. {
  226. // When transactions are nested we only begin/commit/rollback the outermost ones
  227. if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
  228. {
  229. return TRUE;
  230. }
  231. // Reset the transaction failure flag.
  232. // If the $test_mode flag is set to TRUE transactions will be rolled back
  233. // even if the queries produce a successful result.
  234. $this->_trans_failure = ($test_mode === TRUE);
  235. return (bool) @pg_query($this->conn_id, 'BEGIN');
  236. }
  237. // --------------------------------------------------------------------
  238. /**
  239. * Commit Transaction
  240. *
  241. * @return bool
  242. */
  243. public function trans_commit()
  244. {
  245. // When transactions are nested we only begin/commit/rollback the outermost ones
  246. if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
  247. {
  248. return TRUE;
  249. }
  250. return (bool) @pg_query($this->conn_id, 'COMMIT');
  251. }
  252. // --------------------------------------------------------------------
  253. /**
  254. * Rollback Transaction
  255. *
  256. * @return bool
  257. */
  258. public function trans_rollback()
  259. {
  260. // When transactions are nested we only begin/commit/rollback the outermost ones
  261. if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
  262. {
  263. return TRUE;
  264. }
  265. return (bool) @pg_query($this->conn_id, 'ROLLBACK');
  266. }
  267. // --------------------------------------------------------------------
  268. /**
  269. * Platform-dependant string escape
  270. *
  271. * @param string
  272. * @return string
  273. */
  274. protected function _escape_str($str)
  275. {
  276. return pg_escape_string($str);
  277. }
  278. // --------------------------------------------------------------------
  279. /**
  280. * "Smart" Escape String
  281. *
  282. * Escapes data based on type
  283. *
  284. * @param string $str
  285. * @return mixed
  286. */
  287. public function escape($str)
  288. {
  289. if (is_bool($str))
  290. {
  291. return ($str) ? 'TRUE' : 'FALSE';
  292. }
  293. return parent::escape($str);
  294. }
  295. // --------------------------------------------------------------------
  296. /**
  297. * Affected Rows
  298. *
  299. * @return int
  300. */
  301. public function affected_rows()
  302. {
  303. return @pg_affected_rows($this->result_id);
  304. }
  305. // --------------------------------------------------------------------
  306. /**
  307. * Insert ID
  308. *
  309. * @return string
  310. */
  311. public function insert_id()
  312. {
  313. $v = pg_version($this->conn_id);
  314. $v = isset($v['server']) ? $v['server'] : 0; // 'server' key is only available since PosgreSQL 7.4
  315. $table = (func_num_args() > 0) ? func_get_arg(0) : NULL;
  316. $column = (func_num_args() > 1) ? func_get_arg(1) : NULL;
  317. if ($table === NULL && $v >= '8.1')
  318. {
  319. $sql = 'SELECT LASTVAL() AS ins_id';
  320. }
  321. elseif ($table !== NULL)
  322. {
  323. if ($column !== NULL && $v >= '8.0')
  324. {
  325. $sql = 'SELECT pg_get_serial_sequence(\''.$table."', '".$column."') AS seq";
  326. $query = $this->query($sql);
  327. $query = $query->row();
  328. $seq = $query->seq;
  329. }
  330. else
  331. {
  332. // seq_name passed in table parameter
  333. $seq = $table;
  334. }
  335. $sql = 'SELECT CURRVAL(\''.$seq."') AS ins_id";
  336. }
  337. else
  338. {
  339. return pg_last_oid($this->result_id);
  340. }
  341. $query = $this->query($sql);
  342. $query = $query->row();
  343. return (int) $query->ins_id;
  344. }
  345. // --------------------------------------------------------------------
  346. /**
  347. * Show table query
  348. *
  349. * Generates a platform-specific query string so that the table names can be fetched
  350. *
  351. * @param bool $prefix_limit
  352. * @return string
  353. */
  354. protected function _list_tables($prefix_limit = FALSE)
  355. {
  356. $sql = 'SELECT "table_name" FROM "information_schema"."tables" WHERE "table_schema" = \''.$this->schema."'";
  357. if ($prefix_limit !== FALSE && $this->dbprefix !== '')
  358. {
  359. return $sql.' AND "table_name" LIKE \''
  360. .$this->escape_like_str($this->dbprefix)."%' "
  361. .sprintf($this->_like_escape_str, $this->_like_escape_chr);
  362. }
  363. return $sql;
  364. }
  365. // --------------------------------------------------------------------
  366. /**
  367. * List column query
  368. *
  369. * Generates a platform-specific query string so that the column names can be fetched
  370. *
  371. * @param string $table
  372. * @return string
  373. */
  374. protected function _list_columns($table = '')
  375. {
  376. return 'SELECT "column_name"
  377. FROM "information_schema"."columns"
  378. WHERE LOWER("table_name") = '.$this->escape(strtolower($table));
  379. }
  380. // --------------------------------------------------------------------
  381. /**
  382. * Returns an object with field data
  383. *
  384. * @param string $table
  385. * @return array
  386. */
  387. public function field_data($table = '')
  388. {
  389. if ($table === '')
  390. {
  391. return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE;
  392. }
  393. $sql = 'SELECT "column_name", "data_type", "character_maximum_length", "numeric_precision", "column_default"
  394. FROM "information_schema"."columns"
  395. WHERE LOWER("table_name") = '.$this->escape(strtolower($table));
  396. if (($query = $this->query($sql)) === FALSE)
  397. {
  398. return FALSE;
  399. }
  400. $query = $query->result_object();
  401. $retval = array();
  402. for ($i = 0, $c = count($query); $i < $c; $i++)
  403. {
  404. $retval[$i] = new stdClass();
  405. $retval[$i]->name = $query[$i]->column_name;
  406. $retval[$i]->type = $query[$i]->data_type;
  407. $retval[$i]->max_length = ($query[$i]->character_maximum_length > 0) ? $query[$i]->character_maximum_length : $query[$i]->numeric_precision;
  408. $retval[$i]->default = $query[$i]->column_default;
  409. }
  410. return $retval;
  411. }
  412. // --------------------------------------------------------------------
  413. /**
  414. * Error
  415. *
  416. * Returns an array containing code and message of the last
  417. * database error that has occured.
  418. *
  419. * @return array
  420. */
  421. public function error()
  422. {
  423. return array('code' => '', 'message' => pg_last_error($this->conn_id));
  424. }
  425. // --------------------------------------------------------------------
  426. /**
  427. * ORDER BY
  428. *
  429. * @param string $orderby
  430. * @param string $direction ASC or DESC
  431. * @param bool $escape
  432. * @return object
  433. */
  434. public function order_by($orderby, $direction = '', $escape = NULL)
  435. {
  436. $direction = strtoupper(trim($direction));
  437. if ($direction === 'RANDOM')
  438. {
  439. if ( ! is_float($orderby) && ctype_digit((string) $orderby))
  440. {
  441. $orderby = ($orderby > 1)
  442. ? (float) '0.'.$orderby
  443. : (float) $orderby;
  444. }
  445. if (is_float($orderby))
  446. {
  447. $this->simple_query('SET SEED '.$orderby);
  448. }
  449. $orderby = $this->_random_keyword[0];
  450. $direction = '';
  451. $escape = FALSE;
  452. }
  453. return parent::order_by($orderby, $direction, $escape);
  454. }
  455. // --------------------------------------------------------------------
  456. /**
  457. * Update statement
  458. *
  459. * Generates a platform-specific update string from the supplied data
  460. *
  461. * @param string $table
  462. * @param array $values
  463. * @return string
  464. */
  465. protected function _update($table, $values)
  466. {
  467. $this->qb_limit = FALSE;
  468. $this->qb_orderby = array();
  469. return parent::_update($table, $values);
  470. }
  471. // --------------------------------------------------------------------
  472. /**
  473. * Update_Batch statement
  474. *
  475. * Generates a platform-specific batch update string from the supplied data
  476. *
  477. * @param string $table Table name
  478. * @param array $values Update data
  479. * @param string $index WHERE key
  480. * @return string
  481. */
  482. protected function _update_batch($table, $values, $index)
  483. {
  484. $ids = array();
  485. foreach ($values as $key => $val)
  486. {
  487. $ids[] = $val[$index];
  488. foreach (array_keys($val) as $field)
  489. {
  490. if ($field !== $index)
  491. {
  492. $final[$field][] = 'WHEN '.$val[$index].' THEN '.$val[$field];
  493. }
  494. }
  495. }
  496. $cases = '';
  497. foreach ($final as $k => $v)
  498. {
  499. $cases .= $k.' = (CASE '.$index."\n"
  500. .implode("\n", $v)."\n"
  501. .'ELSE '.$k.' END), ';
  502. }
  503. $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE);
  504. return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where');
  505. }
  506. // --------------------------------------------------------------------
  507. /**
  508. * Delete statement
  509. *
  510. * Generates a platform-specific delete string from the supplied data
  511. *
  512. * @param string $table
  513. * @return string
  514. */
  515. protected function _delete($table)
  516. {
  517. $this->qb_limit = FALSE;
  518. return parent::_delete($table);
  519. }
  520. // --------------------------------------------------------------------
  521. /**
  522. * LIMIT
  523. *
  524. * Generates a platform-specific LIMIT clause
  525. *
  526. * @param string $sql SQL Query
  527. * @return string
  528. */
  529. protected function _limit($sql)
  530. {
  531. return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : '');
  532. }
  533. // --------------------------------------------------------------------
  534. /**
  535. * Close DB Connection
  536. *
  537. * @return void
  538. */
  539. protected function _close()
  540. {
  541. @pg_close($this->conn_id);
  542. }
  543. }
  544. /* End of file postgre_driver.php */
  545. /* Location: ./system/database/drivers/postgre/postgre_driver.php */