/core/src/main/php/rdbms/pgsql/PostgreSQLConnection.class.php

https://github.com/treuter/xp-framework · PHP · 216 lines · 111 code · 24 blank · 81 comment · 24 complexity · d7f4c34f2903dc90c40c0c73602f40f4 MD5 · raw file

  1. <?php
  2. /* This class is part of the XP framework
  3. *
  4. * $Id$
  5. */
  6. uses(
  7. 'rdbms.DBConnection',
  8. 'rdbms.Transaction',
  9. 'rdbms.StatementFormatter',
  10. 'rdbms.pgsql.PostgreSQLResultSet',
  11. 'rdbms.pgsql.PostgreSQLDialect'
  12. );
  13. /**
  14. * Connection to PostgreSQL Databases
  15. *
  16. * @see http://www.postgresql.org/
  17. * @see http://www.freebsddiary.org/postgresql.php
  18. * @ext pgsql
  19. * @purpose Database connection
  20. */
  21. class PostgreSQLConnection extends DBConnection {
  22. protected
  23. $result = NULL;
  24. static function __static() {
  25. if (extension_loaded('pgsql')) {
  26. DriverManager::register('pgsql+std', new XPClass(__CLASS__));
  27. }
  28. }
  29. /**
  30. * Constructor
  31. *
  32. * @param rdbms.DSN dsn
  33. */
  34. public function __construct($dsn) {
  35. parent::__construct($dsn);
  36. $this->formatter= new StatementFormatter($this, new PostgreSQLDialect());
  37. }
  38. /**
  39. * Connect
  40. *
  41. * @param bool reconnect default FALSE
  42. * @return bool success
  43. * @throws rdbms.SQLConnectException
  44. */
  45. public function connect($reconnect= FALSE) {
  46. if (is_resource($this->handle)) return TRUE; // Already connected
  47. if (!$reconnect && (FALSE === $this->handle)) return FALSE; // Previously failed connecting
  48. // Build connection string. In PostgreSQL, a dbname must _always_
  49. // be specified.
  50. $cs= 'dbname='.$this->dsn->getDatabase();
  51. if ($this->dsn->getHost()) $cs.= ' host='.$this->dsn->getHost();
  52. if ($this->dsn->getPort()) $cs.= ' port='.$this->dsn->getPort();
  53. if ($this->dsn->getUser()) $cs.= ' user='.$this->dsn->getUser();
  54. if ($this->dsn->getPassword()) $cs.= ' password='.$this->dsn->getPassword();
  55. if ($this->flags & DB_PERSISTENT) {
  56. $this->handle= pg_pconnect($cs);
  57. } else {
  58. $this->handle= pg_connect($cs);
  59. }
  60. if (!is_resource($this->handle)) {
  61. throw new SQLConnectException(rtrim(pg_last_error()), $this->dsn);
  62. }
  63. $this->_obs && $this->notifyObservers(new DBEvent(__FUNCTION__, $reconnect));
  64. return TRUE;
  65. }
  66. /**
  67. * Disconnect
  68. *
  69. * @return bool success
  70. */
  71. public function close() {
  72. if ($this->handle && $r= pg_close($this->handle)) {
  73. $this->handle= NULL;
  74. return $r;
  75. }
  76. return FALSE;
  77. }
  78. /**
  79. * Select database
  80. *
  81. * @param string db name of database to select
  82. * @return bool success
  83. * @throws rdbms.SQLStatementFailedException
  84. */
  85. public function selectdb($db) {
  86. throw new SQLStatementFailedException(
  87. 'Cannot select database, not implemented in PostgreSQL'
  88. );
  89. }
  90. /**
  91. * Retrieve identity
  92. *
  93. * @return var identity value
  94. */
  95. public function identity($field= NULL) {
  96. $q= $this->query('select currval(%s) as id', $field);
  97. $id= $q ? $q->next('id') : NULL;
  98. $this->_obs && $this->notifyObservers(new DBEvent(__FUNCTION__, $id));
  99. return $id;
  100. }
  101. /**
  102. * Retrieve number of affected rows for last query
  103. *
  104. * @return int
  105. */
  106. protected function affectedRows() {
  107. return pg_affected_rows($this->result);
  108. }
  109. /**
  110. * Execute any statement
  111. *
  112. * @param string sql
  113. * @param bool buffered default TRUE
  114. * @return rdbms.pgsql.PostgreSQLResultSet or TRUE if no resultset was created
  115. * @throws rdbms.SQLException
  116. */
  117. protected function query0($sql, $buffered= TRUE) {
  118. if (!is_resource($this->handle)) {
  119. if (!($this->flags & DB_AUTOCONNECT)) throw new SQLStateException('Not connected');
  120. $c= $this->connect();
  121. // Check for subsequent connection errors
  122. if (FALSE === $c) throw new SQLStateException('Previously failed to connect.');
  123. }
  124. $success= pg_send_query($this->handle, $sql);
  125. if (!$success) {
  126. $message= 'Statement failed: '.rtrim(pg_last_error($this->handle)).' @ '.$this->dsn->getHost();
  127. if (PGSQL_CONNECTION_OK !== pg_connection_status($this->handle)) {
  128. throw new SQLConnectionClosedException($message, $sql);
  129. } else {
  130. throw new SQLStatementFailedException($message, $sql);
  131. }
  132. }
  133. $this->result= pg_get_result($this->handle);
  134. switch ($status= pg_result_status($this->result, PGSQL_STATUS_LONG)) {
  135. case PGSQL_FATAL_ERROR:
  136. case PGSQL_BAD_RESPONSE: {
  137. $code= pg_result_error_field($this->result, PGSQL_DIAG_SQLSTATE);
  138. $message= 'Statement failed: '.pg_result_error_field($this->result, PGSQL_DIAG_MESSAGE_PRIMARY).' @ '.$this->dsn->getHost();
  139. if ('40P01' === $code) {
  140. throw new SQLDeadlockException($message, $sql, $code);
  141. } else {
  142. throw new SQLStatementFailedException($message, $sql, $code);
  143. }
  144. }
  145. case PGSQL_COMMAND_OK: {
  146. return TRUE;
  147. }
  148. default: {
  149. return new PostgreSQLResultSet($this->result, $this->tz);
  150. }
  151. }
  152. }
  153. /**
  154. * Begin a transaction
  155. *
  156. * @param rdbms.Transaction transaction
  157. * @return rdbms.Transaction
  158. */
  159. public function begin($transaction) {
  160. $this->query('begin transaction');
  161. $transaction->db= $this;
  162. return $transaction;
  163. }
  164. /**
  165. * Retrieve transaction state
  166. *
  167. * @param string name
  168. * @return var state
  169. */
  170. public function transtate($name) {
  171. return -1;
  172. }
  173. /**
  174. * Rollback a transaction
  175. *
  176. * @param string name
  177. * @return bool success
  178. */
  179. public function rollback($name) {
  180. return $this->query('rollback transaction');
  181. }
  182. /**
  183. * Commit a transaction
  184. *
  185. * @param string name
  186. * @return bool success
  187. */
  188. public function commit($name) {
  189. return $this->query('commit transaction');
  190. }
  191. }
  192. ?>