Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
platform
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 13
812
0.00% covered (danger)
0.00%
0 / 1
 getIdentitySequenceName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getIntegerTypeDeclarationSQL
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getBigIntTypeDeclarationSQL
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSmallIntTypeDeclarationSQL
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultValueDeclarationSQL
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getAlterTableSQL
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
 supportsIdentityColumns
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 _getCreateTableSQL
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 isSerialColumn
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 isNumericType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
12
 getListSequencesSQL
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getDropIndexSQL
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
20
 tableName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 *
4 * This file is part of the phpBB Forum Software package.
5 *
6 * @copyright (c) phpBB Limited <https://www.phpbb.com>
7 * @license GNU General Public License, version 2 (GPL-2.0)
8 *
9 * For full copyright and license information, please see
10 * the docs/CREDITS.txt file.
11 *
12 */
13
14namespace phpbb\db\middleware\postgresql;
15
16use Doctrine\DBAL\Platforms\AbstractPlatform;
17use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
18use Doctrine\DBAL\Schema\Sequence;
19use Doctrine\DBAL\Schema\Table;
20use Doctrine\DBAL\Schema\TableDiff;
21use Doctrine\DBAL\Types\BigIntType;
22use Doctrine\DBAL\Types\IntegerType;
23use Doctrine\DBAL\Types\SmallIntType;
24use Doctrine\DBAL\Types\Type;
25
26/**
27 * PostgreSQL specific schema restrictions for BC.
28 *
29 * Doctrine is using SERIAL which auto creates the sequences with
30 * a name different from the one our driver is using. So in order
31 * to stay compatible with the existing DB we have to change its
32 * naming and not ours.
33 */
34class platform extends PostgreSQLPlatform
35{
36    /**
37     * {@inheritdoc}
38     */
39    public function getIdentitySequenceName($tableName, $columnName): string
40    {
41        return $tableName . '_seq';
42    }
43
44    /**
45     * {@inheritDoc}
46     */
47    public function getIntegerTypeDeclarationSQL(array $column): string
48    {
49        return 'INT';
50    }
51
52    /**
53     * {@inheritDoc}
54     */
55    public function getBigIntTypeDeclarationSQL(array $column): string
56    {
57        return 'BIGINT';
58    }
59
60    /**
61     * {@inheritDoc}
62     */
63    public function getSmallIntTypeDeclarationSQL(array $column): string
64    {
65        return 'SMALLINT';
66    }
67
68    /**
69     * {@inheritDoc}
70     */
71    public function getDefaultValueDeclarationSQL($column): string
72    {
73        if ($this->isSerialColumn($column))
74        {
75            return ' DEFAULT {{placeholder_sequence}}';
76        }
77
78        return AbstractPlatform::getDefaultValueDeclarationSQL($column);
79    }
80
81    /**
82     * {@inheritDoc}
83     */
84    public function getAlterTableSQL(TableDiff $diff)
85    {
86        $sql = parent::getAlterTableSQL($diff);
87        $table_name = $diff->getOldTable()->getName();
88        $columns = $diff->getAddedColumns();
89        $post_sql = $sequence_sql = [];
90
91        foreach ($columns as $column)
92        {
93            $column_name = $column->getName();
94            if (!empty($column->getAutoincrement()))
95            {
96                $sequence = new Sequence($this->getIdentitySequenceName($table_name, $column_name));
97                $sequence_sql[] = $this->getCreateSequenceSQL($sequence);
98                $post_sql[] = 'ALTER SEQUENCE ' . $sequence->getName() . ' OWNED BY ' . $table_name . '.' . $column_name;
99            }
100        }
101        $sql = array_merge($sequence_sql, $sql, $post_sql);
102
103        foreach ($sql as $i => $query)
104        {
105            $sql[$i] = str_replace('{{placeholder_sequence}}', "nextval('{$table_name}_seq')", $query);
106        }
107
108        return $sql;
109    }
110
111    /**
112     * {@inheritDoc}
113     */
114    public function supportsIdentityColumns(): bool
115    {
116        return false;
117    }
118
119    /**
120     * {@inheritDoc}
121     */
122    protected function _getCreateTableSQL($name, array $columns, array $options = []): array
123    {
124        $sql = [];
125        $post_sql = [];
126        foreach ($columns as $column_name => $column)
127        {
128            if (!empty($column['autoincrement']))
129            {
130                $sequence = new Sequence($this->getIdentitySequenceName($name, $column_name));
131                $sql[] = $this->getCreateSequenceSQL($sequence);
132                $post_sql[] = 'ALTER SEQUENCE '.$sequence->getName().' OWNED BY '.$name.'.'.$column_name;
133            }
134        }
135        $sql = array_merge($sql, parent::_getCreateTableSQL($name, $columns, $options), $post_sql);
136
137        foreach ($sql as $i => $query)
138        {
139            $sql[$i] = str_replace('{{placeholder_sequence}}', "nextval('{$name}_seq')", $query);
140        }
141
142        return $sql;
143    }
144
145    /**
146     * Return if column is a "serial" column, i.e. type supporting auto-increment
147     *
148     * @param array $column Column data
149     * @return bool
150     */
151    private function isSerialColumn(array $column): bool
152    {
153        return isset($column['type'], $column['autoincrement'])
154            && $column['autoincrement'] === true
155            && $this->isNumericType($column['type']);
156    }
157
158    /**
159     * Return if supplied type is of numeric type
160     *
161     * @param Type $type
162     * @return bool
163     */
164    private function isNumericType(Type $type): bool
165    {
166        return $type instanceof IntegerType || $type instanceof BigIntType || $type instanceof SmallIntType;
167    }
168
169    /**
170     * {@inheritDoc}
171     */
172    public function getListSequencesSQL($database): string
173    {
174        return "SELECT sequence_name AS relname,
175                sequence_schema AS schemaname,
176                1 AS min_value,
177                1 AS increment_by
178            FROM information_schema.sequences
179            WHERE sequence_schema NOT LIKE 'pg\_%'
180                AND sequence_schema <> 'information_schema'";
181    }
182
183    /**
184     * {@inheritDoc}
185     */
186    public function getDropIndexSQL($index, $table = null): string
187    {
188        // If we have a primary or a unique index, we need to drop the constraint
189        // instead of the index itself or postgreSQL will reject the query.
190        if (is_string($index) && $table !== null && $index === $this->tableName($table) . '_pkey')
191        {
192            return $this->getDropConstraintSQL($index, $this->tableName($table));
193        }
194
195        return parent::getDropIndexSQL($index, $table);
196    }
197
198    /**
199     * {@inheritDoc}
200     */
201    private function tableName($table)
202    {
203        return $table instanceof Table ? $table->getName() : (string) $table;
204    }
205}