Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/*
3
 *  $Id: Pgsql.php 7680 2010-08-19 14:08:28Z lsmith $
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.doctrine-project.org>.
20
 */
21
 
22
/**
23
 * Doctrine_Export_Pgsql
24
 *
25
 * @package     Doctrine
26
 * @subpackage  Export
27
 * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
28
 * @author      Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
29
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
30
 * @link        www.doctrine-project.org
31
 * @since       1.0
32
 * @version     $Revision: 7680 $
33
 */
34
class Doctrine_Export_Pgsql extends Doctrine_Export
35
{
36
    public $tmpConnectionDatabase = 'postgres';
37
 
38
    /**
39
     * createDatabaseSql
40
     *
41
     * @param string $name
42
     * @return void
43
     */
44
    public function createDatabaseSql($name)
45
    {
46
        $query  = 'CREATE DATABASE ' . $this->conn->quoteIdentifier($name);
47
 
48
        return $query;
49
    }
50
 
51
    /**
52
     * drop an existing database
53
     *
54
     * @param string $name name of the database that should be dropped
55
     * @throws PDOException
56
     * @access public
57
     */
58
    public function dropDatabaseSql($name)
59
    {
60
        $query  = 'DROP DATABASE ' . $this->conn->quoteIdentifier($name);
61
 
62
        return $query;
63
    }
64
 
65
    /**
66
     * getAdvancedForeignKeyOptions
67
     * Return the FOREIGN KEY query section dealing with non-standard options
68
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
69
     *
70
     * @param array $definition         foreign key definition
71
     * @return string
72
     * @access protected
73
     */
74
    public function getAdvancedForeignKeyOptions(array $definition)
75
    {
76
        $query = '';
77
        if (isset($definition['match'])) {
78
            $query .= ' MATCH ' . $definition['match'];
79
        }
80
        if (isset($definition['onUpdate'])) {
81
            $query .= ' ON UPDATE ' . $definition['onUpdate'];
82
        }
83
        if (isset($definition['onDelete'])) {
84
            $query .= ' ON DELETE ' . $definition['onDelete'];
85
        }
86
        if (isset($definition['deferrable'])) {
87
            $query .= ' DEFERRABLE';
88
        } else {
89
            $query .= ' NOT DEFERRABLE';
90
        }
91
        if (isset($definition['deferred'])) {
92
            $query .= ' INITIALLY DEFERRED';
93
        } else {
94
            $query .= ' INITIALLY IMMEDIATE';
95
        }
96
        return $query;
97
    }
98
 
99
    /**
100
     * generates the sql for altering an existing table on postgresql
101
     *
102
     * @param string $name          name of the table that is intended to be changed.
103
     * @param array $changes        associative array that contains the details of each type      *
104
     * @param boolean $check        indicates whether the function should just check if the DBMS driver
105
     *                              can perform the requested table alterations if the value is true or
106
     *                              actually perform them otherwise.
107
     * @see Doctrine_Export::alterTable()
108
     * @return array
109
     */
110
    public function alterTableSql($name, array $changes, $check = false)
111
    {
112
        foreach ($changes as $changeName => $change) {
113
            switch ($changeName) {
114
                case 'add':
115
                case 'remove':
116
                case 'change':
117
                case 'name':
118
                case 'rename':
119
                    break;
120
                default:
121
                    throw new Doctrine_Export_Exception('change type "' . $changeName . '\" not yet supported');
122
            }
123
        }
124
 
125
        if ($check) {
126
            return true;
127
        }
128
 
129
        $sql = array();
130
 
131
        if (isset($changes['add']) && is_array($changes['add'])) {
132
            foreach ($changes['add'] as $fieldName => $field) {
133
                $query = 'ADD ' . $this->getDeclaration($fieldName, $field);
134
                $sql[] = 'ALTER TABLE ' . $this->conn->quoteIdentifier($name, true) . ' ' . $query;
135
            }
136
        }
137
 
138
        if (isset($changes['remove']) && is_array($changes['remove'])) {
139
            foreach ($changes['remove'] as $fieldName => $field) {
140
                $fieldName = $this->conn->quoteIdentifier($fieldName, true);
141
                $query = 'DROP ' . $fieldName;
142
                $sql[] = 'ALTER TABLE ' . $this->conn->quoteIdentifier($name, true) . ' ' . $query;
143
            }
144
        }
145
 
146
        if (isset($changes['change']) && is_array($changes['change'])) {
147
            foreach ($changes['change'] as $fieldName => $field) {
148
                $fieldName = $this->conn->quoteIdentifier($fieldName, true);
149
                if (isset($field['definition']['type'])) {
150
                    $serverInfo = $this->conn->getServerVersion();
151
 
152
                    if (is_array($serverInfo) && $serverInfo['major'] < 8) {
153
                        throw new Doctrine_Export_Exception('changing column type for "'.$field['type'].'\" requires PostgreSQL 8.0 or above');
154
                    }
155
                    $query = 'ALTER ' . $fieldName . ' TYPE ' . $this->conn->dataDict->getNativeDeclaration($field['definition']);
156
                    $sql[] = 'ALTER TABLE ' . $this->conn->quoteIdentifier($name, true) . ' ' . $query;
157
                }
158
                if (array_key_exists('default', $field['definition'])) {
159
                    $query = 'ALTER ' . $fieldName . ' SET DEFAULT ' . $this->conn->quote($field['definition']['default'], $field['definition']['type']);
160
                    $sql[] = 'ALTER TABLE ' . $this->conn->quoteIdentifier($name, true) . ' ' . $query;
161
                }
162
                if ( isset($field['definition']['notnull'])) {
163
                    $query = 'ALTER ' . $fieldName . ' ' . ($field['definition']['notnull'] ? 'SET' : 'DROP') . ' NOT NULL';
164
                    $sql[] = 'ALTER TABLE ' . $this->conn->quoteIdentifier($name, true) . ' ' . $query;
165
                }
166
            }
167
        }
168
 
169
        if (isset($changes['rename']) && is_array($changes['rename'])) {
170
            foreach ($changes['rename'] as $fieldName => $field) {
171
                $fieldName = $this->conn->quoteIdentifier($fieldName, true);
172
                $sql[] = 'ALTER TABLE ' . $this->conn->quoteIdentifier($name, true) . ' RENAME COLUMN ' . $fieldName . ' TO ' . $this->conn->quoteIdentifier($field['name'], true);
173
            }
174
        }
175
 
176
        $name = $this->conn->quoteIdentifier($name, true);
177
        if (isset($changes['name'])) {
178
            $changeName = $this->conn->quoteIdentifier($changes['name'], true);
179
            $sql[] = 'ALTER TABLE ' . $this->conn->quoteIdentifier($name, true) . ' RENAME TO ' . $changeName;
180
        }
181
 
182
        return $sql;
183
    }
184
 
185
    /**
186
     * alter an existing table
187
     *
188
     * @param string $name         name of the table that is intended to be changed.
189
     * @param array $changes     associative array that contains the details of each type
190
     *                             of change that is intended to be performed. The types of
191
     *                             changes that are currently supported are defined as follows:
192
     *
193
     *                             name
194
     *
195
     *                                New name for the table.
196
     *
197
     *                            add
198
     *
199
     *                                Associative array with the names of fields to be added as
200
     *                                 indexes of the array. The value of each entry of the array
201
     *                                 should be set to another associative array with the properties
202
     *                                 of the fields to be added. The properties of the fields should
203
     *                                 be the same as defined by the Metabase parser.
204
     *
205
     *
206
     *                            remove
207
     *
208
     *                                Associative array with the names of fields to be removed as indexes
209
     *                                 of the array. Currently the values assigned to each entry are ignored.
210
     *                                 An empty array should be used for future compatibility.
211
     *
212
     *                            rename
213
     *
214
     *                                Associative array with the names of fields to be renamed as indexes
215
     *                                 of the array. The value of each entry of the array should be set to
216
     *                                 another associative array with the entry named name with the new
217
     *                                 field name and the entry named Declaration that is expected to contain
218
     *                                 the portion of the field declaration already in DBMS specific SQL code
219
     *                                 as it is used in the CREATE TABLE statement.
220
     *
221
     *                            change
222
     *
223
     *                                Associative array with the names of the fields to be changed as indexes
224
     *                                 of the array. Keep in mind that if it is intended to change either the
225
     *                                 name of a field and any other properties, the change array entries
226
     *                                 should have the new names of the fields as array indexes.
227
     *
228
     *                                The value of each entry of the array should be set to another associative
229
     *                                 array with the properties of the fields to that are meant to be changed as
230
     *                                 array entries. These entries should be assigned to the new values of the
231
     *                                 respective properties. The properties of the fields should be the same
232
     *                                 as defined by the Metabase parser.
233
     *
234
     *                            Example
235
     *                                array(
236
     *                                    'name' => 'userlist',
237
     *                                    'add' => array(
238
     *                                        'quota' => array(
239
     *                                            'type' => 'integer',
240
     *                                            'unsigned' => 1
241
     *                                        )
242
     *                                    ),
243
     *                                    'remove' => array(
244
     *                                        'file_limit' => array(),
245
     *                                        'time_limit' => array()
246
     *                                    ),
247
     *                                    'change' => array(
248
     *                                        'name' => array(
249
     *                                            'length' => '20',
250
     *                                            'definition' => array(
251
     *                                                'type' => 'text',
252
     *                                                'length' => 20,
253
     *                                            ),
254
     *                                        )
255
     *                                    ),
256
     *                                    'rename' => array(
257
     *                                        'sex' => array(
258
     *                                            'name' => 'gender',
259
     *                                            'definition' => array(
260
     *                                                'type' => 'text',
261
     *                                                'length' => 1,
262
     *                                                'default' => 'M',
263
     *                                            ),
264
     *                                        )
265
     *                                    )
266
     *                                )
267
     *
268
     * @param boolean $check     indicates whether the function should just check if the DBMS driver
269
     *                             can perform the requested table alterations if the value is true or
270
     *                             actually perform them otherwise.
271
     * @throws Doctrine_Connection_Exception
272
     * @return boolean
273
     */
274
    public function alterTable($name, array $changes, $check = false)
275
    {
276
        $sql = $this->alterTableSql($name, $changes, $check);
277
        foreach ($sql as $query) {
278
            $this->conn->exec($query);
279
        }
280
        return true;
281
    }
282
 
283
    /**
284
     * return RDBMS specific create sequence statement
285
     *
286
     * @throws Doctrine_Connection_Exception     if something fails at database level
287
     * @param string    $seqName        name of the sequence to be created
288
     * @param string    $start          start value of the sequence; default is 1
289
     * @param array     $options  An associative array of table options:
290
     *                          array(
291
     *                              'comment' => 'Foo',
292
     *                              'charset' => 'utf8',
293
     *                              'collate' => 'utf8_unicode_ci',
294
     *                          );
295
     * @return string
296
     */
297
    public function createSequenceSql($sequenceName, $start = 1, array $options = array())
298
    {
299
        $sequenceName = $this->conn->quoteIdentifier($this->conn->formatter->getSequenceName($sequenceName), true);
300
        return 'CREATE SEQUENCE ' . $sequenceName . ' INCREMENT 1' .
301
                    ($start < 1 ? ' MINVALUE ' . $start : '') . ' START ' . $start;
302
    }
303
 
304
    /**
305
     * drop existing sequence
306
     *
307
     * @param string $sequenceName name of the sequence to be dropped
308
     */
309
    public function dropSequenceSql($sequenceName)
310
    {
311
        $sequenceName = $this->conn->quoteIdentifier($this->conn->formatter->getSequenceName($sequenceName), true);
312
        return 'DROP SEQUENCE ' . $sequenceName;
313
    }
314
 
315
    /**
316
     * Creates a table.
317
     *
318
     * @param unknown_type $name
319
     * @param array $fields
320
     * @param array $options
321
     * @return unknown
322
     */
323
    public function createTableSql($name, array $fields, array $options = array())
324
    {
325
        if ( ! $name) {
326
            throw new Doctrine_Export_Exception('no valid table name specified');
327
        }
328
 
329
        if (empty($fields)) {
330
            throw new Doctrine_Export_Exception('no fields specified for table ' . $name);
331
        }
332
 
333
        $queryFields = $this->getFieldDeclarationList($fields);
334
 
335
 
336
        if (isset($options['primary']) && ! empty($options['primary'])) {
337
            $keyColumns = array_values($options['primary']);
338
            $keyColumns = array_map(array($this->conn, 'quoteIdentifier'), $keyColumns);
339
            $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
340
        }
341
 
342
        $query = 'CREATE TABLE ' . $this->conn->quoteIdentifier($name, true) . ' (' . $queryFields;
343
 
344
        if ($check = $this->getCheckDeclaration($fields)) {
345
            $query .= ', ' . $check;
346
        }
347
 
348
        if (isset($options['checks']) && $check = $this->getCheckDeclaration($options['checks'])) {
349
            $query .= ', ' . $check;
350
        }
351
 
352
        $query .= ')';
353
 
354
        $sql[] = $query;
355
 
356
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
357
            foreach($options['indexes'] as $index => $definition) {
358
                $sql[] = $this->createIndexSql($name, $index, $definition);
359
            }
360
        }
361
 
362
        if (isset($options['foreignKeys'])) {
363
 
364
            foreach ((array) $options['foreignKeys'] as $k => $definition) {
365
                if (is_array($definition)) {
366
                    $sql[] = $this->createForeignKeySql($name, $definition);
367
                }
368
            }
369
        }
370
        if (isset($options['sequenceName'])) {
371
            $sql[] = $this->createSequenceSql($options['sequenceName']);
372
        }
373
        return $sql;
374
    }
375
 
376
     /**
377
     * Get the stucture of a field into an array.
378
     *
379
     * @param string    $table         name of the table on which the index is to be created
380
     * @param string    $name          name of the index to be created
381
     * @param array     $definition    associative array that defines properties of the index to be created.
382
     * @see Doctrine_Export::createIndex()
383
     * @return string
384
     */
385
    public function createIndexSql($table, $name, array $definition)
386
    {
387
		$query = parent::createIndexSql($table, $name, $definition);
388
		if (isset($definition['where'])) {
389
			return $query . ' WHERE ' . $definition['where'];
390
		}
391
        return $query;
392
    }
393
}