Skip to content

Commit dd45ef5

Browse files
committed
Restored relevant changes from doctrine#2850, PowerKiKi/default-values-with-backslashes
1 parent 773275d commit dd45ef5

File tree

5 files changed

+95
-6
lines changed

5 files changed

+95
-6
lines changed

UPGRADE.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Upgrade to 2.10
2+
3+
## MINOR BC BREAK: escaped default values
4+
5+
Default values will be automatically escaped. So default values must now be specified non-escaped.
6+
7+
Before:
8+
9+
$column->setDefault('Foo\\\\Bar\\\\Baz');
10+
11+
After:
12+
13+
$column->setDefault('Foo\\Bar\\Baz');
14+
115
# Upgrade to 2.9
216

317
## Deprecated `Statement::fetchColumn()` with an invalid index

lib/Doctrine/DBAL/Platforms/AbstractPlatform.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2311,7 +2311,7 @@ public function getDefaultValueDeclarationSQL($field)
23112311
return " DEFAULT '" . $this->convertBooleans($default) . "'";
23122312
}
23132313

2314-
return " DEFAULT '" . $default . "'";
2314+
return ' DEFAULT ' . $this->quoteStringLiteral($default);
23152315
}
23162316

23172317
/**

lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,11 +394,12 @@ protected function _getPortableTableColumnDefinition($tableColumn)
394394
$length = null;
395395
break;
396396
case 'text':
397-
$fixed = false;
398-
break;
397+
case '_varchar':
399398
case 'varchar':
399+
$tableColumn['default'] = $this->parseDefaultExpression($tableColumn['default']);
400+
$fixed = false;
401+
break;
400402
case 'interval':
401-
case '_varchar':
402403
$fixed = false;
403404
break;
404405
case 'char':
@@ -478,4 +479,16 @@ private function fixVersion94NegativeNumericDefaultValue($defaultValue)
478479

479480
return $defaultValue;
480481
}
482+
483+
/**
484+
* Parses a default value expression as given by PostgreSQL
485+
*/
486+
private function parseDefaultExpression(?string $default) : ?string
487+
{
488+
if ($default === null) {
489+
return $default;
490+
}
491+
492+
return str_replace("''", "'", $default);
493+
}
481494
}

lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,9 @@ protected function _getPortableTableColumnDefinition($tableColumn)
325325
$default = null;
326326
}
327327
if ($default !== null) {
328-
// SQLite returns strings wrapped in single quotes, so we need to strip them
329-
$default = preg_replace("/^'(.*)'$/", '\1', $default);
328+
// SQLite returns strings wrapped in single quotes and escaped, so we need to strip them
329+
$default = preg_replace("/^'(.*)'$/s", '\1', $default);
330+
$default = str_replace("''", "'", $default);
330331
}
331332
$notnull = (bool) $tableColumn['notnull'];
332333

tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,6 +1495,67 @@ public function testCreateAndListSequences() : void
14951495
self::assertEquals($sequence2InitialValue, $actualSequence2->getInitialValue());
14961496
}
14971497

1498+
/**
1499+
* Returns potential escaped literals from all platforms combined.
1500+
*
1501+
* @see https://dev.mysql.com/doc/refman/5.7/en/string-literals.html
1502+
* @see http://www.sqlite.org/lang_expr.html
1503+
* @see https://www.postgresql.org/docs/9.6/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE
1504+
*
1505+
* @return mixed[][]
1506+
*/
1507+
private function getEscapedLiterals() : iterable
1508+
{
1509+
return [
1510+
['An ASCII NUL (X\'00\')', "foo\\0bar"],
1511+
['Single quote, C-style', "foo\\'bar"],
1512+
['Single quote, doubled-style', "foo''bar"],
1513+
['Double quote, C-style', 'foo\\"bar'],
1514+
['Double quote, double-style', 'foo""bar'],
1515+
['Backspace', 'foo\\bbar'],
1516+
['New-line', 'foo\\nbar'],
1517+
['Carriage return', 'foo\\rbar'],
1518+
['Tab', 'foo\\tbar'],
1519+
['ASCII 26 (Control+Z)', 'foo\\Zbar'],
1520+
['Backslash (\)', 'foo\\\\bar'],
1521+
['Percent (%)', 'foo\\%bar'],
1522+
['Underscore (_)', 'foo\\_bar'],
1523+
];
1524+
}
1525+
1526+
private function createTableForDefaultValues() : void
1527+
{
1528+
$table = new Table('string_escaped_default_value');
1529+
foreach ($this->getEscapedLiterals() as $i => $literal) {
1530+
$table->addColumn('field' . $i, 'string', ['default' => $literal[1]]);
1531+
}
1532+
1533+
$table->addColumn('def_foo', 'string');
1534+
$this->schemaManager->dropAndCreateTable($table);
1535+
}
1536+
1537+
public function testEscapedDefaultValueCanBeIntrospected() : void
1538+
{
1539+
$this->createTableForDefaultValues();
1540+
1541+
$onlineTable = $this->schemaManager->listTableDetails('string_escaped_default_value');
1542+
foreach ($this->getEscapedLiterals() as $i => $literal) {
1543+
self::assertSame($literal[1], $onlineTable->getColumn('field' . $i)->getDefault(), 'should be able introspect the value of default for: ' . $literal[0]);
1544+
}
1545+
}
1546+
1547+
public function testEscapedDefaultValueCanBeInserted() : void
1548+
{
1549+
$this->createTableForDefaultValues();
1550+
1551+
$this->connection->insert('string_escaped_default_value', ['def_foo' => 'foo']);
1552+
1553+
foreach ($this->getEscapedLiterals() as $i => $literal) {
1554+
$value = $this->connection->fetchColumn('SELECT field' . $i . ' FROM string_escaped_default_value');
1555+
self::assertSame($literal[1], $value, 'inserted default value should be the configured default value for: ' . $literal[0]);
1556+
}
1557+
}
1558+
14981559
/**
14991560
* @group #3086
15001561
*/

0 commit comments

Comments
 (0)