PageRenderTime 47ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/standard/tags/release-1.0.0RC2/library/Zend/Db/Adapter/Pdo/Pgsql.php

https://github.com/bhaumik25/zend-framework
PHP | 281 lines | 141 code | 22 blank | 118 comment | 14 complexity | 185b473b49ed34990d25065a65cf4702 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Db
  17. * @subpackage Adapter
  18. * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id$
  21. */
  22. /**
  23. * @see Zend_Db_Adapter_Pdo_Abstract
  24. */
  25. require_once 'Zend/Db/Adapter/Pdo/Abstract.php';
  26. /**
  27. * Class for connecting to PostgreSQL databases and performing common operations.
  28. *
  29. * @category Zend
  30. * @package Zend_Db
  31. * @subpackage Adapter
  32. * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. */
  35. class Zend_Db_Adapter_Pdo_Pgsql extends Zend_Db_Adapter_Pdo_Abstract
  36. {
  37. /**
  38. * PDO type.
  39. *
  40. * @var string
  41. */
  42. protected $_pdoType = 'pgsql';
  43. /**
  44. * Returns a list of the tables in the database.
  45. *
  46. * @return array
  47. */
  48. public function listTables()
  49. {
  50. // @todo use a better query with joins instead of subqueries
  51. $sql = "SELECT c.relname AS table_name "
  52. . "FROM pg_class c, pg_user u "
  53. . "WHERE c.relowner = u.usesysid AND c.relkind = 'r' "
  54. . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) "
  55. . "AND c.relname !~ '^(pg_|sql_)' "
  56. . "UNION "
  57. . "SELECT c.relname AS table_name "
  58. . "FROM pg_class c "
  59. . "WHERE c.relkind = 'r' "
  60. . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) "
  61. . "AND NOT EXISTS (SELECT 1 FROM pg_user WHERE usesysid = c.relowner) "
  62. . "AND c.relname !~ '^pg_'";
  63. return $this->fetchCol($sql);
  64. }
  65. /**
  66. * Returns the column descriptions for a table.
  67. *
  68. * The return value is an associative array keyed by the column name,
  69. * as returned by the RDBMS.
  70. *
  71. * The value of each array element is an associative array
  72. * with the following keys:
  73. *
  74. * SCHEMA_NAME => string; name of database or schema
  75. * TABLE_NAME => string;
  76. * COLUMN_NAME => string; column name
  77. * COLUMN_POSITION => number; ordinal position of column in table
  78. * DATA_TYPE => string; SQL datatype name of column
  79. * DEFAULT => string; default expression of column, null if none
  80. * NULLABLE => boolean; true if column can have nulls
  81. * LENGTH => number; length of CHAR/VARCHAR
  82. * SCALE => number; scale of NUMERIC/DECIMAL
  83. * PRECISION => number; precision of NUMERIC/DECIMAL
  84. * UNSIGNED => boolean; unsigned property of an integer type
  85. * PRIMARY => boolean; true if column is part of the primary key
  86. * PRIMARY_POSITION => integer; position of column in primary key
  87. * IDENTITY => integer; true if column is auto-generated with unique values
  88. *
  89. * @todo Discover integer unsigned property.
  90. *
  91. * @param string $tableName
  92. * @param string $schemaName OPTIONAL
  93. * @return array
  94. */
  95. public function describeTable($tableName, $schemaName = null)
  96. {
  97. $sql = "SELECT
  98. a.attnum,
  99. n.nspname,
  100. c.relname,
  101. a.attname AS colname,
  102. t.typname AS type,
  103. a.atttypmod,
  104. FORMAT_TYPE(a.atttypid, a.atttypmod) AS complete_type,
  105. d.adsrc AS default_value,
  106. a.attnotnull AS notnull,
  107. a.attlen AS length,
  108. co.contype,
  109. ARRAY_TO_STRING(co.conkey, ',') AS conkey
  110. FROM pg_attribute AS a
  111. JOIN pg_class AS c ON a.attrelid = c.oid
  112. JOIN pg_namespace AS n ON c.relnamespace = n.oid
  113. JOIN pg_type AS t ON a.atttypid = t.oid
  114. LEFT OUTER JOIN pg_constraint AS co ON (co.conrelid = c.oid
  115. AND a.attnum = ANY(co.conkey) AND co.contype = 'p')
  116. LEFT OUTER JOIN pg_attrdef AS d ON d.adrelid = c.oid AND d.adnum = a.attnum
  117. WHERE a.attnum > 0 AND c.relname = ".$this->quote($tableName);
  118. if ($schemaName) {
  119. $sql .= " AND n.nspname = ".$this->quote($schemaName);
  120. }
  121. $sql .= ' ORDER BY a.attnum';
  122. $stmt = $this->query($sql);
  123. // Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection
  124. $result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
  125. $attnum = 0;
  126. $nspname = 1;
  127. $relname = 2;
  128. $colname = 3;
  129. $type = 4;
  130. $atttypemod = 5;
  131. $complete_type = 6;
  132. $default_value = 7;
  133. $notnull = 8;
  134. $length = 9;
  135. $contype = 10;
  136. $conkey = 11;
  137. $desc = array();
  138. foreach ($result as $key => $row) {
  139. if ($row[$type] == 'varchar') {
  140. if (preg_match('/character varying(?:\((\d+)\))?/', $row[$complete_type], $matches)) {
  141. if (isset($matches[1])) {
  142. $row[$length] = $matches[1];
  143. } else {
  144. $row[$length] = null; // unlimited
  145. }
  146. }
  147. }
  148. list($primary, $primaryPosition, $identity) = array(false, null, false);
  149. if ($row[$contype] == 'p') {
  150. $primary = true;
  151. $primaryPosition = array_search($row[$attnum], explode(',', $row[$conkey])) + 1;
  152. $identity = (bool) (preg_match('/^nextval/', $row[$default_value]));
  153. }
  154. $desc[$row[$colname]] = array(
  155. 'SCHEMA_NAME' => $row[$nspname],
  156. 'TABLE_NAME' => $row[$relname],
  157. 'COLUMN_NAME' => $row[$colname],
  158. 'COLUMN_POSITION' => $row[$attnum],
  159. 'DATA_TYPE' => $row[$type],
  160. 'DEFAULT' => $row[$default_value],
  161. 'NULLABLE' => (bool) ($row[$notnull] != 't'),
  162. 'LENGTH' => $row[$length],
  163. 'SCALE' => null, // @todo
  164. 'PRECISION' => null, // @todo
  165. 'UNSIGNED' => null, // @todo
  166. 'PRIMARY' => $primary,
  167. 'PRIMARY_POSITION' => $primaryPosition,
  168. 'IDENTITY' => $identity
  169. );
  170. }
  171. return $desc;
  172. }
  173. /**
  174. * Adds an adapter-specific LIMIT clause to the SELECT statement.
  175. *
  176. * @param string $sql
  177. * @param integer $count
  178. * @param integer $offset OPTIONAL
  179. * @return string
  180. */
  181. public function limit($sql, $count, $offset = 0)
  182. {
  183. $count = intval($count);
  184. if ($count <= 0) {
  185. /**
  186. * @see Zend_Db_Adapter_Exception
  187. */
  188. require_once 'Zend/Db/Adapter/Exception.php';
  189. throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid");
  190. }
  191. $offset = intval($offset);
  192. if ($offset < 0) {
  193. /**
  194. * @see Zend_Db_Adapter_Exception
  195. */
  196. require_once 'Zend/Db/Adapter/Exception.php';
  197. throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid");
  198. }
  199. $sql .= " LIMIT $count";
  200. if ($offset > 0) {
  201. $sql .= " OFFSET $offset";
  202. }
  203. return $sql;
  204. }
  205. /**
  206. * Return the most recent value from the specified sequence in the database.
  207. * This is supported only on RDBMS brands that support sequences
  208. * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null.
  209. *
  210. * @param string $sequenceName
  211. * @return integer
  212. */
  213. public function lastSequenceId($sequenceName)
  214. {
  215. $this->_connect();
  216. $value = $this->fetchOne("SELECT CURRVAL(".$this->quote($sequenceName).")");
  217. return $value;
  218. }
  219. /**
  220. * Generate a new value from the specified sequence in the database, and return it.
  221. * This is supported only on RDBMS brands that support sequences
  222. * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null.
  223. *
  224. * @param string $sequenceName
  225. * @return integer
  226. */
  227. public function nextSequenceId($sequenceName)
  228. {
  229. $this->_connect();
  230. $value = $this->fetchOne("SELECT NEXTVAL(".$this->quote($sequenceName).")");
  231. return $value;
  232. }
  233. /**
  234. * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
  235. *
  236. * As a convention, on RDBMS brands that support sequences
  237. * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
  238. * from the arguments and returns the last id generated by that sequence.
  239. * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
  240. * returns the last value generated for such a column, and the table name
  241. * argument is disregarded.
  242. *
  243. * @param string $tableName OPTIONAL Name of table.
  244. * @param string $primaryKey OPTIONAL Name of primary key column.
  245. * @return integer
  246. */
  247. public function lastInsertId($tableName = null, $primaryKey = null)
  248. {
  249. if ($tableName !== null) {
  250. $sequenceName = $tableName;
  251. if ($primaryKey) {
  252. $sequenceName .= "_$primaryKey";
  253. }
  254. $sequenceName .= '_seq';
  255. return $this->lastSequenceId($sequenceName);
  256. }
  257. return $this->_connection->lastInsertId($tableName);
  258. }
  259. }