diff options
| author | polo <ordipolo@gmx.fr> | 2024-08-13 23:45:21 +0200 |
|---|---|---|
| committer | polo <ordipolo@gmx.fr> | 2024-08-13 23:45:21 +0200 |
| commit | bf6655a534a6775d30cafa67bd801276bda1d98d (patch) | |
| tree | c6381e3f6c81c33eab72508f410b165ba05f7e9c /vendor/doctrine/dbal/src/Schema/PostgreSQLSchemaManager.php | |
| parent | 94d67a4b51f8e62e7d518cce26a526ae1ec48278 (diff) | |
| download | AppliGestionPHP-bf6655a534a6775d30cafa67bd801276bda1d98d.tar.gz AppliGestionPHP-bf6655a534a6775d30cafa67bd801276bda1d98d.tar.bz2 AppliGestionPHP-bf6655a534a6775d30cafa67bd801276bda1d98d.zip | |
VERSION 0.2 doctrine ORM et entités
Diffstat (limited to 'vendor/doctrine/dbal/src/Schema/PostgreSQLSchemaManager.php')
| -rw-r--r-- | vendor/doctrine/dbal/src/Schema/PostgreSQLSchemaManager.php | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/vendor/doctrine/dbal/src/Schema/PostgreSQLSchemaManager.php b/vendor/doctrine/dbal/src/Schema/PostgreSQLSchemaManager.php new file mode 100644 index 0000000..9af16c9 --- /dev/null +++ b/vendor/doctrine/dbal/src/Schema/PostgreSQLSchemaManager.php | |||
| @@ -0,0 +1,572 @@ | |||
| 1 | <?php | ||
| 2 | |||
| 3 | declare(strict_types=1); | ||
| 4 | |||
| 5 | namespace Doctrine\DBAL\Schema; | ||
| 6 | |||
| 7 | use Doctrine\DBAL\Exception; | ||
| 8 | use Doctrine\DBAL\Platforms\PostgreSQLPlatform; | ||
| 9 | use Doctrine\DBAL\Result; | ||
| 10 | use Doctrine\DBAL\Types\JsonType; | ||
| 11 | use Doctrine\DBAL\Types\Type; | ||
| 12 | |||
| 13 | use function array_change_key_case; | ||
| 14 | use function array_key_exists; | ||
| 15 | use function array_map; | ||
| 16 | use function array_merge; | ||
| 17 | use function assert; | ||
| 18 | use function explode; | ||
| 19 | use function implode; | ||
| 20 | use function in_array; | ||
| 21 | use function is_string; | ||
| 22 | use function preg_match; | ||
| 23 | use function sprintf; | ||
| 24 | use function str_contains; | ||
| 25 | use function str_replace; | ||
| 26 | use function strtolower; | ||
| 27 | use function trim; | ||
| 28 | |||
| 29 | use const CASE_LOWER; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * PostgreSQL Schema Manager. | ||
| 33 | * | ||
| 34 | * @extends AbstractSchemaManager<PostgreSQLPlatform> | ||
| 35 | */ | ||
| 36 | class PostgreSQLSchemaManager extends AbstractSchemaManager | ||
| 37 | { | ||
| 38 | private ?string $currentSchema = null; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * {@inheritDoc} | ||
| 42 | */ | ||
| 43 | public function listSchemaNames(): array | ||
| 44 | { | ||
| 45 | return $this->connection->fetchFirstColumn( | ||
| 46 | <<<'SQL' | ||
| 47 | SELECT schema_name | ||
| 48 | FROM information_schema.schemata | ||
| 49 | WHERE schema_name NOT LIKE 'pg\_%' | ||
| 50 | AND schema_name != 'information_schema' | ||
| 51 | SQL, | ||
| 52 | ); | ||
| 53 | } | ||
| 54 | |||
| 55 | public function createSchemaConfig(): SchemaConfig | ||
| 56 | { | ||
| 57 | $config = parent::createSchemaConfig(); | ||
| 58 | |||
| 59 | $config->setName($this->getCurrentSchema()); | ||
| 60 | |||
| 61 | return $config; | ||
| 62 | } | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Returns the name of the current schema. | ||
| 66 | * | ||
| 67 | * @throws Exception | ||
| 68 | */ | ||
| 69 | protected function getCurrentSchema(): ?string | ||
| 70 | { | ||
| 71 | return $this->currentSchema ??= $this->determineCurrentSchema(); | ||
| 72 | } | ||
| 73 | |||
| 74 | /** | ||
| 75 | * Determines the name of the current schema. | ||
| 76 | * | ||
| 77 | * @throws Exception | ||
| 78 | */ | ||
| 79 | protected function determineCurrentSchema(): string | ||
| 80 | { | ||
| 81 | $currentSchema = $this->connection->fetchOne('SELECT current_schema()'); | ||
| 82 | assert(is_string($currentSchema)); | ||
| 83 | |||
| 84 | return $currentSchema; | ||
| 85 | } | ||
| 86 | |||
| 87 | /** | ||
| 88 | * {@inheritDoc} | ||
| 89 | */ | ||
| 90 | protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey): ForeignKeyConstraint | ||
| 91 | { | ||
| 92 | $onUpdate = null; | ||
| 93 | $onDelete = null; | ||
| 94 | |||
| 95 | if ( | ||
| 96 | preg_match( | ||
| 97 | '(ON UPDATE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', | ||
| 98 | $tableForeignKey['condef'], | ||
| 99 | $match, | ||
| 100 | ) === 1 | ||
| 101 | ) { | ||
| 102 | $onUpdate = $match[1]; | ||
| 103 | } | ||
| 104 | |||
| 105 | if ( | ||
| 106 | preg_match( | ||
| 107 | '(ON DELETE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', | ||
| 108 | $tableForeignKey['condef'], | ||
| 109 | $match, | ||
| 110 | ) === 1 | ||
| 111 | ) { | ||
| 112 | $onDelete = $match[1]; | ||
| 113 | } | ||
| 114 | |||
| 115 | $result = preg_match('/FOREIGN KEY \((.+)\) REFERENCES (.+)\((.+)\)/', $tableForeignKey['condef'], $values); | ||
| 116 | assert($result === 1); | ||
| 117 | |||
| 118 | // PostgreSQL returns identifiers that are keywords with quotes, we need them later, don't get | ||
| 119 | // the idea to trim them here. | ||
| 120 | $localColumns = array_map('trim', explode(',', $values[1])); | ||
| 121 | $foreignColumns = array_map('trim', explode(',', $values[3])); | ||
| 122 | $foreignTable = $values[2]; | ||
| 123 | |||
| 124 | return new ForeignKeyConstraint( | ||
| 125 | $localColumns, | ||
| 126 | $foreignTable, | ||
| 127 | $foreignColumns, | ||
| 128 | $tableForeignKey['conname'], | ||
| 129 | ['onUpdate' => $onUpdate, 'onDelete' => $onDelete], | ||
| 130 | ); | ||
| 131 | } | ||
| 132 | |||
| 133 | /** | ||
| 134 | * {@inheritDoc} | ||
| 135 | */ | ||
| 136 | protected function _getPortableViewDefinition(array $view): View | ||
| 137 | { | ||
| 138 | return new View($view['schemaname'] . '.' . $view['viewname'], $view['definition']); | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * {@inheritDoc} | ||
| 143 | */ | ||
| 144 | protected function _getPortableTableDefinition(array $table): string | ||
| 145 | { | ||
| 146 | $currentSchema = $this->getCurrentSchema(); | ||
| 147 | |||
| 148 | if ($table['schema_name'] === $currentSchema) { | ||
| 149 | return $table['table_name']; | ||
| 150 | } | ||
| 151 | |||
| 152 | return $table['schema_name'] . '.' . $table['table_name']; | ||
| 153 | } | ||
| 154 | |||
| 155 | /** | ||
| 156 | * {@inheritDoc} | ||
| 157 | * | ||
| 158 | * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html | ||
| 159 | */ | ||
| 160 | protected function _getPortableTableIndexesList(array $tableIndexes, string $tableName): array | ||
| 161 | { | ||
| 162 | $buffer = []; | ||
| 163 | foreach ($tableIndexes as $row) { | ||
| 164 | $colNumbers = array_map('intval', explode(' ', $row['indkey'])); | ||
| 165 | $columnNameSql = sprintf( | ||
| 166 | 'SELECT attnum, attname FROM pg_attribute WHERE attrelid=%d AND attnum IN (%s) ORDER BY attnum ASC', | ||
| 167 | $row['indrelid'], | ||
| 168 | implode(' ,', $colNumbers), | ||
| 169 | ); | ||
| 170 | |||
| 171 | $indexColumns = $this->connection->fetchAllAssociative($columnNameSql); | ||
| 172 | |||
| 173 | // required for getting the order of the columns right. | ||
| 174 | foreach ($colNumbers as $colNum) { | ||
| 175 | foreach ($indexColumns as $colRow) { | ||
| 176 | if ($colNum !== $colRow['attnum']) { | ||
| 177 | continue; | ||
| 178 | } | ||
| 179 | |||
| 180 | $buffer[] = [ | ||
| 181 | 'key_name' => $row['relname'], | ||
| 182 | 'column_name' => trim($colRow['attname']), | ||
| 183 | 'non_unique' => ! $row['indisunique'], | ||
| 184 | 'primary' => $row['indisprimary'], | ||
| 185 | 'where' => $row['where'], | ||
| 186 | ]; | ||
| 187 | } | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | return parent::_getPortableTableIndexesList($buffer, $tableName); | ||
| 192 | } | ||
| 193 | |||
| 194 | /** | ||
| 195 | * {@inheritDoc} | ||
| 196 | */ | ||
| 197 | protected function _getPortableDatabaseDefinition(array $database): string | ||
| 198 | { | ||
| 199 | return $database['datname']; | ||
| 200 | } | ||
| 201 | |||
| 202 | /** | ||
| 203 | * {@inheritDoc} | ||
| 204 | */ | ||
| 205 | protected function _getPortableSequenceDefinition(array $sequence): Sequence | ||
| 206 | { | ||
| 207 | if ($sequence['schemaname'] !== 'public') { | ||
| 208 | $sequenceName = $sequence['schemaname'] . '.' . $sequence['relname']; | ||
| 209 | } else { | ||
| 210 | $sequenceName = $sequence['relname']; | ||
| 211 | } | ||
| 212 | |||
| 213 | return new Sequence($sequenceName, (int) $sequence['increment_by'], (int) $sequence['min_value']); | ||
| 214 | } | ||
| 215 | |||
| 216 | /** | ||
| 217 | * {@inheritDoc} | ||
| 218 | */ | ||
| 219 | protected function _getPortableTableColumnDefinition(array $tableColumn): Column | ||
| 220 | { | ||
| 221 | $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); | ||
| 222 | |||
| 223 | $length = null; | ||
| 224 | |||
| 225 | if ( | ||
| 226 | in_array(strtolower($tableColumn['type']), ['varchar', 'bpchar'], true) | ||
| 227 | && preg_match('/\((\d*)\)/', $tableColumn['complete_type'], $matches) === 1 | ||
| 228 | ) { | ||
| 229 | $length = (int) $matches[1]; | ||
| 230 | } | ||
| 231 | |||
| 232 | $autoincrement = $tableColumn['attidentity'] === 'd'; | ||
| 233 | |||
| 234 | $matches = []; | ||
| 235 | |||
| 236 | assert(array_key_exists('default', $tableColumn)); | ||
| 237 | assert(array_key_exists('complete_type', $tableColumn)); | ||
| 238 | |||
| 239 | if ($tableColumn['default'] !== null) { | ||
| 240 | if (preg_match("/^['(](.*)[')]::/", $tableColumn['default'], $matches) === 1) { | ||
| 241 | $tableColumn['default'] = $matches[1]; | ||
| 242 | } elseif (preg_match('/^NULL::/', $tableColumn['default']) === 1) { | ||
| 243 | $tableColumn['default'] = null; | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | if ($length === -1 && isset($tableColumn['atttypmod'])) { | ||
| 248 | $length = $tableColumn['atttypmod'] - 4; | ||
| 249 | } | ||
| 250 | |||
| 251 | if ((int) $length <= 0) { | ||
| 252 | $length = null; | ||
| 253 | } | ||
| 254 | |||
| 255 | $fixed = false; | ||
| 256 | |||
| 257 | if (! isset($tableColumn['name'])) { | ||
| 258 | $tableColumn['name'] = ''; | ||
| 259 | } | ||
| 260 | |||
| 261 | $precision = null; | ||
| 262 | $scale = 0; | ||
| 263 | $jsonb = null; | ||
| 264 | |||
| 265 | $dbType = strtolower($tableColumn['type']); | ||
| 266 | if ( | ||
| 267 | $tableColumn['domain_type'] !== null | ||
| 268 | && $tableColumn['domain_type'] !== '' | ||
| 269 | && ! $this->platform->hasDoctrineTypeMappingFor($tableColumn['type']) | ||
| 270 | ) { | ||
| 271 | $dbType = strtolower($tableColumn['domain_type']); | ||
| 272 | $tableColumn['complete_type'] = $tableColumn['domain_complete_type']; | ||
| 273 | } | ||
| 274 | |||
| 275 | $type = $this->platform->getDoctrineTypeMapping($dbType); | ||
| 276 | |||
| 277 | switch ($dbType) { | ||
| 278 | case 'smallint': | ||
| 279 | case 'int2': | ||
| 280 | case 'int': | ||
| 281 | case 'int4': | ||
| 282 | case 'integer': | ||
| 283 | case 'bigint': | ||
| 284 | case 'int8': | ||
| 285 | $length = null; | ||
| 286 | break; | ||
| 287 | |||
| 288 | case 'bool': | ||
| 289 | case 'boolean': | ||
| 290 | if ($tableColumn['default'] === 'true') { | ||
| 291 | $tableColumn['default'] = true; | ||
| 292 | } | ||
| 293 | |||
| 294 | if ($tableColumn['default'] === 'false') { | ||
| 295 | $tableColumn['default'] = false; | ||
| 296 | } | ||
| 297 | |||
| 298 | $length = null; | ||
| 299 | break; | ||
| 300 | |||
| 301 | case 'json': | ||
| 302 | case 'text': | ||
| 303 | case '_varchar': | ||
| 304 | case 'varchar': | ||
| 305 | $tableColumn['default'] = $this->parseDefaultExpression($tableColumn['default']); | ||
| 306 | break; | ||
| 307 | |||
| 308 | case 'char': | ||
| 309 | case 'bpchar': | ||
| 310 | $fixed = true; | ||
| 311 | break; | ||
| 312 | |||
| 313 | case 'float': | ||
| 314 | case 'float4': | ||
| 315 | case 'float8': | ||
| 316 | case 'double': | ||
| 317 | case 'double precision': | ||
| 318 | case 'real': | ||
| 319 | case 'decimal': | ||
| 320 | case 'money': | ||
| 321 | case 'numeric': | ||
| 322 | if ( | ||
| 323 | preg_match( | ||
| 324 | '([A-Za-z]+\(([0-9]+),([0-9]+)\))', | ||
| 325 | $tableColumn['complete_type'], | ||
| 326 | $match, | ||
| 327 | ) === 1 | ||
| 328 | ) { | ||
| 329 | $precision = (int) $match[1]; | ||
| 330 | $scale = (int) $match[2]; | ||
| 331 | $length = null; | ||
| 332 | } | ||
| 333 | |||
| 334 | break; | ||
| 335 | |||
| 336 | case 'year': | ||
| 337 | $length = null; | ||
| 338 | break; | ||
| 339 | |||
| 340 | // PostgreSQL 9.4+ only | ||
| 341 | case 'jsonb': | ||
| 342 | $jsonb = true; | ||
| 343 | break; | ||
| 344 | } | ||
| 345 | |||
| 346 | if ( | ||
| 347 | is_string($tableColumn['default']) && preg_match( | ||
| 348 | "('([^']+)'::)", | ||
| 349 | $tableColumn['default'], | ||
| 350 | $match, | ||
| 351 | ) === 1 | ||
| 352 | ) { | ||
| 353 | $tableColumn['default'] = $match[1]; | ||
| 354 | } | ||
| 355 | |||
| 356 | $options = [ | ||
| 357 | 'length' => $length, | ||
| 358 | 'notnull' => (bool) $tableColumn['isnotnull'], | ||
| 359 | 'default' => $tableColumn['default'], | ||
| 360 | 'precision' => $precision, | ||
| 361 | 'scale' => $scale, | ||
| 362 | 'fixed' => $fixed, | ||
| 363 | 'autoincrement' => $autoincrement, | ||
| 364 | ]; | ||
| 365 | |||
| 366 | if (isset($tableColumn['comment'])) { | ||
| 367 | $options['comment'] = $tableColumn['comment']; | ||
| 368 | } | ||
| 369 | |||
| 370 | $column = new Column($tableColumn['field'], Type::getType($type), $options); | ||
| 371 | |||
| 372 | if (! empty($tableColumn['collation'])) { | ||
| 373 | $column->setPlatformOption('collation', $tableColumn['collation']); | ||
| 374 | } | ||
| 375 | |||
| 376 | if ($column->getType() instanceof JsonType) { | ||
| 377 | $column->setPlatformOption('jsonb', $jsonb); | ||
| 378 | } | ||
| 379 | |||
| 380 | return $column; | ||
| 381 | } | ||
| 382 | |||
| 383 | /** | ||
| 384 | * Parses a default value expression as given by PostgreSQL | ||
| 385 | */ | ||
| 386 | private function parseDefaultExpression(?string $default): ?string | ||
| 387 | { | ||
| 388 | if ($default === null) { | ||
| 389 | return $default; | ||
| 390 | } | ||
| 391 | |||
| 392 | return str_replace("''", "'", $default); | ||
| 393 | } | ||
| 394 | |||
| 395 | protected function selectTableNames(string $databaseName): Result | ||
| 396 | { | ||
| 397 | $sql = <<<'SQL' | ||
| 398 | SELECT quote_ident(table_name) AS table_name, | ||
| 399 | table_schema AS schema_name | ||
| 400 | FROM information_schema.tables | ||
| 401 | WHERE table_catalog = ? | ||
| 402 | AND table_schema NOT LIKE 'pg\_%' | ||
| 403 | AND table_schema != 'information_schema' | ||
| 404 | AND table_name != 'geometry_columns' | ||
| 405 | AND table_name != 'spatial_ref_sys' | ||
| 406 | AND table_type = 'BASE TABLE' | ||
| 407 | SQL; | ||
| 408 | |||
| 409 | return $this->connection->executeQuery($sql, [$databaseName]); | ||
| 410 | } | ||
| 411 | |||
| 412 | protected function selectTableColumns(string $databaseName, ?string $tableName = null): Result | ||
| 413 | { | ||
| 414 | $sql = 'SELECT'; | ||
| 415 | |||
| 416 | if ($tableName === null) { | ||
| 417 | $sql .= ' c.relname AS table_name, n.nspname AS schema_name,'; | ||
| 418 | } | ||
| 419 | |||
| 420 | $sql .= <<<'SQL' | ||
| 421 | a.attnum, | ||
| 422 | quote_ident(a.attname) AS field, | ||
| 423 | t.typname AS type, | ||
| 424 | format_type(a.atttypid, a.atttypmod) AS complete_type, | ||
| 425 | (SELECT tc.collcollate FROM pg_catalog.pg_collation tc WHERE tc.oid = a.attcollation) AS collation, | ||
| 426 | (SELECT t1.typname FROM pg_catalog.pg_type t1 WHERE t1.oid = t.typbasetype) AS domain_type, | ||
| 427 | (SELECT format_type(t2.typbasetype, t2.typtypmod) FROM | ||
| 428 | pg_catalog.pg_type t2 WHERE t2.typtype = 'd' AND t2.oid = a.atttypid) AS domain_complete_type, | ||
| 429 | a.attnotnull AS isnotnull, | ||
| 430 | a.attidentity, | ||
| 431 | (SELECT 't' | ||
| 432 | FROM pg_index | ||
| 433 | WHERE c.oid = pg_index.indrelid | ||
| 434 | AND pg_index.indkey[0] = a.attnum | ||
| 435 | AND pg_index.indisprimary = 't' | ||
| 436 | ) AS pri, | ||
| 437 | (SELECT pg_get_expr(adbin, adrelid) | ||
| 438 | FROM pg_attrdef | ||
| 439 | WHERE c.oid = pg_attrdef.adrelid | ||
| 440 | AND pg_attrdef.adnum=a.attnum | ||
| 441 | ) AS default, | ||
| 442 | (SELECT pg_description.description | ||
| 443 | FROM pg_description WHERE pg_description.objoid = c.oid AND a.attnum = pg_description.objsubid | ||
| 444 | ) AS comment | ||
| 445 | FROM pg_attribute a | ||
| 446 | INNER JOIN pg_class c | ||
| 447 | ON c.oid = a.attrelid | ||
| 448 | INNER JOIN pg_type t | ||
| 449 | ON t.oid = a.atttypid | ||
| 450 | INNER JOIN pg_namespace n | ||
| 451 | ON n.oid = c.relnamespace | ||
| 452 | LEFT JOIN pg_depend d | ||
| 453 | ON d.objid = c.oid | ||
| 454 | AND d.deptype = 'e' | ||
| 455 | AND d.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_class') | ||
| 456 | SQL; | ||
| 457 | |||
| 458 | $conditions = array_merge([ | ||
| 459 | 'a.attnum > 0', | ||
| 460 | "c.relkind = 'r'", | ||
| 461 | 'd.refobjid IS NULL', | ||
| 462 | ], $this->buildQueryConditions($tableName)); | ||
| 463 | |||
| 464 | $sql .= ' WHERE ' . implode(' AND ', $conditions) . ' ORDER BY a.attnum'; | ||
| 465 | |||
| 466 | return $this->connection->executeQuery($sql); | ||
| 467 | } | ||
| 468 | |||
| 469 | protected function selectIndexColumns(string $databaseName, ?string $tableName = null): Result | ||
| 470 | { | ||
| 471 | $sql = 'SELECT'; | ||
| 472 | |||
| 473 | if ($tableName === null) { | ||
| 474 | $sql .= ' tc.relname AS table_name, tn.nspname AS schema_name,'; | ||
| 475 | } | ||
| 476 | |||
| 477 | $sql .= <<<'SQL' | ||
| 478 | quote_ident(ic.relname) AS relname, | ||
| 479 | i.indisunique, | ||
| 480 | i.indisprimary, | ||
| 481 | i.indkey, | ||
| 482 | i.indrelid, | ||
| 483 | pg_get_expr(indpred, indrelid) AS "where" | ||
| 484 | FROM pg_index i | ||
| 485 | JOIN pg_class AS tc ON tc.oid = i.indrelid | ||
| 486 | JOIN pg_namespace tn ON tn.oid = tc.relnamespace | ||
| 487 | JOIN pg_class AS ic ON ic.oid = i.indexrelid | ||
| 488 | WHERE ic.oid IN ( | ||
| 489 | SELECT indexrelid | ||
| 490 | FROM pg_index i, pg_class c, pg_namespace n | ||
| 491 | SQL; | ||
| 492 | |||
| 493 | $conditions = array_merge([ | ||
| 494 | 'c.oid = i.indrelid', | ||
| 495 | 'c.relnamespace = n.oid', | ||
| 496 | ], $this->buildQueryConditions($tableName)); | ||
| 497 | |||
| 498 | $sql .= ' WHERE ' . implode(' AND ', $conditions) . ')'; | ||
| 499 | |||
| 500 | return $this->connection->executeQuery($sql); | ||
| 501 | } | ||
| 502 | |||
| 503 | protected function selectForeignKeyColumns(string $databaseName, ?string $tableName = null): Result | ||
| 504 | { | ||
| 505 | $sql = 'SELECT'; | ||
| 506 | |||
| 507 | if ($tableName === null) { | ||
| 508 | $sql .= ' tc.relname AS table_name, tn.nspname AS schema_name,'; | ||
| 509 | } | ||
| 510 | |||
| 511 | $sql .= <<<'SQL' | ||
| 512 | quote_ident(r.conname) as conname, | ||
| 513 | pg_get_constraintdef(r.oid, true) as condef | ||
| 514 | FROM pg_constraint r | ||
| 515 | JOIN pg_class AS tc ON tc.oid = r.conrelid | ||
| 516 | JOIN pg_namespace tn ON tn.oid = tc.relnamespace | ||
| 517 | WHERE r.conrelid IN | ||
| 518 | ( | ||
| 519 | SELECT c.oid | ||
| 520 | FROM pg_class c, pg_namespace n | ||
| 521 | SQL; | ||
| 522 | |||
| 523 | $conditions = array_merge(['n.oid = c.relnamespace'], $this->buildQueryConditions($tableName)); | ||
| 524 | |||
| 525 | $sql .= ' WHERE ' . implode(' AND ', $conditions) . ") AND r.contype = 'f'"; | ||
| 526 | |||
| 527 | return $this->connection->executeQuery($sql); | ||
| 528 | } | ||
| 529 | |||
| 530 | /** | ||
| 531 | * {@inheritDoc} | ||
| 532 | */ | ||
| 533 | protected function fetchTableOptionsByTable(string $databaseName, ?string $tableName = null): array | ||
| 534 | { | ||
| 535 | $sql = <<<'SQL' | ||
| 536 | SELECT c.relname, | ||
| 537 | CASE c.relpersistence WHEN 'u' THEN true ELSE false END as unlogged, | ||
| 538 | obj_description(c.oid, 'pg_class') AS comment | ||
| 539 | FROM pg_class c | ||
| 540 | INNER JOIN pg_namespace n | ||
| 541 | ON n.oid = c.relnamespace | ||
| 542 | SQL; | ||
| 543 | |||
| 544 | $conditions = array_merge(["c.relkind = 'r'"], $this->buildQueryConditions($tableName)); | ||
| 545 | |||
| 546 | $sql .= ' WHERE ' . implode(' AND ', $conditions); | ||
| 547 | |||
| 548 | return $this->connection->fetchAllAssociativeIndexed($sql); | ||
| 549 | } | ||
| 550 | |||
| 551 | /** @return list<string> */ | ||
| 552 | private function buildQueryConditions(?string $tableName): array | ||
| 553 | { | ||
| 554 | $conditions = []; | ||
| 555 | |||
| 556 | if ($tableName !== null) { | ||
| 557 | if (str_contains($tableName, '.')) { | ||
| 558 | [$schemaName, $tableName] = explode('.', $tableName); | ||
| 559 | $conditions[] = 'n.nspname = ' . $this->platform->quoteStringLiteral($schemaName); | ||
| 560 | } else { | ||
| 561 | $conditions[] = 'n.nspname = ANY(current_schemas(false))'; | ||
| 562 | } | ||
| 563 | |||
| 564 | $identifier = new Identifier($tableName); | ||
| 565 | $conditions[] = 'c.relname = ' . $this->platform->quoteStringLiteral($identifier->getName()); | ||
| 566 | } | ||
| 567 | |||
| 568 | $conditions[] = "n.nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast')"; | ||
| 569 | |||
| 570 | return $conditions; | ||
| 571 | } | ||
| 572 | } | ||
