diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dcc03227..3c0fd7017 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -177,6 +177,7 @@ - Bug #1103: Fix view names' cache refreshing after "drop table" command execution (@vjik) - Chg #1103: Remove `AbstractCommand::refreshTableSchema()` method (@vjik) - Chg #1106: Remove parameters from `PdoConnectionInterface::getActivePdo()` method (@vjik) +- Bug #1109: Fix column definition parsing in cases with brackets and escaped quotes (@vjik) ## 1.3.0 March 21, 2024 diff --git a/src/Syntax/ColumnDefinitionParser.php b/src/Syntax/ColumnDefinitionParser.php index 0fcb775be..a14f83175 100644 --- a/src/Syntax/ColumnDefinitionParser.php +++ b/src/Syntax/ColumnDefinitionParser.php @@ -56,7 +56,7 @@ class ColumnDefinitionParser */ public function parse(string $definition): array { - preg_match('/^(\w*)(?:\(([^)]+)\))?(\[[\d\[\]]*\])?\s*/', $definition, $matches); + preg_match("/^(\w*)(?:\(((?:'[^']*'|[^)])+)\))?(\[[\d\[\]]*\])?\s*/", $definition, $matches); $type = strtolower($matches[1]); $info = ['type' => $type]; @@ -84,9 +84,14 @@ public function parse(string $definition): array */ protected function enumInfo(string $values): array { - preg_match_all("/'([^']*)'/", $values, $matches); + preg_match_all("/'((?:''|[^'])*)'/", $values, $matches); - return ['enumValues' => $matches[1]]; + $values = array_map( + static fn(string $value): string => str_replace("''", "'", $value), + $matches[1], + ); + + return ['enumValues' => $values]; } /** diff --git a/tests/Common/CommonColumnDefinitionParserTest.php b/tests/Common/CommonColumnDefinitionParserTest.php index 89b2b9c7b..ef96f136e 100644 --- a/tests/Common/CommonColumnDefinitionParserTest.php +++ b/tests/Common/CommonColumnDefinitionParserTest.php @@ -9,9 +9,6 @@ use Yiisoft\Db\Syntax\ColumnDefinitionParser; use Yiisoft\Db\Tests\Provider\ColumnDefinitionParserProvider; -/** - * @group db - */ abstract class CommonColumnDefinitionParserTest extends TestCase { #[DataProviderExternal(ColumnDefinitionParserProvider::class, 'parse')] @@ -22,8 +19,5 @@ public function testParse(string $definition, array $expected): void $this->assertSame($expected, $parser->parse($definition)); } - protected function createColumnDefinitionParser(): ColumnDefinitionParser - { - return new ColumnDefinitionParser(); - } + abstract protected function createColumnDefinitionParser(): ColumnDefinitionParser; } diff --git a/tests/Db/Syntax/ColumnDefinitionParserTest.php b/tests/Db/Syntax/ColumnDefinitionParserTest.php new file mode 100644 index 000000000..4210423f2 --- /dev/null +++ b/tests/Db/Syntax/ColumnDefinitionParserTest.php @@ -0,0 +1,19 @@ + 'int', 'defaultValueRaw' => '(1 + 2)']], ["int COMMENT '''Quoted'' comment'", ['type' => 'int', 'comment' => "'Quoted' comment"]], ['int CHECK (value > (1 + 5))', ['type' => 'int', 'check' => 'value > (1 + 5)']], - ["enum('a','b','c')", ['type' => 'enum', 'enumValues' => ['a', 'b', 'c']]], - ["enum('a','b','c') NOT NULL", ['type' => 'enum', 'enumValues' => ['a', 'b', 'c'], 'notNull' => true]], + [ + "enum('a','b','c')", + ['type' => 'enum', 'enumValues' => ['a', 'b', 'c']], + ], + [ + "enum('a','b','c') NOT NULL", + ['type' => 'enum', 'enumValues' => ['a', 'b', 'c'], 'notNull' => true], + ], + 'enum-with-square-brackets' => [ + "enum('[one]', 'the [two]', 'the [three] to') NOT NULL", + ['type' => 'enum', 'enumValues' => ['[one]', 'the [two]', 'the [three] to'], 'notNull' => true], + ], + 'enum-with-parentheses' => [ + "enum('(one)', 'the (two)', 'the (three) to') NOT NULL", + ['type' => 'enum', 'enumValues' => ['(one)', 'the (two)', 'the (three) to'], 'notNull' => true], + ], + 'enum-with-escaped-quotes' => [ + "enum('hello''world''', 'the ''[feature]''') NOT NULL", + ['type' => 'enum', 'enumValues' => ["hello'world'", "the '[feature]'"], 'notNull' => true], + ], + 'enum-with-parentheses-and-escaped-quotes' => [ + "enum('''hey (one)', 'the (t''wo)', 'the (three) ''to') NOT NULL", + ['type' => 'enum', 'enumValues' => ['\'hey (one)', 'the (t\'wo)', 'the (three) \'to'], 'notNull' => true], + ], ['int[]', ['type' => 'int', 'dimension' => 1]], ['string(126)[][]', ['type' => 'string', 'size' => 126, 'dimension' => 2]], ];