Skip to content

Check only the deleted row's validity bit on DELETE - #25

Merged
vlasky merged 1 commit into
vlasky:mainfrom
MayCXC:delete-validity-bit-vlasky
Oct 28, 2026
Merged

vlasky merged 1 commit into
vlasky:mainfrom
MayCXC:delete-validity-bit-vlasky

Conversation

@MayCXC

@MayCXC MayCXC commented Oct 24, 2026 •

Copy link
Copy Markdown

vec0Update_Delete_ClearValidity() checks a row's validity bit with 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. A DELETE of a row whose own bit is already clear therefore succeeds instead of failing with "validity bit is not set". Only a damaged _chunks table has such a row:

create virtual table t1 using vec0(aaa float[4], chunk_size=8);
insert into t1(aaa) values ('[1,1,1,1]'), ('[2,1,1,1]');
update t1_chunks set validity = x'02';  -- row 1's bit clear, row 2's set
delete from t1 where rowid = 1;         -- succeeds on main

The check now tests the row's bit alone, (bx >> (chunk_offset % CHAR_BIT)) & 1. This is photostructure/sqlite-vec@f6a3244 by Matthew McEachen, ported.

test_vec0_delete_errors gains that case, which fails on main and passes here. The full suite passes (143 passed, 4 skipped, 259 snapshots), also with vec0 built with AddressSanitizer and UBSan, and make test-unit passes. It merges cleanly with each of our open PRs here (#9, #10, #11, #12, #13, #14, #17, #18, #19, #20, #21, #22, #23, #24) and with #26, which reads the bitmap through the same handle.

The same change is open upstream as asg017#358.

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.
@vlasky

vlasky commented Oct 28, 2026

Copy link
Copy Markdown
Owner

Thanks, a clear fix: the old test let any higher bit in the same byte stand in for the row's own, and the new case in test_vec0_delete_errors pins it. Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants