Skip to content

Commit c60c31f

Browse files
committed
Merge branch '4.4.x' into 5.0.x
* 4.4.x: CI: Update SQL Server to version 2022 (doctrine#7069) fix(MariaDb): add support of new reserved word `VECTOR` (11.7+) (doctrine#7061) Improve deprecation Update schema definition documentaion Fix binding null as a boolean parameter on pgsql (doctrine#7059) Use provided length for enum type if given for non-mysql platform (doctrine#7034)
2 parents ebfc006 + 40927e8 commit c60c31f

File tree

10 files changed

+204
-27
lines changed

10 files changed

+204
-27
lines changed

.github/workflows/phpunit-sqlserver.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919

2020
services:
2121
sqlserver:
22-
image: mcr.microsoft.com/mssql/server:2019-latest
22+
image: mcr.microsoft.com/mssql/server:2022-latest
2323
ports:
2424
- '1433:1433'
2525
env:

docs/en/reference/schema-representation.rst

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,86 @@ Metadata model. Up to very specific functionality of your database
1212
system this allows you to generate SQL code that makes your Domain
1313
model work.
1414

15-
You will be pleased to hear, that Schema representation is
16-
completely decoupled from the Doctrine ORM though, that is you can
17-
also use it in any other project to implement database migrations
15+
Schema representation is completely decoupled from the Doctrine ORM.
16+
You can also use it in any other project to implement database migrations
1817
or for SQL schema generation for any metadata model that your
19-
application has. You can easily generate a Schema, as a simple
20-
example shows:
18+
application has. You can generate a Schema, as the example below
19+
shows:
2120

2221
.. code-block:: php
2322
2423
<?php
25-
$schema = new \Doctrine\DBAL\Schema\Schema();
26-
$myTable = $schema->createTable("my_table");
27-
$myTable->addColumn("id", "integer", ["unsigned" => true]);
28-
$myTable->addColumn("username", "string", ["length" => 32]);
29-
$myTable->setPrimaryKey(["id"]);
30-
$myTable->addUniqueIndex(["username"]);
31-
$myTable->setComment('Some comment');
32-
$schema->createSequence("my_table_seq");
33-
34-
$myForeign = $schema->createTable("my_foreign");
35-
$myForeign->addColumn("id", "integer");
36-
$myForeign->addColumn("user_id", "integer");
37-
$myForeign->addForeignKeyConstraint($myTable, ["user_id"], ["id"], ["onUpdate" => "CASCADE"]);
38-
39-
$queries = $schema->toSql($myPlatform); // get queries to create this schema.
40-
$dropSchema = $schema->toDropSql($myPlatform); // get queries to safely delete this schema.
24+
25+
use Doctrine\DBAL\Schema\Column;
26+
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
27+
use Doctrine\DBAL\Schema\ForeignKeyConstraint\ReferentialAction;
28+
use Doctrine\DBAL\Schema\Index;
29+
use Doctrine\DBAL\Schema\Index\IndexType;
30+
use Doctrine\DBAL\Schema\PrimaryKeyConstraint;
31+
use Doctrine\DBAL\Schema\Schema;
32+
use Doctrine\DBAL\Schema\Table;
33+
34+
$user = Table::editor()
35+
->setUnquotedName('user')
36+
->addColumn(
37+
Column::editor()
38+
->setUnquotedName('id')
39+
->setTypeName('integer')
40+
->setUnsigned(true)
41+
->create()
42+
)
43+
->addColumn(
44+
Column::editor()
45+
->setUnquotedName('username')
46+
->setTypeName('string')
47+
->setLength(32)
48+
->create()
49+
)
50+
->addPrimaryKeyConstraint(
51+
PrimaryKeyConstraint::editor()
52+
->setUnquotedColumnNames('id')
53+
->create()
54+
)
55+
->addIndex(
56+
Index::editor()
57+
->setUnquotedName('idx_username')
58+
->setUnquotedColumnNames('username')
59+
->setType(IndexType::UNIQUE)
60+
->create()
61+
)
62+
->setComment('User table')
63+
->create();
64+
65+
$post = Table::editor()
66+
->setUnquotedName('post')
67+
->addColumn(
68+
Column::editor()
69+
->setUnquotedName('id')
70+
->setTypeName('integer')
71+
->create()
72+
)
73+
->addColumn(
74+
Column::editor()
75+
->setUnquotedName('user_id')
76+
->setTypeName('integer')
77+
->create()
78+
)
79+
->addForeignKeyConstraint(
80+
ForeignKeyConstraint::editor()
81+
->setUnquotedName('fk_user_id')
82+
->setUnquotedReferencingColumnNames('user_id')
83+
->setUnquotedReferencedTableName('user')
84+
->setUnquotedReferencedColumnNames('id')
85+
->setOnUpdateAction(ReferentialAction::CASCADE)
86+
->create()
87+
)
88+
->create();
89+
90+
$schema = new Schema([$user, $post]);
91+
$schema->createSequence('my_table_seq');
92+
93+
$createSQL = $schema->toSql($myPlatform); // get queries to create this schema
94+
$dropSQL = $schema->toDropSql($myPlatform); // get queries to drop this schema
4195
4296
Now if you want to compare this schema with another schema, you can
4397
use the ``Comparator`` class to get instances of ``SchemaDiff``,

docs/en/reference/types.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,8 @@ Maps and converts a string which is one of a set of predefined values. This
210210
type is specifically designed for MySQL and MariaDB, where it is mapped to
211211
the native ``ENUM`` type. For other database vendors, this type is mapped to
212212
a string field (``VARCHAR``) with the maximum length being the length of the
213-
longest value in the set. Values retrieved from the database are always
214-
converted to PHP's ``string`` type or ``null`` if no data is present.
213+
longest value in the set if none was configured. Values retrieved from the database
214+
are always converted to PHP's ``string`` type or ``null`` if no data is present.
215215

216216
Binary string types
217217
^^^^^^^^^^^^^^^^^^^

src/Driver/PgSQL/Statement.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ public function bindValue(int|string $param, mixed $value, ParameterType $type =
5757
throw UnknownParameter::new((string) $param);
5858
}
5959

60+
if ($value === null) {
61+
$type = ParameterType::NULL;
62+
}
63+
6064
if ($type === ParameterType::BOOLEAN) {
6165
$this->parameters[$this->parameterMap[$param]] = (bool) $value === false ? 'f' : 't';
6266
$this->parameterTypes[$this->parameterMap[$param]] = ParameterType::STRING;

src/Platforms/AbstractPlatform.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,18 @@ public function getEnumDeclarationSQL(array $column): string
226226
? max(...array_map(mb_strlen(...), $column['values']))
227227
: mb_strlen($column['values'][key($column['values'])]);
228228

229+
if (isset($column['length'])) {
230+
if ($length > $column['length']) {
231+
throw new InvalidArgumentException(sprintf(
232+
'Specified column length (%d) is less than the maximum length of provided values (%d).',
233+
$column['length'],
234+
$length,
235+
));
236+
}
237+
238+
$length = $column['length'];
239+
}
240+
229241
return $this->getStringTypeDeclarationSQL(['length' => $length]);
230242
}
231243

tests/Functional/BooleanBindingTest.php

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ protected function setUp(): void
2626
Column::editor()
2727
->setUnquotedName('val')
2828
->setTypeName(Types::BOOLEAN)
29+
->setNotNull(false)
2930
->create(),
3031
)
3132
->create();
@@ -39,7 +40,7 @@ protected function tearDown(): void
3940
}
4041

4142
#[DataProvider('booleanProvider')]
42-
public function testBooleanInsert(bool $input): void
43+
public function testBooleanParameterInsert(?bool $input): void
4344
{
4445
$queryBuilder = $this->connection->createQueryBuilder();
4546

@@ -48,11 +49,37 @@ public function testBooleanInsert(bool $input): void
4849
])->executeStatement();
4950

5051
self::assertSame(1, $result);
52+
53+
self::assertSame($input, $this->connection->convertToPHPValue(
54+
$this->connection->fetchOne('SELECT val FROM boolean_test_table'),
55+
Types::BOOLEAN,
56+
));
57+
}
58+
59+
#[DataProvider('booleanProvider')]
60+
public function testBooleanTypeInsert(?bool $input): void
61+
{
62+
$queryBuilder = $this->connection->createQueryBuilder();
63+
64+
$result = $queryBuilder->insert('boolean_test_table')->values([
65+
'val' => $queryBuilder->createNamedParameter($input, Types::BOOLEAN),
66+
])->executeStatement();
67+
68+
self::assertSame(1, $result);
69+
70+
self::assertSame($input, $this->connection->convertToPHPValue(
71+
$this->connection->fetchOne('SELECT val FROM boolean_test_table'),
72+
Types::BOOLEAN,
73+
));
5174
}
5275

53-
/** @return bool[][] */
76+
/** @return array<string, array{bool|null}> */
5477
public static function booleanProvider(): array
5578
{
56-
return [[true], [false]];
79+
return [
80+
'true' => [true],
81+
'false' => [false],
82+
'null' => [null],
83+
];
5784
}
5885
}

tests/Platforms/AbstractMySQLPlatformTestCase.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Doctrine\DBAL\Schema\Table;
2121
use Doctrine\DBAL\TransactionIsolationLevel;
2222
use Doctrine\DBAL\Types\Types;
23+
use PHPUnit\Framework\Attributes\DataProvider;
2324

2425
use function array_shift;
2526

@@ -594,6 +595,13 @@ protected function createComparator(): Comparator
594595
);
595596
}
596597

598+
/** @param array<string> $values */
599+
#[DataProvider('getEnumDeclarationExceptionWithLengthSQLProvider')]
600+
public function testGetEnumDeclarationExceptionWithLengthSQL(array $values, int $length): void
601+
{
602+
self::markTestSkipped('There is no exception thrown on MySQL.');
603+
}
604+
597605
/** @return array<string, array{array<string>, string}> */
598606
public static function getEnumDeclarationSQLProvider(): array
599607
{
@@ -602,4 +610,15 @@ public static function getEnumDeclarationSQLProvider(): array
602610
'multiple values' => [['foo', 'bar1'], "ENUM('foo', 'bar1')"],
603611
];
604612
}
613+
614+
/** @return array<string, array{array<string>, int, string}> */
615+
public static function getEnumDeclarationWithLengthSQLProvider(): array
616+
{
617+
return [
618+
'single value and bigger length' => [['foo'], 42, "ENUM('foo')"],
619+
'single value and lower length' => [['foo'], 1, "ENUM('foo')"],
620+
'multiple values and bigger length' => [['foo', 'bar1'], 42, "ENUM('foo', 'bar1')"],
621+
'multiple values and lower length' => [['foo', 'bar1'], 2, "ENUM('foo', 'bar1')"],
622+
];
623+
}
605624
}

tests/Platforms/AbstractPlatformTestCase.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Doctrine\DBAL\Tests\Platforms;
66

77
use Doctrine\DBAL\Exception;
8+
use Doctrine\DBAL\Exception\InvalidArgumentException;
89
use Doctrine\DBAL\Exception\InvalidColumnDeclaration;
910
use Doctrine\DBAL\Exception\InvalidColumnType\ColumnValuesRequired;
1011
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
@@ -1047,6 +1048,48 @@ public static function getEnumDeclarationSQLProvider(): array
10471048
];
10481049
}
10491050

1051+
/** @param array<string> $values */
1052+
#[DataProvider('getEnumDeclarationWithLengthSQLProvider')]
1053+
public function testGetEnumDeclarationWithLengthSQL(array $values, int $length, string $expectedSQL): void
1054+
{
1055+
$result = $this->platform->getEnumDeclarationSQL([
1056+
'values' => $values,
1057+
'length' => $length,
1058+
]);
1059+
1060+
self::assertSame($expectedSQL, $result);
1061+
}
1062+
1063+
/** @param array<string> $values */
1064+
#[DataProvider('getEnumDeclarationExceptionWithLengthSQLProvider')]
1065+
public function testGetEnumDeclarationExceptionWithLengthSQL(array $values, int $length): void
1066+
{
1067+
$this->expectException(InvalidArgumentException::class);
1068+
1069+
$this->platform->getEnumDeclarationSQL([
1070+
'values' => $values,
1071+
'length' => $length,
1072+
]);
1073+
}
1074+
1075+
/** @return array<string, array{array<string>, int, string}> */
1076+
public static function getEnumDeclarationWithLengthSQLProvider(): array
1077+
{
1078+
return [
1079+
'single value and bigger length' => [['foo'], 42, 'VARCHAR(42)'],
1080+
'multiple values and bigger length' => [['foo', 'bar1'], 42, 'VARCHAR(42)'],
1081+
];
1082+
}
1083+
1084+
/** @return array<string, array{array<string>, int}> */
1085+
public static function getEnumDeclarationExceptionWithLengthSQLProvider(): array
1086+
{
1087+
return [
1088+
'single value and lower length' => [['foo'], 1],
1089+
'multiple values and lower length' => [['foo', 'bar1'], 2],
1090+
];
1091+
}
1092+
10501093
/** @param array<mixed> $column */
10511094
#[DataProvider('getEnumDeclarationSQLWithInvalidValuesProvider')]
10521095
public function testGetEnumDeclarationSQLWithInvalidValues(array $column): void

tests/Platforms/OraclePlatformTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,4 +597,13 @@ public static function getEnumDeclarationSQLProvider(): array
597597
'multiple values' => [['foo', 'bar1'], 'VARCHAR2(4)'],
598598
];
599599
}
600+
601+
/** @return array<string, array{array<string>, int, string}> */
602+
public static function getEnumDeclarationWithLengthSQLProvider(): array
603+
{
604+
return [
605+
'single value and bigger length' => [['foo'], 42, 'VARCHAR2(42)'],
606+
'multiple values and bigger length' => [['foo', 'bar1'], 42, 'VARCHAR2(42)'],
607+
];
608+
}
600609
}

tests/Platforms/SQLServerPlatformTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,4 +1189,13 @@ public static function getEnumDeclarationSQLProvider(): array
11891189
'multiple values' => [['foo', 'bar1'], 'NVARCHAR(4)'],
11901190
];
11911191
}
1192+
1193+
/** @return array<string, array{array<string>, int, string}> */
1194+
public static function getEnumDeclarationWithLengthSQLProvider(): array
1195+
{
1196+
return [
1197+
'single value and bigger length' => [['foo'], 42, 'NVARCHAR(42)'],
1198+
'multiple values and bigger length' => [['foo', 'bar1'], 42, 'NVARCHAR(42)'],
1199+
];
1200+
}
11921201
}

0 commit comments

Comments
 (0)