From 5698a760f8c519f3d65062bb75095dc99b7e331a Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Fri, 23 Oct 2026 22:09:10 -0500 Subject: [PATCH] Check only the deleted row's validity bit on DELETE vec0Update_Delete_ClearValidity() tested `bx >> (chunk_offset % CHAR_BIT)`, which is nonzero whenever a later row's bit in the same byte of the chunk's validity bitmap is set. Deleting a row whose own bit was already clear therefore succeeded instead of failing with "validity bit is not set". Only a damaged _chunks table has such a row. The check now tests the row's bit alone, `(bx >> (chunk_offset % CHAR_BIT)) & 1`. Ported from photostructure/sqlite-vec@f6a3244 by Matthew McEachen. test_vec0_delete_errors sets a chunk's validity byte to x'02', clearing row 1's bit while row 2's stays set, and expects the delete of row 1 to fail. It fails on main and passes here. The full suite passes (143 passed, 4 skipped, 259 snapshots), and make test-unit passes. --- sqlite-vec.c | 2 +- tests/test-loadable.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/sqlite-vec.c b/sqlite-vec.c index ab77083c..42a166ce 100644 --- a/sqlite-vec.c +++ b/sqlite-vec.c @@ -9576,7 +9576,7 @@ int vec0Update_Delete_ClearValidity(vec0_vtab *p, i64 chunk_id, p->schemaName, p->shadowChunksName, chunk_id, validityOffset); goto cleanup; } - if (!(bx >> (chunk_offset % CHAR_BIT))) { + if (!((bx >> (chunk_offset % CHAR_BIT)) & 1)) { // IMP: V21193_05263 rc = SQLITE_ERROR; vtab_set_error( diff --git a/tests/test-loadable.py b/tests/test-loadable.py index 0ef935c5..6f53a89f 100644 --- a/tests/test-loadable.py +++ b/tests/test-loadable.py @@ -1451,6 +1451,14 @@ def test_vec0_delete_errors(): ): db.execute("delete from t1 where rowid = 1") db.rollback() + # only the row's own bit counts, not a higher one in the same byte + db.execute("begin") + db.execute("UPDATE t1_chunks SET validity = x'02'") + with _raises( + "vec0 deletion error: validity bit is not set for main.t1_chunks.1 at 0" + ): + db.execute("delete from t1 where rowid = 1") + db.rollback() # EVIDENCE-OF: V21193_05263 vec0 DELETE raises error on validity blob error db.commit()