From b9b9a5ecabcfff91dfdca50dfbe07196483c0812 Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Thu, 13 Nov 2025 11:16:01 +0200 Subject: [PATCH] AI-generated tests for DELETE RETURNING --- testing/returning.test | 383 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) diff --git a/testing/returning.test b/testing/returning.test index 23a9382c3..f8baaf475 100755 --- a/testing/returning.test +++ b/testing/returning.test @@ -524,6 +524,383 @@ do_execsql_test_on_specific_db {:memory:} update-returning-row-values { UPDATE t SET (id, name) = (2, 'mordor') RETURNING id, name; } {2|mordor} +# ============================================================================ +# DELETE RETURNING tests +# ============================================================================ + +# Basic column references +do_execsql_test_on_specific_db {:memory:} delete-returning-single-column { + CREATE TABLE t (id INTEGER, name TEXT, value REAL); + INSERT INTO t VALUES (1, 'test', 10.5); + DELETE FROM t WHERE id = 1 RETURNING id; +} {1} + +do_execsql_test_on_specific_db {:memory:} delete-returning-multiple-columns { + CREATE TABLE t (id INTEGER, name TEXT, value REAL); + INSERT INTO t VALUES (1, 'test', 10.5); + DELETE FROM t WHERE id = 1 RETURNING id, name; +} {1|test} + +do_execsql_test_on_specific_db {:memory:} delete-returning-all-columns { + CREATE TABLE t (id INTEGER, name TEXT, value REAL); + INSERT INTO t VALUES (1, 'test', 10.5); + DELETE FROM t WHERE id = 1 RETURNING *; +} {1|test|10.5} + +# Table-qualified column references +do_execsql_test_on_specific_db {:memory:} delete-returning-table-qualified { + CREATE TABLE t (id INTEGER, name TEXT); + INSERT INTO t VALUES (1, 'test'); + DELETE FROM t WHERE id = 1 RETURNING t.id, t.name; +} {1|test} + +# Arbitrary expressions not referencing columns +do_execsql_test_on_specific_db {:memory:} delete-returning-literal { + CREATE TABLE t (id INTEGER); + INSERT INTO t VALUES (1); + DELETE FROM t WHERE id = 1 RETURNING 42; +} {42} + +do_execsql_test_on_specific_db {:memory:} delete-returning-constant-expression { + CREATE TABLE t (id INTEGER); + INSERT INTO t VALUES (1); + DELETE FROM t WHERE id = 1 RETURNING 2 + 3 * 4; +} {14} + +# Expressions referencing deleted columns +do_execsql_test_on_specific_db {:memory:} delete-returning-column-arithmetic { + CREATE TABLE t (id INTEGER, value INTEGER); + INSERT INTO t VALUES (1, 10); + DELETE FROM t WHERE id = 1 RETURNING 2 * value; +} {20} + +do_execsql_test_on_specific_db {:memory:} delete-returning-complex-expression { + CREATE TABLE t (id INTEGER, x INTEGER, y INTEGER); + INSERT INTO t VALUES (1, 5, 3); + DELETE FROM t WHERE id = 1 RETURNING x + y * 2; +} {11} + +do_execsql_test_on_specific_db {:memory:} delete-returning-function-call { + CREATE TABLE t (id INTEGER, name TEXT); + INSERT INTO t VALUES (1, 'hello'); + DELETE FROM t WHERE id = 1 RETURNING upper(name); +} {HELLO} + +do_execsql_test_on_specific_db {:memory:} delete-returning-mixed-expressions { + CREATE TABLE t (id INTEGER, name TEXT, value INTEGER); + INSERT INTO t VALUES (1, 'test', 10); + DELETE FROM t WHERE id = 1 RETURNING id, upper(name), value * 3; +} {1|TEST|30} + +# Multiple rows deleted +do_execsql_test_on_specific_db {:memory:} delete-returning-multiple-rows { + CREATE TABLE t (id INTEGER, name TEXT); + INSERT INTO t VALUES (1, 'first'), (2, 'second'), (3, 'third'); + DELETE FROM t RETURNING id, name; +} {1|first +2|second +3|third} + +do_execsql_test_on_specific_db {:memory:} delete-returning-multiple-rows-expressions { + CREATE TABLE t (id INTEGER, value INTEGER); + INSERT INTO t VALUES (1, 10), (2, 20), (3, 30); + DELETE FROM t RETURNING id, value * 2; +} {1|20 +2|40 +3|60} + +# NULL handling +do_execsql_test_on_specific_db {:memory:} delete-returning-null-values { + CREATE TABLE t (id INTEGER, name TEXT, value INTEGER); + INSERT INTO t VALUES (1, NULL, NULL); + DELETE FROM t WHERE id = 1 RETURNING id, name, value; +} {1||} + +do_execsql_test_on_specific_db {:memory:} delete-returning-null-expression { + CREATE TABLE t (id INTEGER, name TEXT); + INSERT INTO t VALUES (1, NULL); + DELETE FROM t WHERE id = 1 RETURNING coalesce(name, 'default'); +} {default} + +# Rowid +do_execsql_test_on_specific_db {:memory:} delete-returning-rowid { + CREATE TABLE t (name TEXT); + INSERT INTO t VALUES ('test'); + DELETE FROM t RETURNING rowid, name; +} {1|test} + +do_execsql_test_on_specific_db {:memory:} delete-returning-rowid-expression { + CREATE TABLE t (name TEXT); + INSERT INTO t VALUES ('test'); + DELETE FROM t RETURNING rowid * 2; +} {2} + +# WHERE clause filtering +do_execsql_test_on_specific_db {:memory:} delete-returning-with-where { + CREATE TABLE t (id INTEGER, name TEXT); + INSERT INTO t VALUES (1, 'a'), (2, 'b'), (3, 'c'); + DELETE FROM t WHERE id > 1 RETURNING id, name; +} {2|b +3|c} + +do_execsql_test_on_specific_db {:memory:} delete-returning-no-matches { + CREATE TABLE t (id INTEGER, name TEXT); + INSERT INTO t VALUES (1, 'test'); + DELETE FROM t WHERE id = 999 RETURNING *; +} {} + +# Expressions with string operations +do_execsql_test_on_specific_db {:memory:} delete-returning-string-concat { + CREATE TABLE t (id INTEGER, first TEXT, last TEXT); + INSERT INTO t VALUES (1, 'John', 'Doe'); + DELETE FROM t WHERE id = 1 RETURNING first || ' ' || last; +} {"John Doe"} + +do_execsql_test_on_specific_db {:memory:} delete-returning-substring { + CREATE TABLE t (id INTEGER, name TEXT); + INSERT INTO t VALUES (1, 'hello world'); + DELETE FROM t WHERE id = 1 RETURNING substr(name, 1, 5); +} {hello} + +# Case expressions +do_execsql_test_on_specific_db {:memory:} delete-returning-case-expression { + CREATE TABLE t (id INTEGER, value INTEGER); + INSERT INTO t VALUES (1, 5); + DELETE FROM t WHERE id = 1 RETURNING CASE WHEN value > 10 THEN 'high' WHEN value > 0 THEN 'low' ELSE 'zero' END; +} {low} + +# Nested expressions +do_execsql_test_on_specific_db {:memory:} delete-returning-nested-expressions { + CREATE TABLE t (id INTEGER, x INTEGER, y INTEGER, z INTEGER); + INSERT INTO t VALUES (1, 2, 3, 4); + DELETE FROM t WHERE id = 1 RETURNING (x + y) * (z - 1); +} {15} + +# ============================================================================ +# DELETE RETURNING NASTY EDGE CASES +# ============================================================================ + +# Multiple references to same column in RETURNING +do_execsql_test_on_specific_db {:memory:} delete-returning-multiple-column-references { + CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER); + INSERT INTO t VALUES (1, 10), (2, 20), (3, 30); + DELETE FROM t WHERE id = 2 RETURNING x, x * 2, x + x; +} {20|40|40} + +# Column aliases in RETURNING +do_execsql_test_on_specific_db {:memory:} delete-returning-column-aliases { + CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER, y INTEGER); + INSERT INTO t VALUES (1, 1, 2), (2, 3, 4); + DELETE FROM t WHERE x = 1 RETURNING x AS deleted_x, y AS deleted_y, x + y AS sum; +} {1|2|3} + +# Complex WHERE clauses with IN +do_execsql_test_on_specific_db {:memory:} delete-returning-where-in { + CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER); + INSERT INTO t VALUES (1, 1), (2, 2), (3, 3); + DELETE FROM t WHERE val IN (1, 3) RETURNING *; +} {1|1 +3|3} + +# Complex WHERE clauses with BETWEEN +do_execsql_test_on_specific_db {:memory:} delete-returning-where-between { + CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER, y INTEGER); + INSERT INTO t VALUES (1, 1, 10), (2, 2, 20), (3, 3, 30); + DELETE FROM t WHERE x BETWEEN 1 AND 2 RETURNING id, x, y, x + y; +} {1|1|10|11 +2|2|20|22} + +# Complex WHERE clauses with LIKE +do_execsql_test_on_specific_db {:memory:} delete-returning-where-like { + CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT); + INSERT INTO t VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie'); + DELETE FROM t WHERE name LIKE 'B%' RETURNING *; +} {2|Bob} + +# Complex WHERE clauses with AND/OR +do_execsql_test_on_specific_db {:memory:} delete-returning-where-complex { + CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER); + INSERT INTO t VALUES (1, 5), (2, 10), (3, 15); + DELETE FROM t WHERE x > 5 AND x < 15 RETURNING id, x, x * x, x + x + x; +} {2|10|100|30} + +# WHERE clause with modulo operator +do_execsql_test_on_specific_db {:memory:} delete-returning-where-modulo { + CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT, val INTEGER); + INSERT INTO t VALUES (1, 'a', 1), (2, 'b', 2), (3, 'c', 3); + DELETE FROM t WHERE val % 2 = 0 RETURNING id, name, val, length(name), abs(val); +} {2|b|2|1|2} + +# WHERE clause with subquery (correlated) - NOT SUPPORTED YET +# do_execsql_test_on_specific_db {:memory:} delete-returning-where-subquery { +# CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER); +# INSERT INTO t VALUES (1, 1), (2, 2), (3, 3); +# DELETE FROM t WHERE x = (SELECT MAX(x) FROM t) RETURNING *; +# } {3|3} + +# WHERE clause with IN subquery - NOT SUPPORTED YET +# do_execsql_test_on_specific_db {:memory:} delete-returning-where-in-subquery { +# CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER, b INTEGER); +# INSERT INTO t VALUES (1, 1, 2), (2, 3, 4), (3, 5, 6); +# DELETE FROM t WHERE a IN (SELECT a FROM t WHERE a > 3) RETURNING *; +# } {3|5|6} + +# WHERE clause that matches nothing +do_execsql_test_on_specific_db {:memory:} delete-returning-where-false { + CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT); + INSERT INTO t VALUES (1, 'test'); + DELETE FROM t WHERE 1=0 RETURNING *; +} {} + +# Rowid and INTEGER PRIMARY KEY together +do_execsql_test_on_specific_db {:memory:} delete-returning-rowid-and-pk { + CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT); + INSERT INTO t VALUES (1, 'a'), (2, 'b'); + DELETE FROM t RETURNING rowid, id, name; +} {1|1|a +2|2|b} + +# AUTOINCREMENT with RETURNING +do_execsql_test_on_specific_db {:memory:} delete-returning-autoincrement { + CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT); + INSERT INTO t VALUES (NULL, 'a'), (NULL, 'b'); + DELETE FROM t RETURNING id, name; +} {1|a +2|b} + +# Type functions in RETURNING +do_execsql_test_on_specific_db {:memory:} delete-returning-typeof { + CREATE TABLE t (id INTEGER PRIMARY KEY, x REAL, y TEXT); + INSERT INTO t VALUES (1, 1.5, 'test'), (2, 2.5, 'foo'); + DELETE FROM t RETURNING id, x, y, typeof(x), typeof(y); +} {1|1.5|test|real|text +2|2.5|foo|real|text} + +# NULL handling with coalesce +do_execsql_test_on_specific_db {:memory:} delete-returning-null-coalesce { + CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER); + INSERT INTO t VALUES (1, NULL), (2, 42), (3, NULL); + DELETE FROM t WHERE val IS NULL RETURNING id, val, coalesce(val, 999); +} {1||999 +3||999} + +# BLOB handling +do_execsql_test_on_specific_db {:memory:} delete-returning-blob { + CREATE TABLE t (id INTEGER PRIMARY KEY, val BLOB); + INSERT INTO t VALUES (1, zeroblob(10)), (2, x'0102'); + DELETE FROM t RETURNING id, length(val), typeof(val); +} {1|10|blob +2|2|blob} + +# printf function in RETURNING +do_execsql_test_on_specific_db {:memory:} delete-returning-printf { + CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT); + INSERT INTO t VALUES (1, 'hello'), (2, 'world'); + DELETE FROM t WHERE name = 'hello' RETURNING printf('Deleted: %s', name); +} {"Deleted: hello"} + +# Additional edge cases +do_execsql_test_on_specific_db {:memory:} delete-returning-empty-string-null { + CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT); + INSERT INTO t VALUES (1, 'hello'), (2, ''), (3, NULL); + DELETE FROM t RETURNING id, name, length(name), name IS NULL; +} {1|hello|5|0 +2||0|0 +3|||1} + +do_execsql_test_on_specific_db {:memory:} delete-returning-string-concat-numbers { + CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER, y INTEGER); + INSERT INTO t VALUES (1, 1, 2), (2, 3, 4); + DELETE FROM t WHERE x = 1 RETURNING x, y, x + y, x * y, x || y; +} {1|2|3|2|12} + +do_execsql_test_on_specific_db {:memory:} delete-returning-round-precision { + CREATE TABLE t (id INTEGER PRIMARY KEY, val REAL); + INSERT INTO t VALUES (1, 1.23456789), (2, 9.999999); + DELETE FROM t RETURNING id, val, round(val, 2); +} {1|1.23456789|1.23 +2|9.999999|10.0} + +do_execsql_test_on_specific_db {:memory:} delete-returning-glob-pattern { + CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT); + INSERT INTO t VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie'); + DELETE FROM t WHERE name GLOB '[BC]*' RETURNING *; +} {2|Bob +3|Charlie} + +do_execsql_test_on_specific_db {:memory:} delete-returning-operator-precedence { + CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER, b INTEGER, c INTEGER); + INSERT INTO t VALUES (1, 1, 2, 3), (2, 4, 5, 6); + DELETE FROM t RETURNING a, b, c, a + b * c, (a + b) * c; +} {1|2|3|7|9 +4|5|6|34|54} + +do_execsql_test_on_specific_db {:memory:} delete-returning-large-numbers { + CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER); + INSERT INTO t VALUES (1, 999999999), (2, -999999999), (3, 0); + DELETE FROM t RETURNING id, val, val + 1, val * 2; +} {1|999999999|1000000000|1999999998 +2|-999999999|-999999998|-1999999998 +3|0|1|0} + +do_execsql_test_on_specific_db {:memory:} delete-returning-nullif-coalesce { + CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT); + INSERT INTO t VALUES (1, 'test'), (2, 'test'), (3, 'other'); + DELETE FROM t WHERE name = 'test' RETURNING id, name, NULLIF(name, 'test'), COALESCE(NULLIF(name, 'test'), 'was_test'); +} {1|test||was_test +2|test||was_test} + +do_execsql_test_on_specific_db {:memory:} delete-returning-iif-null-handling { + CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER, y INTEGER); + INSERT INTO t VALUES (1, 5, 10), (2, NULL, 20), (3, 15, NULL); + DELETE FROM t RETURNING id, x, y, IIF(x IS NULL OR y IS NULL, 'has_null', x + y); +} {1|5|10|15 +2||20|has_null +3|15||has_null} + +do_execsql_test_on_specific_db {:memory:} delete-returning-string-functions { + CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT); + INSERT INTO t VALUES (1, 'hello'), (2, 'world'); + DELETE FROM t RETURNING id, name, upper(name), lower(name), length(name); +} {1|hello|HELLO|hello|5 +2|world|WORLD|world|5} + +do_execsql_test_on_specific_db {:memory:} delete-returning-replace-function { + CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT); + INSERT INTO t VALUES (1, 'hello world'), (2, 'foo bar'); + DELETE FROM t RETURNING id, name, replace(name, ' ', '_') AS replaced; +} {"1|hello world|hello_world +2|foo bar|foo_bar"} + +do_execsql_test_on_specific_db {:memory:} delete-returning-abs-sign { + CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER); + INSERT INTO t VALUES (1, 42), (2, -10), (3, 0); + DELETE FROM t RETURNING id, val, abs(val), sign(val); +} {1|42|42|1 +2|-10|10|-1 +3|0|0|0} + +do_execsql_test_on_specific_db {:memory:} delete-returning-coalesce-arithmetic { + CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER, y INTEGER); + INSERT INTO t VALUES (1, 5, NULL), (2, NULL, 10), (3, NULL, NULL); + DELETE FROM t RETURNING id, x, y, coalesce(x, 0) + coalesce(y, 0); +} {1|5||5 +2||10|10 +3|||0} + +do_execsql_test_on_specific_db {:memory:} delete-returning-case-expression { + CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT, val INTEGER); + INSERT INTO t VALUES (1, 'test', 10), (2, 'test', 20); + DELETE FROM t WHERE val = 10 RETURNING id, name, val, CASE WHEN val > 15 THEN 'high' ELSE 'low' END; +} {1|test|10|low} + +do_execsql_test_on_specific_db {:memory:} delete-returning-type-cast { + CREATE TABLE t (id INTEGER PRIMARY KEY, x REAL, y INTEGER); + INSERT INTO t VALUES (1, 1.5, 2), (2, 3.7, 4); + DELETE FROM t RETURNING id, x, y, round(x), cast(x AS INTEGER); +} {1|1.5|2|2.0|1 +2|3.7|4|4.0|3} + # ============================================================================ # Edge cases and complex scenarios # ============================================================================ @@ -540,6 +917,12 @@ do_execsql_test_on_specific_db {:memory:} update-returning-no-column-reference { UPDATE t SET id = 2 RETURNING 1 + 1, 'constant', NULL; } {2|constant|} +do_execsql_test_on_specific_db {:memory:} delete-returning-no-column-reference { + CREATE TABLE t (id INTEGER); + INSERT INTO t VALUES (1); + DELETE FROM t WHERE id = 1 RETURNING 1 + 1, 'constant', NULL; +} {2|constant|} + # RETURNING with aggregate-like expressions (should work per-row) do_execsql_test_on_specific_db {:memory:} insert-returning-sum-expression { CREATE TABLE t (id INTEGER, a INTEGER, b INTEGER);