From ef754d4e8904a5cd15af77757f7bf68f30152f59 Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Fri, 23 Oct 2026 09:05:06 -0500 Subject: [PATCH] Refuse int8 and bit columns for IVF indexes IVF's cells, centroids and quantizers hold float32 vectors, sized by ivf_vec_size() and filled by ivf_quantize() from the inserted vector as an array of floats, but the column parser accepted `int8[N]` and `bit[N]` columns with `indexed by ivf(...)`. Every insert into one read past the end of its vector, and every distance was computed from those bytes. The parser now refuses them, as it does for rescore. --- sqlite-vec.c | 3 +++ tests/test-ivf.py | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/sqlite-vec.c b/sqlite-vec.c index 7af3b6a7..48e14a0a 100644 --- a/sqlite-vec.c +++ b/sqlite-vec.c @@ -3151,6 +3151,9 @@ int vec0_parse_vector_column(const char *source, int source_length, else if (sqlite3_strnicmp(token.start, "ivf", indexNameLen) == 0) { #if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE indexType = VEC0_INDEX_TYPE_IVF; + if (elementType != SQLITE_VEC_ELEMENT_TYPE_FLOAT32) { + return SQLITE_ERROR; + } memset(&ivfConfig, 0, sizeof(ivfConfig)); rc = vec0_parse_ivf_options(&scanner, &ivfConfig); if (rc != SQLITE_OK) { diff --git a/tests/test-ivf.py b/tests/test-ivf.py index 8b7f566b..00f25e99 100644 --- a/tests/test-ivf.py +++ b/tests/test-ivf.py @@ -100,6 +100,16 @@ def test_ivf_create_error_nprobe_gt_nlist(db): assert "error" in result +@pytest.mark.parametrize("column", ["v int8[8]", "v bit[8]"]) +def test_ivf_create_error_non_float32_column(db, column): + """IVF cells, centroids and quantizers hold float32 vectors.""" + result = exec( + db, + f"CREATE VIRTUAL TABLE t USING vec0({column} indexed by ivf(nlist=2))", + ) + assert "error" in result + + # ============================================================================ # Shadow table tests # ============================================================================