The SQLite SET-AND Gotcha
Posted February 21, 2022 ‐ 2 min read
In SQLite, suppose that we have the following table:
TEXT PRIMARY KEY NOT NULL,
atime TEXT NOT NULL,
content TEXT NOT NULL
);
(
name |
And we have inserted a row:
INSERT INTO external_data
VALUES ("name", "october", "a");
|
Plus, we have executed an 'upsert' statement:
INSERT INTO external_data
VALUES ("name", "december", "b")
ON CONFLICT (name)
DO UPDATE SET content = "b"
AND atime = "december";
|
Without conflicts, it does what you expect. But we do have a conflict, and we end up with the following in the table:
sqlite> SELECT * FROM external_data ;
name|october|0
|
Instead of what we wanted to accomplish with the query, content
received the
value of "0"
while the atime
field remained with the old value "october"
instead of being set with "december"
.
What the hell is going on
Well, we misplaced the SET
separator ,
with AND
because having AND
in WHERE
makes sense and we casually did cut&paste from a WHERE
statement to a SET
statement... well, this SET
statement is in fact
equivalent to the following:
SET content = ("b" AND atime = "december")
|
Where ("b" AND atime = "december")
evaluates to 0 because the second AND
operand is not true.
Wait, but SQLite has 'StrictMode'
Yes, there's StrictMode, but it
doesn't help here as of SQLite 3.37.2. A String is a valid operand to AND
.
Wait again, but there's STRICT
for CREATE TABLE
Nope, doesn't help either. Sorry.