PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.35.1
MailPoet – Newsletters, Email Marketing, and Automation v5.35.1
5.36.0 5.35.1 5.35.0 5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / vendor-prefixed / doctrine / dbal / src / Schema / PostgreSQLSchemaManager.php
mailpoet / vendor-prefixed / doctrine / dbal / src / Schema Last commit date
Exception 2 years ago Visitor 9 months ago AbstractAsset.php 2 years ago AbstractSchemaManager.php 9 months ago Column.php 2 years ago ColumnDiff.php 2 years ago Comparator.php 2 years ago Constraint.php 2 years ago DB2SchemaManager.php 2 years ago DefaultSchemaManagerFactory.php 2 years ago ForeignKeyConstraint.php 9 months ago Identifier.php 2 years ago Index.php 2 years ago LegacySchemaManagerFactory.php 2 years ago MySQLSchemaManager.php 9 months ago OracleSchemaManager.php 2 years ago PostgreSQLSchemaManager.php 9 months ago SQLServerSchemaManager.php 9 months ago Schema.php 2 years ago SchemaConfig.php 2 years ago SchemaDiff.php 2 years ago SchemaException.php 2 years ago SchemaManagerFactory.php 2 years ago Sequence.php 2 years ago SqliteSchemaManager.php 8 months ago Table.php 2 years ago TableDiff.php 2 years ago UniqueConstraint.php 2 years ago View.php 2 years ago
PostgreSQLSchemaManager.php
466 lines
1 <?php
2 namespace MailPoetVendor\Doctrine\DBAL\Schema;
3 if (!defined('ABSPATH')) exit;
4 use MailPoetVendor\Doctrine\DBAL\Exception;
5 use MailPoetVendor\Doctrine\DBAL\Platforms\PostgreSQLPlatform;
6 use MailPoetVendor\Doctrine\DBAL\Result;
7 use MailPoetVendor\Doctrine\DBAL\Types\JsonType;
8 use MailPoetVendor\Doctrine\DBAL\Types\Type;
9 use MailPoetVendor\Doctrine\DBAL\Types\Types;
10 use MailPoetVendor\Doctrine\Deprecations\Deprecation;
11 use function array_change_key_case;
12 use function array_filter;
13 use function array_map;
14 use function array_merge;
15 use function array_shift;
16 use function assert;
17 use function explode;
18 use function get_class;
19 use function implode;
20 use function in_array;
21 use function preg_match;
22 use function preg_replace;
23 use function sprintf;
24 use function str_replace;
25 use function strpos;
26 use function strtolower;
27 use function trim;
28 use const CASE_LOWER;
29 class PostgreSQLSchemaManager extends AbstractSchemaManager
30 {
31 private ?array $existingSchemaPaths = null;
32 public function listTableNames()
33 {
34 return $this->doListTableNames();
35 }
36 public function listTables()
37 {
38 return $this->doListTables();
39 }
40 public function listTableDetails($name)
41 {
42 Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5595', '%s is deprecated. Use introspectTable() instead.', __METHOD__);
43 return $this->doListTableDetails($name);
44 }
45 public function listTableColumns($table, $database = null)
46 {
47 return $this->doListTableColumns($table, $database);
48 }
49 public function listTableIndexes($table)
50 {
51 return $this->doListTableIndexes($table);
52 }
53 public function listTableForeignKeys($table, $database = null)
54 {
55 return $this->doListTableForeignKeys($table, $database);
56 }
57 public function getSchemaNames()
58 {
59 Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/4503', 'PostgreSQLSchemaManager::getSchemaNames() is deprecated,' . ' use PostgreSQLSchemaManager::listSchemaNames() instead.');
60 return $this->listNamespaceNames();
61 }
62 public function listSchemaNames() : array
63 {
64 return $this->_conn->fetchFirstColumn(<<<'SQL'
65 SELECT schema_name
66 FROM information_schema.schemata
67 WHERE schema_name NOT LIKE 'pg\_%'
68 AND schema_name != 'information_schema'
69 SQL
70 );
71 }
72 public function getSchemaSearchPaths()
73 {
74 Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4821', 'PostgreSQLSchemaManager::getSchemaSearchPaths() is deprecated.');
75 $params = $this->_conn->getParams();
76 $searchPaths = $this->_conn->fetchOne('SHOW search_path');
77 assert($searchPaths !== \false);
78 $schema = explode(',', $searchPaths);
79 if (isset($params['user'])) {
80 $schema = str_replace('"$user"', $params['user'], $schema);
81 }
82 return array_map('trim', $schema);
83 }
84 public function getExistingSchemaSearchPaths()
85 {
86 if ($this->existingSchemaPaths === null) {
87 $this->determineExistingSchemaSearchPaths();
88 }
89 assert($this->existingSchemaPaths !== null);
90 return $this->existingSchemaPaths;
91 }
92 protected function getCurrentSchema()
93 {
94 $schemas = $this->getExistingSchemaSearchPaths();
95 return array_shift($schemas);
96 }
97 public function determineExistingSchemaSearchPaths()
98 {
99 $names = $this->listSchemaNames();
100 $paths = $this->getSchemaSearchPaths();
101 $this->existingSchemaPaths = array_filter($paths, static function ($v) use($names) : bool {
102 return in_array($v, $names, \true);
103 });
104 }
105 protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
106 {
107 $onUpdate = null;
108 $onDelete = null;
109 if (preg_match('(ON UPDATE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', $tableForeignKey['condef'], $match) === 1) {
110 $onUpdate = $match[1];
111 }
112 if (preg_match('(ON DELETE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', $tableForeignKey['condef'], $match) === 1) {
113 $onDelete = $match[1];
114 }
115 $result = preg_match('/FOREIGN KEY \\((.+)\\) REFERENCES (.+)\\((.+)\\)/', $tableForeignKey['condef'], $values);
116 assert($result === 1);
117 // PostgreSQL returns identifiers that are keywords with quotes, we need them later, don't get
118 // the idea to trim them here.
119 $localColumns = array_map('trim', explode(',', $values[1]));
120 $foreignColumns = array_map('trim', explode(',', $values[3]));
121 $foreignTable = $values[2];
122 return new ForeignKeyConstraint($localColumns, $foreignTable, $foreignColumns, $tableForeignKey['conname'], ['onUpdate' => $onUpdate, 'onDelete' => $onDelete]);
123 }
124 protected function _getPortableViewDefinition($view)
125 {
126 return new View($view['schemaname'] . '.' . $view['viewname'], $view['definition']);
127 }
128 protected function _getPortableTableDefinition($table)
129 {
130 $currentSchema = $this->getCurrentSchema();
131 if ($table['schema_name'] === $currentSchema) {
132 return $table['table_name'];
133 }
134 return $table['schema_name'] . '.' . $table['table_name'];
135 }
136 protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)
137 {
138 $buffer = [];
139 foreach ($tableIndexes as $row) {
140 $colNumbers = array_map('intval', explode(' ', $row['indkey']));
141 $columnNameSql = sprintf(<<<'SQL'
142 SELECT attnum,
143 quote_ident(attname) AS attname
144 FROM pg_attribute
145 WHERE attrelid = %d
146 AND attnum IN (%s)
147 ORDER BY attnum
148 SQL
149 , $row['indrelid'], implode(', ', $colNumbers));
150 $indexColumns = $this->_conn->fetchAllAssociative($columnNameSql);
151 // required for getting the order of the columns right.
152 foreach ($colNumbers as $colNum) {
153 foreach ($indexColumns as $colRow) {
154 if ($colNum !== $colRow['attnum']) {
155 continue;
156 }
157 $buffer[] = ['key_name' => $row['relname'], 'column_name' => trim($colRow['attname']), 'non_unique' => !$row['indisunique'], 'primary' => $row['indisprimary'], 'where' => $row['where']];
158 }
159 }
160 }
161 return parent::_getPortableTableIndexesList($buffer, $tableName);
162 }
163 protected function _getPortableDatabaseDefinition($database)
164 {
165 return $database['datname'];
166 }
167 protected function getPortableNamespaceDefinition(array $namespace)
168 {
169 Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/4503', 'PostgreSQLSchemaManager::getPortableNamespaceDefinition() is deprecated,' . ' use PostgreSQLSchemaManager::listSchemaNames() instead.');
170 return $namespace['nspname'];
171 }
172 protected function _getPortableSequenceDefinition($sequence)
173 {
174 if ($sequence['schemaname'] !== 'public') {
175 $sequenceName = $sequence['schemaname'] . '.' . $sequence['relname'];
176 } else {
177 $sequenceName = $sequence['relname'];
178 }
179 return new Sequence($sequenceName, (int) $sequence['increment_by'], (int) $sequence['min_value']);
180 }
181 protected function _getPortableTableColumnDefinition($tableColumn)
182 {
183 $tableColumn = array_change_key_case($tableColumn, CASE_LOWER);
184 if (strtolower($tableColumn['type']) === 'varchar' || strtolower($tableColumn['type']) === 'bpchar') {
185 // get length from varchar definition
186 $length = preg_replace('~.*\\(([0-9]*)\\).*~', '$1', $tableColumn['complete_type']);
187 $tableColumn['length'] = $length;
188 }
189 $matches = [];
190 $autoincrement = \false;
191 if ($tableColumn['default'] !== null && preg_match("/^nextval\\('(.*)'(::.*)?\\)\$/", $tableColumn['default'], $matches) === 1) {
192 $tableColumn['sequence'] = $matches[1];
193 $tableColumn['default'] = null;
194 $autoincrement = \true;
195 }
196 if ($tableColumn['default'] !== null) {
197 if (preg_match("/^['(](.*)[')]::/", $tableColumn['default'], $matches) === 1) {
198 $tableColumn['default'] = $matches[1];
199 } elseif (preg_match('/^NULL::/', $tableColumn['default']) === 1) {
200 $tableColumn['default'] = null;
201 }
202 }
203 $length = $tableColumn['length'] ?? null;
204 if ($length === '-1' && isset($tableColumn['atttypmod'])) {
205 $length = $tableColumn['atttypmod'] - 4;
206 }
207 if ((int) $length <= 0) {
208 $length = null;
209 }
210 $fixed = null;
211 if (!isset($tableColumn['name'])) {
212 $tableColumn['name'] = '';
213 }
214 $precision = null;
215 $scale = null;
216 $jsonb = null;
217 $dbType = strtolower($tableColumn['type']);
218 if ($tableColumn['domain_type'] !== null && $tableColumn['domain_type'] !== '' && !$this->_platform->hasDoctrineTypeMappingFor($tableColumn['type'])) {
219 $dbType = strtolower($tableColumn['domain_type']);
220 $tableColumn['complete_type'] = $tableColumn['domain_complete_type'];
221 }
222 $type = $this->_platform->getDoctrineTypeMapping($dbType);
223 $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type);
224 $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type);
225 switch ($dbType) {
226 case 'smallint':
227 case 'int2':
228 $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']);
229 $length = null;
230 break;
231 case 'int':
232 case 'int4':
233 case 'integer':
234 $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']);
235 $length = null;
236 break;
237 case 'bigint':
238 case 'int8':
239 $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']);
240 $length = null;
241 break;
242 case 'bool':
243 case 'boolean':
244 if ($tableColumn['default'] === 'true') {
245 $tableColumn['default'] = \true;
246 }
247 if ($tableColumn['default'] === 'false') {
248 $tableColumn['default'] = \false;
249 }
250 $length = null;
251 break;
252 case 'json':
253 case 'text':
254 case '_varchar':
255 case 'varchar':
256 $tableColumn['default'] = $this->parseDefaultExpression($tableColumn['default']);
257 $fixed = \false;
258 break;
259 case 'interval':
260 $fixed = \false;
261 break;
262 case 'char':
263 case 'bpchar':
264 $fixed = \true;
265 break;
266 case 'float':
267 case 'float4':
268 case 'float8':
269 case 'double':
270 case 'double precision':
271 case 'real':
272 case 'decimal':
273 case 'money':
274 case 'numeric':
275 $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']);
276 if (preg_match('([A-Za-z]+\\(([0-9]+),([0-9]+)\\))', $tableColumn['complete_type'], $match) === 1) {
277 $precision = $match[1];
278 $scale = $match[2];
279 $length = null;
280 }
281 break;
282 case 'year':
283 $length = null;
284 break;
285 // PostgreSQL 9.4+ only
286 case 'jsonb':
287 $jsonb = \true;
288 break;
289 }
290 if ($tableColumn['default'] !== null && preg_match("('([^']+)'::)", $tableColumn['default'], $match) === 1) {
291 $tableColumn['default'] = $match[1];
292 }
293 $options = ['length' => $length, 'notnull' => (bool) $tableColumn['isnotnull'], 'default' => $tableColumn['default'], 'precision' => $precision, 'scale' => $scale, 'fixed' => $fixed, 'autoincrement' => $autoincrement, 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' ? $tableColumn['comment'] : null];
294 $column = new Column($tableColumn['field'], Type::getType($type), $options);
295 if (!empty($tableColumn['collation'])) {
296 $column->setPlatformOption('collation', $tableColumn['collation']);
297 }
298 if ($column->getType()->getName() === Types::JSON) {
299 if (!$column->getType() instanceof JsonType) {
300 Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5049', <<<'DEPRECATION'
301 %s not extending %s while being named %s is deprecated,
302 and will lead to jsonb never to being used in 4.0.,
303 DEPRECATION
304 , get_class($column->getType()), JsonType::class, Types::JSON);
305 }
306 $column->setPlatformOption('jsonb', $jsonb);
307 }
308 return $column;
309 }
310 private function fixVersion94NegativeNumericDefaultValue($defaultValue)
311 {
312 if ($defaultValue !== null && strpos($defaultValue, '(') === 0) {
313 return trim($defaultValue, '()');
314 }
315 return $defaultValue;
316 }
317 private function parseDefaultExpression(?string $default) : ?string
318 {
319 if ($default === null) {
320 return $default;
321 }
322 return str_replace("''", "'", $default);
323 }
324 protected function selectTableNames(string $databaseName) : Result
325 {
326 $sql = <<<'SQL'
327 SELECT quote_ident(table_name) AS table_name,
328 table_schema AS schema_name
329 FROM information_schema.tables
330 WHERE table_catalog = ?
331 AND table_schema NOT LIKE 'pg\_%'
332 AND table_schema != 'information_schema'
333 AND table_name != 'geometry_columns'
334 AND table_name != 'spatial_ref_sys'
335 AND table_type = 'BASE TABLE'
336 ORDER BY
337 quote_ident(table_name)
338 SQL;
339 return $this->_conn->executeQuery($sql, [$databaseName]);
340 }
341 protected function selectTableColumns(string $databaseName, ?string $tableName = null) : Result
342 {
343 $sql = 'SELECT';
344 if ($tableName === null) {
345 $sql .= ' quote_ident(c.relname) AS table_name, quote_ident(n.nspname) AS schema_name,';
346 }
347 $sql .= sprintf(<<<'SQL'
348 a.attnum,
349 quote_ident(a.attname) AS field,
350 t.typname AS type,
351 format_type(a.atttypid, a.atttypmod) AS complete_type,
352 (SELECT tc.collcollate FROM pg_catalog.pg_collation tc WHERE tc.oid = a.attcollation) AS collation,
353 (SELECT t1.typname FROM pg_catalog.pg_type t1 WHERE t1.oid = t.typbasetype) AS domain_type,
354 (SELECT format_type(t2.typbasetype, t2.typtypmod) FROM
355 pg_catalog.pg_type t2 WHERE t2.typtype = 'd' AND t2.oid = a.atttypid) AS domain_complete_type,
356 a.attnotnull AS isnotnull,
357 (SELECT 't'
358 FROM pg_index
359 WHERE c.oid = pg_index.indrelid
360 AND pg_index.indkey[0] = a.attnum
361 AND pg_index.indisprimary = 't'
362 ) AS pri,
363 (%s) AS default,
364 (SELECT pg_description.description
365 FROM pg_description WHERE pg_description.objoid = c.oid AND a.attnum = pg_description.objsubid
366 ) AS comment
367 FROM pg_attribute a
368 INNER JOIN pg_class c
369 ON c.oid = a.attrelid
370 INNER JOIN pg_type t
371 ON t.oid = a.atttypid
372 INNER JOIN pg_namespace n
373 ON n.oid = c.relnamespace
374 LEFT JOIN pg_depend d
375 ON d.objid = c.oid
376 AND d.deptype = 'e'
377 AND d.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_class')
378 SQL
379 , $this->_platform->getDefaultColumnValueSQLSnippet());
380 $conditions = array_merge(['a.attnum > 0', "c.relkind = 'r'", 'd.refobjid IS NULL'], $this->buildQueryConditions($tableName));
381 $sql .= ' WHERE ' . implode(' AND ', $conditions) . ' ORDER BY a.attnum';
382 return $this->_conn->executeQuery($sql);
383 }
384 protected function selectIndexColumns(string $databaseName, ?string $tableName = null) : Result
385 {
386 $sql = 'SELECT';
387 if ($tableName === null) {
388 $sql .= ' quote_ident(tc.relname) AS table_name, quote_ident(tn.nspname) AS schema_name,';
389 }
390 $sql .= <<<'SQL'
391 quote_ident(ic.relname) AS relname,
392 i.indisunique,
393 i.indisprimary,
394 i.indkey,
395 i.indrelid,
396 pg_get_expr(indpred, indrelid) AS "where"
397 FROM pg_index i
398 JOIN pg_class AS tc ON tc.oid = i.indrelid
399 JOIN pg_namespace tn ON tn.oid = tc.relnamespace
400 JOIN pg_class AS ic ON ic.oid = i.indexrelid
401 WHERE ic.oid IN (
402 SELECT indexrelid
403 FROM pg_index i, pg_class c, pg_namespace n
404 SQL;
405 $conditions = array_merge(['c.oid = i.indrelid', 'c.relnamespace = n.oid'], $this->buildQueryConditions($tableName));
406 $sql .= ' WHERE ' . implode(' AND ', $conditions) . ') ORDER BY quote_ident(ic.relname)';
407 return $this->_conn->executeQuery($sql);
408 }
409 protected function selectForeignKeyColumns(string $databaseName, ?string $tableName = null) : Result
410 {
411 $sql = 'SELECT';
412 if ($tableName === null) {
413 $sql .= ' quote_ident(tc.relname) AS table_name, quote_ident(tn.nspname) AS schema_name,';
414 }
415 $sql .= <<<'SQL'
416 quote_ident(r.conname) as conname,
417 pg_get_constraintdef(r.oid, true) as condef
418 FROM pg_constraint r
419 JOIN pg_class AS tc ON tc.oid = r.conrelid
420 JOIN pg_namespace tn ON tn.oid = tc.relnamespace
421 WHERE r.conrelid IN
422 (
423 SELECT c.oid
424 FROM pg_class c, pg_namespace n
425 SQL;
426 $conditions = array_merge(['n.oid = c.relnamespace'], $this->buildQueryConditions($tableName));
427 $sql .= ' WHERE ' . implode(' AND ', $conditions) . ") AND r.contype = 'f' ORDER BY quote_ident(r.conname)";
428 return $this->_conn->executeQuery($sql);
429 }
430 protected function fetchTableOptionsByTable(string $databaseName, ?string $tableName = null) : array
431 {
432 $sql = <<<'SQL'
433 SELECT n.nspname AS schema_name,
434 c.relname AS table_name,
435 CASE c.relpersistence WHEN 'u' THEN true ELSE false END as unlogged,
436 obj_description(c.oid, 'pg_class') AS comment
437 FROM pg_class c
438 INNER JOIN pg_namespace n
439 ON n.oid = c.relnamespace
440 SQL;
441 $conditions = array_merge(["c.relkind = 'r'"], $this->buildQueryConditions($tableName));
442 $sql .= ' WHERE ' . implode(' AND ', $conditions);
443 $tableOptions = [];
444 foreach ($this->_conn->iterateAssociative($sql) as $row) {
445 $tableOptions[$this->_getPortableTableDefinition($row)] = $row;
446 }
447 return $tableOptions;
448 }
449 private function buildQueryConditions($tableName) : array
450 {
451 $conditions = [];
452 if ($tableName !== null) {
453 if (strpos($tableName, '.') !== \false) {
454 [$schemaName, $tableName] = explode('.', $tableName);
455 $conditions[] = 'n.nspname = ' . $this->_platform->quoteStringLiteral($schemaName);
456 } else {
457 $conditions[] = 'n.nspname = ANY(current_schemas(false))';
458 }
459 $identifier = new Identifier($tableName);
460 $conditions[] = 'c.relname = ' . $this->_platform->quoteStringLiteral($identifier->getName());
461 }
462 $conditions[] = "n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')";
463 return $conditions;
464 }
465 }
466