PostgreSqlPlatform.php 24 KB
Newer Older
1
<?php
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the LGPL. For more information, see
 * <http://www.doctrine-project.org>.
 */
19

20
namespace Doctrine\DBAL\Platforms;
21

22 23
use Doctrine\DBAL\Schema\TableDiff,
    Doctrine\DBAL\Schema\Table;
24

25 26 27 28 29 30
/**
 * PostgreSqlPlatform.
 *
 * @since 2.0
 * @author Roman Borschel <roman@code-factory.org>
 * @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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
{
    /**
     * Returns part of a string.
     *
     * Note: Not SQL92, but common functionality.
     *
     * @param string $value the target $value the string or the string column.
     * @param int $from extract from this characeter.
     * @param int $len extract this amount of characters.
     * @return string sql that extracts part of a string.
     * @override
     */
    public function getSubstringExpression($value, $from, $len = null)
    {
        if ($len === null) {
            return 'SUBSTR(' . $value . ', ' . $from . ')';
        } else {
            return 'SUBSTR(' . $value . ', ' . $from . ', ' . $len . ')';
        }
    }

    /**
     * Returns the SQL string to return the current system date and time.
     *
     * @return string
     */
    public function getNowExpression()
    {
        return 'LOCALTIMESTAMP(0)';
    }

    /**
     * regexp
     *
     * @return string           the regular expression operator
     * @override
     */
    public function getRegexpExpression()
    {
        return 'SIMILAR TO';
    }
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93

    /**
     * returns the position of the first occurrence of substring $substr in string $str
     *
     * @param string $substr    literal string to find
     * @param string $str       literal string
     * @param int    $pos       position to start at, beginning of string by default
     * @return integer
     */
    public function getLocateExpression($str, $substr, $startPos = false)
    {
        if ($startPos !== false) {
            $str = $this->getSubstringExpression($str, $startPos);
            return 'CASE WHEN (POSITION('.$substr.' IN '.$str.') = 0) THEN 0 ELSE (POSITION('.$substr.' IN '.$str.') + '.($startPos-1).') END';
        } else {
            return 'POSITION('.$substr.' IN '.$str.')';
        }
    }
94 95 96

    public function getDateDiffExpression($date1, $date2)
    {
97
        return '(DATE(' . $date1 . ')-DATE(' . $date2 . '))';
98 99 100 101
    }

    public function getDateAddDaysExpression($date, $days)
    {
102
        return "(" . $date . "+ interval '" . $days . " day')";
103 104 105 106
    }

    public function getDateSubDaysExpression($date, $days)
    {
107
        return "(" . $date . "- interval '" . $days . " day')";
108 109 110 111
    }

    public function getDateAddMonthExpression($date, $months)
    {
112
        return "(" . $date . "+ interval '" . $months . " month')";
113 114 115 116
    }

    public function getDateSubMonthExpression($date, $months)
    {
117
        return "(" . $date . "- interval '" . $months . " month')";
118
    }
119 120 121 122 123 124 125 126
    
    /**
     * parses a literal boolean value and returns
     * proper sql equivalent
     *
     * @param string $value     boolean value to be parsed
     * @return string           parsed boolean value
     */
127
    /*public function parseBoolean($value)
128 129
    {
        return $value;
130
    }*/
romanb's avatar
romanb committed
131 132 133 134 135 136 137 138 139 140 141 142
    
    /**
     * Whether the platform supports sequences.
     * Postgres has native support for sequences.
     *
     * @return boolean
     */
    public function supportsSequences()
    {
        return true;
    }
    
143 144 145 146 147 148 149 150 151 152
    /**
     * Whether the platform supports database schemas.
     * 
     * @return boolean
     */
    public function supportsSchemas()
    {
        return true;
    }
    
romanb's avatar
romanb committed
153 154 155 156 157 158 159 160 161 162
    /**
     * Whether the platform supports identity columns.
     * Postgres supports these through the SERIAL keyword.
     *
     * @return boolean
     */
    public function supportsIdentityColumns()
    {
        return true;
    }
163 164 165 166 167

    public function supportsCommentOnStatement()
    {
        return true;
    }
romanb's avatar
romanb committed
168 169 170 171 172 173 174 175 176 177
    
    /**
     * Whether the platform prefers sequences for ID generation.
     *
     * @return boolean
     */
    public function prefersSequences()
    {
        return true;
    }
178

179
    public function getListDatabasesSQL()
180 181 182
    {
        return 'SELECT datname FROM pg_database';
    }
183

184
    public function getListSequencesSQL($database)
185 186
    {
        return "SELECT
187
                    c.relname, n.nspname AS schemaname
188
                FROM
189 190 191
                   pg_class c, pg_namespace n
                WHERE relkind = 'S' AND n.oid = c.relnamespace AND 
                    (n.nspname NOT LIKE 'pg_%' AND n.nspname != 'information_schema')";
192
    }
193

194
    public function getListTablesSQL()
195
    {
196 197
        return "SELECT tablename AS table_name, schemaname AS schema_name
                FROM pg_tables WHERE schemaname NOT LIKE 'pg_%' AND schemaname != 'information_schema'";
198
    }
199

200
    public function getListViewsSQL($database)
201
    {
202
        return 'SELECT viewname, definition FROM pg_views';
203
    }
204

205
    public function getListTableForeignKeysSQL($table, $database = null)
206
    {
207
        return "SELECT r.conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef
208 209 210 211
                  FROM pg_catalog.pg_constraint r
                  WHERE r.conrelid =
                  (
                      SELECT c.oid
212 213 214
                      FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n
                      WHERE " .$this->getTableWhereClause($table) ."
                        AND n.oid = c.relnamespace
215 216 217 218
                  )
                  AND r.contype = 'f'";
    }

219
    public function getCreateViewSQL($name, $sql)
220 221 222 223
    {
        return 'CREATE VIEW ' . $name . ' AS ' . $sql;
    }

224
    public function getDropViewSQL($name)
225 226 227 228
    {
        return 'DROP VIEW '. $name;
    }

229
    public function getListTableConstraintsSQL($table)
230 231 232 233 234 235 236 237
    {
        return "SELECT
                    relname
                FROM
                    pg_class
                WHERE oid IN (
                    SELECT indexrelid
                    FROM pg_index, pg_class
238
                    WHERE pg_class.relname = '$table'
239 240 241 242
                        AND pg_class.oid = pg_index.indrelid
                        AND (indisunique = 't' OR indisprimary = 't')
                        )";
    }
243

244 245 246 247 248 249
    /**
     * @license New BSD License
     * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
     * @param  string $table
     * @return string
     */
250
    public function getListTableIndexesSQL($table, $currentDatabase = null)
251
    {
252 253 254 255
        return "SELECT relname, pg_index.indisunique, pg_index.indisprimary,
                       pg_index.indkey, pg_index.indrelid
                 FROM pg_class, pg_index
                 WHERE oid IN (
256
                    SELECT indexrelid
257 258
                    FROM pg_index si, pg_class sc, pg_namespace sn
                    WHERE " . $this->getTableWhereClause($table, 'sc', 'sn')." AND sc.oid=si.indrelid AND sc.relnamespace = sn.oid
259
                 ) AND pg_index.indexrelid = oid";
260
    }
261

262 263 264 265 266 267 268 269 270 271 272 273
    private function getTableWhereClause($table, $classAlias = 'c', $namespaceAlias = 'n')
    {
        $whereClause = "";
        if (strpos($table, ".") !== false) {
            list($schema, $table) = explode(".", $table);
            $whereClause = "$classAlias.relname = '" . $table . "' AND $namespaceAlias.nspname = '" . $schema . "'";
        } else {
            $whereClause = "$classAlias.relname = '" . $table . "'";
        }
        return $whereClause;
    }

274
    public function getListTableColumnsSQL($table, $database = null)
275 276 277 278 279 280
    {
        return "SELECT
                    a.attnum,
                    a.attname AS field,
                    t.typname AS type,
                    format_type(a.atttypid, a.atttypmod) AS complete_type,
281 282 283
                    (SELECT t1.typname FROM pg_catalog.pg_type t1 WHERE t1.oid = t.typbasetype) AS domain_type,
                    (SELECT format_type(t2.typbasetype, t2.typtypmod) FROM pg_catalog.pg_type t2
                     WHERE t2.typtype = 'd' AND t2.typname = format_type(a.atttypid, a.atttypmod)) AS domain_complete_type,
284 285 286 287 288 289 290 291 292 293 294
                    a.attnotnull AS isnotnull,
                    (SELECT 't'
                     FROM pg_index
                     WHERE c.oid = pg_index.indrelid
                        AND pg_index.indkey[0] = a.attnum
                        AND pg_index.indisprimary = 't'
                    ) AS pri,
                    (SELECT pg_attrdef.adsrc
                     FROM pg_attrdef
                     WHERE c.oid = pg_attrdef.adrelid
                        AND pg_attrdef.adnum=a.attnum
295 296
                    ) AS default,
                    (SELECT pg_description.description
297
                        FROM pg_description WHERE pg_description.objoid = c.oid AND a.attnum = pg_description.objsubid
298 299
                    ) AS comment
                    FROM pg_attribute a, pg_class c, pg_type t, pg_namespace n
300
                    WHERE ".$this->getTableWhereClause($table, 'c', 'n') ."
301 302 303
                        AND a.attnum > 0
                        AND a.attrelid = c.oid
                        AND a.atttypid = t.oid
304
                        AND n.oid = c.relnamespace
305 306 307 308 309 310 311 312 313 314 315
                    ORDER BY a.attnum";
    }
    
    /**
     * create a new database
     *
     * @param string $name name of the database that should be created
     * @throws PDOException
     * @return void
     * @override
     */
316
    public function getCreateDatabaseSQL($name)
317
    {
318
        return 'CREATE DATABASE ' . $name;
319
    }
320

321 322 323 324 325 326 327
    /**
     * drop an existing database
     *
     * @param string $name name of the database that should be dropped
     * @throws PDOException
     * @access public
     */
328
    public function getDropDatabaseSQL($name)
329
    {
330
        return 'DROP DATABASE ' . $name;
331
    }
332

333 334 335 336
    /**
     * Return the FOREIGN KEY query section dealing with non-standard options
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
     *
337
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey         foreign key definition
338 339 340
     * @return string
     * @override
     */
341
    public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey)
342 343
    {
        $query = '';
344 345
        if ($foreignKey->hasOption('match')) {
            $query .= ' MATCH ' . $foreignKey->getOption('match');
346
        }
347
        $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey);
348
        if ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false) {
349 350 351 352
            $query .= ' DEFERRABLE';
        } else {
            $query .= ' NOT DEFERRABLE';
        }
353
        if ($foreignKey->hasOption('feferred') && $foreignKey->getOption('feferred') !== false) {
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
            $query .= ' INITIALLY DEFERRED';
        } else {
            $query .= ' INITIALLY IMMEDIATE';
        }
        return $query;
    }
    
    /**
     * generates the sql for altering an existing table on postgresql
     *
     * @param string $name          name of the table that is intended to be changed.
     * @param array $changes        associative array that contains the details of each type      *
     * @param boolean $check        indicates whether the function should just check if the DBMS driver
     *                              can perform the requested table alterations if the value is true or
     *                              actually perform them otherwise.
     * @see Doctrine_Export::alterTable()
     * @return array
     * @override
     */
373
    public function getAlterTableSQL(TableDiff $diff)
374
    {
375
        $sql = array();
376
        $commentsSQL = array();
377 378

        foreach ($diff->addedColumns as $column) {
379
            $query = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray());
380
            $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
381 382
            if ($comment = $this->getColumnComment($column)) {
                $commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment);
383
            }
384 385
        }

386
        foreach ($diff->removedColumns as $column) {
387
            $query = 'DROP ' . $column->getQuotedName($this);
388
            $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
389 390
        }

391 392 393 394 395 396
        foreach ($diff->changedColumns AS $columnDiff) {
            $oldColumnName = $columnDiff->oldColumnName;
            $column = $columnDiff->column;
            
            if ($columnDiff->hasChanged('type')) {
                $type = $column->getType();
397

398 399 400
                // here was a server version check before, but DBAL API does not support this anymore.
                $query = 'ALTER ' . $oldColumnName . ' TYPE ' . $type->getSqlDeclaration($column->toArray(), $this);
                $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
401
            }
402
            if ($columnDiff->hasChanged('default')) {
403
                $query = 'ALTER ' . $oldColumnName . ' SET ' . $this->getDefaultValueDeclarationSQL($column->toArray());
404
                $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
405
            }
406 407 408
            if ($columnDiff->hasChanged('notnull')) {
                $query = 'ALTER ' . $oldColumnName . ' ' . ($column->getNotNull() ? 'SET' : 'DROP') . ' NOT NULL';
                $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query;
409
            }
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
            if ($columnDiff->hasChanged('autoincrement')) {
                if ($column->getAutoincrement()) {
                    // add autoincrement
                    $seqName = $diff->name . '_' . $oldColumnName . '_seq';

                    $sql[] = "CREATE SEQUENCE " . $seqName;
                    $sql[] = "SELECT setval('" . $seqName . "', (SELECT MAX(" . $oldColumnName . ") FROM " . $diff->name . "))";
                    $query = "ALTER " . $oldColumnName . " SET DEFAULT nextval('" . $seqName . "')";
                    $sql[] = "ALTER TABLE " . $diff->name . " " . $query;
                } else {
                    // Drop autoincrement, but do NOT drop the sequence. It might be re-used by other tables or have
                    $query = "ALTER " . $oldColumnName . " " . "DROP DEFAULT";
                    $sql[] = "ALTER TABLE " . $diff->name . " " . $query;
                }
            }
425 426
            if ($columnDiff->hasChanged('comment') && $comment = $this->getColumnComment($column)) {
                $commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment);
427
            }
428 429
        }

430
        foreach ($diff->renamedColumns as $oldColumnName => $column) {
431
            $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME COLUMN ' . $oldColumnName . ' TO ' . $column->getQuotedName($this);
432 433
        }

434 435
        if ($diff->newName !== false) {
            $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME TO ' . $diff->newName;
436 437
        }

438
        return array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff), $commentsSQL);
439 440 441
    }
    
    /**
442 443 444
     * Gets the SQL to create a sequence on this platform.
     *
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
445
     * @return string
446
     */
447
    public function getCreateSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
448
    {
449
        return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) .
450
               ' INCREMENT BY ' . $sequence->getAllocationSize() .
451
               ' MINVALUE ' . $sequence->getInitialValue() .
452
               ' START ' . $sequence->getInitialValue();
453 454
    }
    
455 456 457 458 459 460
    public function getAlterSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence)
    {
        return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . 
               ' INCREMENT BY ' . $sequence->getAllocationSize();
    }
    
461
    /**
462 463 464
     * Drop existing sequence
     * @param  \Doctrine\DBAL\Schema\Sequence $sequence
     * @return string
465
     */
466
    public function getDropSequenceSQL($sequence)
467
    {
468
        if ($sequence instanceof \Doctrine\DBAL\Schema\Sequence) {
469
            $sequence = $sequence->getQuotedName($this);
470 471
        }
        return 'DROP SEQUENCE ' . $sequence;
472
    }
473 474 475 476 477 478

    /**
     * @param  ForeignKeyConstraint|string $foreignKey
     * @param  Table|string $table
     * @return string
     */
479
    public function getDropForeignKeySQL($foreignKey, $table)
480
    {
481
        return $this->getDropConstraintSQL($foreignKey, $table);
482
    }
483 484 485 486
    
    /**
     * Gets the SQL used to create a table.
     *
487 488
     * @param unknown_type $tableName
     * @param array $columns
489 490 491
     * @param array $options
     * @return unknown
     */
492
    protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
493
    {
494
        $queryFields = $this->getColumnDeclarationListSQL($columns);
495 496

        if (isset($options['primary']) && ! empty($options['primary'])) {
497
            $keyColumns = array_unique(array_values($options['primary']));
498 499 500
            $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')';
        }

501
        $query = 'CREATE TABLE ' . $tableName . ' (' . $queryFields . ')';
502 503 504 505

        $sql[] = $query;

        if (isset($options['indexes']) && ! empty($options['indexes'])) {
506
            foreach ($options['indexes'] AS $index) {
507
                $sql[] = $this->getCreateIndexSQL($index, $tableName);
508 509 510 511
            }
        }

        if (isset($options['foreignKeys'])) {
512
            foreach ((array) $options['foreignKeys'] as $definition) {
513
                $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
            }
        }

        return $sql;
    }
    
    /**
     * Postgres wants boolean values converted to the strings 'true'/'false'.
     *
     * @param array $item
     * @override
     */
    public function convertBooleans($item)
    {
        if (is_array($item)) {
            foreach ($item as $key => $value) {
                if (is_bool($value) || is_numeric($item)) {
                    $item[$key] = ($value) ? 'true' : 'false';
                }
            }
        } else {
           if (is_bool($item) || is_numeric($item)) {
               $item = ($item) ? 'true' : 'false';
           }
        }
        return $item;
    }
541

542
    public function getSequenceNextValSQL($sequenceName)
543 544 545
    {
        return "SELECT NEXTVAL('" . $sequenceName . "')";
    }
546

547
    public function getSetTransactionIsolationSQL($level)
romanb's avatar
romanb committed
548 549
    {
        return 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL '
550
                . $this->_getTransactionIsolationLevelSQL($level);
romanb's avatar
romanb committed
551
    }
552 553 554 555
    
    /**
     * @override
     */
556
    public function getBooleanTypeDeclarationSQL(array $field)
557 558 559
    {
        return 'BOOLEAN';
    }
560 561 562 563

    /**
     * @override
     */
564
    public function getIntegerTypeDeclarationSQL(array $field)
565 566 567 568
    {
        if ( ! empty($field['autoincrement'])) {
            return 'SERIAL';
        }
569
        
570 571 572 573 574 575
        return 'INT';
    }

    /**
     * @override
     */
576
    public function getBigIntTypeDeclarationSQL(array $field)
577 578 579 580 581 582 583 584 585 586
    {
        if ( ! empty($field['autoincrement'])) {
            return 'BIGSERIAL';
        }
        return 'BIGINT';
    }

    /**
     * @override
     */
587
    public function getSmallIntTypeDeclarationSQL(array $field)
588 589 590 591
    {
        return 'SMALLINT';
    }

592 593 594
    /**
     * @override
     */
595
    public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
596 597 598 599 600 601 602
    {
        return 'TIMESTAMP(0) WITHOUT TIME ZONE';
    }

    /**
     * @override
     */
603
    public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
604
    {
605 606 607 608 609 610
        return 'TIMESTAMP(0) WITH TIME ZONE';
    }
    
    /**
     * @override
     */
611
    public function getDateTypeDeclarationSQL(array $fieldDeclaration)
612 613
    {
        return 'DATE';
614 615
    }

616 617 618
    /**
     * @override
     */
619
    public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
620
    {
621
        return 'TIME(0) WITHOUT TIME ZONE';
622 623
    }

624 625 626
    /**
     * @override
     */
627
    protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef)
628 629 630 631 632 633 634 635 636 637
    {
        return '';
    }

    /**
     * Gets the SQL snippet used to declare a VARCHAR column on the MySql platform.
     *
     * @params array $field
     * @override
     */
638
    protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
639 640
    {
        return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
641
                : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)');
642
    }
643 644
    
    /** @override */
645
    public function getClobTypeDeclarationSQL(array $field)
646 647 648
    {
        return 'TEXT';
    }
649 650 651 652 653 654 655 656 657 658

    /**
     * Get the platform name for this instance
     *
     * @return string
     */
    public function getName()
    {
        return 'postgresql';
    }
659
    
660 661 662 663 664 665 666 667
    /**
     * Gets the character casing of a column in an SQL result set.
     * 
     * PostgreSQL returns all column names in SQL result sets in lowercase.
     * 
     * @param string $column The column name for which to get the correct character casing.
     * @return string The column name in the character casing used in SQL result sets.
     */
668
    public function getSQLResultCasing($column)
669 670 671
    {
        return strtolower($column);
    }
672
    
673
    public function getDateTimeTzFormatString()
674
    {
675 676
        return 'Y-m-d H:i:sO';
    }
677 678 679 680 681 682 683 684

    /**
     * Get the insert sql for an empty insert statement
     *
     * @param string $tableName 
     * @param string $identifierColumnName 
     * @return string $sql
     */
685
    public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName)
686 687 688
    {
        return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (DEFAULT)';
    }
689 690 691 692

    /**
     * @inheritdoc
     */
693
    public function getTruncateTableSQL($tableName, $cascade = false)
694
    {
695
        return 'TRUNCATE '.$tableName.' '.(($cascade)?'CASCADE':'');
696
    }
697 698 699 700 701

    public function getReadLockSQL()
    {
        return 'FOR SHARE';
    }
702 703 704 705

    protected function initializeDoctrineTypeMappings()
    {
        $this->doctrineTypeMapping = array(
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
            'smallint'      => 'smallint',
            'int2'          => 'smallint',
            'serial'        => 'integer',
            'serial4'       => 'integer',
            'int'           => 'integer',
            'int4'          => 'integer',
            'integer'       => 'integer',
            'bigserial'     => 'bigint',
            'serial8'       => 'bigint',
            'bigint'        => 'bigint',
            'int8'          => 'bigint',
            'bool'          => 'boolean',
            'boolean'       => 'boolean',
            'text'          => 'text',
            'varchar'       => 'string',
            'interval'      => 'string',
            '_varchar'      => 'string',
            'char'          => 'string',
            'bpchar'        => 'string',
            'date'          => 'date',
            'datetime'      => 'datetime',
            'timestamp'     => 'datetime',
            'timestamptz'   => 'datetimetz',
            'time'          => 'time',
            'timetz'        => 'time',
            'float'         => 'float',
            'float4'        => 'float',
            'float8'        => 'float',
            'double'        => 'float',
            'double precision' => 'float',
            'real'          => 'float',
            'decimal'       => 'decimal',
            'money'         => 'decimal',
            'numeric'       => 'decimal',
            'year'          => 'date',
741 742
        );
    }
743 744 745 746 747

    public function getVarcharMaxLength()
    {
        return 65535;
    }
748 749 750 751 752
    
    protected function getReservedKeywordsClass()
    {
        return 'Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords';
    }
753
}