# Source for file Pgsql.php

Documentation is available at Pgsql.php

1. <?php
2. /*
3. * $Id: Pgsql.php 2291 2007-08-29 22:03:55Z zYne $
4. *
5. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16. *
17. * This software consists of voluntary contributions made by many individuals
18. * and is licensed under the LGPL. For more information, see
19. * <http://www.phpdoctrine.com>.
20. */
21. Doctrine::autoload('Doctrine_Export');
22. /**
23. * Doctrine_Export_Pgsql
24. *
25. * @package Doctrine
26. * @author Konsta Vesterinen <kvesteri@cc.hut.fi>
27. * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
28. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
29. * @category Object Relational Mapping
30. * @link www.phpdoctrine.com
31. * @since 1.0
32. * @version $Revision: 2291 $
33. */
34. class Doctrine_Export_Pgsql extends Doctrine_Export
35. {
36. /**
37. * create a new database
38. *
39. * @param string $name name of the database that should be created
40. * @throws PDOException
41. * @return void
42. */
43. public function createDatabaseSql($name)
44. {
45. $query = 'CREATE DATABASE ' . $this->conn->quoteIdentifier($name);
47. return $query;
48. }
49. /**
50. * drop an existing database
51. *
52. * @param string $name name of the database that should be dropped
53. * @throws PDOException
54. * @access public
55. */
56. public function dropDatabaseSql($name)
57. {
58. $query = 'DROP DATABASE ' . $this->conn->quoteIdentifier($name);
60. return $query;
61. }
62. /**
63. * getAdvancedForeignKeyOptions
64. * Return the FOREIGN KEY query section dealing with non-standard options
65. * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
66. *
67. * @param array $definition foreign key definition
68. * @return string
69. * @access protected
70. */
71. public function getAdvancedForeignKeyOptions(array $definition)
72. {
73. $query = '';
74. if (isset($definition['match'])) {
75. $query .= ' MATCH ' . $definition['match'];
76. }
77. if (isset($definition['onUpdate'])) {
78. $query .= ' ON UPDATE ' . $definition['onUpdate'];
79. }
80. if (isset($definition['onDelete'])) {
81. $query .= ' ON DELETE ' . $definition['onDelete'];
82. }
83. if (isset($definition['deferrable'])) {
84. $query .= ' DEFERRABLE';
85. } else {
86. $query .= ' NOT DEFERRABLE';
87. }
88. if (isset($definition['feferred'])) {
89. $query .= ' INITIALLY DEFERRED';
90. } else {
91. $query .= ' INITIALLY IMMEDIATE';
92. }
93. return $query;
94. }
96. /**
97. * alter an existing table
98. *
99. * @param string $name name of the table that is intended to be changed.
100. * @param array $changes associative array that contains the details of each type
101. * of change that is intended to be performed. The types of
102. * changes that are currently supported are defined as follows:
103. *
104. * name
105. *
106. * New name for the table.
107. *
108. * add
109. *
110. * Associative array with the names of fields to be added as
111. * indexes of the array. The value of each entry of the array
112. * should be set to another associative array with the properties
113. * of the fields to be added. The properties of the fields should
114. * be the same as defined by the Metabase parser.
115. *
116. *
117. * remove
118. *
119. * Associative array with the names of fields to be removed as indexes
120. * of the array. Currently the values assigned to each entry are ignored.
121. * An empty array should be used for future compatibility.
122. *
123. * rename
124. *
125. * Associative array with the names of fields to be renamed as indexes
126. * of the array. The value of each entry of the array should be set to
127. * another associative array with the entry named name with the new
128. * field name and the entry named Declaration that is expected to contain
129. * the portion of the field declaration already in DBMS specific SQL code
130. * as it is used in the CREATE TABLE statement.
131. *
132. * change
133. *
134. * Associative array with the names of the fields to be changed as indexes
135. * of the array. Keep in mind that if it is intended to change either the
136. * name of a field and any other properties, the change array entries
137. * should have the new names of the fields as array indexes.
138. *
139. * The value of each entry of the array should be set to another associative
140. * array with the properties of the fields to that are meant to be changed as
141. * array entries. These entries should be assigned to the new values of the
142. * respective properties. The properties of the fields should be the same
143. * as defined by the Metabase parser.
144. *
145. * Example
146. * array(
147. * 'name' => 'userlist',
148. * 'add' => array(
149. * 'quota' => array(
150. * 'type' => 'integer',
151. * 'unsigned' => 1
152. * )
153. * ),
154. * 'remove' => array(
155. * 'file_limit' => array(),
156. * 'time_limit' => array()
157. * ),
158. * 'change' => array(
159. * 'name' => array(
160. * 'length' => '20',
161. * 'definition' => array(
162. * 'type' => 'text',
163. * 'length' => 20,
164. * ),
165. * )
166. * ),
167. * 'rename' => array(
168. * 'sex' => array(
169. * 'name' => 'gender',
170. * 'definition' => array(
171. * 'type' => 'text',
172. * 'length' => 1,
173. * 'default' => 'M',
174. * ),
175. * )
176. * )
177. * )
178. *
179. * @param boolean $check indicates whether the function should just check if the DBMS driver
180. * can perform the requested table alterations if the value is true or
181. * actually perform them otherwise.
182. * @throws Doctrine_Connection_Exception
183. * @return boolean
184. */
185. public function alterTable($name, array $changes, $check)
186. {
187. foreach ($changes as $changeName => $change) {
188. switch ($changeName) {
189. case 'add':
190. case 'remove':
191. case 'change':
192. case 'name':
193. case 'rename':
194. break;
195. default:
196. throw new Doctrine_Export_Exception('change type "' . $changeName . '\" not yet supported');
197. }
198. }
200. if ($check) {
201. return true;
202. }
204. if (isset($changes['add']) && is_array($changes['add'])) {
205. foreach ($changes['add'] as $fieldName => $field) {
206. $query = 'ADD ' . $this->getDeclaration($fieldName, $field);
207. $this->conn->exec('ALTER TABLE ' . $name . ' ' . $query);
208. }
209. }
211. if (isset($changes['remove']) && is_array($changes['remove'])) {
212. foreach ($changes['remove'] as $fieldName => $field) {
213. $fieldName = $this->conn->quoteIdentifier($fieldName, true);
214. $query = 'DROP ' . $fieldName;
215. $this->conn->exec('ALTER TABLE ' . $name . ' ' . $query);
216. }
217. }
219. if (isset($changes['change']) && is_array($changes['change'])) {
220. foreach ($changes['change'] as $fieldName => $field) {
221. $fieldName = $this->conn->quoteIdentifier($fieldName, true);
222. if (isset($field['type'])) {
223. $serverInfo = $this->conn->getServerVersion();
225. if (is_array($serverInfo) && $serverInfo['major'] < 8) {
226. throw new Doctrine_Export_Exception('changing column type for "'.$field['type'].'\" requires PostgreSQL 8.0 or above');
227. }
228. $query = 'ALTER ' . $fieldName . ' TYPE ' . $this->conn->datatype->getTypeDeclaration($field['definition']);
229. $this->conn->exec('ALTER TABLE ' . $name . ' ' . $query);;
230. }
231. if (array_key_exists('default', $field)) {
232. $query = 'ALTER ' . $fieldName . ' SET DEFAULT ' . $this->conn->quote($field['definition']['default'], $field['definition']['type']);
233. $this->conn->exec('ALTER TABLE ' . $name . ' ' . $query);
234. }
235. if (!empty($field['notnull'])) {
236. $query = 'ALTER ' . $fieldName . ' ' . ($field['definition']['notnull'] ? 'SET' : 'DROP') . ' NOT NULL';
237. $this->conn->exec('ALTER TABLE ' . $name . ' ' . $query);
238. }
239. }
240. }
242. if (isset($changes['rename']) && is_array($changes['rename'])) {
243. foreach ($changes['rename'] as $fieldName => $field) {
244. $fieldName = $this->conn->quoteIdentifier($fieldName, true);
245. $this->conn->exec('ALTER TABLE ' . $name . ' RENAME COLUMN ' . $fieldName . ' TO ' . $this->conn->quoteIdentifier($field['name'], true));
246. }
247. }
249. $name = $this->conn->quoteIdentifier($name, true);
250. if (isset($changes['name'])) {
251. $changeName = $this->conn->quoteIdentifier($changes['name'], true);
252. $this->conn->exec('ALTER TABLE ' . $name . ' RENAME TO ' . $changeName);
253. }
254. }
255. /**
256. * return RDBMS specific create sequence statement
257. *
258. * @throws Doctrine_Connection_Exception if something fails at database level
259. * @param string $seqName name of the sequence to be created
260. * @param string $start start value of the sequence; default is 1
261. * @param array $options An associative array of table options:
262. * array(
263. * 'comment' => 'Foo',
264. * 'charset' => 'utf8',
265. * 'collate' => 'utf8_unicode_ci',
266. * );
267. * @return string
268. */
269. public function createSequenceSql($sequenceName, $start = 1, array $options = array())
270. {
271. $sequenceName = $this->conn->quoteIdentifier($this->conn->formatter->getSequenceName($sequenceName), true);
272. return $this->conn->exec('CREATE SEQUENCE ' . $sequenceName . ' INCREMENT 1' .
273. ($start < 1 ? ' MINVALUE ' . $start : '') . ' START ' . $start);
274. }
275. /**
276. * drop existing sequence
277. *
278. * @param string $sequenceName name of the sequence to be dropped
279. */
280. public function dropSequenceSql($sequenceName)
281. {
282. $sequenceName = $this->conn->quoteIdentifier($this->conn->formatter->getSequenceName($sequenceName), true);
283. return 'DROP SEQUENCE ' . $sequenceName;
284. }
286. /**
287. * Creates a table.
288. *
289. * @param unknown_type $name
290. * @param array $fields
291. * @param array $options
292. * @return unknown
293. */
294. public function createTableSql($name, array $fields, array $options = array())
295. {
296. if ( ! $name) {
297. throw new Doctrine_Export_Exception('no valid table name specified');
298. }
300. if (empty($fields)) {
301. throw new Doctrine_Export_Exception('no fields specified for table ' . $name);
302. }
304. $queryFields = $this->getFieldDeclarationList($fields);
307. if (isset($options['primary']) && ! empty($options['primary'])) {
308. $queryFields .= ', PRIMARY KEY(' . implode(', ', array_values($options['primary'])) . ')';
309. }
311. $query = 'CREATE TABLE ' . $this->conn->quoteIdentifier($name, true) . ' (' . $queryFields . ')';
313. $sql[] = $query;
315. if (isset($options['indexes']) && ! empty($options['indexes'])) {
316. foreach($options['indexes'] as $index => $definition) {
317. $sql[] = $this->createIndexSql($name, $index, $definition);
318. }
319. }
321. if (isset($options['foreignKeys'])) {
323. foreach ((array) $options['foreignKeys'] as $k => $definition) {
324. if (is_array($definition)) {
325. $sql[] = $this->createForeignKeySql($name, $definition);
326. }
327. }
328. }
330. return $sql;
331. }
333. /**
334. * createForeignKeySql
335. *
336. * @param string $table name of the table on which the foreign key is to be created
337. * @param array $definition associative array that defines properties of the foreign key to be created.
338. * @return string
339. */
340. public function createForeignKeySql($table, array $definition)
341. {
342. $table = $this->conn->quoteIdentifier($table);
344. $query = 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclaration($definition);
346. return $query;
348. }