diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d408078..9db75187 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Oracle driver for Yii Database Change Log -## 1.3.1 under development +## 2.0.0 under development -- no changes in this release. +- Enh #255: Implement `SqlParser` and `ExpressionBuilder` driver classes (@Tigrov) ## 1.3.0 March 21, 2024 diff --git a/rector.php b/rector.php index 7a9f3ac6..34351531 100644 --- a/rector.php +++ b/rector.php @@ -11,7 +11,10 @@ return static function (RectorConfig $rectorConfig): void { $rectorConfig->paths([ __DIR__ . '/src', - __DIR__ . '/tests', + /** + * Disabled ./tests directory due to different branches with main package when testing + */ + // __DIR__ . '/tests', ]); // register a single rule diff --git a/src/Builder/ExpressionBuilder.php b/src/Builder/ExpressionBuilder.php new file mode 100644 index 00000000..ad381158 --- /dev/null +++ b/src/Builder/ExpressionBuilder.php @@ -0,0 +1,16 @@ +getName())); return new Expression('TO_BLOB(UTL_RAW.CAST_TO_RAW(:' . $placeholder . '))', [$placeholder => $value]); } diff --git a/src/DQLQueryBuilder.php b/src/DQLQueryBuilder.php index c2a95cd7..f798ccb0 100644 --- a/src/DQLQueryBuilder.php +++ b/src/DQLQueryBuilder.php @@ -4,7 +4,9 @@ namespace Yiisoft\Db\Oracle; +use Yiisoft\Db\Expression\Expression; use Yiisoft\Db\Expression\ExpressionInterface; +use Yiisoft\Db\Oracle\Builder\ExpressionBuilder; use Yiisoft\Db\Oracle\Builder\InConditionBuilder; use Yiisoft\Db\Oracle\Builder\LikeConditionBuilder; use Yiisoft\Db\Query\Query; @@ -87,6 +89,7 @@ protected function defaultExpressionBuilders(): array [ InCondition::class => InConditionBuilder::class, LikeCondition::class => LikeConditionBuilder::class, + Expression::class => ExpressionBuilder::class, ], ); } diff --git a/src/SqlParser.php b/src/SqlParser.php new file mode 100644 index 00000000..7d03db6a --- /dev/null +++ b/src/SqlParser.php @@ -0,0 +1,64 @@ +length - 1; + + while ($this->position < $length) { + $pos = $this->position++; + + match ($this->sql[$pos]) { + ':' => ($word = $this->parseWord()) === '' + ? $this->skipChars(':') + : $result = ':' . $word, + '"' => $this->skipToAfterChar('"'), + "'" => $this->skipQuotedWithoutEscape($this->sql[$pos]), + 'q', 'Q' => $this->sql[$this->position] === "'" + ? $this->skipQuotedWithQ() + : null, + '-' => $this->sql[$this->position] === '-' + ? ++$this->position && $this->skipToAfterChar("\n") + : null, + '/' => $this->sql[$this->position] === '*' + ? ++$this->position && $this->skipToAfterString('*/') + : null, + default => null, + }; + + if ($result !== null) { + $position = $pos; + + return $result; + } + } + + return null; + } + + /** + * Skips quoted string with Q-operator. + */ + private function skipQuotedWithQ(): void + { + $endChar = match ($this->sql[++$this->position]) { + '[' => ']', + '<' => '>', + '{' => '}', + '(' => ')', + default => $this->sql[$this->position], + }; + + ++$this->position; + + $this->skipToAfterString("$endChar'"); + } +} diff --git a/tests/CommandTest.php b/tests/CommandTest.php index 80c0d44b..c9731874 100644 --- a/tests/CommandTest.php +++ b/tests/CommandTest.php @@ -527,9 +527,10 @@ public function testUpdate( array $columns, array|string $conditions, array $params, - string $expected + array $expectedValues, + int $expectedCount, ): void { - parent::testUpdate($table, $columns, $conditions, $params, $expected); + parent::testUpdate($table, $columns, $conditions, $params, $expectedValues, $expectedCount); } /** diff --git a/tests/Provider/SqlParserProvider.php b/tests/Provider/SqlParserProvider.php new file mode 100644 index 00000000..5d7be748 --- /dev/null +++ b/tests/Provider/SqlParserProvider.php @@ -0,0 +1,35 @@ +