Skip to content

Commit

Permalink
Revert "Revert "Merge pull request doctrine#2850 from PowerKiKi/defau…
Browse files Browse the repository at this point in the history
…lt-values-with-backslashes""

This reverts commit a5d3e33.
  • Loading branch information
morozov committed Apr 11, 2019
1 parent 773275d commit 73a2909
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 6 deletions.
14 changes: 14 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# Upgrade to 2.10

## MINOR BC BREAK: escaped default values

Default values will be automatically escaped. So default values must now be specified non-escaped.

Before:

$column->setDefault('Foo\\\\Bar\\\\Baz');

After:

$column->setDefault('Foo\\Bar\\Baz');

# Upgrade to 2.9

## Deprecated `Statement::fetchColumn()` with an invalid index
Expand Down
10 changes: 9 additions & 1 deletion lib/Doctrine/DBAL/Platforms/AbstractPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -2311,7 +2311,7 @@ public function getDefaultValueDeclarationSQL($field)
return " DEFAULT '" . $this->convertBooleans($default) . "'";
}

return " DEFAULT '" . $default . "'";
return ' DEFAULT ' . $this->quoteDefaultStringLiteral($default);
}

/**
Expand Down Expand Up @@ -3614,4 +3614,12 @@ protected function getLikeWildcardCharacters() : string
{
return '%_';
}

/**
* Quote a literal string for usage as DEFAULT value.
*/
protected function quoteDefaultStringLiteral(string $str) : string
{
return $this->quoteStringLiteral($str);
}
}
8 changes: 8 additions & 0 deletions lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -1252,4 +1252,12 @@ private function getOldColumnComment(ColumnDiff $columnDiff) : ?string
{
return $columnDiff->fromColumn ? $this->getColumnComment($columnDiff->fromColumn) : null;
}

/**
* {@inheritDoc}
*/
protected function quoteDefaultStringLiteral(string $str) : string
{
return parent::quoteStringLiteral($str);
}
}
21 changes: 18 additions & 3 deletions lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,12 @@ protected function _getPortableTableColumnDefinition($tableColumn)
$length = null;
break;
case 'text':
$fixed = false;
break;
case '_varchar':
case 'varchar':
$tableColumn['default'] = $this->unescapeDefaultValue($tableColumn['default']);
$fixed = false;
break;
case 'interval':
case '_varchar':
$fixed = false;
break;
case 'char':
Expand Down Expand Up @@ -478,4 +479,18 @@ private function fixVersion94NegativeNumericDefaultValue($defaultValue)

return $defaultValue;
}

/**
* Un-escape a default value as given by PostgreSQL
*/
private function unescapeDefaultValue(?string $default) : ?string
{
if ($default === null) {
return $default;
}

$default = str_replace("''", "'", $default);

return $default;
}
}
5 changes: 3 additions & 2 deletions lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,9 @@ protected function _getPortableTableColumnDefinition($tableColumn)
$default = null;
}
if ($default !== null) {
// SQLite returns strings wrapped in single quotes, so we need to strip them
$default = preg_replace("/^'(.*)'$/", '\1', $default);
// SQLite returns strings wrapped in single quotes and escaped, so we need to strip them
$default = preg_replace("/^'(.*)'$/s", '\1', $default);
$default = str_replace("''", "'", $default);
}
$notnull = (bool) $tableColumn['notnull'];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1495,6 +1495,67 @@ public function testCreateAndListSequences() : void
self::assertEquals($sequence2InitialValue, $actualSequence2->getInitialValue());
}

/**
* Returns potential escaped literals from all platforms combined.
*
* @see https://dev.mysql.com/doc/refman/5.7/en/string-literals.html
* @see http://www.sqlite.org/lang_expr.html
* @see https://www.postgresql.org/docs/9.6/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE
*
* @return mixed[][]
*/
private function getEscapedLiterals() : iterable
{
return [
['An ASCII NUL (X\'00\')', "foo\\0bar"],
['Single quote, C-style', "foo\\'bar"],
['Single quote, doubled-style', "foo''bar"],
['Double quote, C-style', 'foo\\"bar'],
['Double quote, double-style', 'foo""bar'],
['Backspace', 'foo\\bbar'],
['New-line', 'foo\\nbar'],
['Carriage return', 'foo\\rbar'],
['Tab', 'foo\\tbar'],
['ASCII 26 (Control+Z)', 'foo\\Zbar'],
['Backslash (\)', 'foo\\\\bar'],
['Percent (%)', 'foo\\%bar'],
['Underscore (_)', 'foo\\_bar'],
];
}

private function createTableForDefaultValues() : void
{
$table = new Table('string_escaped_default_value');
foreach ($this->getEscapedLiterals() as $i => $literal) {
$table->addColumn('field' . $i, 'string', ['default' => $literal[1]]);
}

$table->addColumn('def_foo', 'string');
$this->schemaManager->dropAndCreateTable($table);
}

public function testEscapedDefaultValueCanBeIntrospected() : void
{
$this->createTableForDefaultValues();

$onlineTable = $this->schemaManager->listTableDetails('string_escaped_default_value');
foreach ($this->getEscapedLiterals() as $i => $literal) {
self::assertSame($literal[1], $onlineTable->getColumn('field' . $i)->getDefault(), 'should be able introspect the value of default for: ' . $literal[0]);
}
}

public function testEscapedDefaultValueCanBeInserted() : void
{
$this->createTableForDefaultValues();

$this->connection->insert('string_escaped_default_value', ['def_foo' => 'foo']);

foreach ($this->getEscapedLiterals() as $i => $literal) {
$value = $this->connection->fetchColumn('SELECT field' . $i . ' FROM string_escaped_default_value');
self::assertSame($literal[1], $value, 'inserted default value should be the configured default value for: ' . $literal[0]);
}
}

/**
* @group #3086
*/
Expand Down

0 comments on commit 73a2909

Please sign in to comment.