doctrine /
dbal
| 1 | <?php |
||
| 2 | |||
| 3 | declare(strict_types=1); |
||
| 4 | |||
| 5 | namespace Doctrine\DBAL\Schema; |
||
| 6 | |||
| 7 | use Doctrine\DBAL\Exception\DriverException; |
||
| 8 | use Doctrine\DBAL\FetchMode; |
||
| 9 | use Doctrine\DBAL\Platforms\PostgreSQL94Platform; |
||
| 10 | use Doctrine\DBAL\Types\Type; |
||
| 11 | use Doctrine\DBAL\Types\Types; |
||
| 12 | use function array_change_key_case; |
||
| 13 | use function array_filter; |
||
| 14 | use function array_keys; |
||
| 15 | use function array_map; |
||
| 16 | use function array_shift; |
||
| 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_replace; |
||
| 25 | use function strpos; |
||
| 26 | use function strtolower; |
||
| 27 | use function trim; |
||
| 28 | use const CASE_LOWER; |
||
| 29 | |||
| 30 | /** |
||
| 31 | * PostgreSQL Schema Manager. |
||
| 32 | */ |
||
| 33 | class PostgreSqlSchemaManager extends AbstractSchemaManager |
||
| 34 | { |
||
| 35 | /** @var array<int, string> */ |
||
| 36 | private $existingSchemaPaths; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * Gets all the existing schema names. |
||
| 40 | * |
||
| 41 | * @return array<int, string> |
||
| 42 | */ |
||
| 43 | 10 | public function getSchemaNames() : array |
|
| 44 | { |
||
| 45 | 10 | $statement = $this->_conn->executeQuery("SELECT nspname FROM pg_namespace WHERE nspname !~ '^pg_.*' AND nspname != 'information_schema'"); |
|
| 46 | |||
| 47 | 10 | return $statement->fetchAll(FetchMode::COLUMN); |
|
| 48 | } |
||
| 49 | |||
| 50 | /** |
||
| 51 | * Returns an array of schema search paths. |
||
| 52 | * |
||
| 53 | * This is a PostgreSQL only function. |
||
| 54 | * |
||
| 55 | * @return array<int, string> |
||
| 56 | */ |
||
| 57 | 85 | public function getSchemaSearchPaths() : array |
|
| 58 | { |
||
| 59 | 85 | $params = $this->_conn->getParams(); |
|
| 60 | 85 | $schema = explode(',', $this->_conn->fetchColumn('SHOW search_path')); |
|
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 61 | |||
| 62 | 85 | if (isset($params['user'])) { |
|
| 63 | 85 | $schema = str_replace('"$user"', $params['user'], $schema); |
|
| 64 | } |
||
| 65 | |||
| 66 | 85 | return array_map('trim', $schema); |
|
| 67 | } |
||
| 68 | |||
| 69 | /** |
||
| 70 | * Gets names of all existing schemas in the current users search path. |
||
| 71 | * |
||
| 72 | * This is a PostgreSQL only function. |
||
| 73 | * |
||
| 74 | * @return array<int, string> |
||
| 75 | */ |
||
| 76 | 70 | public function getExistingSchemaSearchPaths() : array |
|
| 77 | { |
||
| 78 | 70 | if ($this->existingSchemaPaths === null) { |
|
| 79 | 5 | $this->determineExistingSchemaSearchPaths(); |
|
| 80 | } |
||
| 81 | |||
| 82 | 70 | return $this->existingSchemaPaths; |
|
| 83 | } |
||
| 84 | |||
| 85 | /** |
||
| 86 | * Sets or resets the order of the existing schemas in the current search path of the user. |
||
| 87 | * |
||
| 88 | * This is a PostgreSQL only function. |
||
| 89 | */ |
||
| 90 | 5 | public function determineExistingSchemaSearchPaths() : void |
|
| 91 | { |
||
| 92 | 5 | $names = $this->getSchemaNames(); |
|
| 93 | 5 | $paths = $this->getSchemaSearchPaths(); |
|
| 94 | |||
| 95 | $this->existingSchemaPaths = array_filter($paths, static function ($v) use ($names) : bool { |
||
| 96 | 5 | return in_array($v, $names, true); |
|
| 97 | 5 | }); |
|
| 98 | 5 | } |
|
| 99 | |||
| 100 | 10 | public function dropDatabase(string $database) : void |
|
| 101 | { |
||
| 102 | try { |
||
| 103 | 10 | parent::dropDatabase($database); |
|
| 104 | 10 | } catch (DriverException $exception) { |
|
| 105 | // If we have a SQLSTATE 55006, the drop database operation failed |
||
| 106 | // because of active connections on the database. |
||
| 107 | // To force dropping the database, we first have to close all active connections |
||
| 108 | // on that database and issue the drop database operation again. |
||
| 109 | 10 | if ($exception->getSQLState() !== '55006') { |
|
| 110 | 10 | throw $exception; |
|
| 111 | } |
||
| 112 | |||
| 113 | assert($this->_platform instanceof PostgreSQL94Platform); |
||
| 114 | |||
| 115 | $this->_execSql( |
||
| 116 | [ |
||
| 117 | $this->_platform->getDisallowDatabaseConnectionsSQL($database), |
||
| 118 | $this->_platform->getCloseActiveDatabaseConnectionsSQL($database), |
||
| 119 | ] |
||
| 120 | ); |
||
| 121 | |||
| 122 | parent::dropDatabase($database); |
||
| 123 | } |
||
| 124 | 5 | } |
|
| 125 | |||
| 126 | /** |
||
| 127 | * {@inheritdoc} |
||
| 128 | */ |
||
| 129 | 85 | protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey) : ForeignKeyConstraint |
|
| 130 | { |
||
| 131 | 85 | $onUpdate = null; |
|
| 132 | 85 | $onDelete = null; |
|
| 133 | 85 | $localColumns = []; |
|
| 134 | 85 | $foreignColumns = []; |
|
| 135 | 85 | $foreignTable = null; |
|
| 136 | |||
| 137 | 85 | if (preg_match( |
|
| 138 | '(ON UPDATE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', |
||
| 139 | 85 | $tableForeignKey['condef'], |
|
| 140 | 85 | $match |
|
| 141 | 85 | ) === 1) { |
|
| 142 | 20 | $onUpdate = $match[1]; |
|
| 143 | } |
||
| 144 | |||
| 145 | 85 | if (preg_match( |
|
| 146 | '(ON DELETE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', |
||
| 147 | 85 | $tableForeignKey['condef'], |
|
| 148 | 85 | $match |
|
| 149 | 85 | ) === 1) { |
|
| 150 | 20 | $onDelete = $match[1]; |
|
| 151 | } |
||
| 152 | |||
| 153 | 85 | if (preg_match( |
|
| 154 | '/FOREIGN KEY \((.+)\) REFERENCES (.+)\((.+)\)/', |
||
| 155 | 85 | $tableForeignKey['condef'], |
|
| 156 | 85 | $values |
|
| 157 | 85 | ) === 1) { |
|
| 158 | // PostgreSQL returns identifiers that are keywords with quotes, we need them later, don't get |
||
| 159 | // the idea to trim them here. |
||
| 160 | 85 | $localColumns = array_map('trim', explode(',', $values[1])); |
|
| 161 | 85 | $foreignColumns = array_map('trim', explode(',', $values[3])); |
|
| 162 | 85 | $foreignTable = $values[2]; |
|
| 163 | } |
||
| 164 | |||
| 165 | 85 | return new ForeignKeyConstraint( |
|
| 166 | 85 | $localColumns, |
|
| 167 | $foreignTable, |
||
| 168 | $foreignColumns, |
||
| 169 | 85 | $tableForeignKey['conname'], |
|
| 170 | 85 | ['onUpdate' => $onUpdate, 'onDelete' => $onDelete] |
|
| 171 | ); |
||
| 172 | } |
||
| 173 | |||
| 174 | /** |
||
| 175 | * {@inheritdoc} |
||
| 176 | */ |
||
| 177 | 5 | protected function _getPortableViewDefinition(array $view) : View |
|
| 178 | { |
||
| 179 | 5 | return new View($view['schemaname'] . '.' . $view['viewname'], $view['definition']); |
|
| 180 | } |
||
| 181 | |||
| 182 | /** |
||
| 183 | * {@inheritdoc} |
||
| 184 | */ |
||
| 185 | protected function _getPortableUserDefinition(array $user) : array |
||
| 186 | { |
||
| 187 | return [ |
||
| 188 | 'user' => $user['usename'], |
||
| 189 | 'password' => $user['passwd'], |
||
| 190 | ]; |
||
| 191 | } |
||
| 192 | |||
| 193 | /** |
||
| 194 | * {@inheritdoc} |
||
| 195 | */ |
||
| 196 | 70 | protected function _getPortableTableDefinition(array $table) : string |
|
| 197 | { |
||
| 198 | 70 | $schemas = $this->getExistingSchemaSearchPaths(); |
|
| 199 | 70 | $firstSchema = array_shift($schemas); |
|
| 200 | |||
| 201 | 70 | if ($table['schema_name'] === $firstSchema) { |
|
| 202 | 70 | return $table['table_name']; |
|
| 203 | } |
||
| 204 | |||
| 205 | 30 | return $table['schema_name'] . '.' . $table['table_name']; |
|
| 206 | } |
||
| 207 | |||
| 208 | /** |
||
| 209 | * {@inheritdoc} |
||
| 210 | * |
||
| 211 | * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html |
||
| 212 | */ |
||
| 213 | 345 | protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array |
|
| 214 | { |
||
| 215 | 345 | $buffer = []; |
|
| 216 | 345 | foreach ($tableIndexRows as $row) { |
|
| 217 | 135 | $colNumbers = array_map('intval', explode(' ', $row['indkey'])); |
|
| 218 | 135 | $columnNameSql = sprintf( |
|
| 219 | 'SELECT attnum, attname FROM pg_attribute WHERE attrelid=%d AND attnum IN (%s) ORDER BY attnum ASC', |
||
| 220 | 135 | $row['indrelid'], |
|
| 221 | 135 | implode(' ,', $colNumbers) |
|
| 222 | ); |
||
| 223 | |||
| 224 | 135 | $stmt = $this->_conn->executeQuery($columnNameSql); |
|
| 225 | 135 | $indexColumns = $stmt->fetchAll(); |
|
| 226 | |||
| 227 | // required for getting the order of the columns right. |
||
| 228 | 135 | foreach ($colNumbers as $colNum) { |
|
| 229 | 135 | foreach ($indexColumns as $colRow) { |
|
| 230 | 135 | if ($colNum !== $colRow['attnum']) { |
|
| 231 | 35 | continue; |
|
| 232 | } |
||
| 233 | |||
| 234 | 135 | $buffer[] = [ |
|
| 235 | 135 | 'key_name' => $row['relname'], |
|
| 236 | 135 | 'column_name' => trim($colRow['attname']), |
|
| 237 | 135 | 'non_unique' => ! $row['indisunique'], |
|
| 238 | 135 | 'primary' => $row['indisprimary'], |
|
| 239 | 135 | 'where' => $row['where'], |
|
| 240 | ]; |
||
| 241 | } |
||
| 242 | } |
||
| 243 | } |
||
| 244 | |||
| 245 | 345 | return parent::_getPortableTableIndexesList($buffer, $tableName); |
|
| 246 | } |
||
| 247 | |||
| 248 | /** |
||
| 249 | * {@inheritdoc} |
||
| 250 | */ |
||
| 251 | 10 | protected function _getPortableDatabaseDefinition(array $database) : string |
|
| 252 | { |
||
| 253 | 10 | return $database['datname']; |
|
| 254 | } |
||
| 255 | |||
| 256 | /** |
||
| 257 | * {@inheritdoc} |
||
| 258 | */ |
||
| 259 | 30 | protected function _getPortableSequencesList(array $sequences) : array |
|
| 260 | { |
||
| 261 | 30 | $sequenceDefinitions = []; |
|
| 262 | |||
| 263 | 30 | foreach ($sequences as $sequence) { |
|
| 264 | 30 | if ($sequence['schemaname'] !== 'public') { |
|
| 265 | 30 | $sequenceName = $sequence['schemaname'] . '.' . $sequence['relname']; |
|
| 266 | } else { |
||
| 267 | 30 | $sequenceName = $sequence['relname']; |
|
| 268 | } |
||
| 269 | |||
| 270 | 30 | $sequenceDefinitions[$sequenceName] = $sequence; |
|
| 271 | } |
||
| 272 | |||
| 273 | 30 | $list = []; |
|
| 274 | |||
| 275 | 30 | foreach ($this->filterAssetNames(array_keys($sequenceDefinitions)) as $sequenceName) { |
|
| 276 | 30 | $list[] = $this->_getPortableSequenceDefinition($sequenceDefinitions[$sequenceName]); |
|
| 277 | } |
||
| 278 | |||
| 279 | 30 | return $list; |
|
| 280 | } |
||
| 281 | |||
| 282 | /** |
||
| 283 | * {@inheritdoc} |
||
| 284 | */ |
||
| 285 | 10 | protected function getPortableNamespaceDefinition(array $namespace) : string |
|
| 286 | { |
||
| 287 | 10 | return $namespace['nspname']; |
|
| 288 | } |
||
| 289 | |||
| 290 | /** |
||
| 291 | * {@inheritdoc} |
||
| 292 | */ |
||
| 293 | 30 | protected function _getPortableSequenceDefinition(array $sequence) : Sequence |
|
| 294 | { |
||
| 295 | 30 | if ($sequence['schemaname'] !== 'public') { |
|
| 296 | 30 | $sequenceName = $sequence['schemaname'] . '.' . $sequence['relname']; |
|
| 297 | } else { |
||
| 298 | 30 | $sequenceName = $sequence['relname']; |
|
| 299 | } |
||
| 300 | |||
| 301 | 30 | if (! isset($sequence['increment_by'], $sequence['min_value'])) { |
|
| 302 | /** @var string[] $data */ |
||
| 303 | 18 | $data = $this->_conn->fetchAssoc('SELECT min_value, increment_by FROM ' . $this->_platform->quoteIdentifier($sequenceName)); |
|
| 304 | |||
| 305 | 18 | $sequence += $data; |
|
| 306 | } |
||
| 307 | |||
| 308 | 30 | return new Sequence($sequenceName, (int) $sequence['increment_by'], (int) $sequence['min_value']); |
|
| 309 | } |
||
| 310 | |||
| 311 | /** |
||
| 312 | * {@inheritdoc} |
||
| 313 | */ |
||
| 314 | 380 | protected function _getPortableTableColumnDefinition(array $tableColumn) : Column |
|
| 315 | { |
||
| 316 | 380 | $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); |
|
| 317 | |||
| 318 | 380 | $length = null; |
|
| 319 | |||
| 320 | 380 | if (in_array(strtolower($tableColumn['type']), ['varchar', 'bpchar'], true) |
|
| 321 | 380 | && preg_match('/\((\d*)\)/', $tableColumn['complete_type'], $matches) === 1) { |
|
| 322 | 195 | $length = (int) $matches[1]; |
|
| 323 | } |
||
| 324 | |||
| 325 | 380 | $matches = []; |
|
| 326 | |||
| 327 | 380 | $autoincrement = false; |
|
| 328 | 380 | if ($tableColumn['default'] !== null && preg_match("/^nextval\('(.*)'(::.*)?\)$/", $tableColumn['default'], $matches) === 1) { |
|
| 329 | 85 | $tableColumn['sequence'] = $matches[1]; |
|
| 330 | 85 | $tableColumn['default'] = null; |
|
| 331 | 85 | $autoincrement = true; |
|
| 332 | } |
||
| 333 | |||
| 334 | 380 | if ($tableColumn['default'] !== null) { |
|
| 335 | 150 | if (preg_match("/^['(](.*)[')]::/", $tableColumn['default'], $matches) === 1) { |
|
| 336 | 135 | $tableColumn['default'] = $matches[1]; |
|
| 337 | 141 | } elseif (preg_match('/^NULL::/', $tableColumn['default']) === 1) { |
|
| 338 | 115 | $tableColumn['default'] = null; |
|
| 339 | } |
||
| 340 | } |
||
| 341 | |||
| 342 | 380 | if ($length === -1 && isset($tableColumn['atttypmod'])) { |
|
| 343 | $length = $tableColumn['atttypmod'] - 4; |
||
| 344 | } |
||
| 345 | |||
| 346 | 380 | if ((int) $length <= 0) { |
|
| 347 | 375 | $length = null; |
|
| 348 | } |
||
| 349 | |||
| 350 | 380 | $fixed = false; |
|
| 351 | |||
| 352 | 380 | if (! isset($tableColumn['name'])) { |
|
| 353 | 380 | $tableColumn['name'] = ''; |
|
| 354 | } |
||
| 355 | |||
| 356 | 380 | $precision = null; |
|
| 357 | 380 | $scale = 0; |
|
| 358 | 380 | $jsonb = null; |
|
| 359 | |||
| 360 | 380 | $dbType = strtolower($tableColumn['type']); |
|
| 361 | 380 | if ($tableColumn['domain_type'] !== null |
|
| 362 | 380 | && $tableColumn['domain_type'] !== '' |
|
| 363 | 380 | && ! $this->_platform->hasDoctrineTypeMappingFor($tableColumn['type']) |
|
| 364 | ) { |
||
| 365 | 5 | $dbType = strtolower($tableColumn['domain_type']); |
|
| 366 | 5 | $tableColumn['complete_type'] = $tableColumn['domain_complete_type']; |
|
| 367 | } |
||
| 368 | |||
| 369 | 380 | $type = $this->extractDoctrineTypeFromComment($tableColumn['comment']) |
|
| 370 | 380 | ?? $this->_platform->getDoctrineTypeMapping($dbType); |
|
| 371 | |||
| 372 | switch ($dbType) { |
||
| 373 | 380 | case 'smallint': |
|
| 374 | 380 | case 'int2': |
|
| 375 | 15 | $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); |
|
| 376 | 15 | $length = null; |
|
| 377 | 15 | break; |
|
| 378 | |||
| 379 | 380 | case 'int': |
|
| 380 | 380 | case 'int4': |
|
| 381 | 275 | case 'integer': |
|
| 382 | 350 | $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); |
|
| 383 | 350 | $length = null; |
|
| 384 | 350 | break; |
|
| 385 | |||
| 386 | 275 | case 'bigint': |
|
| 387 | 275 | case 'int8': |
|
| 388 | 35 | $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); |
|
| 389 | 35 | $length = null; |
|
| 390 | 35 | break; |
|
| 391 | |||
| 392 | 255 | case 'bool': |
|
| 393 | 245 | case 'boolean': |
|
| 394 | 25 | if ($tableColumn['default'] === 'true') { |
|
| 395 | $tableColumn['default'] = true; |
||
| 396 | } |
||
| 397 | |||
| 398 | 25 | if ($tableColumn['default'] === 'false') { |
|
| 399 | 25 | $tableColumn['default'] = false; |
|
| 400 | } |
||
| 401 | |||
| 402 | 25 | $length = null; |
|
| 403 | 25 | break; |
|
| 404 | |||
| 405 | 245 | case 'text': |
|
| 406 | 245 | case '_varchar': |
|
| 407 | 245 | case 'varchar': |
|
| 408 | 210 | $tableColumn['default'] = $this->parseDefaultExpression($tableColumn['default']); |
|
| 409 | 210 | break; |
|
| 410 | |||
| 411 | 70 | case 'char': |
|
| 412 | 70 | case 'bpchar': |
|
| 413 | 25 | $fixed = true; |
|
| 414 | 25 | break; |
|
| 415 | |||
| 416 | 60 | case 'float': |
|
| 417 | 60 | case 'float4': |
|
| 418 | 60 | case 'float8': |
|
| 419 | 60 | case 'double': |
|
| 420 | 60 | case 'double precision': |
|
| 421 | 60 | case 'real': |
|
| 422 | 60 | case 'decimal': |
|
| 423 | 60 | case 'money': |
|
| 424 | 60 | case 'numeric': |
|
| 425 | 35 | $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); |
|
| 426 | |||
| 427 | 35 | if (preg_match( |
|
| 428 | '([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', |
||
| 429 | 35 | $tableColumn['complete_type'], |
|
| 430 | 35 | $match |
|
| 431 | 35 | ) === 1) { |
|
| 432 | 35 | $precision = (int) $match[1]; |
|
| 433 | 35 | $scale = (int) $match[2]; |
|
| 434 | 35 | $length = null; |
|
| 435 | } |
||
| 436 | |||
| 437 | 35 | break; |
|
| 438 | |||
| 439 | 55 | case 'year': |
|
| 440 | $length = null; |
||
| 441 | break; |
||
| 442 | |||
| 443 | // PostgreSQL 9.4+ only |
||
| 444 | 55 | case 'jsonb': |
|
| 445 | 15 | $jsonb = true; |
|
| 446 | 15 | break; |
|
| 447 | } |
||
| 448 | |||
| 449 | 380 | if (is_string($tableColumn['default']) && preg_match( |
|
| 450 | "('([^']+)'::)", |
||
| 451 | 140 | $tableColumn['default'], |
|
| 452 | 140 | $match |
|
| 453 | 380 | ) === 1) { |
|
| 454 | 100 | $tableColumn['default'] = $match[1]; |
|
| 455 | } |
||
| 456 | |||
| 457 | $options = [ |
||
| 458 | 380 | 'length' => $length, |
|
| 459 | 380 | 'notnull' => (bool) $tableColumn['isnotnull'], |
|
| 460 | 380 | 'default' => $tableColumn['default'], |
|
| 461 | 380 | 'precision' => $precision, |
|
| 462 | 380 | 'scale' => $scale, |
|
| 463 | 380 | 'fixed' => $fixed, |
|
| 464 | 'unsigned' => false, |
||
| 465 | 380 | 'autoincrement' => $autoincrement, |
|
| 466 | ]; |
||
| 467 | |||
| 468 | 380 | if (isset($tableColumn['comment'])) { |
|
| 469 | 80 | $options['comment'] = $tableColumn['comment']; |
|
| 470 | } |
||
| 471 | |||
| 472 | 380 | $column = new Column($tableColumn['field'], Type::getType($type), $options); |
|
| 473 | |||
| 474 | 380 | if (isset($tableColumn['collation']) && ! empty($tableColumn['collation'])) { |
|
| 475 | $column->setPlatformOption('collation', $tableColumn['collation']); |
||
| 476 | } |
||
| 477 | |||
| 478 | 380 | if ($column->getType()->getName() === Types::JSON) { |
|
| 479 | 20 | $column->setPlatformOption('jsonb', $jsonb); |
|
| 480 | } |
||
| 481 | |||
| 482 | 380 | return $column; |
|
| 483 | } |
||
| 484 | |||
| 485 | /** |
||
| 486 | * PostgreSQL 9.4 puts parentheses around negative numeric default values that need to be stripped eventually. |
||
| 487 | * |
||
| 488 | * @param mixed $defaultValue |
||
| 489 | * |
||
| 490 | * @return mixed |
||
| 491 | */ |
||
| 492 | 360 | private function fixVersion94NegativeNumericDefaultValue($defaultValue) |
|
| 493 | { |
||
| 494 | 360 | if ($defaultValue !== null && strpos($defaultValue, '(') === 0) { |
|
| 495 | 3 | return trim($defaultValue, '()'); |
|
| 496 | } |
||
| 497 | |||
| 498 | 359 | return $defaultValue; |
|
| 499 | } |
||
| 500 | |||
| 501 | /** |
||
| 502 | * Parses a default value expression as given by PostgreSQL |
||
| 503 | */ |
||
| 504 | 210 | private function parseDefaultExpression(?string $default) : ?string |
|
| 505 | { |
||
| 506 | 210 | if ($default === null) { |
|
| 507 | 200 | return $default; |
|
| 508 | } |
||
| 509 | |||
| 510 | 130 | return str_replace("''", "'", $default); |
|
| 511 | } |
||
| 512 | |||
| 513 | 320 | public function listTableDetails(string $tableName) : Table |
|
| 514 | { |
||
| 515 | 320 | $table = parent::listTableDetails($tableName); |
|
| 516 | |||
| 517 | 320 | $platform = $this->_platform; |
|
| 518 | 320 | assert($platform instanceof PostgreSQL94Platform); |
|
| 519 | 320 | $sql = $platform->getListTableMetadataSQL($tableName); |
|
| 520 | |||
| 521 | 320 | $tableOptions = $this->_conn->fetchAssoc($sql); |
|
| 522 | |||
| 523 | 320 | if ($tableOptions !== false) { |
|
| 524 | 320 | $table->addOption('comment', $tableOptions['table_comment']); |
|
| 525 | } |
||
| 526 | |||
| 527 | 320 | return $table; |
|
| 528 | } |
||
| 529 | } |
||
| 530 |