All notable changes to this community fork will be documented in this file.
- Cosine distance returned ±Inf, NULL or a wrong value for very small or very large nonzero float32 vectors (upstream #324)
- Squared magnitudes were accumulated in float32, so elements below roughly 3e-23 underflowed to a zero magnitude and elements above roughly 2e19 overflowed to Inf (giving a distance of 1.0 whatever the direction). In a cosine
vec0table the affected rows ranked ahead of (or behind) the true nearest neighbours vec_distance_cosine(), cosine KNN queries and MMR reranking now accumulate in double precision, as doesvec_normalize(), which returned NULL, a zero vector or a non-unit vector for the same inputs- Cosine distances of ordinary float32 vectors can differ from previous releases in the last few significant digits, as they are now correctly rounded
- Squared magnitudes were accumulated in float32, so elements below roughly 3e-23 underflowed to a zero magnitude and elements above roughly 2e19 overflowed to Inf (giving a distance of 1.0 whatever the direction). In a cosine
NPY_MAGICinitialiser no longer relies on dropping the string terminator (upstream #321) - fixes-Wunterminated-string-initializationon newer GCC and Clang, and a hard error when compiled as C++
xShadowNamenow reportsvector_chunksNNtables (upstream #320) - a partial improvement, not a complete fix- SQLite matches a newly created table to its virtual table by splitting the name at the last underscore, which the
vector_chunksNNsuffix defeats, so SQLite only learns that these are shadow tables in the cases below - SQLite 3.37 to 3.53: they are listed as
shadowbyPRAGMA table_list, and write-protected underSQLITE_DBCONFIG_DEFENSIVE, only once the database has been VACUUMed. A vec0 table created after that VACUUM is not covered until the next one - SQLite 3.54 (unreleased at the time of writing) is expected to recognise them without a VACUUM, once the vec0 table has been used in a connection, though still not in the connection that created the table
- Once they are recognised, scripts that write to or drop a
vector_chunksNNtable directly are refused in defensive mode, as they already are for the other backing tables - Tools should keep identifying vec0 backing tables by name instead of relying on
type = 'shadow'
- SQLite matches a newly created table to its virtual table by splitting the name at the last underscore, which the
- INSERT OR REPLACE support for vec0 tables (ports asg017/sqlite-vec@b95c05b, upstream #127)
- Upserts now work with both integer rowids and text primary keys, replacing vectors, metadata, and auxiliary values
- Empty-chunk reclamation on DELETE (ports asg017/sqlite-vec@cb147c8, upstream #268)
- Deleting the last row of a chunk now removes the chunk and its vector/metadata shadow rows immediately, returning disk space without a manual
optimize - Fixes a shadow-table quirk where the internal SQLite rowid could diverge from the user rowid after chunk delete/recreate cycles, breaking blob lookups
- Deleting the last row of a chunk now removes the chunk and its vector/metadata shadow rows immediately, returning disk space without a manual
- NEON and AVX2 SIMD Hamming distance (ports asg017/sqlite-vec@d684178)
- Bit-vector distance uses NEON
vcntat 128+ dimensions and AVX2 VPSHUFB popcount at 256+ dimensions - Hardened beyond upstream: AVX2 code requires
__AVX2__and the Makefile probes the host CPU (sysctl hw.optional.avx2_0), so pre-2013 Intel Macs without AVX2 still build and run correctly
- Bit-vector distance uses NEON
- libFuzzer targets and nightly fuzz CI (ports upstream fuzz infrastructure)
- 12 fuzz targets covering vector parsing, vec0 operations, scalar functions, metadata columns, shadow-table corruption, and delete completeness
- GitHub Actions workflow runs all targets under ASan+UBSan on push to main and nightly
Found by this fork's own first fuzzing runs:
- Use-after-free in vec0 constructor parsing - 21 token-scanner guards used
&&where||was intended, so truncated or garbled column definitions could read stale token state pointing at freed memory - Signed integer overflow in JSON number parsing - exponents like
1e440444444overflowed the parser's int accumulator; now clamped and rejected as out of range vec_npy_eachhang and buffer over-read - numpy headers missing mandatory keys left the element count uninitialized, iterating effectively unbounded rows (a 14-byte input hung for 29 minutes), and a"False"comparison could read past the end of the header buffer
Ports the applicable correctness fixes from upstream v0.1.8 through v0.1.10, most found by upstream's fuzzing suite:
- Wrong L2 distances for int8 vectors on ARM NEON builds (asg017/sqlite-vec@7de925b) - an int16 overflow in the NEON distance loop produced NaN or wrong results for element differences above 181; the default Apple Silicon build was affected
- DELETE on long text metadata (asg017/sqlite-vec@ee9bd2b) - metadata-clear errors were silently swallowed, and the long-text path returned a status the caller would have treated as an error
- NaN and Inf elements now rejected in float32 vector input (asg017/sqlite-vec@c4c23bd) - NaN elements break KNN ordering invariants
- Undefined behaviour fixes (asg017/sqlite-vec@cdbc347, @2f4c2e4, @1b53b94) - unaligned float/u64 loads from blobs, a one-past-end read in the numpy header tokenizer, an out-of-range float-to-int8 conversion in
vec_quantize_int8(now clamped, NaN-safe), and an ABI-incompatible cleanup function pointer
- SIMD flags are no longer added when cross-compiling for Android (
CCcontaining "android") - Removed dead typedef macros inherited from sqlite3.c
- MMR (Maximal Marginal Relevance) reranking for KNN queries (#6, rebased from asg017/sqlite-vec#267)
- New hidden
mmr_lambdacolumn on vec0 tables:SELECT rowid, distance FROM v WHERE embedding MATCH ? AND k = 10 AND mmr_lambda = 0.5 mmr_lambdabalances relevance against diversity (1.0 = pure relevance, 0.0 = maximum diversity)- Diversity term is normalized for consistent behaviour across all distance metrics
- Includes pytest + syrupy snapshot tests
- New hidden
- Memory leaks in vec0 operations and error paths (#7, ports asg017/sqlite-vec#258)
- Freed column names and shadow-table names for partition, auxiliary, and metadata columns on table close
- Freed SQL strings, statements, blob handles, and KNN buffers on error paths across insert, update, delete, and query code
- Freed column names copied into the vtab when a constructor parse fails midway
- Verified with macOS
leaks(1): 17 leaks (1,168 bytes) before, 0 after, on a workload exercising all affected paths
- NaN results from cosine distance on zero-magnitude vectors (#8)
vec_distance_cosine()now returns NULL when either input has zero magnitude (float, int8, and bit vectors)vec_normalize()now returns NULL for a zero vector instead of a vector of NaNs- vec0 tables with
distance_metric=cosinenow reject zero-magnitude vectors at INSERT and UPDATE time, and reject zero-magnitude query vectors in KNN queries, so NaN can never corrupt KNN orderings (behaviour change: such inserts previously succeeded silently)
- Wrong pointer passed to cleanup in
ensure_vector_matcherror path (#3) - Removed duplicate Rust package from repo root (#4) -
cargo addfrom this git repository now resolves the single crate inbindings/rust/
- Fixed errors in Ruby documentation examples
- Documented the exclusive database access requirement for
optimizeandVACUUM
- Lua binding with IEEE 754 compliant float serialization (#237)
bindings/lua/sqlite_vec.luaprovidesload(),serialize_f32(), andserialize_json()functions- Lua 5.1+ compatible with lsqlite3
- IEEE 754 single-precision float encoding with round-half-to-even (banker's rounding)
- Proper handling of special values: NaN, Inf, -Inf, -0.0, subnormals
- Example script and runner in
/examples/simple-lua/
-
Android 16KB page support (#254)
- Added
LDFLAGSsupport to Makefile for passing linker-specific flags - Enables Android 15+ compatibility via
-Wl,-z,max-page-size=16384 - Required for Play Store app submissions on devices with 16KB memory pages
- Added
-
Improved shared library build and installation (#149)
- Configurable install paths via
INSTALL_PREFIX,INSTALL_LIB_DIR,INSTALL_INCLUDE_DIR,INSTALL_BIN_DIR - Hidden internal symbols with
-fvisibility=hidden, exposing only public API EXT_CFLAGScaptures user-providedCFLAGSandCPPFLAGS
- Configurable install paths via
-
Optimize/VACUUM integration test and documentation
- Added test demonstrating optimize command with VACUUM for full space reclamation
- Linux linking error with libm (#252)
- Moved
-lmflag fromCFLAGStoLDLIBSat end of linker command - Fixes "undefined symbol: sqrtf" errors on some Linux distributions
- Linker now correctly resolves math library symbols
- Moved
- Fixed incomplete KNN and Matryoshka guides (#208, #209)
- Completed unfinished sentence describing manual KNN method trade-offs
- Added paper citation and Matryoshka naming explanation
-
GLOB operator for text metadata columns (#191)
- Standard SQL pattern matching with
*(any characters) and?(single character) wildcards - Case-sensitive matching (unlike LIKE)
- Fast path optimization for prefix-only patterns (e.g.,
'prefix*') - Full pattern matching with
sqlite3_strglob()for complex patterns
- Standard SQL pattern matching with
-
IS/IS NOT/IS NULL/IS NOT NULL operators for metadata columns (#190)
- Note: sqlite-vec metadata columns do not currently support NULL values. These operators provide syntactic compatibility within this limitation.
ISbehaves like=(all metadata values are non-NULL)IS NOTbehaves like!=(all metadata values are non-NULL)IS NULLalways returns false (no NULL values exist in metadata)IS NOT NULLalways returns true (all metadata values are non-NULL)- Works on all metadata types: INTEGER, FLOAT, TEXT, and BOOLEAN
- All compilation warnings eliminated
- Fixed critical logic bug:
metadataInIdxtype corrected fromsize_ttoint(prevented -1 wrapping to SIZE_MAX) - Fixed 5 sign comparison warnings with proper type casts
- Fixed 7 uninitialized variable warnings by adding initializers and default cases
- Clean compilation with
-Wall -Wextra(zero warnings)
- Fixed critical logic bug:
- LIKE operator for text metadata columns (#197)
- Standard SQL pattern matching with
%and_wildcards - Case-insensitive matching (SQLite default)
- Standard SQL pattern matching with
-
Locale-dependent JSON parsing (#241)
- Custom locale-independent float parser fixes JSON parsing in non-C locales
- No platform dependencies, thread-safe
-
musl libc compilation (Alpine Linux)
- Removed non-portable preprocessor macros from vendored sqlite3.c
-
Distance constraints for KNN queries (#166)
- Support GT, GE, LT, LE operators on the
distancecolumn in KNN queries - Enables cursor-based pagination:
WHERE embedding MATCH ? AND k = 10 AND distance > 0.5 - Enables range queries:
WHERE embedding MATCH ? AND k = 100 AND distance BETWEEN 0.5 AND 1.0 - Works with all vector types (float32, int8, bit)
- Compatible with partition keys, metadata, and auxiliary columns
- Comprehensive test coverage (15 tests)
- Fixed variable shadowing issues from original PR
- Documented precision handling and pagination caveats
- Support GT, GE, LT, LE operators on the
-
Optimize command for space reclamation (#210)
- New special command:
INSERT INTO vec_table(vec_table) VALUES('optimize') - Reclaims disk space after DELETE operations by compacting shadow tables
- Rebuilds vector chunks with only valid rows
- Updates rowid mappings to maintain data integrity
- New special command:
-
Cosine distance support for binary vectors (#212)
- Added
distance_cosine_bit()function for binary quantized vectors - Enables cosine similarity metric on bit-packed vectors
- Useful for memory-efficient semantic search
- Added
-
ALTER TABLE RENAME support (#203)
- Implement
vec0Rename()callback for virtual table module - Allows renaming vec0 tables with standard SQL:
ALTER TABLE old_name RENAME TO new_name - Properly renames all shadow tables and internal metadata
- Implement
-
Language bindings and package configurations for GitHub installation
- Go CGO bindings (
bindings/go/cgo/) withAuto()and serialization helpers - Python package configuration (
pyproject.toml,setup.py) forpip install git+... - Node.js package configuration (
package.json) fornpm install vlasky/sqlite-vec - Ruby gem configuration (
sqlite-vec.gemspec) forgem installfrom git - Rust crate configuration (
Cargo.toml,src/lib.rs) forcargo add --git - All packages support installing from main branch or specific version tags
- Documentation in README with installation table for all languages
- Go CGO bindings (
-
Python loadable extension support documentation
- Added note about Python requiring
--enable-loadable-sqlite-extensionsbuild flag - Recommended using
uvfor virtual environments (uses system Python with extension support) - Documented workarounds for pyenv and custom Python builds
- Added note about Python requiring
-
Memory leak on DELETE operations (#243)
- Added
vec0Update_Delete_ClearRowid()to clear deleted rowids - Added
vec0Update_Delete_ClearVectors()to clear deleted vector data - Prevents memory accumulation from deleted rows
- Vectors and rowids now properly zeroed out on deletion
- Added
-
CI/CD build infrastructure (#228)
- Upgraded deprecated ubuntu-20.04 runners to ubuntu-latest
- Added native ARM64 builds using ubuntu-24.04-arm
- Removed cross-compilation dependencies (gcc-aarch64-linux-gnu)
- Fixed macOS link flags for undefined symbols
This fork is based on asg017/sqlite-vec v0.1.7-alpha.2.
All features and functionality from the original repository are preserved. See the original documentation for complete usage information.
This is a community-maintained fork created to merge pending upstream PRs and provide continued support while the original author is unavailable. Once development resumes on the original repository, users are encouraged to switch back.
All original implementation credit goes to Alex Garcia.