Skip to content

Commit 0e81fa2

Browse files
authored
Passive support for partitioned tables on Postgres (#6516)
<!-- Fill in the relevant information below to help triage your pull request. --> | Q | A |------------- | ----------- | Type | improvement Partitioned tables is a complex topic which [is not fully supported by Doctrine](#4657). Currently, with PostgreSQL, Doctrine does not "see" partitioned tables, and only "sees" partitions, which is problematic and should be done the other way. This PR fixes this in `PostgreSQLSchemaManager::selectTableColumns()`. **Before this PR:** - does not see at all "partitioned tables" (which are the actual tables related to an entity) - doctrine suggest to remove all "partitions" **After this PR:** - `doctrine:schema:validate` is happy, even if tables have been partitioned manually see #4657 (comment) Note: I'd want to see if maintainers folks are willing to accept such modification before digging into the tests for this
1 parent 44e2f25 commit 0e81fa2

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

src/Schema/PostgreSQLSchemaManager.php

+14-1
Original file line numberDiff line numberDiff line change
@@ -453,8 +453,21 @@ protected function selectTableColumns(string $databaseName, ?string $tableName =
453453

454454
$conditions = array_merge([
455455
'a.attnum > 0',
456-
"c.relkind = 'r'",
457456
'd.refobjid IS NULL',
457+
458+
// 'r' for regular tables - 'p' for partitioned tables
459+
"c.relkind IN('r', 'p')",
460+
461+
// exclude partitions (tables that inherit from partitioned tables)
462+
<<<'SQL'
463+
NOT EXISTS (
464+
SELECT 1
465+
FROM pg_inherits
466+
INNER JOIN pg_class parent on pg_inherits.inhparent = parent.oid
467+
AND parent.relkind = 'p'
468+
WHERE inhrelid = c.oid
469+
)
470+
SQL,
458471
], $this->buildQueryConditions($tableName));
459472

460473
$sql .= ' WHERE ' . implode(' AND ', $conditions) . ' ORDER BY a.attnum';

tests/Functional/Schema/PostgreSQLSchemaManagerTest.php

+51
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Doctrine\DBAL\Platforms\AbstractPlatform;
88
use Doctrine\DBAL\Platforms\PostgreSQL120Platform;
99
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
10+
use Doctrine\DBAL\Schema\Exception\TableDoesNotExist;
1011
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
1112
use Doctrine\DBAL\Schema\Schema;
1213
use Doctrine\DBAL\Schema\Table;
@@ -598,6 +599,56 @@ public static function autoIncrementTypeMigrations(): iterable
598599
'bigint->int' => ['bigint', 'integer', 'INT'],
599600
];
600601
}
602+
603+
public function testPartitionTable(): void
604+
{
605+
$this->connection->executeStatement('DROP TABLE IF EXISTS partitioned_table');
606+
$this->connection->executeStatement(
607+
'CREATE TABLE partitioned_table (id INT) PARTITION BY LIST (id);',
608+
);
609+
$this->connection->executeStatement('CREATE TABLE partition PARTITION OF partitioned_table FOR VALUES IN (1);');
610+
try {
611+
$this->schemaManager->introspectTable('partition');
612+
} catch (TableDoesNotExist $e) {
613+
}
614+
615+
self::assertNotNull($e ?? null, 'Partition table should not be introspected');
616+
617+
$tableFrom = $this->schemaManager->introspectTable('partitioned_table');
618+
619+
$tableTo = $this->schemaManager->introspectTable('partitioned_table');
620+
$tableTo->addColumn('foo', Types::INTEGER);
621+
622+
$platform = $this->connection->getDatabasePlatform();
623+
$diff = $this->schemaManager->createComparator()->compareTables($tableFrom, $tableTo);
624+
625+
$sql = $platform->getAlterTableSQL($diff);
626+
self::assertSame(['ALTER TABLE partitioned_table ADD foo INT NOT NULL'], $sql);
627+
628+
$this->schemaManager->alterTable($diff);
629+
630+
$tableFinal = $this->schemaManager->introspectTable('partitioned_table');
631+
self::assertTrue($tableFinal->hasColumn('id'));
632+
self::assertTrue($tableFinal->hasColumn('foo'));
633+
634+
$partitionedTableCount = (int) ($this->connection->fetchOne(
635+
"select count(*) as count from pg_class where relname = 'partitioned_table' and relkind = 'p'",
636+
));
637+
self::assertSame(1, $partitionedTableCount);
638+
639+
$partitionsCount = (int) ($this->connection->fetchOne(
640+
<<<'SQL'
641+
select count(*) as count
642+
from pg_class parent
643+
inner join pg_inherits on pg_inherits.inhparent = parent.oid
644+
inner join pg_class child on pg_inherits.inhrelid = child.oid
645+
and child.relkind = 'r'
646+
and child.relname = 'partition'
647+
where parent.relname = 'partitioned_table' and parent.relkind = 'p';
648+
SQL,
649+
));
650+
self::assertSame(1, $partitionsCount);
651+
}
601652
}
602653

603654
class MoneyType extends Type

0 commit comments

Comments
 (0)