Rajout de doctrine/orm
[zf2.biz/galerie.git] / vendor / doctrine / dbal / lib / Doctrine / DBAL / Platforms / PostgreSqlPlatform.php
1 <?php
2 /*
3  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  *
15  * This software consists of voluntary contributions made by many individuals
16  * and is licensed under the MIT license. For more information, see
17  * <http://www.doctrine-project.org>.
18  */
19
20 namespace Doctrine\DBAL\Platforms;
21
22 use Doctrine\DBAL\Schema\TableDiff,
23     Doctrine\DBAL\Schema\Table;
24
25 /**
26  * PostgreSqlPlatform.
27  *
28  * @since 2.0
29  * @author Roman Borschel <roman@code-factory.org>
30  * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
31  * @author Benjamin Eberlei <kontakt@beberlei.de>
32  * @todo Rename: PostgreSQLPlatform
33  */
34 class PostgreSqlPlatform extends AbstractPlatform
35 {
36     /**
37      * {@inheritDoc}
38      */
39     public function getSubstringExpression($value, $from, $length = null)
40     {
41         if ($length === null) {
42             return 'SUBSTR(' . $value . ', ' . $from . ')';
43         }
44
45         return 'SUBSTR(' . $value . ', ' . $from . ', ' . $length . ')';
46     }
47
48     /**
49      * {@inheritDoc}
50      */
51     public function getNowExpression()
52     {
53         return 'LOCALTIMESTAMP(0)';
54     }
55
56     /**
57      * {@inheritDoc}
58      */
59     public function getRegexpExpression()
60     {
61         return 'SIMILAR TO';
62     }
63
64     /**
65      * {@inheritDoc}
66      */
67     public function getLocateExpression($str, $substr, $startPos = false)
68     {
69         if ($startPos !== false) {
70             $str = $this->getSubstringExpression($str, $startPos);
71
72             return 'CASE WHEN (POSITION('.$substr.' IN '.$str.') = 0) THEN 0 ELSE (POSITION('.$substr.' IN '.$str.') + '.($startPos-1).') END';
73         }
74
75         return 'POSITION('.$substr.' IN '.$str.')';
76     }
77
78     /**
79      * {@inheritDoc}
80      */
81     public function getDateDiffExpression($date1, $date2)
82     {
83         return '(DATE(' . $date1 . ')-DATE(' . $date2 . '))';
84     }
85
86     /**
87      * {@inheritDoc}
88      */
89     public function getDateAddDaysExpression($date, $days)
90     {
91         return "(" . $date ." + (" . $days . " || ' day')::interval)";
92     }
93
94     /**
95      * {@inheritDoc}
96      */
97     public function getDateSubDaysExpression($date, $days)
98     {
99         return "(" . $date ." - (" . $days . " || ' day')::interval)";
100     }
101
102     /**
103      * {@inheritDoc}
104      */
105     public function getDateAddMonthExpression($date, $months)
106     {
107         return "(" . $date ." + (" . $months . " || ' month')::interval)";
108     }
109
110     /**
111      * {@inheritDoc}
112      */
113     public function getDateSubMonthExpression($date, $months)
114     {
115         return "(" . $date ." - (" . $months . " || ' month')::interval)";
116     }
117
118     /**
119      * {@inheritDoc}
120      */
121     public function supportsSequences()
122     {
123         return true;
124     }
125
126     /**
127      * {@inheritDoc}
128      */
129     public function supportsSchemas()
130     {
131         return true;
132     }
133
134     /**
135      * {@inheritDoc}
136      */
137     public function supportsIdentityColumns()
138     {
139         return true;
140     }
141
142     /**
143      * {@inheritDoc}
144      */
145     public function supportsCommentOnStatement()
146     {
147         return true;
148     }
149
150     /**
151      * {@inheritDoc}
152      */
153     public function prefersSequences()
154     {
155         return true;
156     }
157
158     public function getListDatabasesSQL()
159     {
160         return 'SELECT datname FROM pg_database';
161     }
162
163     public function getListSequencesSQL($database)
164     {
165         return "SELECT
166                     c.relname, n.nspname AS schemaname
167                 FROM
168                    pg_class c, pg_namespace n
169                 WHERE relkind = 'S' AND n.oid = c.relnamespace AND
170                     (n.nspname NOT LIKE 'pg_%' AND n.nspname != 'information_schema')";
171     }
172
173     public function getListTablesSQL()
174     {
175         return "SELECT tablename AS table_name, schemaname AS schema_name
176                 FROM pg_tables WHERE schemaname NOT LIKE 'pg_%' AND schemaname != 'information_schema' AND tablename != 'geometry_columns' AND tablename != 'spatial_ref_sys'";
177     }
178
179     /**
180      * {@inheritDoc}
181      */
182     public function getListViewsSQL($database)
183     {
184         return 'SELECT viewname, definition FROM pg_views';
185     }
186
187     public function getListTableForeignKeysSQL($table, $database = null)
188     {
189         return "SELECT r.conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef
190                   FROM pg_catalog.pg_constraint r
191                   WHERE r.conrelid =
192                   (
193                       SELECT c.oid
194                       FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n
195                       WHERE " .$this->getTableWhereClause($table) ." AND n.oid = c.relnamespace
196                   )
197                   AND r.contype = 'f'";
198     }
199
200     public function getCreateViewSQL($name, $sql)
201     {
202         return 'CREATE VIEW ' . $name . ' AS ' . $sql;
203     }
204
205     public function getDropViewSQL($name)
206     {
207         return 'DROP VIEW '. $name;
208     }
209
210     public function getListTableConstraintsSQL($table)
211     {
212         return "SELECT
213                     relname
214                 FROM
215                     pg_class
216                 WHERE oid IN (
217                     SELECT indexrelid
218                     FROM pg_index, pg_class
219                     WHERE pg_class.relname = '$table'
220                         AND pg_class.oid = pg_index.indrelid
221                         AND (indisunique = 't' OR indisprimary = 't')
222                         )";
223     }
224
225     /**
226      * {@inheritDoc}
227      *
228      * @license New BSD License
229      * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
230      */
231     public function getListTableIndexesSQL($table, $currentDatabase = null)
232     {
233         return "SELECT relname, pg_index.indisunique, pg_index.indisprimary,
234                        pg_index.indkey, pg_index.indrelid
235                  FROM pg_class, pg_index
236                  WHERE oid IN (
237                     SELECT indexrelid
238                     FROM pg_index si, pg_class sc, pg_namespace sn
239                     WHERE " . $this->getTableWhereClause($table, 'sc', 'sn')." AND sc.oid=si.indrelid AND sc.relnamespace = sn.oid
240                  ) AND pg_index.indexrelid = oid";
241     }
242
243     /**
244      * @param string $table
245      * @param string $classAlias
246      * @param string $namespaceAlias
247      *
248      * @return string
249      */
250     private function getTableWhereClause($table, $classAlias = 'c', $namespaceAlias = 'n')
251     {
252         $whereClause = $namespaceAlias.".nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast') AND ";
253         if (strpos($table, ".") !== false) {
254             list($schema, $table) = explode(".", $table);
255             $schema = "'" . $schema . "'";
256         } else {
257             $schema = "ANY(string_to_array((select setting from pg_catalog.pg_settings where name = 'search_path'),','))";
258         }
259         $whereClause .= "$classAlias.relname = '" . $table . "' AND $namespaceAlias.nspname = $schema";
260
261         return $whereClause;
262     }
263
264     public function getListTableColumnsSQL($table, $database = null)
265     {
266         return "SELECT
267                     a.attnum,
268                     a.attname AS field,
269                     t.typname AS type,
270                     format_type(a.atttypid, a.atttypmod) AS complete_type,
271                     (SELECT t1.typname FROM pg_catalog.pg_type t1 WHERE t1.oid = t.typbasetype) AS domain_type,
272                     (SELECT format_type(t2.typbasetype, t2.typtypmod) FROM pg_catalog.pg_type t2
273                      WHERE t2.typtype = 'd' AND t2.typname = format_type(a.atttypid, a.atttypmod)) AS domain_complete_type,
274                     a.attnotnull AS isnotnull,
275                     (SELECT 't'
276                      FROM pg_index
277                      WHERE c.oid = pg_index.indrelid
278                         AND pg_index.indkey[0] = a.attnum
279                         AND pg_index.indisprimary = 't'
280                     ) AS pri,
281                     (SELECT pg_attrdef.adsrc
282                      FROM pg_attrdef
283                      WHERE c.oid = pg_attrdef.adrelid
284                         AND pg_attrdef.adnum=a.attnum
285                     ) AS default,
286                     (SELECT pg_description.description
287                         FROM pg_description WHERE pg_description.objoid = c.oid AND a.attnum = pg_description.objsubid
288                     ) AS comment
289                     FROM pg_attribute a, pg_class c, pg_type t, pg_namespace n
290                     WHERE ".$this->getTableWhereClause($table, 'c', 'n') ."
291                         AND a.attnum > 0
292                         AND a.attrelid = c.oid
293                         AND a.atttypid = t.oid
294                         AND n.oid = c.relnamespace
295                     ORDER BY a.attnum";
296     }
297
298     /**
299      * {@inheritDoc}
300      */
301     public function getCreateDatabaseSQL($name)
302     {
303         return 'CREATE DATABASE ' . $name;
304     }
305
306     /**
307      * {@inheritDoc}
308      */
309     public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey)
310     {
311         $query = '';
312
313         if ($foreignKey->hasOption('match')) {
314             $query .= ' MATCH ' . $foreignKey->getOption('match');
315         }
316
317         $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
318
319         if ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false) {
320             $query .= ' DEFERRABLE';
321         } else {
322             $query .= ' NOT DEFERRABLE';
323         }
324
325         if ($foreignKey->hasOption('feferred') && $foreignKey->getOption('feferred') !== false) {
326             $query .= ' INITIALLY DEFERRED';
327         } else {
328             $query .= ' INITIALLY IMMEDIATE';
329         }
330
331         return $query;
332     }
333
334     /**
335      * {@inheritDoc}
336      */
337     public function getAlterTableSQL(TableDiff $diff)
338     {
339         $sql = array();
340         $commentsSQL = array();
341         $columnSql = array();
342
343         foreach ($diff->addedColumns as $column) {
344             if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) {
345                 continue;
346             }
347
348             $query = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
349             $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
350             if ($comment = $this->getColumnComment($column)) {
351                 $commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment);
352             }
353         }
354
355         foreach ($diff->removedColumns as $column) {
356             if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) {
357                 continue;
358             }
359
360             $query = 'DROP ' . $column->getQuotedName($this);
361             $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
362         }
363
364         foreach ($diff->changedColumns as $columnDiff) {
365             /** @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */
366             if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) {
367                 continue;
368             }
369
370             $oldColumnName = $columnDiff->oldColumnName;
371             $column = $columnDiff->column;
372
373             if ($columnDiff->hasChanged('type')) {
374                 $type = $column->getType();
375
376                 // here was a server version check before, but DBAL API does not support this anymore.
377                 $query = 'ALTER ' . $oldColumnName . ' TYPE ' . $type->getSqlDeclaration($column->toArray(), $this);
378                 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
379             }
380
381             if ($columnDiff->hasChanged('default')) {
382                 $query = 'ALTER ' . $oldColumnName . ' SET ' . $this->getDefaultValueDeclarationSQL($column->toArray());
383                 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
384             }
385
386             if ($columnDiff->hasChanged('notnull')) {
387                 $query = 'ALTER ' . $oldColumnName . ' ' . ($column->getNotNull() ? 'SET' : 'DROP') . ' NOT NULL';
388                 $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
389             }
390
391             if ($columnDiff->hasChanged('autoincrement')) {
392                 if ($column->getAutoincrement()) {
393                     // add autoincrement
394                     $seqName = $diff->name . '_' . $oldColumnName . '_seq';
395
396                     $sql[] = "CREATE SEQUENCE " . $seqName;
397                     $sql[] = "SELECT setval('" . $seqName . "', (SELECT MAX(" . $oldColumnName . ") FROM " . $diff->name . "))";
398                     $query = "ALTER " . $oldColumnName . " SET DEFAULT nextval('" . $seqName . "')";
399                     $sql[] = "ALTER TABLE " . $diff->name . " " . $query;
400                 } else {
401                     // Drop autoincrement, but do NOT drop the sequence. It might be re-used by other tables or have
402                     $query = "ALTER " . $oldColumnName . " " . "DROP DEFAULT";
403                     $sql[] = "ALTER TABLE " . $diff->name . " " . $query;
404                 }
405             }
406
407             if ($columnDiff->hasChanged('comment') && $comment = $this->getColumnComment($column)) {
408                 $commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment);
409             }
410         }
411
412         foreach ($diff->renamedColumns as $oldColumnName => $column) {
413             if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) {
414                 continue;
415             }
416
417             $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME COLUMN ' . $oldColumnName . ' TO ' . $column->getQuotedName($this);
418         }
419
420         $tableSql = array();
421
422         if ( ! $this->onSchemaAlterTable($diff, $tableSql)) {
423             if ($diff->newName !== false) {
424                 $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME TO ' . $diff->newName;
425             }
426
427             $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff), $commentsSQL);
428         }
429
430         return array_merge($sql, $tableSql, $columnSql);
431     }
432
433     /**
434      * {@inheritDoc}
435      */
436     public function getCreateSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
437     {
438         return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) .
439                ' INCREMENT BY ' . $sequence->getAllocationSize() .
440                ' MINVALUE ' . $sequence->getInitialValue() .
441                ' START ' . $sequence->getInitialValue();
442     }
443
444     /**
445      * {@inheritDoc}
446      */
447     public function getAlterSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
448     {
449         return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) .
450                ' INCREMENT BY ' . $sequence->getAllocationSize();
451     }
452
453     /**
454      * {@inheritDoc}
455      */
456     public function getDropSequenceSQL($sequence)
457     {
458         if ($sequence instanceof \Doctrine\DBAL\Schema\Sequence) {
459             $sequence = $sequence->getQuotedName($this);
460         }
461         return 'DROP SEQUENCE ' . $sequence;
462     }
463
464     /**
465      * {@inheritDoc}
466      */
467     public function getDropForeignKeySQL($foreignKey, $table)
468     {
469         return $this->getDropConstraintSQL($foreignKey, $table);
470     }
471
472     /**
473      * {@inheritDoc}
474      */
475     protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
476     {
477         $queryFields = $this->getColumnDeclarationListSQL($columns);
478
479         if (isset($options['primary']) && ! empty($options['primary'])) {
480             $keyColumns = array_unique(array_values($options['primary']));
481             $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
482         }
483
484         $query = 'CREATE TABLE ' . $tableName . ' (' . $queryFields . ')';
485
486         $sql[] = $query;
487
488         if (isset($options['indexes']) && ! empty($options['indexes'])) {
489             foreach ($options['indexes'] as $index) {
490                 $sql[] = $this->getCreateIndexSQL($index, $tableName);
491             }
492         }
493
494         if (isset($options['foreignKeys'])) {
495             foreach ((array) $options['foreignKeys'] as $definition) {
496                 $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
497             }
498         }
499
500         return $sql;
501     }
502
503     /**
504      * {@inheritDoc}
505      *
506      * Postgres wants boolean values converted to the strings 'true'/'false'.
507      */
508     public function convertBooleans($item)
509     {
510         if (is_array($item)) {
511             foreach ($item as $key => $value) {
512                 if (is_bool($value) || is_numeric($item)) {
513                     $item[$key] = ($value) ? 'true' : 'false';
514                 }
515             }
516         } else {
517            if (is_bool($item) || is_numeric($item)) {
518                $item = ($item) ? 'true' : 'false';
519            }
520         }
521
522         return $item;
523     }
524
525     public function getSequenceNextValSQL($sequenceName)
526     {
527         return "SELECT NEXTVAL('" . $sequenceName . "')";
528     }
529
530     /**
531      * {@inheritDoc}
532      */
533     public function getSetTransactionIsolationSQL($level)
534     {
535         return 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL '
536                 . $this->_getTransactionIsolationLevelSQL($level);
537     }
538
539     /**
540      * {@inheritDoc}
541      */
542     public function getBooleanTypeDeclarationSQL(array $field)
543     {
544         return 'BOOLEAN';
545     }
546
547     /**
548      * {@inheritDoc}
549      */
550     public function getIntegerTypeDeclarationSQL(array $field)
551     {
552         if ( ! empty($field['autoincrement'])) {
553             return 'SERIAL';
554         }
555
556         return 'INT';
557     }
558
559     /**
560      * {@inheritDoc}
561      */
562     public function getBigIntTypeDeclarationSQL(array $field)
563     {
564         if ( ! empty($field['autoincrement'])) {
565             return 'BIGSERIAL';
566         }
567         return 'BIGINT';
568     }
569
570     /**
571      * {@inheritDoc}
572      */
573     public function getSmallIntTypeDeclarationSQL(array $field)
574     {
575         return 'SMALLINT';
576     }
577
578     /**
579      * {@inheritDoc}
580      */
581     public function getGuidTypeDeclarationSQL(array $field)
582     {
583         return 'UUID';
584     }
585
586     /**
587      * {@inheritDoc}
588      */
589     public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
590     {
591         return 'TIMESTAMP(0) WITHOUT TIME ZONE';
592     }
593
594     /**
595      * {@inheritDoc}
596      */
597     public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
598     {
599         return 'TIMESTAMP(0) WITH TIME ZONE';
600     }
601
602     /**
603      * {@inheritDoc}
604      */
605     public function getDateTypeDeclarationSQL(array $fieldDeclaration)
606     {
607         return 'DATE';
608     }
609
610     /**
611      * {@inheritDoc}
612      */
613     public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
614     {
615         return 'TIME(0) WITHOUT TIME ZONE';
616     }
617
618     /**
619      * {@inheritDoc}
620      */
621     protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
622     {
623         return '';
624     }
625
626     /**
627      * {@inheritDoc}
628      */
629     protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
630     {
631         return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
632                 : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)');
633     }
634
635     /**
636      * {@inheritDoc}
637      */
638     public function getClobTypeDeclarationSQL(array $field)
639     {
640         return 'TEXT';
641     }
642
643     /**
644      * {@inheritDoc}
645      */
646     public function getName()
647     {
648         return 'postgresql';
649     }
650
651     /**
652      * {@inheritDoc}
653      *
654      * PostgreSQL returns all column names in SQL result sets in lowercase.
655      */
656     public function getSQLResultCasing($column)
657     {
658         return strtolower($column);
659     }
660
661     /**
662      * {@inheritDoc}
663      */
664     public function getDateTimeTzFormatString()
665     {
666         return 'Y-m-d H:i:sO';
667     }
668
669     /**
670      * {@inheritDoc}
671      */
672     public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName)
673     {
674         return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (DEFAULT)';
675     }
676
677     /**
678      * {@inheritDoc}
679      */
680     public function getTruncateTableSQL($tableName, $cascade = false)
681     {
682         return 'TRUNCATE '.$tableName.' '.(($cascade)?'CASCADE':'');
683     }
684
685     /**
686      * {@inheritDoc}
687      */
688     public function getReadLockSQL()
689     {
690         return 'FOR SHARE';
691     }
692
693     /**
694      * {@inheritDoc}
695      */
696     protected function initializeDoctrineTypeMappings()
697     {
698         $this->doctrineTypeMapping = array(
699             'smallint'      => 'smallint',
700             'int2'          => 'smallint',
701             'serial'        => 'integer',
702             'serial4'       => 'integer',
703             'int'           => 'integer',
704             'int4'          => 'integer',
705             'integer'       => 'integer',
706             'bigserial'     => 'bigint',
707             'serial8'       => 'bigint',
708             'bigint'        => 'bigint',
709             'int8'          => 'bigint',
710             'bool'          => 'boolean',
711             'boolean'       => 'boolean',
712             'text'          => 'text',
713             'varchar'       => 'string',
714             'interval'      => 'string',
715             '_varchar'      => 'string',
716             'char'          => 'string',
717             'bpchar'        => 'string',
718             'date'          => 'date',
719             'datetime'      => 'datetime',
720             'timestamp'     => 'datetime',
721             'timestamptz'   => 'datetimetz',
722             'time'          => 'time',
723             'timetz'        => 'time',
724             'float'         => 'float',
725             'float4'        => 'float',
726             'float8'        => 'float',
727             'double'        => 'float',
728             'double precision' => 'float',
729             'real'          => 'float',
730             'decimal'       => 'decimal',
731             'money'         => 'decimal',
732             'numeric'       => 'decimal',
733             'year'          => 'date',
734             'uuid'          => 'guid',
735             'bytea'         => 'blob',
736         );
737     }
738
739     /**
740      * {@inheritDoc}
741      */
742     public function getVarcharMaxLength()
743     {
744         return 65535;
745     }
746
747     /**
748      * {@inheritDoc}
749      */
750     protected function getReservedKeywordsClass()
751     {
752         return 'Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords';
753     }
754
755     /**
756      * {@inheritDoc}
757      */
758     public function getBlobTypeDeclarationSQL(array $field)
759     {
760         return 'BYTEA';
761     }
762 }