Skip to content

Commit

Permalink
impl. binary REGEXP for SQLite
Browse files Browse the repository at this point in the history
  • Loading branch information
mvorisek committed Apr 23, 2024
1 parent 235b4ea commit 39657de
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 10 deletions.
21 changes: 21 additions & 0 deletions src/Persistence/Sql/Sqlite/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ',')
{
Expand Down
9 changes: 5 additions & 4 deletions tests/ConditionSqlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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')) {
Expand All @@ -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));
Expand Down Expand Up @@ -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'));
Expand Down
6 changes: 4 additions & 2 deletions tests/Persistence/Sql/QueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 9 additions & 4 deletions tests/Schema/MigratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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']));
}
}
}
Expand Down

0 comments on commit 39657de

Please sign in to comment.