From b259119a211a3855c4d3c34ddfe2bed7e4fe9907 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Sat, 23 Sep 2023 14:10:32 +0700 Subject: [PATCH 1/5] Refactor `Quoter` --- src/Schema/Quoter.php | 32 ++++++++++++++++++++++---------- tests/Db/Schema/QuoterTest.php | 15 +++++++++++++++ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/Schema/Quoter.php b/src/Schema/Quoter.php index 10a559222..edc913625 100644 --- a/src/Schema/Quoter.php +++ b/src/Schema/Quoter.php @@ -8,11 +8,16 @@ use Yiisoft\Db\Expression\ExpressionInterface; use function addcslashes; +use function array_slice; +use function count; use function explode; use function implode; use function is_string; +use function preg_match; +use function preg_replace; use function preg_replace_callback; use function str_contains; +use function str_ends_with; use function str_replace; use function str_starts_with; use function strrpos; @@ -44,7 +49,7 @@ public function cleanUpTableNames(array $tableNames): array { $cleanedUpTableNames = []; $pattern = << $tableNames */ @@ -104,7 +109,7 @@ public function ensureColumnName(string $name): string $name = $parts[count($parts) - 1]; } - return preg_replace('|^\[\[([_\w\-. ]+)\]\]$|', '\1', $name); + return preg_replace('|^\[\[([\w\-. ]+)]]$|', '\1', $name); } public function quoteColumnName(string $name): string @@ -135,8 +140,9 @@ public function quoteSimpleColumnName(string $name): string [$startingCharacter, $endingCharacter] = $this->columnQuoteCharacter; } - return $name === '*' || str_contains($name, $startingCharacter) ? $name : $startingCharacter . $name - . $endingCharacter; + return $name === '*' || str_starts_with($name, $startingCharacter) + ? $name + : $startingCharacter . $name . $endingCharacter; } public function quoteSimpleTableName(string $name): string @@ -147,13 +153,15 @@ public function quoteSimpleTableName(string $name): string [$startingCharacter, $endingCharacter] = $this->tableQuoteCharacter; } - return str_contains($name, $startingCharacter) ? $name : $startingCharacter . $name . $endingCharacter; + return str_starts_with($name, $startingCharacter) + ? $name + : $startingCharacter . $name . $endingCharacter; } public function quoteSql(string $sql): string { return preg_replace_callback( - '/({{(%?[\w\-. ]+%?)}}|\\[\\[([\w\-. ]+)]])/', + '/({{(%?[\w\-. ]+)%?}}|\\[\\[([\w\-. ]+)]])/', function ($matches) { if (isset($matches[3])) { return $this->quoteColumnName($matches[3]); @@ -194,7 +202,7 @@ public function quoteValue(mixed $value): mixed return $value; } - return '\'' . str_replace('\'', '\'\'', addcslashes($value, "\000\032")) . '\''; + return "'" . str_replace("'", "''", addcslashes($value, "\000\032")) . "'"; } public function unquoteSimpleColumnName(string $name): string @@ -205,7 +213,9 @@ public function unquoteSimpleColumnName(string $name): string $startingCharacter = $this->columnQuoteCharacter[0]; } - return !str_contains($name, $startingCharacter) ? $name : substr($name, 1, -1); + return !str_starts_with($name, $startingCharacter) + ? $name + : substr($name, 1, -1); } public function unquoteSimpleTableName(string $name): string @@ -216,7 +226,9 @@ public function unquoteSimpleTableName(string $name): string $startingCharacter = $this->tableQuoteCharacter[0]; } - return !str_contains($name, $startingCharacter) ? $name : substr($name, 1, -1); + return !str_starts_with($name, $startingCharacter) + ? $name + : substr($name, 1, -1); } /** @@ -229,7 +241,7 @@ protected function unquoteParts(array $parts, bool $withColumn): array $lastKey = count($parts) - 1; foreach ($parts as $k => &$part) { - $part = ($withColumn || $lastKey === $k) ? + $part = ($withColumn && $lastKey === $k) ? $this->unquoteSimpleColumnName($part) : $this->unquoteSimpleTableName($part); } diff --git a/tests/Db/Schema/QuoterTest.php b/tests/Db/Schema/QuoterTest.php index 0841dca80..a98d1dbba 100644 --- a/tests/Db/Schema/QuoterTest.php +++ b/tests/Db/Schema/QuoterTest.php @@ -87,4 +87,19 @@ public function testCleanUpTableNamesWithCastException(): void ['tableAlias' => 123], ); } + + public function testGetTableNamePartsWithDifferentQuotes(): void + { + $quoter = new Quoter('`', '"'); + + $this->assertSame(['schema', 'table'], $quoter->getTableNameParts('"schema"."table"')); + } + + public function testQuoteSqlWithTablePrefix(): void + { + $quoter = new Quoter('`', '`', 'prefix_'); + $sql = 'SELECT * FROM {{%table%}}'; + + $this->assertSame('SELECT * FROM `prefix_table`', $quoter->quoteSql($sql)); + } } From d9d1ee247a34ea5bc6aad50d16804715c8b7e7be Mon Sep 17 00:00:00 2001 From: Tigrov Date: Mon, 25 Sep 2023 17:34:49 +0700 Subject: [PATCH 2/5] Fix bug with sub-query with alias as table name --- src/Schema/Quoter.php | 2 +- tests/Db/Schema/QuoterTest.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Schema/Quoter.php b/src/Schema/Quoter.php index edc913625..d6e4d5d34 100644 --- a/src/Schema/Quoter.php +++ b/src/Schema/Quoter.php @@ -175,7 +175,7 @@ function ($matches) { public function quoteTableName(string $name): string { - if (str_starts_with($name, '(') && str_ends_with($name, ')')) { + if (str_starts_with($name, '(')) { return $name; } diff --git a/tests/Db/Schema/QuoterTest.php b/tests/Db/Schema/QuoterTest.php index a98d1dbba..ec8323913 100644 --- a/tests/Db/Schema/QuoterTest.php +++ b/tests/Db/Schema/QuoterTest.php @@ -102,4 +102,12 @@ public function testQuoteSqlWithTablePrefix(): void $this->assertSame('SELECT * FROM `prefix_table`', $quoter->quoteSql($sql)); } + + public function testQuoteTableNameWithQueryAlias() + { + $quoter = new Quoter('`', '`', 'prefix_'); + $name = '(SELECT * FROM table) alias'; + + $this->assertSame($name, $quoter->quoteTableName($name)); + } } From b824b71973a8ceecbaed7df3bfe9378c622e02c7 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Mon, 25 Sep 2023 17:37:20 +0700 Subject: [PATCH 3/5] Fix CI --- src/Schema/Quoter.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Schema/Quoter.php b/src/Schema/Quoter.php index d6e4d5d34..1f8aef970 100644 --- a/src/Schema/Quoter.php +++ b/src/Schema/Quoter.php @@ -17,7 +17,6 @@ use function preg_replace; use function preg_replace_callback; use function str_contains; -use function str_ends_with; use function str_replace; use function str_starts_with; use function strrpos; From 194aa6731349a5eea8f2f70f8413dc5e827fc6f0 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Tue, 26 Sep 2023 08:38:18 +0700 Subject: [PATCH 4/5] Add Add line to CHANGELOG.md, update test --- CHANGELOG.md | 4 ++++ tests/Db/Schema/QuoterTest.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3af0daf3b..ae9ea1644 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ ## 1.1.2 under development - Bug #751: Fix collected debug actions (@xepozz) +- Enh #756: Refactor Quoter (@Tigrov) +- Bug #756: Fix `quoteSql()` for sql containing table with prefix (@Tigrov) +- Bug #756: Fix `getTableNameParts()` for cases when different quotes for tables and columns (@Tigrov) +- Bug #756: Fix `quoteTableName()` for sub-query with alias (@Tigrov) ## 1.1.1 August 16, 2023 diff --git a/tests/Db/Schema/QuoterTest.php b/tests/Db/Schema/QuoterTest.php index ec8323913..3d7bd8599 100644 --- a/tests/Db/Schema/QuoterTest.php +++ b/tests/Db/Schema/QuoterTest.php @@ -105,7 +105,7 @@ public function testQuoteSqlWithTablePrefix(): void public function testQuoteTableNameWithQueryAlias() { - $quoter = new Quoter('`', '`', 'prefix_'); + $quoter = new Quoter('`', '`'); $name = '(SELECT * FROM table) alias'; $this->assertSame($name, $quoter->quoteTableName($name)); From 63bccfbdfcd9081d3bbb5c638f6bacbfe05c1b98 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 26 Sep 2023 08:44:28 +0300 Subject: [PATCH 5/5] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae9ea1644..137af005f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,8 @@ ## 1.1.2 under development - Bug #751: Fix collected debug actions (@xepozz) -- Enh #756: Refactor Quoter (@Tigrov) -- Bug #756: Fix `quoteSql()` for sql containing table with prefix (@Tigrov) +- Enh #756: Refactor `Quoter` (@Tigrov) +- Bug #756: Fix `quoteSql()` for SQL containing table with prefix (@Tigrov) - Bug #756: Fix `getTableNameParts()` for cases when different quotes for tables and columns (@Tigrov) - Bug #756: Fix `quoteTableName()` for sub-query with alias (@Tigrov)