Source for file PostgreSQLDatabase.class.php

Documentation is available at PostgreSQLDatabase.class.php

  1. <?php
  2. /**
  3. * @package harmoni.dbc.postgre
  4. *
  5. * @copyright Copyright &copy; 2005, Middlebury College
  6. * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License (GPL)
  7. *
  8. * @version $Id: PostgreSQLDatabase.class.php,v 1.1 2007/09/14 13:57:08 adamfranco Exp $
  9. */
  10. require_once(HARMONI."DBHandler/Database.abstract.php");
  11. require_once(HARMONI."DBHandler/PostgreSQL/PostgreSQLSelectQueryResult.class.php");
  12. require_once(HARMONI."DBHandler/PostgreSQL/PostgreSQLInsertQueryResult.class.php");
  13. require_once(HARMONI."DBHandler/PostgreSQL/PostgreSQLUpdateQueryResult.class.php");
  14. require_once(HARMONI."DBHandler/PostgreSQL/PostgreSQLDeleteQueryResult.class.php");
  15. require_once(HARMONI."DBHandler/PostgreSQL/PostgreSQLGenericQueryResult.class.php");
  16. require_once(HARMONI."DBHandler/PostgreSQL/PostgreSQL_SQLGenerator.class.php");
  17.  
  18. /**
  19. * A PostgreSQLDatabase class provides the tools to connect, query, etc., a PostgreSQL database.
  20. *
  21. * @package harmoni.dbc.postgre
  22. *
  23. * @copyright Copyright &copy; 2005, Middlebury College
  24. * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License (GPL)
  25. *
  26. * @version $Id: PostgreSQLDatabase.class.php,v 1.1 2007/09/14 13:57:08 adamfranco Exp $
  27. ***/
  28. class PostgreSQLDatabase
  29. extends DatabaseAbstract
  30. {
  31.  
  32. /**
  33. * The hostname of the database, i.e. myserver.mydomain.edu.
  34. * The hostname of the database, i.e. myserver.mydomain.edu.
  35. * @var string $_dbHost The hostname of the database, i.e. myserver.mydomain.edu.
  36. * @access private
  37. */
  38. var $_dbHost;
  39. /**
  40. * The name of the default database to use.
  41. * The name of the default database to use.
  42. * @var string $_dbName The name of the default database to use.
  43. * @access private
  44. */
  45. var $_dbName;
  46. /**
  47. * The username with which to connect to the database.
  48. * The username with which to connect to the database.
  49. * @var string $_dbUser The username with which to connect to the database.
  50. * @access private
  51. */
  52. var $_dbUser;
  53. /**
  54. * The password for $_dbUser with which to connect to the database.
  55. * The password for $_dbUser with which to connect to the database.
  56. * @var string $_dbPass The password for $_dbUser with which to connect to the database.
  57. * @access private
  58. */
  59. var $_dbPass;
  60. /**
  61. * Stores the current connection's link identifier.
  62. * If a connection is open, this stores the connection's identifier. Otherwise,
  63. * it stores FALSE.
  64. * @var mixed $_linkId If a connection is open, this stores the connection's identifier. Otherwise,
  65. * it stores FALSE.
  66. * @access private
  67. */
  68. var $_linkId;
  69. /**
  70. * The total number of successful queries executed since the last call to connect().
  71. * The total number of failed queries executed since the last call to connect().
  72. * @var integer $_successfulQueries The total number of failed queries executed since the last call to connect().
  73. * @access private
  74. */
  75. var $_successfulQueries;
  76. /**
  77. * The total number of failed queries executed since the last call to connect().
  78. * The total number of failed queries executed since the last call to connect().
  79. * @var integer $_failedQueries The total number of failed queries executed since the last call to connect().
  80. * @access private
  81. */
  82. var $_failedQueries;
  83.  
  84. /**
  85. * Creates a new database connection.
  86. * @param string $dbHost The hostname for the database, i.e. myserver.mydomain.edu.
  87. * @param string $dbName The name of the default database to use.
  88. * @param string $dbUser The username with which to connect to the database.
  89. * @param string $dbPass The password for $_dbUser with which to connect to the database.
  90. * @return integer $dbIndex The index of the new database
  91. * @access public
  92. */
  93. function PostgreSQLDatabase($dbHost, $dbName, $dbUser, $dbPass) {
  94. // ** parameter validation
  95. $stringRule = StringValidatorRule::getRule();
  96. ArgumentValidator::validate($dbHost, $stringRule, true);
  97. ArgumentValidator::validate($dbName, $stringRule, true);
  98. ArgumentValidator::validate($dbUser, $stringRule, true);
  99. ArgumentValidator::validate($dbPass, $stringRule, true);
  100. // ** end of parameter validation
  101.  
  102. $this->_dbHost = $dbHost;
  103. $this->_dbName = $dbName;
  104. $this->_dbUser = $dbUser;
  105. $this->_dbPass = $dbPass;
  106. $this->_linkId = false;
  107. $this->_successfulQueries = 0;
  108. $this->_failedQueries = 0;
  109. }
  110.  
  111. /**
  112. * Returns a short string name for this database type. Example: 'MySQL'
  113. * @access public
  114. * @return string
  115. */
  116. function getStringName() {
  117. return "PostgreSQL";
  118. }
  119.  
  120. /**
  121. * Returns a list of the tables that exist in the currently connected database.
  122. * @return array
  123. * @access public
  124. */
  125. function getTableList() {
  126. $query = new SelectQuery();
  127. $query->addTable("pg_stat_user_tables");
  128. $query->addColumn("relname");
  129. $query->addOrderBy("relname", ASCENDING);
  130. $res =$this->query($query);
  131. $list = array();
  132. while($res->hasMoreRows()) {
  133. $list[] = $res->field(0);
  134. $res->advanceRow();
  135. }
  136. $res->free();
  137. return $list;
  138. }
  139. /**
  140. * Connects to the database.
  141. * Connects to the database.
  142. * @access public
  143. * @return mixed The connection's link identifier, if successful; False, otherwise.
  144. */
  145. function connect() {
  146. // if connected, need to disconnect first
  147. if ($this->isConnected())
  148. return false;
  149. // attempt to connect
  150. $conStr = "";
  151. $conStr .= " host = ".$this->_dbHost;
  152. $conStr .= " user = ".$this->_dbUser;
  153. $conStr .= " password = ".$this->_dbPass;
  154. $conStr .= " dbname = ".$this->_dbName;
  155. ob_start();
  156. $linkId = pg_connect($conStr);
  157. $errorText = ob_get_clean();
  158. // see if successful
  159. if ($linkId) {
  160. // reset the query counters
  161. $this->_successfulQueries = 0;
  162. $this->_failedQueries = 0;
  163. $this->_linkId = $linkId;
  164. return $linkId;
  165. }
  166. else {
  167. $this->_linkId = false;
  168. throw new ConnectionDatabaseException($this->getConnectionErrorInfo()."Cannot connect to database. ".$errorText);
  169. return false;
  170. }
  171. }
  172.  
  173. /**
  174. * Makes a persistent database connection.
  175. * Makes a persistent database connection.
  176. * @access public
  177. * @return mixed The connection's link identifier, if successful; False, otherwise.
  178. */
  179. function pConnect() {
  180. // if connected, need to disconnect first
  181. if ($this->isConnected())
  182. return false;
  183. // attempt to connect
  184. $conStr = "";
  185. if ($this->_dbHost != "localhost")
  186. $conStr .= " host = ".$this->_dbHost;
  187. $conStr .= " user = ".$this->_dbUser;
  188. $conStr .= " password = ".$this->_dbPass;
  189. $conStr .= " dbname = ".$this->_dbName;
  190. ob_start();
  191. $linkId = pg_pconnect($conStr);
  192. $errorText = ob_get_clean();
  193. // see if successful
  194. if ($linkId) {
  195. // reset the query counters
  196. $this->_successfulQueries = 0;
  197. $this->_failedQueries = 0;
  198. $this->_linkId = $linkId;
  199. return $linkId;
  200. }
  201. else {
  202. $this->_linkId = false;
  203. throw new ConnectionDatabaseException($this->getConnectionErrorInfo()."Cannot connect to database. ".$errorText);
  204. return false;
  205. }
  206.  
  207. }
  208.  
  209.  
  210. /**
  211. * Executes an SQL query.
  212. * Executes an SQL query. The method is passed a query object, which it
  213. * converts to a SQL query string using the appropriate SQLGenerator
  214. * object.
  215. * @access public
  216. * @param object Query $query A Query object from which the SQL query will be constructed.
  217. * @return mixed The appropriate QueryResult object. If the query failed, it would
  218. * return NULL.
  219. */
  220. function query(Query $query) {
  221. // do not attempt, to query, if not connected
  222. if (!$this->isConnected()) {
  223. throw new ConnectionDatabaseException("Attempted to query but there was no database connection.");
  224. return false;
  225. }
  226. // generate the SQL query string
  227. $queryString = PostgreSQL_SQLGenerator::generateSQLQuery($query);
  228. // if query is an insert, do it in a transaction (cause you will need
  229. // to fetch the last inserted id)
  230. if ($query->getType() == INSERT && $query->_sequence)
  231. $this->_query("BEGIN");
  232. // attempt to run the query
  233. $resourceId = $this->_query($queryString);
  234.  
  235. // if query was unsuccessful, return a null QueryResult object
  236. if ($resourceId === false)
  237. return null;
  238.  
  239. // create the appropriate QueryResult object
  240. switch($query->getType()) {
  241. case INSERT : {
  242. // we need to fetch the last inserted id
  243. // this is only possible if the user has specified the sequence
  244. // object with the setAutoIncrementColumn() method.
  245. $lastId = null;
  246. if ($query->_sequence) {
  247. $lastIdQuery = "SELECT CURRVAL('".$query->_sequence."')";
  248. $lastIdResourceId = $this->_query($lastIdQuery);
  249. $this->_query("COMMIT");
  250. $arr = pg_fetch_row($lastIdResourceId, 0);
  251. $lastId = intval($arr[0]);
  252. }
  253. $result = new PostgreSQLInsertQueryResult($resourceId, $lastId);
  254. break;
  255. }
  256. case UPDATE :
  257. $result = new PostgreSQLUpdateQueryResult($resourceId);
  258. break;
  259. case DELETE :
  260. $result = new PostgreSQLDeleteQueryResult($resourceId);
  261. break;
  262. case SELECT :
  263. $result = new PostgreSQLSelectQueryResult($resourceId, $this->_linkId);
  264. break;
  265. case GENERIC :
  266. $result = new PostgreSQLGenericQueryResult($resourceId, $this->_linkId);
  267. break;
  268. default:
  269. throw new DatabaseException("Unsupported query type.");
  270. } // switch
  271. return $result;
  272. }
  273. /**
  274. * Answer the string SQL for the query
  275. *
  276. * @param object $query
  277. * @return string
  278. * @access public
  279. * @since 11/14/06
  280. */
  281. function generateSQL ($query) {
  282. return PostgreSQL_SQLGenerator::generateSQLQuery($query);
  283. }
  284.  
  285. /**
  286. * Executes an SQL query.
  287. * Executes an SQL query.
  288. * @access private
  289. * @param mixed query Either a string (this would be the case, normally) or
  290. * an array of strings. Each string is corresponding to an SQL query.
  291. * @return mixed For a SELECT statement, a resource identifier, if
  292. * successful; For INSERT, DELETE, UPDATE statements, TRUE if successful;
  293. * for all: FALSE, if not successful. If <code>$query</code> had several
  294. * queries, this would be the result for the last one.
  295. */
  296. function _query($query) {
  297. // do not attempt to query, if not connected
  298. if (!$this->isConnected()) {
  299. throw new ConnectionDatabaseException("Attempted to query but there was no database connection.");
  300. return false;
  301. }
  302. if (is_array($query))
  303. $queries = $query;
  304. else if (is_string($query))
  305. $queries = array($query);
  306. $count = count($queries);
  307. // if more than one queries - do them in a transaction
  308. if ($count > 1)
  309. $this->_query("BEGIN");
  310. foreach ($queries as $q) {
  311. // attempt to execute the query
  312. $resourceId = @pg_query($this->_linkId, $q);
  313. if ($resourceId === false) {
  314. $this->_failedQueries++;
  315. throw new QueryDatabaseException(pg_last_error($this->_linkId));
  316. }
  317. else
  318. $this->_successfulQueries++;
  319. }
  320. if ($count > 1)
  321. $this->_query("COMMIT");
  322.  
  323. return $resourceId;
  324. }
  325.  
  326.  
  327.  
  328. /**
  329. * Disconnects from the database.
  330. * Disconnects from the database.
  331. * @access public
  332. * @return boolean True, if successful; False, otherwise.
  333. */
  334. function disconnect() {
  335. // do not disconnect, if not connected
  336. if (!$this->isConnected())
  337. return false;
  338. // attempt to disconnect
  339. $isSuccessful = pg_close($this->_linkId);
  340. if ($isSuccessful)
  341. $this->_linkId = false;
  342. return $isSuccessful;
  343. }
  344.  
  345.  
  346. /**
  347. * Indicates whether there is an open connection to the database.
  348. * Indicates whether there is an open connection to the database.
  349. * @access public
  350. * @return boolean True if there is an open connection to the database; False, otherwise.
  351. */
  352. function isConnected() {
  353. $isConnected = ($this->_linkId !== false);
  354. return $isConnected;
  355. }
  356.  
  357.  
  358.  
  359.  
  360. /**
  361. * Returns the total number of successful queries executed since the last call to connect().
  362. * Returns the total number of successful queries executed since the last call to connect().
  363. * @access public
  364. * @return integer The total number of successful queries executed since the last call to connect().
  365. ***/
  366. function getNumberSuccessfulQueries() {
  367. return $this->_successfulQueries;
  368. }
  369. /**
  370. * Returns the total number of failed queries executed since the last call to connect().
  371. * Returns the total number of failed queries executed since the last call to connect().
  372. * @access public
  373. * @return integer The total number of failed queries executed since the last call to connect().
  374. ***/
  375. function getNumberFailedQueries() {
  376. return $this->_failedQueries;
  377. }
  378.  
  379. /**
  380. * This method selects the default database to use in queries.
  381. * @access public
  382. * @param string database The name of the default database.
  383. * @return boolean True, if successful; False, otherwise.
  384. */
  385. function selectDatabase($database) {
  386. // ** parameter validation
  387. $stringRule = StringValidatorRule::getRule();
  388. ArgumentValidator::validate($database, $stringRule, true);
  389. // ** end of parameter validation
  390. $this->disconnect();
  391. $conStr = "";
  392. $conStr .= " host = ".$this->_dbHost;
  393. $conStr .= " user = ".$this->_dbUser;
  394. $conStr .= " password = ".$this->_dbPass;
  395. $conStr .= " dbname = ".$database;
  396. $linkId = pg_pconnect($conStr);
  397. // see if successful
  398. if ($linkId) {
  399. $this->_linkId = $linkId;
  400. return true;
  401. }
  402. else {
  403. throw new ConnectionDatabaseException("Cannot connect to database.");
  404. $this->_linkId = false;
  405. return false;
  406. }
  407. }
  408.  
  409. /**
  410. * Converts a DateAndTime object to a proper datetime/timestamp/time representation
  411. * for this Database.
  412. *
  413. * The easiest way to convert is to create a string in the following
  414. * format:
  415. * 'YYYY-MM-DD HH:MM:SS', i.e. 1999-01-08 04:05:06
  416. * You can pass this to a PostgreSQL date or timestamp column types
  417. * and it gets parsed automatically by PostgreSQL.
  418. *
  419. * @access public
  420. * @param ref object DateAndTime The DateAndTime object to convert.
  421. * @return mixed A proper datetime/timestamp/time representation for this Database.
  422. */
  423. function toDBDate(DateAndTime $dateAndTime) {
  424. $dateAndTime =$dateAndTime->asDateAndTime();
  425. $string = sprintf("%s-%02d-%02d %02d:%02d:%02d", $dateAndTime->year(),
  426. $dateAndTime->month(), $dateAndTime->dayOfMonth(),
  427. $dateAndTime->hour24(), $dateAndTime->minute(),
  428. $dateAndTime->second());
  429. return "'".$string."'";
  430. }
  431. /**
  432. * Converts a database datetime/timestamp/time value (that has been fetched
  433. * from the db) to a DateAndTime object.
  434. *
  435. * Depending on the server configuration PostgreSQL retrieves date/time
  436. * types as 4 different formats. (format could be set with SET DateStyle
  437. * ). The default formatting is 'ISO'. Note that timestamp column types
  438. * return the full string. Date column types only return the date (no time).
  439. *
  440. * Style Description Example
  441. * 'ISO' ISO-8601 standard 1997-12-17 07:37:16-08
  442. * 'SQL' Traditional style 12/17/1997 07:37:16.00 PST
  443. * 'PostgreSQL' Original style Wed Dec 17 07:37:16 1997 PST
  444. * 'German' Regional style 17.12.1997 07:37:16.00 PST
  445. *
  446. * @access public
  447. * @param mixed A database datetime/timestamp/time value (that has been fetched
  448. * from the db).
  449. * @return ref object The DateAndTime object.
  450. */
  451. function fromDBDate($value) {
  452. if (in_array($value, array(NULL, '', '0000-00-00 00:00:00')))
  453. return NULL;
  454. // Postgre
  455. if (ereg("([a-zA-Z]{3}) ([a-zA-Z]{3}) ([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) ([0-9]{4})",$value,$r)) {
  456. $months = array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,
  457. "Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12);
  458. return DateAndTime::withYearMonthDayHourMinuteSecond(
  459. $r[7], $months[$r[2]], $r[3], $r[4], $r[5], $r[6]);
  460. }
  461. // German
  462. if (ereg("([0-9]{2})\.([0-9]{2})\.([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2}).([0-9]{2}) ...",$value,$r))
  463. return DateAndTime::withYearMonthDayHourMinuteSecond(
  464. $r[3], $r[2], $r[1], $r[4], $r[5], $r[6]);
  465. // ISO/SQL
  466. $obj = DateAndTime::fromString($value);
  467. return $obj;
  468. }
  469. /**
  470. * Return TRUE if this database supports transactions.
  471. *
  472. * @return boolean
  473. * @access public
  474. * @since 3/9/05
  475. */
  476. function supportsTransactions () {
  477. return TRUE;
  478. }
  479. /**
  480. * Begin a transaction.
  481. *
  482. * @return void
  483. * @access public
  484. * @since 3/9/05
  485. */
  486. function beginTransaction () {
  487. $this->_query("BEGIN");
  488. }
  489. /**
  490. * Commit a transaction. This will roll-back changes if errors occured in the
  491. * transaction block.
  492. *
  493. * @return void
  494. * @access public
  495. * @since 3/9/05
  496. */
  497. function commitTransaction () {
  498. $this->_query("COMMIT");
  499. }
  500. /**
  501. * Roll-back a transaction manually instead of committing
  502. *
  503. * @return void
  504. * @access public
  505. * @since 3/9/05
  506. */
  507. function rollbackTransaction () {
  508. $this->_query("ROLLBACK");
  509. }
  510. }
  511.  
  512. ?>

Documentation generated on Wed, 19 Sep 2007 10:25:32 -0400 by phpDocumentor 1.3.0RC3