Skip to content

Commit

Permalink
Ensure the pg_depend relation is for a table object.
Browse files Browse the repository at this point in the history
This fixes a bug where there was a pg_proc which was a dependency of
an extention and also had an identical oid to the table class being
described.  Oids are not guaranteed to be unique because they will
wrap around once they hit the unsigned integer max.  The added
conditional will ensure that the target object of the dependency is a
table.

Fixes: #5781
  • Loading branch information
Allen Lai committed Dec 21, 2022
1 parent 63e513c commit f183fcd
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Schema/PostgreSQLSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ protected function selectTableColumns(string $databaseName, ?string $tableName =
LEFT JOIN pg_depend d
ON d.objid = c.oid
AND d.deptype = 'e'
AND d.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_class')
SQL;

$conditions = array_merge([
Expand Down
65 changes: 65 additions & 0 deletions tests/Functional/Schema/PostgreSQLSchemaManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
use function array_unshift;
use function assert;
use function count;
use function explode;
use function sprintf;
use function strtolower;

class PostgreSQLSchemaManagerTest extends SchemaManagerFunctionalTestCase
Expand Down Expand Up @@ -561,6 +563,69 @@ public function testAlterTableAutoIncrementIntToBigInt(
self::assertTrue($tableFinal->getColumn('id')->getAutoincrement());
}

public function testListTableColumnsOidConflictWithNonTableObject(): void
{
$semanticVersion = $this->connection->fetchOne('SHOW SERVER_VERSION');
$majorVersion = explode('.', $semanticVersion)[0];

if ($majorVersion === '9') {
self::markTestSkipped('Manually setting the Oid is not supported in 9.4');
}

$table = 'test_list_table_columns_oid_conflicts';
$this->connection->executeStatement(sprintf('CREATE TABLE IF NOT EXISTS %s(id INT NOT NULL)', $table));
$beforeColumns = $this->schemaManager->listTableColumns($table);
$this->assertArrayHasKey('id', $beforeColumns);

$this->connection->executeStatement('CREATE EXTENSION IF NOT EXISTS pg_prewarm');
$originalTableOid = $this->connection->fetchOne(
'SELECT oid FROM pg_class WHERE pg_class.relname = ?',
[$table],
);

$getConflictingOidSql = <<<'SQL'
SELECT objid
FROM pg_depend
JOIN pg_extension as ex on ex.oid = pg_depend.refobjid
WHERE ex.extname = 'pg_prewarm'
ORDER BY objid
LIMIT 1
SQL;
$conflictingOid = $this->connection->fetchOne($getConflictingOidSql);

$this->connection->executeStatement(
'UPDATE pg_attribute SET attrelid = ? WHERE attrelid = ?',
[$conflictingOid, $originalTableOid],
);
$this->connection->executeStatement(
'UPDATE pg_description SET objoid = ? WHERE objoid = ?',
[$conflictingOid, $originalTableOid],
);
$this->connection->executeStatement(
'UPDATE pg_class SET oid = ? WHERE oid = ?',
[$conflictingOid, $originalTableOid],
);

$afterColumns = $this->schemaManager->listTableColumns($table);
$this->assertArrayHasKey('id', $afterColumns);

// revert to the original oid
$this->connection->executeStatement(
'UPDATE pg_attribute SET attrelid = ? WHERE attrelid = ?',
[$originalTableOid, $conflictingOid],
);
$this->connection->executeStatement(
'UPDATE pg_description SET objoid = ? WHERE objoid = ?',
[$originalTableOid, $conflictingOid],
);
$this->connection->executeStatement(
'UPDATE pg_class SET oid = ? WHERE oid = ?',
[$originalTableOid, $conflictingOid],
);

$this->connection->executeStatement(sprintf('DROP TABLE IF EXISTS %s', $table));
}

/** @return iterable<mixed[]> */
public static function autoIncrementTypeMigrations(): iterable
{
Expand Down

0 comments on commit f183fcd

Please sign in to comment.