Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ jobs:
dependencies:
- "highest"
extension:
- "sqlite3"
- "pdo_sqlite"
include:
- os: "ubuntu-20.04"
php-version: "8.1"
dependencies: "lowest"
extension: "pdo_sqlite"
- os: "ubuntu-22.04"
php-version: "8.1"
php-version: "8.4"
dependencies: "highest"
extension: "sqlite3"

Expand Down
6 changes: 6 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,12 @@ The following methods have been removed.
| `QueryCacheProfile` | `setResultCacheDriver()` | `setResultCache()` |
| `QueryCacheProfile` | `getResultCacheDriver()` | `getResultCache()` |

# Upgrade to 3.10

The `doctrine/cache` package is now an optional dependency. If you are using the
`Doctrine\DBAL\Cache` classes, you need to require the `doctrine/cache` package
explicitly.

# Upgrade to 3.8

## Deprecated lock-related `AbstractPlatform` methods
Expand Down
8 changes: 7 additions & 1 deletion src/Platforms/SQLServerPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -1198,11 +1198,17 @@ protected function getLikeWildcardCharacters(): string

protected function getCommentOnTableSQL(string $tableName, string $comment): string
{
if (str_contains($tableName, '.')) {
[$schemaName, $tableName] = explode('.', $tableName);
} else {
$schemaName = 'dbo';
}

return $this->getAddExtendedPropertySQL(
'MS_Description',
$comment,
'SCHEMA',
$this->quoteStringLiteral('dbo'),
$this->quoteStringLiteral($schemaName),
'TABLE',
$this->quoteStringLiteral($this->unquoteSingleIdentifier($tableName)),
);
Expand Down
27 changes: 20 additions & 7 deletions src/Schema/PostgreSQLSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,16 @@
foreach ($tableIndexes as $row) {
$colNumbers = array_map('intval', explode(' ', $row['indkey']));
$columnNameSql = sprintf(
'SELECT attnum, attname FROM pg_attribute WHERE attrelid=%d AND attnum IN (%s) ORDER BY attnum ASC',
<<<'SQL'

Check warning on line 164 in src/Schema/PostgreSQLSchemaManager.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/PostgreSQLSchemaManager.php#L164

Added line #L164 was not covered by tests
SELECT attnum,
quote_ident(attname) AS attname
FROM pg_attribute
WHERE attrelid = %d
AND attnum IN (%s)
ORDER BY attnum
SQL,

Check warning on line 171 in src/Schema/PostgreSQLSchemaManager.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/PostgreSQLSchemaManager.php#L171

Added line #L171 was not covered by tests
$row['indrelid'],
implode(' ,', $colNumbers),
implode(', ', $colNumbers),

Check warning on line 173 in src/Schema/PostgreSQLSchemaManager.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/PostgreSQLSchemaManager.php#L173

Added line #L173 was not covered by tests
);

$indexColumns = $this->connection->fetchAllAssociative($columnNameSql);
Expand Down Expand Up @@ -412,7 +419,7 @@
$sql = 'SELECT ';

if ($tableName === null) {
$sql .= 'c.relname AS table_name, n.nspname AS schema_name,';
$sql .= 'quote_ident(c.relname) AS table_name, quote_ident(n.nspname) AS schema_name,';

Check warning on line 422 in src/Schema/PostgreSQLSchemaManager.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/PostgreSQLSchemaManager.php#L422

Added line #L422 was not covered by tests
}

$sql .= sprintf(<<<'SQL'
Expand Down Expand Up @@ -478,7 +485,7 @@
$sql = 'SELECT';

if ($tableName === null) {
$sql .= ' tc.relname AS table_name, tn.nspname AS schema_name,';
$sql .= ' quote_ident(tc.relname) AS table_name, quote_ident(tn.nspname) AS schema_name,';

Check warning on line 488 in src/Schema/PostgreSQLSchemaManager.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/PostgreSQLSchemaManager.php#L488

Added line #L488 was not covered by tests
}

$sql .= <<<'SQL'
Expand Down Expand Up @@ -512,7 +519,7 @@
$sql = 'SELECT';

if ($tableName === null) {
$sql .= ' tc.relname AS table_name, tn.nspname AS schema_name,';
$sql .= ' quote_ident(tc.relname) AS table_name, quote_ident(tn.nspname) AS schema_name,';

Check warning on line 522 in src/Schema/PostgreSQLSchemaManager.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/PostgreSQLSchemaManager.php#L522

Added line #L522 was not covered by tests
}

$sql .= <<<'SQL'
Expand Down Expand Up @@ -540,7 +547,8 @@
protected function fetchTableOptionsByTable(string $databaseName, ?string $tableName = null): array
{
$sql = <<<'SQL'
SELECT c.relname,
SELECT quote_ident(n.nspname) AS schema_name,
quote_ident(c.relname) AS table_name,
CASE c.relpersistence WHEN 'u' THEN true ELSE false END as unlogged,
obj_description(c.oid, 'pg_class') AS comment
FROM pg_class c
Expand All @@ -552,7 +560,12 @@

$sql .= ' WHERE ' . implode(' AND ', $conditions);

return $this->connection->fetchAllAssociativeIndexed($sql);
$tableOptions = [];
foreach ($this->connection->iterateAssociative($sql) as $row) {
$tableOptions[$this->_getPortableTableDefinition($row)] = $row;

Check warning on line 565 in src/Schema/PostgreSQLSchemaManager.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/PostgreSQLSchemaManager.php#L563-L565

Added lines #L563 - L565 were not covered by tests
}

return $tableOptions;

Check warning on line 568 in src/Schema/PostgreSQLSchemaManager.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/PostgreSQLSchemaManager.php#L568

Added line #L568 was not covered by tests
}

/** @return list<string> */
Expand Down
26 changes: 15 additions & 11 deletions src/Schema/SQLServerSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,15 @@ protected function _getPortableTableForeignKeysList(array $tableForeignKeys): ar
$name = $tableForeignKey['ForeignKey'];

if (! isset($foreignKeys[$name])) {
$referencedTableName = $tableForeignKey['ReferenceTableName'];

if ($tableForeignKey['ReferenceSchemaName'] !== 'dbo') {
$referencedTableName = $tableForeignKey['ReferenceSchemaName'] . '.' . $referencedTableName;
}

$foreignKeys[$name] = [
'local_columns' => [$tableForeignKey['ColumnName']],
'foreign_table' => $tableForeignKey['ReferenceTableName'],
'foreign_table' => $referencedTableName,
'foreign_columns' => [$tableForeignKey['ReferenceColumnName']],
'name' => $name,
'options' => [
Expand Down Expand Up @@ -443,31 +449,29 @@ protected function fetchTableOptionsByTable(string $databaseName, ?string $table
{
$sql = <<<'SQL'
SELECT
tbl.name,
scm.name AS schema_name,
tbl.name AS table_name,
p.value AS [table_comment]
FROM
sys.tables AS tbl
JOIN sys.schemas AS scm
ON tbl.schema_id = scm.schema_id
INNER JOIN sys.extended_properties AS p ON p.major_id=tbl.object_id AND p.minor_id=0 AND p.class=1
SQL;

$conditions = ["SCHEMA_NAME(tbl.schema_id) = N'dbo'", "p.name = N'MS_Description'"];
$params = [];
$conditions = ["p.name = N'MS_Description'"];

if ($tableName !== null) {
$conditions[] = "tbl.name = N'" . $tableName . "'";
$conditions[] = $this->getTableWhereClause($tableName, 'scm.name', 'tbl.name');
}

$sql .= ' WHERE ' . implode(' AND ', $conditions);

/** @var array<string,array<string,mixed>> $metadata */
$metadata = $this->connection->executeQuery($sql, $params)
->fetchAllAssociativeIndexed();

$tableOptions = [];
foreach ($metadata as $table => $data) {
foreach ($this->connection->iterateAssociative($sql) as $data) {
$data = array_change_key_case($data, CASE_LOWER);

$tableOptions[$table] = [
$tableOptions[$this->_getPortableTableDefinition($data)] = [
'comment' => $data['table_comment'],
];
}
Expand Down
112 changes: 0 additions & 112 deletions tests/Functional/Schema/OracleSchemaManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,118 +69,6 @@ public function testAlterTableColumnNotNull(): void
self::assertTrue($columns['bar']->getNotnull());
}

public function testListTableDetailsWithDifferentIdentifierQuotingRequirements(): void
{
$primaryTableName = '"Primary_Table"';
$offlinePrimaryTable = new Table($primaryTableName);
$offlinePrimaryTable->addColumn(
'"Id"',
Types::INTEGER,
['autoincrement' => true],
);
$offlinePrimaryTable->addColumn('select', Types::INTEGER);
$offlinePrimaryTable->addColumn('foo', Types::INTEGER);
$offlinePrimaryTable->addColumn('BAR', Types::INTEGER);
$offlinePrimaryTable->addColumn('"BAZ"', Types::INTEGER);
$offlinePrimaryTable->addIndex(['select'], 'from');
$offlinePrimaryTable->addIndex(['foo'], 'foo_index');
$offlinePrimaryTable->addIndex(['BAR'], 'BAR_INDEX');
$offlinePrimaryTable->addIndex(['"BAZ"'], 'BAZ_INDEX');
$offlinePrimaryTable->setPrimaryKey(['"Id"']);

$foreignTableName = 'foreign';
$offlineForeignTable = new Table($foreignTableName);
$offlineForeignTable->addColumn('id', Types::INTEGER, ['autoincrement' => true]);
$offlineForeignTable->addColumn('"Fk"', Types::INTEGER);
$offlineForeignTable->addIndex(['"Fk"'], '"Fk_index"');
$offlineForeignTable->addForeignKeyConstraint(
$primaryTableName,
['"Fk"'],
['"Id"'],
[],
'"Primary_Table_Fk"',
);
$offlineForeignTable->setPrimaryKey(['id']);

$this->dropTableIfExists($foreignTableName);
$this->dropTableIfExists($primaryTableName);

$this->schemaManager->createTable($offlinePrimaryTable);
$this->schemaManager->createTable($offlineForeignTable);

$onlinePrimaryTable = $this->schemaManager->introspectTable($primaryTableName);
$onlineForeignTable = $this->schemaManager->introspectTable($foreignTableName);

$platform = $this->connection->getDatabasePlatform();

// Primary table assertions
self::assertSame($primaryTableName, $onlinePrimaryTable->getQuotedName($platform));

self::assertTrue($onlinePrimaryTable->hasColumn('"Id"'));
self::assertSame('"Id"', $onlinePrimaryTable->getColumn('"Id"')->getQuotedName($platform));

$onlinePrimaryTablePrimaryKey = $onlinePrimaryTable->getPrimaryKey();
self::assertNotNull($onlinePrimaryTablePrimaryKey);
self::assertSame(['"Id"'], $onlinePrimaryTablePrimaryKey->getQuotedColumns($platform));

self::assertTrue($onlinePrimaryTable->hasColumn('select'));
self::assertSame('"select"', $onlinePrimaryTable->getColumn('select')->getQuotedName($platform));

self::assertTrue($onlinePrimaryTable->hasColumn('foo'));
self::assertSame('FOO', $onlinePrimaryTable->getColumn('foo')->getQuotedName($platform));

self::assertTrue($onlinePrimaryTable->hasColumn('BAR'));
self::assertSame('BAR', $onlinePrimaryTable->getColumn('BAR')->getQuotedName($platform));

self::assertTrue($onlinePrimaryTable->hasColumn('"BAZ"'));
self::assertSame('BAZ', $onlinePrimaryTable->getColumn('"BAZ"')->getQuotedName($platform));

self::assertTrue($onlinePrimaryTable->hasIndex('from'));
self::assertTrue($onlinePrimaryTable->getIndex('from')->hasColumnAtPosition('"select"'));
self::assertSame(['"select"'], $onlinePrimaryTable->getIndex('from')->getQuotedColumns($platform));

self::assertTrue($onlinePrimaryTable->hasIndex('foo_index'));
self::assertTrue($onlinePrimaryTable->getIndex('foo_index')->hasColumnAtPosition('foo'));
self::assertSame(['FOO'], $onlinePrimaryTable->getIndex('foo_index')->getQuotedColumns($platform));

self::assertTrue($onlinePrimaryTable->hasIndex('BAR_INDEX'));
self::assertTrue($onlinePrimaryTable->getIndex('BAR_INDEX')->hasColumnAtPosition('BAR'));
self::assertSame(['BAR'], $onlinePrimaryTable->getIndex('BAR_INDEX')->getQuotedColumns($platform));

self::assertTrue($onlinePrimaryTable->hasIndex('BAZ_INDEX'));
self::assertTrue($onlinePrimaryTable->getIndex('BAZ_INDEX')->hasColumnAtPosition('"BAZ"'));
self::assertSame(['BAZ'], $onlinePrimaryTable->getIndex('BAZ_INDEX')->getQuotedColumns($platform));

// Foreign table assertions
self::assertTrue($onlineForeignTable->hasColumn('id'));
self::assertSame('ID', $onlineForeignTable->getColumn('id')->getQuotedName($platform));

$onlineForeignTablePrimaryKey = $onlineForeignTable->getPrimaryKey();
self::assertNotNull($onlineForeignTablePrimaryKey);
self::assertSame(['ID'], $onlineForeignTablePrimaryKey->getQuotedColumns($platform));

self::assertTrue($onlineForeignTable->hasColumn('"Fk"'));
self::assertSame('"Fk"', $onlineForeignTable->getColumn('"Fk"')->getQuotedName($platform));

self::assertTrue($onlineForeignTable->hasIndex('"Fk_index"'));
self::assertTrue($onlineForeignTable->getIndex('"Fk_index"')->hasColumnAtPosition('"Fk"'));
self::assertSame(['"Fk"'], $onlineForeignTable->getIndex('"Fk_index"')->getQuotedColumns($platform));

self::assertTrue($onlineForeignTable->hasForeignKey('"Primary_Table_Fk"'));
self::assertSame(
$primaryTableName,
$onlineForeignTable->getForeignKey('"Primary_Table_Fk"')->getQuotedForeignTableName($platform),
);
self::assertSame(
['"Fk"'],
$onlineForeignTable->getForeignKey('"Primary_Table_Fk"')->getQuotedLocalColumns($platform),
);
self::assertSame(
['"Id"'],
$onlineForeignTable->getForeignKey('"Primary_Table_Fk"')->getQuotedForeignColumns($platform),
);
}

public function testListTableColumnsSameTableNamesInDifferentSchemas(): void
{
$table = $this->createListTableColumns();
Expand Down
39 changes: 0 additions & 39 deletions tests/Functional/Schema/PostgreSQLSchemaManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
use PHPUnit\Framework\Attributes\DataProvider;

use function array_map;
use function array_pop;
use function count;
use function sprintf;
use function strtolower;
Expand Down Expand Up @@ -121,44 +120,6 @@ public function testAlterTableAutoIncrementDrop(): void
self::assertFalse($tableFinal->getColumn('id')->getAutoincrement());
}

public function testTableWithSchema(): void
{
$this->connection->executeStatement('CREATE SCHEMA nested');

$nestedRelatedTable = new Table('nested.schemarelated');
$column = $nestedRelatedTable->addColumn('id', Types::INTEGER);
$column->setAutoincrement(true);
$nestedRelatedTable->setPrimaryKey(['id']);

$nestedSchemaTable = new Table('nested.schematable');
$column = $nestedSchemaTable->addColumn('id', Types::INTEGER);
$column->setAutoincrement(true);
$nestedSchemaTable->setPrimaryKey(['id']);
$nestedSchemaTable->addForeignKeyConstraint($nestedRelatedTable->getName(), ['id'], ['id']);

$this->schemaManager->createTable($nestedRelatedTable);
$this->schemaManager->createTable($nestedSchemaTable);

$tableNames = $this->schemaManager->listTableNames();
self::assertContains('nested.schematable', $tableNames);

$tables = $this->schemaManager->listTables();
self::assertNotNull($this->findTableByName($tables, 'nested.schematable'));

$nestedSchemaTable = $this->schemaManager->introspectTable('nested.schematable');
self::assertTrue($nestedSchemaTable->hasColumn('id'));

$primaryKey = $nestedSchemaTable->getPrimaryKey();
self::assertNotNull($primaryKey);
self::assertEquals(['id'], $primaryKey->getColumns());

$relatedFks = $nestedSchemaTable->getForeignKeys();
self::assertCount(1, $relatedFks);
$relatedFk = array_pop($relatedFks);
self::assertNotNull($relatedFk);
self::assertEquals('nested.schemarelated', $relatedFk->getForeignTableName());
}

public function testListSameTableNameColumnsWithDifferentSchema(): void
{
$this->connection->executeStatement('CREATE SCHEMA another');
Expand Down
Loading