diff --git a/src/Persistence/Sql/Sqlite/Query.php b/src/Persistence/Sql/Sqlite/Query.php index b6c969750..b6887867c 100644 --- a/src/Persistence/Sql/Sqlite/Query.php +++ b/src/Persistence/Sql/Sqlite/Query.php @@ -137,6 +137,27 @@ function ($sqlLeft, $sqlRight) { ); } + #[\Override] + protected function _renderConditionRegexpOperator(bool $negated, string $sqlLeft, string $sqlRight, ?bool $caseSensitive = null): string + { + if ($caseSensitive !== null) { + return parent::_renderConditionRegexpOperator($negated, $sqlLeft, $sqlRight, $caseSensitive); + } + + return ($negated ? 'not ' : '') . $this->_renderConditionBinaryReuse( + $sqlLeft, + $sqlRight, + function ($sqlLeft, $sqlRight) { + $res = 'case when ' . $sqlLeft . ' = lower(' . $sqlLeft . ') and ' . $sqlLeft . ' = upper(' . $sqlLeft . ')' + . ' then ' . parent::_renderConditionRegexpOperator(false, $sqlLeft, $sqlRight) + . ' else ' . parent::_renderConditionRegexpOperator(false, $sqlLeft, $sqlRight, true) + . ' end'; + + return $res; + } + ); + } + #[\Override] public function groupConcat($field, string $separator = ',') { diff --git a/tests/ConditionSqlTest.php b/tests/ConditionSqlTest.php index 659e2eedc..c5166c8ca 100644 --- a/tests/ConditionSqlTest.php +++ b/tests/ConditionSqlTest.php @@ -689,10 +689,11 @@ public function testRegexpCondition(string $type, bool $isBinary): void return $res; }; + // TODO SQLSTATE[HY000]: General error: 3995 Character set 'binary' cannot be used in conjunction with 'utf8mb4_general_ci' in call to regexp_like. if ($this->getDatabasePlatform() instanceof MySQLPlatform && $type === 'binary' && $this->getConnection()->getConnection()->getNativeConnection() instanceof \PDO) { self::assertTrue(true); // @phpstan-ignore-line - return; // TODO SQLSTATE[HY000]: General error: 3995 Character set 'binary' cannot be used in conjunction with 'utf8mb4_general_ci' in call to regexp_like. + return; } if ($this->getDatabasePlatform() instanceof MySQLPlatform && ($type === 'binary' || $type === 'blob')) { @@ -719,9 +720,9 @@ public function testRegexpCondition(string $type, bool $isBinary): void } self::assertSame([1], $findIdsRegexFx('name', 'John')); - self::assertSame(/* $isBinary ? [] : */ [1], $findIdsRegexFx('name', 'john')); + self::assertSame($isBinary ? [] : [1], $findIdsRegexFx('name', 'john')); self::assertSame([13], $findIdsRegexFx('name', 'heiß')); - self::assertSame(/* $isBinary ? [] : */ [13], $findIdsRegexFx('name', 'Heiß')); + self::assertSame($isBinary ? [] : [13], $findIdsRegexFx('name', 'Heiß')); self::assertSame([1], $findIdsRegexFx('name', 'Joh')); self::assertSame([1], $findIdsRegexFx('name', 'ohn')); self::assertSame([1, 2, 3, ...($this->getDatabasePlatform() instanceof OraclePlatform ? [] : [4]), 13], $findIdsRegexFx('name', 'a', true)); @@ -758,7 +759,7 @@ public function testRegexpCondition(string $type, bool $isBinary): void self::assertSame([5, 6, 7, 8, 9, 11, 12], $findIdsRegexFx('name', 'Sa.ra')); self::assertSame([2, 3, 13], $findIdsRegexFx('name', '[e]')); self::assertSame([1, 2, 3, 13], $findIdsRegexFx('name', '[eo]')); - self::assertSame([1, 2, 3, .../* ($isBinary ? [] : */ [13] /* ) */], $findIdsRegexFx('name', '[A-P][aeo]')); + self::assertSame([1, 2, 3, ...($isBinary ? [] : [13])], $findIdsRegexFx('name', '[A-P][aeo]')); self::assertSame([3], $findIdsRegexFx('name', 'o[^h]')); self::assertSame([5, 6, 7, 8, 9, 10, 11, 12], $findIdsRegexFx('name', '^Sa')); self::assertSame([], $findIdsRegexFx('name', '^ra')); diff --git a/tests/Persistence/Sql/QueryTest.php b/tests/Persistence/Sql/QueryTest.php index 62c5b60e0..589b21ce6 100644 --- a/tests/Persistence/Sql/QueryTest.php +++ b/tests/Persistence/Sql/QueryTest.php @@ -842,11 +842,13 @@ public function testWhereSpecialValues(): void $this->q('[where]')->where('name', 'not regexp', '^foo')->render()[0] ); self::assertSame( - 'where regexp_like(`name`, :a, \'is\')', + 'where case when `name` = lower(`name`) and `name` = upper(`name`) then regexp_like(`name`, :a, \'is\') else regexp_like(`name`, :a, \'s\') end', (new SqliteQuery('[where]'))->where('name', 'regexp', 'foo')->render()[0] ); self::assertSame( - 'where regexp_like(`name`, sum("b"), \'is\')', + version_compare(SqliteConnection::getDriverVersion(), '3.45') < 0 + ? 'where case when `name` = lower(`name`) and `name` = upper(`name`) then regexp_like(`name`, sum("b"), \'is\') else regexp_like(`name`, sum("b"), \'s\') end' + : 'where (select case when `name` = lower(`name`) and `name` = upper(`name`) then regexp_like(`name`, `__atk4_reuse_right__`, \'is\') else regexp_like(`name`, `__atk4_reuse_right__`, \'s\') end from (select sum("b") `__atk4_reuse_right__`) `__atk4_reuse_tmp__`)', (new SqliteQuery('[where]'))->where('name', 'regexp', $this->e('sum({})', ['b']))->render()[0] ); // TODO add MysqlQuery test once MySQL 5.x support is dropped diff --git a/tests/Schema/MigratorTest.php b/tests/Schema/MigratorTest.php index d24479af1..0ee2c9b36 100644 --- a/tests/Schema/MigratorTest.php +++ b/tests/Schema/MigratorTest.php @@ -11,6 +11,7 @@ use Atk4\Data\Schema\TestCase; use Doctrine\DBAL\Exception\TableExistsException; use Doctrine\DBAL\Exception\TableNotFoundException; +use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Platforms\OraclePlatform; use Doctrine\DBAL\Platforms\PostgreSQLPlatform; use Doctrine\DBAL\Platforms\SQLServerPlatform; @@ -128,10 +129,14 @@ public function testCharacterTypeFieldCaseSensitivity(string $type, bool $isBina $model->addCondition('v', 'like', '%ix%Case'); self::assertSameExportUnordered($expectedExport, $model->export(['id'])); - // TODO - // $model->scope()->clear(); - // $model->addCondition('v', 'regexp', 'ix.+Case'); - // self::assertSameExportUnordered($expectedExport, $model->export(['id'])); + // TODO SQLSTATE[HY000]: General error: 3995 Character set 'binary' cannot be used in conjunction with 'utf8mb4_general_ci' in call to regexp_like. + if ($this->getDatabasePlatform() instanceof MySQLPlatform && $type === 'binary' && $this->getConnection()->getConnection()->getNativeConnection() instanceof \PDO) { + return; + } + + $model->scope()->clear(); + $model->addCondition('v', 'regexp', 'ix.+Case'); + self::assertSameExportUnordered($expectedExport, $model->export(['id'])); } } }