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 27, 2022
1 parent 63e513c commit 6ddef91
Show file tree
Hide file tree
Showing 2 changed files with 71 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
70 changes: 70 additions & 0 deletions tests/Functional/Schema/PostgreSQLSchemaManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Types\Types;
use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
use Exception;

use function array_map;
use function array_merge;
use function array_pop;
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 +564,73 @@ public function testAlterTableAutoIncrementIntToBigInt(
self::assertTrue($tableFinal->getColumn('id')->getAutoincrement());
}

public function testListTableColumnsOidConflictWithNonTableObject(): void
{
$semanticVersion = $this->connection->fetchOne('SHOW SERVER_VERSION');
if ($semanticVersion === false) {
throw new Exception("Query to fetch server version failed when it shouldn't have.");
}

$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 6ddef91

Please sign in to comment.