Refactor fragile SQLite regex rewrites into driver-aware query methods
Move the ON DUPLICATE KEY UPDATE and UPDATE...AS alias SQL rewrites out of Database::rewriteForSQLite() and into Tag::createNew() and Tag::recount() as driver-aware branches via a new Database::getDriver() method. This keeps dialect-specific SQL explicit at the call site rather than buried in fragile regex transforms. Also fix Tag::getAlbums() and Tag::getPeople() failing on SQLite when id_parent is NULL by adding an IS NULL fallback for root-level queries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -73,36 +73,18 @@ class Database
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public function getDriver()
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
private function rewriteForSQLite($sql)
|
||||
{
|
||||
// REPLACE INTO → INSERT OR REPLACE INTO
|
||||
$sql = preg_replace('/\bREPLACE\s+INTO\b/i', 'INSERT OR REPLACE INTO', $sql);
|
||||
|
||||
// ON DUPLICATE KEY UPDATE → ON CONFLICT(slug) DO UPDATE SET
|
||||
// When present, strip INSERT IGNORE down to INSERT (OR IGNORE conflicts with ON CONFLICT).
|
||||
if (preg_match('/\bON\s+DUPLICATE\s+KEY\s+UPDATE\b/i', $sql))
|
||||
{
|
||||
$sql = preg_replace('/\bINSERT\s+IGNORE\s+INTO\b/i', 'INSERT INTO', $sql);
|
||||
$sql = preg_replace(
|
||||
'/\bON\s+DUPLICATE\s+KEY\s+UPDATE\s+(.+)/i',
|
||||
'ON CONFLICT(slug) DO UPDATE SET $1',
|
||||
$sql
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// INSERT IGNORE INTO → INSERT OR IGNORE INTO
|
||||
$sql = preg_replace('/\bINSERT\s+IGNORE\s+INTO\b/i', 'INSERT OR IGNORE INTO', $sql);
|
||||
}
|
||||
|
||||
// UPDATE table AS alias SET ... → UPDATE table SET ... (with alias replaced by table name)
|
||||
if (preg_match('/\bUPDATE\s+(\w+)\s+AS\s+(\w+)\s+SET\b/i', $sql, $m))
|
||||
{
|
||||
$table = $m[1];
|
||||
$alias = $m[2];
|
||||
$sql = preg_replace('/\bUPDATE\s+\w+\s+AS\s+\w+\s+SET\b/i', "UPDATE $table SET", $sql);
|
||||
$sql = preg_replace('/\b' . preg_quote($alias, '/') . '\.(\w+)\b/', "$table.$1", $sql);
|
||||
}
|
||||
// INSERT IGNORE INTO → INSERT OR IGNORE INTO
|
||||
$sql = preg_replace('/\bINSERT\s+IGNORE\s+INTO\b/i', 'INSERT OR IGNORE INTO', $sql);
|
||||
|
||||
// LIMIT :offset, :limit → LIMIT :limit OFFSET :offset
|
||||
$sql = preg_replace(
|
||||
|
||||
@@ -122,10 +122,12 @@ class Tag
|
||||
|
||||
public static function getAlbums($id_parent = 0, $offset = 0, $limit = 24, $return_format = 'array')
|
||||
{
|
||||
$parent_clause = empty($id_parent) ? '(id_parent = :id_parent OR id_parent IS NULL)' : 'id_parent = :id_parent';
|
||||
|
||||
$rows = Registry::get('db')->queryAssocs('
|
||||
SELECT *
|
||||
FROM tags
|
||||
WHERE id_parent = :id_parent AND kind = :kind
|
||||
WHERE ' . $parent_clause . ' AND kind = :kind
|
||||
ORDER BY tag ASC
|
||||
LIMIT :offset, :limit',
|
||||
[
|
||||
@@ -163,10 +165,12 @@ class Tag
|
||||
|
||||
public static function getPeople($id_parent = 0, $offset = 0, $limit = 24, $return_format = 'array')
|
||||
{
|
||||
$parent_clause = empty($id_parent) ? '(id_parent = :id_parent OR id_parent IS NULL)' : 'id_parent = :id_parent';
|
||||
|
||||
$rows = Registry::get('db')->queryAssocs('
|
||||
SELECT *
|
||||
FROM tags
|
||||
WHERE id_parent = :id_parent AND kind = :kind
|
||||
WHERE ' . $parent_clause . ' AND kind = :kind
|
||||
ORDER BY tag ASC
|
||||
LIMIT :offset, :limit',
|
||||
[
|
||||
@@ -249,7 +253,21 @@ class Tag
|
||||
|
||||
public static function recount(array $id_tags = [])
|
||||
{
|
||||
return Registry::get('db')->query('
|
||||
$db = Registry::get('db');
|
||||
|
||||
if ($db->getDriver() === 'sqlite')
|
||||
{
|
||||
return $db->query('
|
||||
UPDATE tags SET count = (
|
||||
SELECT COUNT(*)
|
||||
FROM `assets_tags` AS at
|
||||
WHERE at.id_tag = tags.id_tag
|
||||
)' . (!empty($id_tags) ? '
|
||||
WHERE tags.id_tag IN(@id_tags)' : ''),
|
||||
['id_tags' => $id_tags]);
|
||||
}
|
||||
|
||||
return $db->query('
|
||||
UPDATE tags AS t SET count = (
|
||||
SELECT COUNT(*)
|
||||
FROM `assets_tags` AS at
|
||||
@@ -272,13 +290,26 @@ class Tag
|
||||
if (!isset($data['count']))
|
||||
$data['count'] = 0;
|
||||
|
||||
$res = $db->query('
|
||||
INSERT IGNORE INTO tags
|
||||
(id_parent, tag, slug, kind, description, count)
|
||||
VALUES
|
||||
(:id_parent, :tag, :slug, :kind, :description, :count)
|
||||
ON DUPLICATE KEY UPDATE count = count + 1',
|
||||
$data);
|
||||
if ($db->getDriver() === 'sqlite')
|
||||
{
|
||||
$res = $db->query('
|
||||
INSERT INTO tags
|
||||
(id_parent, tag, slug, kind, description, count)
|
||||
VALUES
|
||||
(:id_parent, :tag, :slug, :kind, :description, :count)
|
||||
ON CONFLICT(slug) DO UPDATE SET count = count + 1',
|
||||
$data);
|
||||
}
|
||||
else
|
||||
{
|
||||
$res = $db->query('
|
||||
INSERT IGNORE INTO tags
|
||||
(id_parent, tag, slug, kind, description, count)
|
||||
VALUES
|
||||
(:id_parent, :tag, :slug, :kind, :description, :count)
|
||||
ON DUPLICATE KEY UPDATE count = count + 1',
|
||||
$data);
|
||||
}
|
||||
|
||||
if (!$res)
|
||||
throw new Exception('Could not create the requested tag.');
|
||||
|
||||
Reference in New Issue
Block a user