vendor/doctrine-dbal/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
     5  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
     6  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
     7  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       
     8  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
     9  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       
    10  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       
    11  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    12  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    13  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    14  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    15  *
       
    16  * This software consists of voluntary contributions made by many individuals
       
    17  * and is licensed under the LGPL. For more information, see
       
    18  * <http://www.doctrine-project.org>.
       
    19  */
       
    20 
       
    21 namespace Doctrine\DBAL\Schema;
       
    22 
       
    23 /**
       
    24  * xxx
       
    25  *
       
    26  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
       
    27  * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
       
    28  * @author      Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
       
    29  * @author      Benjamin Eberlei <kontakt@beberlei.de>
       
    30  * @version     $Revision$
       
    31  * @since       2.0
       
    32  */
       
    33 class PostgreSqlSchemaManager extends AbstractSchemaManager
       
    34 {
       
    35 
       
    36     protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
       
    37     {
       
    38         $onUpdate = null;
       
    39         $onDelete = null;
       
    40 
       
    41         if (preg_match('(ON UPDATE ([a-zA-Z0-9]+))', $tableForeignKey['condef'], $match)) {
       
    42             $onUpdate = $match[1];
       
    43         }
       
    44         if (preg_match('(ON DELETE ([a-zA-Z0-9]+))', $tableForeignKey['condef'], $match)) {
       
    45             $onDelete = $match[1];
       
    46         }
       
    47 
       
    48         if (preg_match('/FOREIGN KEY \((.+)\) REFERENCES (.+)\((.+)\)/', $tableForeignKey['condef'], $values)) {
       
    49             // PostgreSQL returns identifiers that are keywords with quotes, we need them later, don't get
       
    50             // the idea to trim them here.
       
    51             $localColumns = array_map('trim', explode(",", $values[1]));
       
    52             $foreignColumns = array_map('trim', explode(",", $values[3]));
       
    53             $foreignTable = $values[2];
       
    54         }
       
    55 
       
    56         return new ForeignKeyConstraint(
       
    57                 $localColumns, $foreignTable, $foreignColumns, $tableForeignKey['conname'],
       
    58                 array('onUpdate' => $onUpdate, 'onDelete' => $onDelete)
       
    59         );
       
    60     }
       
    61 
       
    62     public function dropDatabase($database)
       
    63     {
       
    64         $params = $this->_conn->getParams();
       
    65         $params["dbname"] = "postgres";
       
    66         $tmpPlatform = $this->_platform;
       
    67         $tmpConn = $this->_conn;
       
    68 
       
    69         $this->_conn = \Doctrine\DBAL\DriverManager::getConnection($params);
       
    70         $this->_platform = $this->_conn->getDatabasePlatform();
       
    71 
       
    72         parent::dropDatabase($database);
       
    73 
       
    74         $this->_platform = $tmpPlatform;
       
    75         $this->_conn = $tmpConn;
       
    76     }
       
    77 
       
    78     public function createDatabase($database)
       
    79     {
       
    80         $params = $this->_conn->getParams();
       
    81         $params["dbname"] = "postgres";
       
    82         $tmpPlatform = $this->_platform;
       
    83         $tmpConn = $this->_conn;
       
    84 
       
    85         $this->_conn = \Doctrine\DBAL\DriverManager::getConnection($params);
       
    86         $this->_platform = $this->_conn->getDatabasePlatform();
       
    87 
       
    88         parent::createDatabase($database);
       
    89 
       
    90         $this->_platform = $tmpPlatform;
       
    91         $this->_conn = $tmpConn;
       
    92     }
       
    93 
       
    94     protected function _getPortableTriggerDefinition($trigger)
       
    95     {
       
    96         return $trigger['trigger_name'];
       
    97     }
       
    98 
       
    99     protected function _getPortableViewDefinition($view)
       
   100     {
       
   101         return new View($view['viewname'], $view['definition']);
       
   102     }
       
   103 
       
   104     protected function _getPortableUserDefinition($user)
       
   105     {
       
   106         return array(
       
   107             'user' => $user['usename'],
       
   108             'password' => $user['passwd']
       
   109         );
       
   110     }
       
   111 
       
   112     protected function _getPortableTableDefinition($table)
       
   113     {
       
   114         if ($table['schema_name'] == 'public') {
       
   115             return $table['table_name'];
       
   116         } else {
       
   117             return $table['schema_name'] . "." . $table['table_name'];
       
   118         }
       
   119     }
       
   120 
       
   121     /**
       
   122      * @license New BSD License
       
   123      * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
       
   124      * @param  array $tableIndexes
       
   125      * @param  string $tableName
       
   126      * @return array
       
   127      */
       
   128     protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
       
   129     {
       
   130         $buffer = array();
       
   131         foreach ($tableIndexes AS $row) {
       
   132             $colNumbers = explode(' ', $row['indkey']);
       
   133             $colNumbersSql = 'IN (' . join(' ,', $colNumbers) . ' )';
       
   134             $columnNameSql = "SELECT attnum, attname FROM pg_attribute
       
   135                 WHERE attrelid={$row['indrelid']} AND attnum $colNumbersSql ORDER BY attnum ASC;";
       
   136 
       
   137             $stmt = $this->_conn->executeQuery($columnNameSql);
       
   138             $indexColumns = $stmt->fetchAll();
       
   139 
       
   140             // required for getting the order of the columns right.
       
   141             foreach ($colNumbers AS $colNum) {
       
   142                 foreach ($indexColumns as $colRow) {
       
   143                     if ($colNum == $colRow['attnum']) {
       
   144                         $buffer[] = array(
       
   145                             'key_name' => $row['relname'],
       
   146                             'column_name' => trim($colRow['attname']),
       
   147                             'non_unique' => !$row['indisunique'],
       
   148                             'primary' => $row['indisprimary']
       
   149                         );
       
   150                     }
       
   151                 }
       
   152             }
       
   153         }
       
   154         return parent::_getPortableTableIndexesList($buffer);
       
   155     }
       
   156 
       
   157     protected function _getPortableDatabaseDefinition($database)
       
   158     {
       
   159         return $database['datname'];
       
   160     }
       
   161 
       
   162     protected function _getPortableSequenceDefinition($sequence)
       
   163     {
       
   164         if ($sequence['schemaname'] != 'public') {
       
   165             $sequenceName = $sequence['schemaname'] . "." . $sequence['relname'];
       
   166         } else {
       
   167             $sequenceName = $sequence['relname'];
       
   168         }
       
   169 
       
   170         $data = $this->_conn->fetchAll('SELECT min_value, increment_by FROM ' . $sequenceName);
       
   171         return new Sequence($sequenceName, $data[0]['increment_by'], $data[0]['min_value']);
       
   172     }
       
   173 
       
   174     protected function _getPortableTableColumnDefinition($tableColumn)
       
   175     {
       
   176         $tableColumn = array_change_key_case($tableColumn, CASE_LOWER);
       
   177 
       
   178         if (strtolower($tableColumn['type']) === 'varchar') {
       
   179             // get length from varchar definition
       
   180             $length = preg_replace('~.*\(([0-9]*)\).*~', '$1', $tableColumn['complete_type']);
       
   181             $tableColumn['length'] = $length;
       
   182         }
       
   183 
       
   184         $matches = array();
       
   185 
       
   186         $autoincrement = false;
       
   187         if (preg_match("/^nextval\('(.*)'(::.*)?\)$/", $tableColumn['default'], $matches)) {
       
   188             $tableColumn['sequence'] = $matches[1];
       
   189             $tableColumn['default'] = null;
       
   190             $autoincrement = true;
       
   191         }
       
   192 
       
   193         if (stripos($tableColumn['default'], 'NULL') === 0) {
       
   194             $tableColumn['default'] = null;
       
   195         }
       
   196 
       
   197         $length = (isset($tableColumn['length'])) ? $tableColumn['length'] : null;
       
   198         if ($length == '-1' && isset($tableColumn['atttypmod'])) {
       
   199             $length = $tableColumn['atttypmod'] - 4;
       
   200         }
       
   201         if ((int) $length <= 0) {
       
   202             $length = null;
       
   203         }
       
   204         $fixed = null;
       
   205 
       
   206         if (!isset($tableColumn['name'])) {
       
   207             $tableColumn['name'] = '';
       
   208         }
       
   209 
       
   210         $precision = null;
       
   211         $scale = null;
       
   212 
       
   213         if ($this->_platform->hasDoctrineTypeMappingFor($tableColumn['type'])) {
       
   214             $dbType = strtolower($tableColumn['type']);
       
   215         } else {
       
   216             $dbType = strtolower($tableColumn['domain_type']);
       
   217             $tableColumn['complete_type'] = $tableColumn['domain_complete_type'];
       
   218         }
       
   219 
       
   220         $type = $this->_platform->getDoctrineTypeMapping($dbType);
       
   221         $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type);
       
   222         $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type);
       
   223 
       
   224         switch ($dbType) {
       
   225             case 'smallint':
       
   226             case 'int2':
       
   227                 $length = null;
       
   228                 break;
       
   229             case 'int':
       
   230             case 'int4':
       
   231             case 'integer':
       
   232                 $length = null;
       
   233                 break;
       
   234             case 'bigint':
       
   235             case 'int8':
       
   236                 $length = null;
       
   237                 break;
       
   238             case 'bool':
       
   239             case 'boolean':
       
   240                 $length = null;
       
   241                 break;
       
   242             case 'text':
       
   243                 $fixed = false;
       
   244                 break;
       
   245             case 'varchar':
       
   246             case 'interval':
       
   247             case '_varchar':
       
   248                 $fixed = false;
       
   249                 break;
       
   250             case 'char':
       
   251             case 'bpchar':
       
   252                 $fixed = true;
       
   253                 break;
       
   254             case 'float':
       
   255             case 'float4':
       
   256             case 'float8':
       
   257             case 'double':
       
   258             case 'double precision':
       
   259             case 'real':
       
   260             case 'decimal':
       
   261             case 'money':
       
   262             case 'numeric':
       
   263                 if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['complete_type'], $match)) {
       
   264                     $precision = $match[1];
       
   265                     $scale = $match[2];
       
   266                     $length = null;
       
   267                 }
       
   268                 break;
       
   269             case 'year':
       
   270                 $length = null;
       
   271                 break;
       
   272         }
       
   273 
       
   274         $options = array(
       
   275             'length'        => $length,
       
   276             'notnull'       => (bool) $tableColumn['isnotnull'],
       
   277             'default'       => $tableColumn['default'],
       
   278             'primary'       => (bool) ($tableColumn['pri'] == 't'),
       
   279             'precision'     => $precision,
       
   280             'scale'         => $scale,
       
   281             'fixed'         => $fixed,
       
   282             'unsigned'      => false,
       
   283             'autoincrement' => $autoincrement,
       
   284             'comment'       => $tableColumn['comment'],
       
   285         );
       
   286 
       
   287         return new Column($tableColumn['field'], \Doctrine\DBAL\Types\Type::getType($type), $options);
       
   288     }
       
   289 
       
   290 }