Skip to content

Trigger pseudo-tables NEW/OLD not resolved when uppercase (case-sensitive matching) #771

Description

@NikolayMetchev

Summary

The trigger pseudo-tables NEW / OLD are only resolved when written in lowercase (new / old). When written in uppercase (NEW / OLD) — which is valid SQLite, since these references are case-insensitive — sql-psi fails resolution with No table found with name NEW (or OLD).

This is a compile-time-only problem: the SQL runs fine in SQLite either way, so triggers authored in uppercase work at runtime but cannot be expressed in a .sq schema file. Mixed/uppercase is extremely common in hand-written SQL, so this bites anyone migrating existing trigger DDL into SQLDelight.

Minimal reproduction

CREATE TABLE foo (id INTEGER PRIMARY KEY, val TEXT);
CREATE TABLE log (foo_id INTEGER, val TEXT);

-- ✅ Compiles
CREATE TRIGGER lower_ok
AFTER UPDATE ON foo
BEGIN
    INSERT INTO log (foo_id, val) VALUES (new.id, new.val);
END;

-- ❌ Fails: "No table found with name NEW"
CREATE TRIGGER upper_fails
AFTER UPDATE ON foo
BEGIN
    INSERT INTO log (foo_id, val) VALUES (NEW.id, NEW.val);
END;

The two triggers are identical apart from the case of new vs NEW. The lowercase one generates fine; the uppercase one fails at code generation:

... :9:48 No table found with name NEW
... :9:56 No table found with name NEW

The same applies to old / OLD in AFTER UPDATE / AFTER DELETE triggers, and in every body position (VALUES lists, INSERT ... SELECT row sources, UPDATE ... SET/WHERE, WHEN clauses, and subqueries).

Expected behaviour

Both triggers should compile. Per the SQLite grammar these NEW/OLD references are case-insensitive, like other identifiers/keywords, so resolution of the synthetic trigger tables should be case-insensitive.

Actual behaviour

Only the lowercase form resolves. Uppercase NEW/OLD is treated as an unknown table reference.

Environment

  • SQLDelight 2.3.2, dialect app.cash.sqldelight:sqlite-3-25-dialect
  • Reproduced via the SQLDelight Gradle generate…Interface task.

Notes

Likely the synthetic trigger-table names are matched case-sensitively where they're injected into the statement scope (cf. #96 "Pass the trigger-tables to select statements"). A case-insensitive comparison (matching how SQLite itself treats these references) should resolve it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions