Bug Summary

File:root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c
Warning:line 3001, column 24
The left operand of '!=' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name sqlite-vec.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/sqlite3/ext -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/sqlite3/ext -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D SQLITE_VEC_ENABLE_DISKANN=0 -I /root/firefox-clang/third_party/sqlite3/ext -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/sqlite3/ext -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/15/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=tautological-type-limit-compare -Wno-range-loop-analysis -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-unknown-warning-option -Wno-character-conversion -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-07-16-093543-1626485-1 -x c /root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c
1#include "sqlite-vec.h"
2
3#include <assert.h>
4#include <errno(*__errno_location ()).h>
5#include <float.h>
6#include <inttypes.h>
7#include <limits.h>
8#include <math.h>
9#include <stdbool.h>
10#include <stdint.h>
11#include <stdlib.h>
12#include <string.h>
13
14#ifdef SQLITE_VEC_DEBUG
15#include <stdio.h>
16#endif
17
18#ifndef SQLITE_CORE
19#include "sqlite3ext.h"
20SQLITE_EXTENSION_INIT3extern const sqlite3_api_routines *sqlite3_api;
21#else
22#include "sqlite3.h"
23#endif
24
25#ifndef SQLITE_VEC_ENABLE_DISKANN0
26#define SQLITE_VEC_ENABLE_DISKANN0 1
27#endif
28
29typedef int8_t i8;
30typedef uint8_t u8;
31typedef int16_t i16;
32typedef int32_t i32;
33typedef sqlite3_int64 i64;
34typedef uint32_t u32;
35typedef uint64_t u64;
36typedef float f32;
37typedef size_t usize;
38
39#ifndef UNUSED_PARAMETER
40#define UNUSED_PARAMETER(X)(void)(X) (void)(X)
41#endif
42
43// sqlite3_vtab_in() was added in SQLite version 3.38 (2022-02-22)
44// https://www.sqlite.org/changes.html#version_3_38_0
45#if SQLITE_VERSION_NUMBER3053002 >= 3038000
46#define COMPILER_SUPPORTS_VTAB_IN1 1
47#endif
48
49#ifndef SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
50#define SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0 0
51#endif
52
53#ifndef SQLITE_SUBTYPE0x000100000
54#define SQLITE_SUBTYPE0x000100000 0x000100000
55#endif
56
57#ifndef SQLITE_RESULT_SUBTYPE0x001000000
58#define SQLITE_RESULT_SUBTYPE0x001000000 0x001000000
59#endif
60
61#ifndef SQLITE_INDEX_CONSTRAINT_LIMIT73
62#define SQLITE_INDEX_CONSTRAINT_LIMIT73 73
63#endif
64
65#ifndef SQLITE_INDEX_CONSTRAINT_OFFSET74
66#define SQLITE_INDEX_CONSTRAINT_OFFSET74 74
67#endif
68
69#define countof(x)(sizeof(x) / sizeof((x)[0])) (sizeof(x) / sizeof((x)[0]))
70#define min(a, b)(((a) <= (b)) ? (a) : (b)) (((a) <= (b)) ? (a) : (b))
71
72#ifndef SQLITE_VEC_ENABLE_RESCORE1
73#define SQLITE_VEC_ENABLE_RESCORE1 1
74#endif
75
76enum VectorElementType {
77 // clang-format off
78 SQLITE_VEC_ELEMENT_TYPE_FLOAT32 = 223 + 0,
79 SQLITE_VEC_ELEMENT_TYPE_BIT = 223 + 1,
80 SQLITE_VEC_ELEMENT_TYPE_INT8 = 223 + 2,
81 // clang-format on
82};
83
84#ifdef SQLITE_VEC_ENABLE_AVX
85#include <immintrin.h>
86#define PORTABLE_ALIGN32 __attribute__((aligned(32)))
87#define PORTABLE_ALIGN64 __attribute__((aligned(64)))
88
89static f32 l2_sqr_float_avx(const void *pVect1v, const void *pVect2v,
90 const void *qty_ptr) {
91 f32 *pVect1 = (f32 *)pVect1v;
92 f32 *pVect2 = (f32 *)pVect2v;
93 size_t qty = *((size_t *)qty_ptr);
94 f32 PORTABLE_ALIGN32 TmpRes[8];
95 size_t qty16 = qty >> 4;
96
97 const f32 *pEnd1 = pVect1 + (qty16 << 4);
98
99 __m256 diff, v1, v2;
100 __m256 sum = _mm256_set1_ps(0);
101
102 while (pVect1 < pEnd1) {
103 v1 = _mm256_loadu_ps(pVect1);
104 pVect1 += 8;
105 v2 = _mm256_loadu_ps(pVect2);
106 pVect2 += 8;
107 diff = _mm256_sub_ps(v1, v2);
108 sum = _mm256_add_ps(sum, _mm256_mul_ps(diff, diff));
109
110 v1 = _mm256_loadu_ps(pVect1);
111 pVect1 += 8;
112 v2 = _mm256_loadu_ps(pVect2);
113 pVect2 += 8;
114 diff = _mm256_sub_ps(v1, v2);
115 sum = _mm256_add_ps(sum, _mm256_mul_ps(diff, diff));
116 }
117
118 _mm256_store_ps(TmpRes, sum);
119 return sqrt(TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3] + TmpRes[4] +
120 TmpRes[5] + TmpRes[6] + TmpRes[7]);
121}
122#endif
123
124#ifdef SQLITE_VEC_ENABLE_NEON
125#include <arm_neon.h>
126
127#define PORTABLE_ALIGN32 __attribute__((aligned(32)))
128
129// thx https://github.com/nmslib/hnswlib/pull/299/files
130static f32 l2_sqr_float_neon(const void *pVect1v, const void *pVect2v,
131 const void *qty_ptr) {
132 f32 *pVect1 = (f32 *)pVect1v;
133 f32 *pVect2 = (f32 *)pVect2v;
134 size_t qty = *((size_t *)qty_ptr);
135 size_t qty16 = qty >> 4;
136
137 const f32 *pEnd1 = pVect1 + (qty16 << 4);
138
139 float32x4_t diff, v1, v2;
140 float32x4_t sum0 = vdupq_n_f32(0);
141 float32x4_t sum1 = vdupq_n_f32(0);
142 float32x4_t sum2 = vdupq_n_f32(0);
143 float32x4_t sum3 = vdupq_n_f32(0);
144
145 while (pVect1 < pEnd1) {
146 v1 = vld1q_f32(pVect1);
147 pVect1 += 4;
148 v2 = vld1q_f32(pVect2);
149 pVect2 += 4;
150 diff = vsubq_f32(v1, v2);
151 sum0 = vfmaq_f32(sum0, diff, diff);
152
153 v1 = vld1q_f32(pVect1);
154 pVect1 += 4;
155 v2 = vld1q_f32(pVect2);
156 pVect2 += 4;
157 diff = vsubq_f32(v1, v2);
158 sum1 = vfmaq_f32(sum1, diff, diff);
159
160 v1 = vld1q_f32(pVect1);
161 pVect1 += 4;
162 v2 = vld1q_f32(pVect2);
163 pVect2 += 4;
164 diff = vsubq_f32(v1, v2);
165 sum2 = vfmaq_f32(sum2, diff, diff);
166
167 v1 = vld1q_f32(pVect1);
168 pVect1 += 4;
169 v2 = vld1q_f32(pVect2);
170 pVect2 += 4;
171 diff = vsubq_f32(v1, v2);
172 sum3 = vfmaq_f32(sum3, diff, diff);
173 }
174
175 f32 sum_scalar =
176 vaddvq_f32(vaddq_f32(vaddq_f32(sum0, sum1), vaddq_f32(sum2, sum3)));
177 const f32 *pEnd2 = pVect1 + (qty - (qty16 << 4));
178 while (pVect1 < pEnd2) {
179 f32 diff = *pVect1 - *pVect2;
180 sum_scalar += diff * diff;
181 pVect1++;
182 pVect2++;
183 }
184
185 return sqrt(sum_scalar);
186}
187
188static f32 cosine_float_neon(const void *pVect1v, const void *pVect2v,
189 const void *qty_ptr) {
190 f32 *pVect1 = (f32 *)pVect1v;
191 f32 *pVect2 = (f32 *)pVect2v;
192 size_t qty = *((size_t *)qty_ptr);
193 size_t qty16 = qty >> 4;
194 const f32 *pEnd1 = pVect1 + (qty16 << 4);
195
196 float32x4_t dot0 = vdupq_n_f32(0), dot1 = vdupq_n_f32(0);
197 float32x4_t dot2 = vdupq_n_f32(0), dot3 = vdupq_n_f32(0);
198 float32x4_t amag0 = vdupq_n_f32(0), amag1 = vdupq_n_f32(0);
199 float32x4_t amag2 = vdupq_n_f32(0), amag3 = vdupq_n_f32(0);
200 float32x4_t bmag0 = vdupq_n_f32(0), bmag1 = vdupq_n_f32(0);
201 float32x4_t bmag2 = vdupq_n_f32(0), bmag3 = vdupq_n_f32(0);
202
203 while (pVect1 < pEnd1) {
204 float32x4_t v1, v2;
205 v1 = vld1q_f32(pVect1); pVect1 += 4;
206 v2 = vld1q_f32(pVect2); pVect2 += 4;
207 dot0 = vfmaq_f32(dot0, v1, v2);
208 amag0 = vfmaq_f32(amag0, v1, v1);
209 bmag0 = vfmaq_f32(bmag0, v2, v2);
210
211 v1 = vld1q_f32(pVect1); pVect1 += 4;
212 v2 = vld1q_f32(pVect2); pVect2 += 4;
213 dot1 = vfmaq_f32(dot1, v1, v2);
214 amag1 = vfmaq_f32(amag1, v1, v1);
215 bmag1 = vfmaq_f32(bmag1, v2, v2);
216
217 v1 = vld1q_f32(pVect1); pVect1 += 4;
218 v2 = vld1q_f32(pVect2); pVect2 += 4;
219 dot2 = vfmaq_f32(dot2, v1, v2);
220 amag2 = vfmaq_f32(amag2, v1, v1);
221 bmag2 = vfmaq_f32(bmag2, v2, v2);
222
223 v1 = vld1q_f32(pVect1); pVect1 += 4;
224 v2 = vld1q_f32(pVect2); pVect2 += 4;
225 dot3 = vfmaq_f32(dot3, v1, v2);
226 amag3 = vfmaq_f32(amag3, v1, v1);
227 bmag3 = vfmaq_f32(bmag3, v2, v2);
228 }
229
230 f32 dot_s = vaddvq_f32(vaddq_f32(vaddq_f32(dot0, dot1), vaddq_f32(dot2, dot3)));
231 f32 amag_s = vaddvq_f32(vaddq_f32(vaddq_f32(amag0, amag1), vaddq_f32(amag2, amag3)));
232 f32 bmag_s = vaddvq_f32(vaddq_f32(vaddq_f32(bmag0, bmag1), vaddq_f32(bmag2, bmag3)));
233
234 const f32 *pEnd2 = pVect1 + (qty - (qty16 << 4));
235 while (pVect1 < pEnd2) {
236 dot_s += *pVect1 * *pVect2;
237 amag_s += *pVect1 * *pVect1;
238 bmag_s += *pVect2 * *pVect2;
239 pVect1++; pVect2++;
240 }
241
242 return 1.0f - (dot_s / (sqrtf(amag_s) * sqrtf(bmag_s)));
243}
244
245static f32 l2_sqr_int8_neon(const void *pVect1v, const void *pVect2v,
246 const void *qty_ptr) {
247 i8 *pVect1 = (i8 *)pVect1v;
248 i8 *pVect2 = (i8 *)pVect2v;
249 size_t qty = *((size_t *)qty_ptr);
250
251 const i8 *pEnd1 = pVect1 + qty;
252 i32 sum_scalar = 0;
253
254 while (pVect1 < pEnd1 - 7) {
255 // loading 8 at a time
256 int8x8_t v1 = vld1_s8(pVect1);
257 int8x8_t v2 = vld1_s8(pVect2);
258 pVect1 += 8;
259 pVect2 += 8;
260
261 // widen i8 to i16 for subtraction
262 int16x8_t v1_wide = vmovl_s8(v1);
263 int16x8_t v2_wide = vmovl_s8(v2);
264 int16x8_t diff = vsubq_s16(v1_wide, v2_wide);
265
266 // widening multiply: i16*i16 -> i32 to avoid i16 overflow
267 // (diff can be up to 255, so diff*diff can be up to 65025 > INT16_MAX)
268 int32x4_t sq_lo = vmull_s16(vget_low_s16(diff), vget_low_s16(diff));
269 int32x4_t sq_hi = vmull_s16(vget_high_s16(diff), vget_high_s16(diff));
270 int32x4_t sum = vaddq_s32(sq_lo, sq_hi);
271
272 sum_scalar += vgetq_lane_s32(sum, 0) + vgetq_lane_s32(sum, 1) +
273 vgetq_lane_s32(sum, 2) + vgetq_lane_s32(sum, 3);
274 }
275
276 // handle leftovers
277 while (pVect1 < pEnd1) {
278 i16 diff = (i16)*pVect1 - (i16)*pVect2;
279 sum_scalar += diff * diff;
280 pVect1++;
281 pVect2++;
282 }
283
284 return sqrtf(sum_scalar);
285}
286
287static i32 l1_int8_neon(const void *pVect1v, const void *pVect2v,
288 const void *qty_ptr) {
289 i8 *pVect1 = (i8 *)pVect1v;
290 i8 *pVect2 = (i8 *)pVect2v;
291 size_t qty = *((size_t *)qty_ptr);
292
293 const int8_t *pEnd1 = pVect1 + qty;
294
295 int32x4_t acc1 = vdupq_n_s32(0);
296 int32x4_t acc2 = vdupq_n_s32(0);
297 int32x4_t acc3 = vdupq_n_s32(0);
298 int32x4_t acc4 = vdupq_n_s32(0);
299
300 while (pVect1 < pEnd1 - 63) {
301 int8x16_t v1 = vld1q_s8(pVect1);
302 int8x16_t v2 = vld1q_s8(pVect2);
303 int8x16_t diff1 = vabdq_s8(v1, v2);
304 acc1 = vaddq_s32(acc1, vpaddlq_u16(vpaddlq_u8(diff1)));
305
306 v1 = vld1q_s8(pVect1 + 16);
307 v2 = vld1q_s8(pVect2 + 16);
308 int8x16_t diff2 = vabdq_s8(v1, v2);
309 acc2 = vaddq_s32(acc2, vpaddlq_u16(vpaddlq_u8(diff2)));
310
311 v1 = vld1q_s8(pVect1 + 32);
312 v2 = vld1q_s8(pVect2 + 32);
313 int8x16_t diff3 = vabdq_s8(v1, v2);
314 acc3 = vaddq_s32(acc3, vpaddlq_u16(vpaddlq_u8(diff3)));
315
316 v1 = vld1q_s8(pVect1 + 48);
317 v2 = vld1q_s8(pVect2 + 48);
318 int8x16_t diff4 = vabdq_s8(v1, v2);
319 acc4 = vaddq_s32(acc4, vpaddlq_u16(vpaddlq_u8(diff4)));
320
321 pVect1 += 64;
322 pVect2 += 64;
323 }
324
325 while (pVect1 < pEnd1 - 15) {
326 int8x16_t v1 = vld1q_s8(pVect1);
327 int8x16_t v2 = vld1q_s8(pVect2);
328 int8x16_t diff = vabdq_s8(v1, v2);
329 acc1 = vaddq_s32(acc1, vpaddlq_u16(vpaddlq_u8(diff)));
330 pVect1 += 16;
331 pVect2 += 16;
332 }
333
334 int32x4_t acc = vaddq_s32(vaddq_s32(acc1, acc2), vaddq_s32(acc3, acc4));
335
336 int32_t sum = 0;
337 while (pVect1 < pEnd1) {
338 int32_t diff = abs((int32_t)*pVect1 - (int32_t)*pVect2);
339 sum += diff;
340 pVect1++;
341 pVect2++;
342 }
343
344 return vaddvq_s32(acc) + sum;
345}
346
347static double l1_f32_neon(const void *pVect1v, const void *pVect2v,
348 const void *qty_ptr) {
349 f32 *pVect1 = (f32 *)pVect1v;
350 f32 *pVect2 = (f32 *)pVect2v;
351 size_t qty = *((size_t *)qty_ptr);
352
353 const f32 *pEnd1 = pVect1 + qty;
354 float64x2_t acc = vdupq_n_f64(0);
355
356 while (pVect1 < pEnd1 - 3) {
357 float32x4_t v1 = vld1q_f32(pVect1);
358 float32x4_t v2 = vld1q_f32(pVect2);
359 pVect1 += 4;
360 pVect2 += 4;
361
362 // f32x4 -> f64x2 pad for overflow
363 float64x2_t low_diff = vabdq_f64(vcvt_f64_f32(vget_low_f32(v1)),
364 vcvt_f64_f32(vget_low_f32(v2)));
365 float64x2_t high_diff =
366 vabdq_f64(vcvt_high_f64_f32(v1), vcvt_high_f64_f32(v2));
367
368 acc = vaddq_f64(acc, vaddq_f64(low_diff, high_diff));
369 }
370
371 double sum = 0;
372 while (pVect1 < pEnd1) {
373 sum += fabs((double)*pVect1 - (double)*pVect2);
374 pVect1++;
375 pVect2++;
376 }
377
378 return vaddvq_f64(acc) + sum;
379}
380#endif
381
382static f32 l2_sqr_float(const void *pVect1v, const void *pVect2v,
383 const void *qty_ptr) {
384 f32 *pVect1 = (f32 *)pVect1v;
385 f32 *pVect2 = (f32 *)pVect2v;
386 size_t qty = *((size_t *)qty_ptr);
387
388 f32 res = 0;
389 for (size_t i = 0; i < qty; i++) {
390 f32 t = *pVect1 - *pVect2;
391 pVect1++;
392 pVect2++;
393 res += t * t;
394 }
395 return sqrt(res);
396}
397
398static f32 l2_sqr_int8(const void *pA, const void *pB, const void *pD) {
399 i8 *a = (i8 *)pA;
400 i8 *b = (i8 *)pB;
401 size_t d = *((size_t *)pD);
402
403 f32 res = 0;
404 for (size_t i = 0; i < d; i++) {
405 f32 t = *a - *b;
406 a++;
407 b++;
408 res += t * t;
409 }
410 return sqrt(res);
411}
412
413static f32 distance_l2_sqr_float(const void *a, const void *b, const void *d) {
414#ifdef SQLITE_VEC_ENABLE_NEON
415 if ((*(const size_t *)d) > 16) {
416 return l2_sqr_float_neon(a, b, d);
417 }
418#endif
419#ifdef SQLITE_VEC_ENABLE_AVX
420 if (((*(const size_t *)d) % 16 == 0)) {
421 return l2_sqr_float_avx(a, b, d);
422 }
423#endif
424 return l2_sqr_float(a, b, d);
425}
426
427static f32 distance_l2_sqr_int8(const void *a, const void *b, const void *d) {
428#ifdef SQLITE_VEC_ENABLE_NEON
429 if ((*(const size_t *)d) > 7) {
430 return l2_sqr_int8_neon(a, b, d);
431 }
432#endif
433 return l2_sqr_int8(a, b, d);
434}
435
436static i32 l1_int8(const void *pA, const void *pB, const void *pD) {
437 i8 *a = (i8 *)pA;
438 i8 *b = (i8 *)pB;
439 size_t d = *((size_t *)pD);
440
441 i32 res = 0;
442 for (size_t i = 0; i < d; i++) {
443 res += abs(*a - *b);
444 a++;
445 b++;
446 }
447
448 return res;
449}
450
451static i32 distance_l1_int8(const void *a, const void *b, const void *d) {
452#ifdef SQLITE_VEC_ENABLE_NEON
453 if ((*(const size_t *)d) > 15) {
454 return l1_int8_neon(a, b, d);
455 }
456#endif
457 return l1_int8(a, b, d);
458}
459
460static double l1_f32(const void *pA, const void *pB, const void *pD) {
461 f32 *a = (f32 *)pA;
462 f32 *b = (f32 *)pB;
463 size_t d = *((size_t *)pD);
464
465 double res = 0;
466 for (size_t i = 0; i < d; i++) {
467 res += fabs((double)*a - (double)*b);
468 a++;
469 b++;
470 }
471
472 return res;
473}
474
475static double distance_l1_f32(const void *a, const void *b, const void *d) {
476#ifdef SQLITE_VEC_ENABLE_NEON
477 if ((*(const size_t *)d) > 3) {
478 return l1_f32_neon(a, b, d);
479 }
480#endif
481 return l1_f32(a, b, d);
482}
483
484static f32 distance_cosine_float(const void *pVect1v, const void *pVect2v,
485 const void *qty_ptr) {
486#ifdef SQLITE_VEC_ENABLE_NEON
487 if ((*(const size_t *)qty_ptr) > 16) {
488 return cosine_float_neon(pVect1v, pVect2v, qty_ptr);
489 }
490#endif
491 f32 *pVect1 = (f32 *)pVect1v;
492 f32 *pVect2 = (f32 *)pVect2v;
493 size_t qty = *((size_t *)qty_ptr);
494
495 f32 dot = 0;
496 f32 aMag = 0;
497 f32 bMag = 0;
498 for (size_t i = 0; i < qty; i++) {
499 dot += *pVect1 * *pVect2;
500 aMag += *pVect1 * *pVect1;
501 bMag += *pVect2 * *pVect2;
502 pVect1++;
503 pVect2++;
504 }
505 return 1 - (dot / (sqrt(aMag) * sqrt(bMag)));
506}
507static f32 cosine_int8(const void *pA, const void *pB, const void *pD) {
508 i8 *a = (i8 *)pA;
509 i8 *b = (i8 *)pB;
510 size_t d = *((size_t *)pD);
511
512 f32 dot = 0;
513 f32 aMag = 0;
514 f32 bMag = 0;
515 for (size_t i = 0; i < d; i++) {
516 dot += *a * *b;
517 aMag += *a * *a;
518 bMag += *b * *b;
519 a++;
520 b++;
521 }
522 return 1 - (dot / (sqrt(aMag) * sqrt(bMag)));
523}
524
525#ifdef SQLITE_VEC_ENABLE_NEON
526static f32 cosine_int8_neon(const void *pA, const void *pB, const void *pD) {
527 const i8 *a = (const i8 *)pA;
528 const i8 *b = (const i8 *)pB;
529 size_t d = *((const size_t *)pD);
530 const i8 *aEnd = a + d;
531
532 int32x4_t dot_acc1 = vdupq_n_s32(0);
533 int32x4_t dot_acc2 = vdupq_n_s32(0);
534 int32x4_t aMag_acc1 = vdupq_n_s32(0);
535 int32x4_t aMag_acc2 = vdupq_n_s32(0);
536 int32x4_t bMag_acc1 = vdupq_n_s32(0);
537 int32x4_t bMag_acc2 = vdupq_n_s32(0);
538
539 while (a < aEnd - 31) {
540 int8x16_t va1 = vld1q_s8(a);
541 int8x16_t vb1 = vld1q_s8(b);
542 int16x8_t a1_lo = vmovl_s8(vget_low_s8(va1));
543 int16x8_t a1_hi = vmovl_s8(vget_high_s8(va1));
544 int16x8_t b1_lo = vmovl_s8(vget_low_s8(vb1));
545 int16x8_t b1_hi = vmovl_s8(vget_high_s8(vb1));
546
547 dot_acc1 = vmlal_s16(dot_acc1, vget_low_s16(a1_lo), vget_low_s16(b1_lo));
548 dot_acc1 = vmlal_s16(dot_acc1, vget_high_s16(a1_lo), vget_high_s16(b1_lo));
549 dot_acc2 = vmlal_s16(dot_acc2, vget_low_s16(a1_hi), vget_low_s16(b1_hi));
550 dot_acc2 = vmlal_s16(dot_acc2, vget_high_s16(a1_hi), vget_high_s16(b1_hi));
551
552 aMag_acc1 = vmlal_s16(aMag_acc1, vget_low_s16(a1_lo), vget_low_s16(a1_lo));
553 aMag_acc1 = vmlal_s16(aMag_acc1, vget_high_s16(a1_lo), vget_high_s16(a1_lo));
554 aMag_acc2 = vmlal_s16(aMag_acc2, vget_low_s16(a1_hi), vget_low_s16(a1_hi));
555 aMag_acc2 = vmlal_s16(aMag_acc2, vget_high_s16(a1_hi), vget_high_s16(a1_hi));
556
557 bMag_acc1 = vmlal_s16(bMag_acc1, vget_low_s16(b1_lo), vget_low_s16(b1_lo));
558 bMag_acc1 = vmlal_s16(bMag_acc1, vget_high_s16(b1_lo), vget_high_s16(b1_lo));
559 bMag_acc2 = vmlal_s16(bMag_acc2, vget_low_s16(b1_hi), vget_low_s16(b1_hi));
560 bMag_acc2 = vmlal_s16(bMag_acc2, vget_high_s16(b1_hi), vget_high_s16(b1_hi));
561
562 int8x16_t va2 = vld1q_s8(a + 16);
563 int8x16_t vb2 = vld1q_s8(b + 16);
564 int16x8_t a2_lo = vmovl_s8(vget_low_s8(va2));
565 int16x8_t a2_hi = vmovl_s8(vget_high_s8(va2));
566 int16x8_t b2_lo = vmovl_s8(vget_low_s8(vb2));
567 int16x8_t b2_hi = vmovl_s8(vget_high_s8(vb2));
568
569 dot_acc1 = vmlal_s16(dot_acc1, vget_low_s16(a2_lo), vget_low_s16(b2_lo));
570 dot_acc1 = vmlal_s16(dot_acc1, vget_high_s16(a2_lo), vget_high_s16(b2_lo));
571 dot_acc2 = vmlal_s16(dot_acc2, vget_low_s16(a2_hi), vget_low_s16(b2_hi));
572 dot_acc2 = vmlal_s16(dot_acc2, vget_high_s16(a2_hi), vget_high_s16(b2_hi));
573
574 aMag_acc1 = vmlal_s16(aMag_acc1, vget_low_s16(a2_lo), vget_low_s16(a2_lo));
575 aMag_acc1 = vmlal_s16(aMag_acc1, vget_high_s16(a2_lo), vget_high_s16(a2_lo));
576 aMag_acc2 = vmlal_s16(aMag_acc2, vget_low_s16(a2_hi), vget_low_s16(a2_hi));
577 aMag_acc2 = vmlal_s16(aMag_acc2, vget_high_s16(a2_hi), vget_high_s16(a2_hi));
578
579 bMag_acc1 = vmlal_s16(bMag_acc1, vget_low_s16(b2_lo), vget_low_s16(b2_lo));
580 bMag_acc1 = vmlal_s16(bMag_acc1, vget_high_s16(b2_lo), vget_high_s16(b2_lo));
581 bMag_acc2 = vmlal_s16(bMag_acc2, vget_low_s16(b2_hi), vget_low_s16(b2_hi));
582 bMag_acc2 = vmlal_s16(bMag_acc2, vget_high_s16(b2_hi), vget_high_s16(b2_hi));
583
584 a += 32;
585 b += 32;
586 }
587
588 while (a < aEnd - 15) {
589 int8x16_t va = vld1q_s8(a);
590 int8x16_t vb = vld1q_s8(b);
591 int16x8_t a_lo = vmovl_s8(vget_low_s8(va));
592 int16x8_t a_hi = vmovl_s8(vget_high_s8(va));
593 int16x8_t b_lo = vmovl_s8(vget_low_s8(vb));
594 int16x8_t b_hi = vmovl_s8(vget_high_s8(vb));
595
596 dot_acc1 = vmlal_s16(dot_acc1, vget_low_s16(a_lo), vget_low_s16(b_lo));
597 dot_acc1 = vmlal_s16(dot_acc1, vget_high_s16(a_lo), vget_high_s16(b_lo));
598 dot_acc1 = vmlal_s16(dot_acc1, vget_low_s16(a_hi), vget_low_s16(b_hi));
599 dot_acc1 = vmlal_s16(dot_acc1, vget_high_s16(a_hi), vget_high_s16(b_hi));
600
601 aMag_acc1 = vmlal_s16(aMag_acc1, vget_low_s16(a_lo), vget_low_s16(a_lo));
602 aMag_acc1 = vmlal_s16(aMag_acc1, vget_high_s16(a_lo), vget_high_s16(a_lo));
603 aMag_acc1 = vmlal_s16(aMag_acc1, vget_low_s16(a_hi), vget_low_s16(a_hi));
604 aMag_acc1 = vmlal_s16(aMag_acc1, vget_high_s16(a_hi), vget_high_s16(a_hi));
605
606 bMag_acc1 = vmlal_s16(bMag_acc1, vget_low_s16(b_lo), vget_low_s16(b_lo));
607 bMag_acc1 = vmlal_s16(bMag_acc1, vget_high_s16(b_lo), vget_high_s16(b_lo));
608 bMag_acc1 = vmlal_s16(bMag_acc1, vget_low_s16(b_hi), vget_low_s16(b_hi));
609 bMag_acc1 = vmlal_s16(bMag_acc1, vget_high_s16(b_hi), vget_high_s16(b_hi));
610
611 a += 16;
612 b += 16;
613 }
614
615 int32x4_t dot_sum = vaddq_s32(dot_acc1, dot_acc2);
616 int32x4_t aMag_sum = vaddq_s32(aMag_acc1, aMag_acc2);
617 int32x4_t bMag_sum = vaddq_s32(bMag_acc1, bMag_acc2);
618
619 i32 dot = vaddvq_s32(dot_sum);
620 i32 aMag = vaddvq_s32(aMag_sum);
621 i32 bMag = vaddvq_s32(bMag_sum);
622
623 while (a < aEnd) {
624 dot += (i32)*a * (i32)*b;
625 aMag += (i32)*a * (i32)*a;
626 bMag += (i32)*b * (i32)*b;
627 a++;
628 b++;
629 }
630
631 return 1.0f - ((f32)dot / (sqrtf((f32)aMag) * sqrtf((f32)bMag)));
632}
633#endif
634
635static f32 distance_cosine_int8(const void *a, const void *b, const void *d) {
636#ifdef SQLITE_VEC_ENABLE_NEON
637 if ((*(const size_t *)d) > 15) {
638 return cosine_int8_neon(a, b, d);
639 }
640#endif
641 return cosine_int8(a, b, d);
642}
643
644// https://github.com/facebookresearch/faiss/blob/77e2e79cd0a680adc343b9840dd865da724c579e/faiss/utils/hamming_distance/common.h#L34
645static u8 hamdist_table[256] = {
646 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4,
647 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
648 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4,
649 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
650 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
651 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
652 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5,
653 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
654 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
655 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
656 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
657
658#ifdef SQLITE_VEC_ENABLE_NEON
659static f32 distance_hamming_neon(const u8 *a, const u8 *b, size_t n_bytes) {
660 const u8 *pEnd = a + n_bytes;
661
662 uint32x4_t acc1 = vdupq_n_u32(0);
663 uint32x4_t acc2 = vdupq_n_u32(0);
664 uint32x4_t acc3 = vdupq_n_u32(0);
665 uint32x4_t acc4 = vdupq_n_u32(0);
666
667 while (a <= pEnd - 64) {
668 uint8x16_t v1 = vld1q_u8(a);
669 uint8x16_t v2 = vld1q_u8(b);
670 acc1 = vaddq_u32(acc1, vpaddlq_u16(vpaddlq_u8(vcntq_u8(veorq_u8(v1, v2)))));
671
672 v1 = vld1q_u8(a + 16);
673 v2 = vld1q_u8(b + 16);
674 acc2 = vaddq_u32(acc2, vpaddlq_u16(vpaddlq_u8(vcntq_u8(veorq_u8(v1, v2)))));
675
676 v1 = vld1q_u8(a + 32);
677 v2 = vld1q_u8(b + 32);
678 acc3 = vaddq_u32(acc3, vpaddlq_u16(vpaddlq_u8(vcntq_u8(veorq_u8(v1, v2)))));
679
680 v1 = vld1q_u8(a + 48);
681 v2 = vld1q_u8(b + 48);
682 acc4 = vaddq_u32(acc4, vpaddlq_u16(vpaddlq_u8(vcntq_u8(veorq_u8(v1, v2)))));
683
684 a += 64;
685 b += 64;
686 }
687
688 while (a <= pEnd - 16) {
689 uint8x16_t v1 = vld1q_u8(a);
690 uint8x16_t v2 = vld1q_u8(b);
691 acc1 = vaddq_u32(acc1, vpaddlq_u16(vpaddlq_u8(vcntq_u8(veorq_u8(v1, v2)))));
692 a += 16;
693 b += 16;
694 }
695
696 acc1 = vaddq_u32(acc1, acc2);
697 acc3 = vaddq_u32(acc3, acc4);
698 acc1 = vaddq_u32(acc1, acc3);
699 u32 sum = vaddvq_u32(acc1);
700
701 while (a < pEnd) {
702 sum += hamdist_table[*a ^ *b];
703 a++;
704 b++;
705 }
706
707 return (f32)sum;
708}
709#endif
710
711#ifdef SQLITE_VEC_ENABLE_AVX
712/**
713 * AVX2 Hamming distance using VPSHUFB-based popcount.
714 * Processes 32 bytes (256 bits) per iteration.
715 */
716static f32 distance_hamming_avx2(const u8 *a, const u8 *b, size_t n_bytes) {
717 const u8 *pEnd = a + n_bytes;
718
719 // VPSHUFB lookup table: popcount of low nibble
720 const __m256i lookup = _mm256_setr_epi8(
721 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
722 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4);
723 const __m256i low_mask = _mm256_set1_epi8(0x0f);
724
725 __m256i acc = _mm256_setzero_si256();
726
727 while (a <= pEnd - 32) {
728 __m256i va = _mm256_loadu_si256((const __m256i *)a);
729 __m256i vb = _mm256_loadu_si256((const __m256i *)b);
730 __m256i xored = _mm256_xor_si256(va, vb);
731
732 // VPSHUFB popcount: split into nibbles, lookup each
733 __m256i lo = _mm256_and_si256(xored, low_mask);
734 __m256i hi = _mm256_and_si256(_mm256_srli_epi16(xored, 4), low_mask);
735 __m256i popcnt = _mm256_add_epi8(_mm256_shuffle_epi8(lookup, lo),
736 _mm256_shuffle_epi8(lookup, hi));
737
738 // Horizontal sum: u8 -> u64 via sad against zero
739 acc = _mm256_add_epi64(acc, _mm256_sad_epu8(popcnt, _mm256_setzero_si256()));
740 a += 32;
741 b += 32;
742 }
743
744 // Horizontal sum of 4 x u64 lanes
745 u64 tmp[4];
746 _mm256_storeu_si256((__m256i *)tmp, acc);
747 u32 sum = (u32)(tmp[0] + tmp[1] + tmp[2] + tmp[3]);
748
749 // Scalar tail
750 while (a < pEnd) {
751 u8 x = *a ^ *b;
752 x = x - ((x >> 1) & 0x55);
753 x = (x & 0x33) + ((x >> 2) & 0x33);
754 sum += (x + (x >> 4)) & 0x0F;
755 a++;
756 b++;
757 }
758
759 return (f32)sum;
760}
761#endif
762
763static f32 distance_hamming_u8(u8 *a, u8 *b, size_t n) {
764 int same = 0;
765 for (unsigned long i = 0; i < n; i++) {
766 same += hamdist_table[a[i] ^ b[i]];
767 }
768 return (f32)same;
769}
770
771#ifdef _MSC_VER
772#if !defined(__clang__1) && (defined(_M_ARM) || defined(_M_ARM64))
773// From
774// https://github.com/ngtcp2/ngtcp2/blob/b64f1e77b5e0d880b93d31f474147fae4a1d17cc/lib/ngtcp2_ringbuf.c,
775// line 34-43
776static unsigned int __builtin_popcountl(unsigned int x) {
777 unsigned int c = 0;
778 for (; x; ++c) {
779 x &= x - 1;
780 }
781 return c;
782}
783#else
784#include <intrin.h>
785#define __builtin_popcountl __popcnt64
786#endif
787#endif
788
789static f32 distance_hamming_u64(const u8 *a, const u8 *b, size_t n) {
790 int same = 0;
791 for (unsigned long i = 0; i < n; i++) {
792 u64 va, vb;
793 memcpy(&va, a + i * sizeof(u64), sizeof(u64));
794 memcpy(&vb, b + i * sizeof(u64), sizeof(u64));
795 same += __builtin_popcountl(va ^ vb);
796 }
797 return (f32)same;
798}
799
800/**
801 * @brief Calculate the hamming distance between two bitvectors.
802 *
803 * @param a - first bitvector, MUST have d dimensions
804 * @param b - second bitvector, MUST have d dimensions
805 * @param d - pointer to size_t, MUST be divisible by CHAR_BIT
806 * @return f32
807 */
808static f32 distance_hamming(const void *a, const void *b, const void *d) {
809 size_t dimensions = *((size_t *)d);
810 size_t n_bytes = dimensions / CHAR_BIT8;
811
812#ifdef SQLITE_VEC_ENABLE_NEON
813 if (dimensions >= 128) {
814 return distance_hamming_neon((const u8 *)a, (const u8 *)b, n_bytes);
815 }
816#endif
817#ifdef SQLITE_VEC_ENABLE_AVX
818 if (n_bytes >= 32) {
819 return distance_hamming_avx2((const u8 *)a, (const u8 *)b, n_bytes);
820 }
821#endif
822
823 if ((dimensions % 64) == 0) {
824 return distance_hamming_u64((const u8 *)a, (const u8 *)b, n_bytes / sizeof(u64));
825 }
826 return distance_hamming_u8((u8 *)a, (u8 *)b, n_bytes);
827}
828
829#ifdef SQLITE_VEC_TEST
830f32 _test_distance_l2_sqr_float(const f32 *a, const f32 *b, size_t dims) {
831 return distance_l2_sqr_float(a, b, &dims);
832}
833f32 _test_distance_cosine_float(const f32 *a, const f32 *b, size_t dims) {
834 return distance_cosine_float(a, b, &dims);
835}
836f32 _test_distance_hamming(const u8 *a, const u8 *b, size_t dims) {
837 return distance_hamming(a, b, &dims);
838}
839#endif
840
841// from SQLite source:
842// https://github.com/sqlite/sqlite/blob/a509a90958ddb234d1785ed7801880ccb18b497e/src/json.c#L153
843static const char vecJsonIsSpaceX[] = {
844 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
845 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
846 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
847 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
848 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
849 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
850
851 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
852 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
853 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
854 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
855 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
856 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
857};
858
859#define vecJsonIsspace(x)(vecJsonIsSpaceX[(unsigned char)x]) (vecJsonIsSpaceX[(unsigned char)x])
860
861typedef void (*vector_cleanup)(void *p);
862
863void vector_cleanup_noop(void *_) { UNUSED_PARAMETER(_)(void)(_); }
864
865#define JSON_SUBTYPE74 74
866
867void vtab_set_error(sqlite3_vtab *pVTab, const char *zFormat, ...) {
868 va_list args;
869 sqlite3_freesqlite3_api->free(pVTab->zErrMsg);
870 va_start(args, zFormat)__builtin_va_start(args, zFormat);
871 pVTab->zErrMsg = sqlite3_vmprintfsqlite3_api->vmprintf(zFormat, args);
872 va_end(args)__builtin_va_end(args);
873}
874struct Array {
875 size_t element_size;
876 size_t length;
877 size_t capacity;
878 void *z;
879};
880
881/**
882 * @brief Initial an array with the given element size and capacity.
883 *
884 * @param array
885 * @param element_size
886 * @param init_capacity
887 * @return SQLITE_OK on success, error code on failure. Only error is
888 * SQLITE_NOMEM
889 */
890int array_init(struct Array *array, size_t element_size, size_t init_capacity) {
891 int sz = element_size * init_capacity;
892 void *z = sqlite3_mallocsqlite3_api->malloc(sz);
893 if (!z) {
894 return SQLITE_NOMEM7;
895 }
896 memset(z, 0, sz);
897
898 array->element_size = element_size;
899 array->length = 0;
900 array->capacity = init_capacity;
901 array->z = z;
902 return SQLITE_OK0;
903}
904
905int array_append(struct Array *array, const void *element) {
906 if (array->length == array->capacity) {
907 size_t new_capacity = array->capacity * 2 + 100;
908 void *z = sqlite3_realloc64sqlite3_api->realloc64(array->z, array->element_size * new_capacity);
909 if (z) {
910 array->capacity = new_capacity;
911 array->z = z;
912 } else {
913 return SQLITE_NOMEM7;
914 }
915 }
916 memcpy(&((unsigned char *)array->z)[array->length * array->element_size],
917 element, array->element_size);
918 array->length++;
919 return SQLITE_OK0;
920}
921
922void array_cleanup(struct Array *array) {
923 if (!array)
924 return;
925 array->element_size = 0;
926 array->length = 0;
927 array->capacity = 0;
928 sqlite3_freesqlite3_api->free(array->z);
929 array->z = NULL((void*)0);
930}
931
932char *vector_subtype_name(int subtype) {
933 switch (subtype) {
934 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32:
935 return "float32";
936 case SQLITE_VEC_ELEMENT_TYPE_INT8:
937 return "int8";
938 case SQLITE_VEC_ELEMENT_TYPE_BIT:
939 return "bit";
940 }
941 return "";
942}
943char *type_name(int type) {
944 switch (type) {
945 case SQLITE_INTEGER1:
946 return "INTEGER";
947 case SQLITE_BLOB4:
948 return "BLOB";
949 case SQLITE_TEXT3:
950 return "TEXT";
951 case SQLITE_FLOAT2:
952 return "FLOAT";
953 case SQLITE_NULL5:
954 return "NULL";
955 }
956 return "";
957}
958
959typedef void (*fvec_cleanup)(void *vector);
960
961void fvec_cleanup_noop(void *_) { UNUSED_PARAMETER(_)(void)(_); }
962
963static int fvec_from_value(sqlite3_value *value, f32 **vector,
964 size_t *dimensions, fvec_cleanup *cleanup,
965 char **pzErr) {
966 int value_type = sqlite3_value_typesqlite3_api->value_type(value);
967
968 if (value_type == SQLITE_BLOB4) {
969 const void *blob = sqlite3_value_blobsqlite3_api->value_blob(value);
970 int bytes = sqlite3_value_bytessqlite3_api->value_bytes(value);
971 if (bytes == 0) {
972 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("zero-length vectors are not supported.");
973 return SQLITE_ERROR1;
974 }
975 if ((bytes % sizeof(f32)) != 0) {
976 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("invalid float32 vector BLOB length. Must be "
977 "divisible by %d, found %d",
978 sizeof(f32), bytes);
979 return SQLITE_ERROR1;
980 }
981 f32 *buf = sqlite3_mallocsqlite3_api->malloc(bytes);
982 if (!buf) {
983 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("out of memory");
984 return SQLITE_NOMEM7;
985 }
986 memcpy(buf, blob, bytes);
987 size_t n = bytes / sizeof(f32);
988 for (size_t i = 0; i < n; i++) {
989 if (isnan(buf[i])__builtin_isnan (buf[i]) || isinf(buf[i])__builtin_isinf_sign (buf[i])) {
990 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
991 "invalid float32 vector: element %d is %s",
992 (int)i, isnan(buf[i])__builtin_isnan (buf[i]) ? "NaN" : "Inf");
993 sqlite3_freesqlite3_api->free(buf);
994 return SQLITE_ERROR1;
995 }
996 }
997 *vector = buf;
998 *dimensions = n;
999 *cleanup = sqlite3_freesqlite3_api->free;
1000 return SQLITE_OK0;
1001 }
1002
1003 if (value_type == SQLITE_TEXT3) {
1004 const char *source = (const char *)sqlite3_value_textsqlite3_api->value_text(value);
1005 int source_len = sqlite3_value_bytessqlite3_api->value_bytes(value);
1006 if (source_len == 0) {
1007 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("zero-length vectors are not supported.");
1008 return SQLITE_ERROR1;
1009 }
1010 int i = 0;
1011
1012 struct Array x;
1013 int rc = array_init(&x, sizeof(f32), ceil(source_len / 2.0));
1014 if (rc != SQLITE_OK0) {
1015 return rc;
1016 }
1017
1018 // advance leading whitespace to first '['
1019 while (i < source_len) {
1020 if (vecJsonIsspace(source[i])(vecJsonIsSpaceX[(unsigned char)source[i]])) {
1021 i++;
1022 continue;
1023 }
1024 if (source[i] == '[') {
1025 break;
1026 }
1027
1028 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
1029 "JSON array parsing error: Input does not start with '['");
1030 array_cleanup(&x);
1031 return SQLITE_ERROR1;
1032 }
1033 if (source[i] != '[') {
1034 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
1035 "JSON array parsing error: Input does not start with '['");
1036 array_cleanup(&x);
1037 return SQLITE_ERROR1;
1038 }
1039 int offset = i + 1;
1040
1041 while (offset < source_len) {
1042 char *ptr = (char *)&source[offset];
1043 char *endptr;
1044
1045 errno(*__errno_location ()) = 0;
1046 double result = strtod(ptr, &endptr);
1047 if ((errno(*__errno_location ()) != 0 && result == 0) // some interval error?
1048 || (errno(*__errno_location ()) == ERANGE34 &&
1049 (result == HUGE_VAL(__builtin_huge_val ()) || result == -HUGE_VAL(__builtin_huge_val ()))) // too big / smalls
1050 ) {
1051 sqlite3_freesqlite3_api->free(x.z);
1052 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("JSON parsing error");
1053 return SQLITE_ERROR1;
1054 }
1055
1056 if (endptr == ptr) {
1057 if (*ptr != ']') {
1058 sqlite3_freesqlite3_api->free(x.z);
1059 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("JSON parsing error");
1060 return SQLITE_ERROR1;
1061 }
1062 goto done;
1063 }
1064
1065 f32 res = (f32)result;
1066 if (isnan(res)__builtin_isnan (res) || isinf(res)__builtin_isinf_sign (res)) {
1067 sqlite3_freesqlite3_api->free(x.z);
1068 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
1069 "invalid float32 vector: element %d is %s",
1070 (int)x.length, isnan(res)__builtin_isnan (res) ? "NaN" : "Inf");
1071 return SQLITE_ERROR1;
1072 }
1073 array_append(&x, (const void *)&res);
1074
1075 offset += (endptr - ptr);
1076 while (offset < source_len) {
1077 if (vecJsonIsspace(source[offset])(vecJsonIsSpaceX[(unsigned char)source[offset]])) {
1078 offset++;
1079 continue;
1080 }
1081 if (source[offset] == ',') {
1082 offset++;
1083 continue;
1084 }
1085 if (source[offset] == ']')
1086 goto done;
1087 break;
1088 }
1089 }
1090
1091 done:
1092
1093 if (x.length > 0) {
1094 *vector = (f32 *)x.z;
1095 *dimensions = x.length;
1096 *cleanup = sqlite3_freesqlite3_api->free;
1097 return SQLITE_OK0;
1098 }
1099 sqlite3_freesqlite3_api->free(x.z);
1100 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("zero-length vectors are not supported.");
1101 return SQLITE_ERROR1;
1102 }
1103
1104 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
1105 "Input must have type BLOB (compact format) or TEXT (JSON), found %s",
1106 type_name(value_type));
1107 return SQLITE_ERROR1;
1108}
1109
1110static int bitvec_from_value(sqlite3_value *value, u8 **vector,
1111 size_t *dimensions, vector_cleanup *cleanup,
1112 char **pzErr) {
1113 int value_type = sqlite3_value_typesqlite3_api->value_type(value);
1114 if (value_type == SQLITE_BLOB4) {
1115 const void *blob = sqlite3_value_blobsqlite3_api->value_blob(value);
1116 int bytes = sqlite3_value_bytessqlite3_api->value_bytes(value);
1117 if (bytes == 0) {
1118 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("zero-length vectors are not supported.");
1119 return SQLITE_ERROR1;
1120 }
1121 *vector = (u8 *)blob;
1122 *dimensions = bytes * CHAR_BIT8;
1123 *cleanup = vector_cleanup_noop;
1124 return SQLITE_OK0;
1125 }
1126 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Unknown type for bitvector.");
1127 return SQLITE_ERROR1;
1128}
1129
1130static int int8_vec_from_value(sqlite3_value *value, i8 **vector,
1131 size_t *dimensions, vector_cleanup *cleanup,
1132 char **pzErr) {
1133 int value_type = sqlite3_value_typesqlite3_api->value_type(value);
1134 if (value_type == SQLITE_BLOB4) {
1135 const void *blob = sqlite3_value_blobsqlite3_api->value_blob(value);
1136 int bytes = sqlite3_value_bytessqlite3_api->value_bytes(value);
1137 if (bytes == 0) {
1138 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("zero-length vectors are not supported.");
1139 return SQLITE_ERROR1;
1140 }
1141 *vector = (i8 *)blob;
1142 *dimensions = bytes;
1143 *cleanup = vector_cleanup_noop;
1144 return SQLITE_OK0;
1145 }
1146
1147 if (value_type == SQLITE_TEXT3) {
1148 const char *source = (const char *)sqlite3_value_textsqlite3_api->value_text(value);
1149 int source_len = sqlite3_value_bytessqlite3_api->value_bytes(value);
1150 int i = 0;
1151
1152 if (source_len == 0) {
1153 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("zero-length vectors are not supported.");
1154 return SQLITE_ERROR1;
1155 }
1156
1157 struct Array x;
1158 int rc = array_init(&x, sizeof(i8), ceil(source_len / 2.0));
1159 if (rc != SQLITE_OK0) {
1160 return rc;
1161 }
1162
1163 // advance leading whitespace to first '['
1164 while (i < source_len) {
1165 if (vecJsonIsspace(source[i])(vecJsonIsSpaceX[(unsigned char)source[i]])) {
1166 i++;
1167 continue;
1168 }
1169 if (source[i] == '[') {
1170 break;
1171 }
1172
1173 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
1174 "JSON array parsing error: Input does not start with '['");
1175 array_cleanup(&x);
1176 return SQLITE_ERROR1;
1177 }
1178 if (source[i] != '[') {
1179 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
1180 "JSON array parsing error: Input does not start with '['");
1181 array_cleanup(&x);
1182 return SQLITE_ERROR1;
1183 }
1184 int offset = i + 1;
1185
1186 while (offset < source_len) {
1187 char *ptr = (char *)&source[offset];
1188 char *endptr;
1189
1190 errno(*__errno_location ()) = 0;
1191 long result = strtol(ptr, &endptr, 10);
1192 if ((errno(*__errno_location ()) != 0 && result == 0) ||
1193 (errno(*__errno_location ()) == ERANGE34 && (result == LONG_MAX9223372036854775807L || result == LONG_MIN(-9223372036854775807L -1L)))) {
1194 sqlite3_freesqlite3_api->free(x.z);
1195 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("JSON parsing error");
1196 return SQLITE_ERROR1;
1197 }
1198
1199 if (endptr == ptr) {
1200 if (*ptr != ']') {
1201 sqlite3_freesqlite3_api->free(x.z);
1202 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("JSON parsing error");
1203 return SQLITE_ERROR1;
1204 }
1205 goto done;
1206 }
1207
1208 if (result < INT8_MIN(-128) || result > INT8_MAX(127)) {
1209 sqlite3_freesqlite3_api->free(x.z);
1210 *pzErr =
1211 sqlite3_mprintfsqlite3_api->mprintf("JSON parsing error: value out of range for int8");
1212 return SQLITE_ERROR1;
1213 }
1214
1215 i8 res = (i8)result;
1216 array_append(&x, (const void *)&res);
1217
1218 offset += (endptr - ptr);
1219 while (offset < source_len) {
1220 if (vecJsonIsspace(source[offset])(vecJsonIsSpaceX[(unsigned char)source[offset]])) {
1221 offset++;
1222 continue;
1223 }
1224 if (source[offset] == ',') {
1225 offset++;
1226 continue;
1227 }
1228 if (source[offset] == ']')
1229 goto done;
1230 break;
1231 }
1232 }
1233
1234 done:
1235
1236 if (x.length > 0) {
1237 *vector = (i8 *)x.z;
1238 *dimensions = x.length;
1239 *cleanup = (vector_cleanup)sqlite3_freesqlite3_api->free;
1240 return SQLITE_OK0;
1241 }
1242 sqlite3_freesqlite3_api->free(x.z);
1243 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("zero-length vectors are not supported.");
1244 return SQLITE_ERROR1;
1245 }
1246
1247 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Unknown type for int8 vector.");
1248 return SQLITE_ERROR1;
1249}
1250
1251/**
1252 * @brief Extract a vector from a sqlite3_value. Can be a float32, int8, or bit
1253 * vector.
1254 *
1255 * @param value: the sqlite3_value to read from.
1256 * @param vector: Output pointer to vector data.
1257 * @param dimensions: Output number of dimensions
1258 * @param dimensions: Output vector element type
1259 * @param cleanup
1260 * @param pzErrorMessage
1261 * @return int SQLITE_OK on success, error code otherwise
1262 */
1263int vector_from_value(sqlite3_value *value, void **vector, size_t *dimensions,
1264 enum VectorElementType *element_type,
1265 vector_cleanup *cleanup, char **pzErrorMessage) {
1266 int subtype = sqlite3_value_subtypesqlite3_api->value_subtype(value);
1267 if (!subtype || (subtype == SQLITE_VEC_ELEMENT_TYPE_FLOAT32) ||
1268 (subtype == JSON_SUBTYPE74)) {
1269 int rc = fvec_from_value(value, (f32 **)vector, dimensions,
1270 (fvec_cleanup *)cleanup, pzErrorMessage);
1271 if (rc == SQLITE_OK0) {
1272 *element_type = SQLITE_VEC_ELEMENT_TYPE_FLOAT32;
1273 }
1274 return rc;
1275 }
1276
1277 if (subtype == SQLITE_VEC_ELEMENT_TYPE_BIT) {
1278 int rc = bitvec_from_value(value, (u8 **)vector, dimensions, cleanup,
1279 pzErrorMessage);
1280 if (rc == SQLITE_OK0) {
1281 *element_type = SQLITE_VEC_ELEMENT_TYPE_BIT;
1282 }
1283 return rc;
1284 }
1285 if (subtype == SQLITE_VEC_ELEMENT_TYPE_INT8) {
1286 int rc = int8_vec_from_value(value, (i8 **)vector, dimensions, cleanup,
1287 pzErrorMessage);
1288 if (rc == SQLITE_OK0) {
1289 *element_type = SQLITE_VEC_ELEMENT_TYPE_INT8;
1290 }
1291 return rc;
1292 }
1293 *pzErrorMessage = sqlite3_mprintfsqlite3_api->mprintf("Unknown subtype: %d", subtype);
1294 return SQLITE_ERROR1;
1295}
1296
1297int ensure_vector_match(sqlite3_value *aValue, sqlite3_value *bValue, void **a,
1298 void **b, enum VectorElementType *element_type,
1299 size_t *dimensions, vector_cleanup *outACleanup,
1300 vector_cleanup *outBCleanup, char **outError) {
1301 int rc;
1302 enum VectorElementType aType, bType;
1303 size_t aDims, bDims;
1304 char *error = NULL((void*)0);
1305 vector_cleanup aCleanup, bCleanup;
1306
1307 rc = vector_from_value(aValue, a, &aDims, &aType, &aCleanup, &error);
1308 if (rc != SQLITE_OK0) {
1309 *outError = sqlite3_mprintfsqlite3_api->mprintf("Error reading 1st vector: %s", error);
1310 sqlite3_freesqlite3_api->free(error);
1311 return SQLITE_ERROR1;
1312 }
1313
1314 rc = vector_from_value(bValue, b, &bDims, &bType, &bCleanup, &error);
1315 if (rc != SQLITE_OK0) {
1316 *outError = sqlite3_mprintfsqlite3_api->mprintf("Error reading 2nd vector: %s", error);
1317 sqlite3_freesqlite3_api->free(error);
1318 aCleanup(*a);
1319 return SQLITE_ERROR1;
1320 }
1321
1322 if (aType != bType) {
1323 *outError =
1324 sqlite3_mprintfsqlite3_api->mprintf("Vector type mistmatch. First vector has type %s, "
1325 "while the second has type %s.",
1326 vector_subtype_name(aType), vector_subtype_name(bType));
1327 aCleanup(*a);
1328 bCleanup(*b);
1329 return SQLITE_ERROR1;
1330 }
1331 if (aDims != bDims) {
1332 *outError = sqlite3_mprintfsqlite3_api->mprintf(
1333 "Vector dimension mistmatch. First vector has %ld dimensions, "
1334 "while the second has %ld dimensions.",
1335 aDims, bDims);
1336 aCleanup(*a);
1337 bCleanup(*b);
1338 return SQLITE_ERROR1;
1339 }
1340 *element_type = aType;
1341 *dimensions = aDims;
1342 *outACleanup = aCleanup;
1343 *outBCleanup = bCleanup;
1344 return SQLITE_OK0;
1345}
1346
1347int _cmp(const void *a, const void *b) { return (*(i64 *)a - *(i64 *)b); }
1348
1349#pragma region scalar functions
1350static void vec_f32(sqlite3_context *context, int argc, sqlite3_value **argv) {
1351 assert(argc == 1)((void) sizeof ((argc == 1) ? 1 : 0), __extension__ ({ if (argc
== 1) ; else __assert_fail ("argc == 1", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1351, __extension__ __PRETTY_FUNCTION__); }))
;
1352 int rc;
1353 f32 *vector = NULL((void*)0);
1354 size_t dimensions;
1355 fvec_cleanup cleanup;
1356 char *errmsg;
1357 rc = fvec_from_value(argv[0], &vector, &dimensions, &cleanup, &errmsg);
1358 if (rc != SQLITE_OK0) {
1359 sqlite3_result_errorsqlite3_api->result_error(context, errmsg, -1);
1360 sqlite3_freesqlite3_api->free(errmsg);
1361 return;
1362 }
1363 sqlite3_result_blobsqlite3_api->result_blob(context, vector, dimensions * sizeof(f32),
1364 (void (*)(void *))cleanup);
1365 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_FLOAT32);
1366}
1367
1368static void vec_bit(sqlite3_context *context, int argc, sqlite3_value **argv) {
1369 assert(argc == 1)((void) sizeof ((argc == 1) ? 1 : 0), __extension__ ({ if (argc
== 1) ; else __assert_fail ("argc == 1", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1369, __extension__ __PRETTY_FUNCTION__); }))
;
1370 int rc;
1371 u8 *vector;
1372 size_t dimensions;
1373 vector_cleanup cleanup;
1374 char *errmsg;
1375 rc = bitvec_from_value(argv[0], &vector, &dimensions, &cleanup, &errmsg);
1376 if (rc != SQLITE_OK0) {
1377 sqlite3_result_errorsqlite3_api->result_error(context, errmsg, -1);
1378 sqlite3_freesqlite3_api->free(errmsg);
1379 return;
1380 }
1381 sqlite3_result_blobsqlite3_api->result_blob(context, vector, dimensions / CHAR_BIT8, SQLITE_TRANSIENT((sqlite3_destructor_type)-1));
1382 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_BIT);
1383 cleanup(vector);
1384}
1385static void vec_int8(sqlite3_context *context, int argc, sqlite3_value **argv) {
1386 assert(argc == 1)((void) sizeof ((argc == 1) ? 1 : 0), __extension__ ({ if (argc
== 1) ; else __assert_fail ("argc == 1", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1386, __extension__ __PRETTY_FUNCTION__); }))
;
1387 int rc;
1388 i8 *vector;
1389 size_t dimensions;
1390 vector_cleanup cleanup;
1391 char *errmsg;
1392 rc = int8_vec_from_value(argv[0], &vector, &dimensions, &cleanup, &errmsg);
1393 if (rc != SQLITE_OK0) {
1394 sqlite3_result_errorsqlite3_api->result_error(context, errmsg, -1);
1395 sqlite3_freesqlite3_api->free(errmsg);
1396 return;
1397 }
1398 sqlite3_result_blobsqlite3_api->result_blob(context, vector, dimensions, SQLITE_TRANSIENT((sqlite3_destructor_type)-1));
1399 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_INT8);
1400 cleanup(vector);
1401}
1402
1403static void vec_length(sqlite3_context *context, int argc,
1404 sqlite3_value **argv) {
1405 assert(argc == 1)((void) sizeof ((argc == 1) ? 1 : 0), __extension__ ({ if (argc
== 1) ; else __assert_fail ("argc == 1", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1405, __extension__ __PRETTY_FUNCTION__); }))
;
1406 int rc;
1407 void *vector;
1408 size_t dimensions;
1409 vector_cleanup cleanup;
1410 char *errmsg;
1411 enum VectorElementType elementType;
1412 rc = vector_from_value(argv[0], &vector, &dimensions, &elementType, &cleanup,
1413 &errmsg);
1414 if (rc != SQLITE_OK0) {
1415 sqlite3_result_errorsqlite3_api->result_error(context, errmsg, -1);
1416 sqlite3_freesqlite3_api->free(errmsg);
1417 return;
1418 }
1419 sqlite3_result_int64sqlite3_api->result_int64(context, dimensions);
1420 cleanup(vector);
1421}
1422
1423static void vec_distance_cosine(sqlite3_context *context, int argc,
1424 sqlite3_value **argv) {
1425 assert(argc == 2)((void) sizeof ((argc == 2) ? 1 : 0), __extension__ ({ if (argc
== 2) ; else __assert_fail ("argc == 2", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1425, __extension__ __PRETTY_FUNCTION__); }))
;
1426 int rc;
1427 void *a = NULL((void*)0), *b = NULL((void*)0);
1428 size_t dimensions;
1429 vector_cleanup aCleanup, bCleanup;
1430 char *error;
1431 enum VectorElementType elementType;
1432 rc = ensure_vector_match(argv[0], argv[1], &a, &b, &elementType, &dimensions,
1433 &aCleanup, &bCleanup, &error);
1434 if (rc != SQLITE_OK0) {
1435 sqlite3_result_errorsqlite3_api->result_error(context, error, -1);
1436 sqlite3_freesqlite3_api->free(error);
1437 return;
1438 }
1439
1440 switch (elementType) {
1441 case SQLITE_VEC_ELEMENT_TYPE_BIT: {
1442 sqlite3_result_errorsqlite3_api->result_error(
1443 context, "Cannot calculate cosine distance between two bitvectors.",
1444 -1);
1445 goto finish;
1446 }
1447 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32: {
1448 f32 result = distance_cosine_float(a, b, &dimensions);
1449 sqlite3_result_doublesqlite3_api->result_double(context, result);
1450 goto finish;
1451 }
1452 case SQLITE_VEC_ELEMENT_TYPE_INT8: {
1453 f32 result = distance_cosine_int8(a, b, &dimensions);
1454 sqlite3_result_doublesqlite3_api->result_double(context, result);
1455 goto finish;
1456 }
1457 }
1458
1459finish:
1460 aCleanup(a);
1461 bCleanup(b);
1462 return;
1463}
1464
1465static void vec_distance_l2(sqlite3_context *context, int argc,
1466 sqlite3_value **argv) {
1467 assert(argc == 2)((void) sizeof ((argc == 2) ? 1 : 0), __extension__ ({ if (argc
== 2) ; else __assert_fail ("argc == 2", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1467, __extension__ __PRETTY_FUNCTION__); }))
;
1468 int rc;
1469 void *a = NULL((void*)0), *b = NULL((void*)0);
1470 size_t dimensions;
1471 vector_cleanup aCleanup, bCleanup;
1472 char *error;
1473 enum VectorElementType elementType;
1474 rc = ensure_vector_match(argv[0], argv[1], &a, &b, &elementType, &dimensions,
1475 &aCleanup, &bCleanup, &error);
1476 if (rc != SQLITE_OK0) {
1477 sqlite3_result_errorsqlite3_api->result_error(context, error, -1);
1478 sqlite3_freesqlite3_api->free(error);
1479 return;
1480 }
1481
1482 switch (elementType) {
1483 case SQLITE_VEC_ELEMENT_TYPE_BIT: {
1484 sqlite3_result_errorsqlite3_api->result_error(
1485 context, "Cannot calculate L2 distance between two bitvectors.", -1);
1486 goto finish;
1487 }
1488 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32: {
1489 f32 result = distance_l2_sqr_float(a, b, &dimensions);
1490 sqlite3_result_doublesqlite3_api->result_double(context, result);
1491 goto finish;
1492 }
1493 case SQLITE_VEC_ELEMENT_TYPE_INT8: {
1494 f32 result = distance_l2_sqr_int8(a, b, &dimensions);
1495 sqlite3_result_doublesqlite3_api->result_double(context, result);
1496 goto finish;
1497 }
1498 }
1499
1500finish:
1501 aCleanup(a);
1502 bCleanup(b);
1503 return;
1504}
1505
1506static void vec_distance_l1(sqlite3_context *context, int argc,
1507 sqlite3_value **argv) {
1508 assert(argc == 2)((void) sizeof ((argc == 2) ? 1 : 0), __extension__ ({ if (argc
== 2) ; else __assert_fail ("argc == 2", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1508, __extension__ __PRETTY_FUNCTION__); }))
;
1509 int rc;
1510 void *a, *b;
1511 size_t dimensions;
1512 vector_cleanup aCleanup, bCleanup;
1513 char *error;
1514 enum VectorElementType elementType;
1515 rc = ensure_vector_match(argv[0], argv[1], &a, &b, &elementType, &dimensions,
1516 &aCleanup, &bCleanup, &error);
1517 if (rc != SQLITE_OK0) {
1518 sqlite3_result_errorsqlite3_api->result_error(context, error, -1);
1519 sqlite3_freesqlite3_api->free(error);
1520 return;
1521 }
1522
1523 switch (elementType) {
1524 case SQLITE_VEC_ELEMENT_TYPE_BIT: {
1525 sqlite3_result_errorsqlite3_api->result_error(
1526 context, "Cannot calculate L1 distance between two bitvectors.", -1);
1527 goto finish;
1528 }
1529 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32: {
1530 double result = distance_l1_f32(a, b, &dimensions);
1531 sqlite3_result_doublesqlite3_api->result_double(context, result);
1532 goto finish;
1533 }
1534 case SQLITE_VEC_ELEMENT_TYPE_INT8: {
1535 i64 result = distance_l1_int8(a, b, &dimensions);
1536 sqlite3_result_intsqlite3_api->result_int(context, result);
1537 goto finish;
1538 }
1539 }
1540
1541finish:
1542 aCleanup(a);
1543 bCleanup(b);
1544 return;
1545}
1546
1547static void vec_distance_hamming(sqlite3_context *context, int argc,
1548 sqlite3_value **argv) {
1549 assert(argc == 2)((void) sizeof ((argc == 2) ? 1 : 0), __extension__ ({ if (argc
== 2) ; else __assert_fail ("argc == 2", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1549, __extension__ __PRETTY_FUNCTION__); }))
;
1550 int rc;
1551 void *a = NULL((void*)0), *b = NULL((void*)0);
1552 size_t dimensions;
1553 vector_cleanup aCleanup, bCleanup;
1554 char *error;
1555 enum VectorElementType elementType;
1556 rc = ensure_vector_match(argv[0], argv[1], &a, &b, &elementType, &dimensions,
1557 &aCleanup, &bCleanup, &error);
1558 if (rc != SQLITE_OK0) {
1559 sqlite3_result_errorsqlite3_api->result_error(context, error, -1);
1560 sqlite3_freesqlite3_api->free(error);
1561 return;
1562 }
1563
1564 switch (elementType) {
1565 case SQLITE_VEC_ELEMENT_TYPE_BIT: {
1566 sqlite3_result_doublesqlite3_api->result_double(context, distance_hamming(a, b, &dimensions));
1567 goto finish;
1568 }
1569 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32: {
1570 sqlite3_result_errorsqlite3_api->result_error(
1571 context,
1572 "Cannot calculate hamming distance between two float32 vectors.", -1);
1573 goto finish;
1574 }
1575 case SQLITE_VEC_ELEMENT_TYPE_INT8: {
1576 sqlite3_result_errorsqlite3_api->result_error(
1577 context, "Cannot calculate hamming distance between two int8 vectors.",
1578 -1);
1579 goto finish;
1580 }
1581 }
1582
1583finish:
1584 aCleanup(a);
1585 bCleanup(b);
1586 return;
1587}
1588
1589char *vec_type_name(enum VectorElementType elementType) {
1590 switch (elementType) {
1591 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32:
1592 return "float32";
1593 case SQLITE_VEC_ELEMENT_TYPE_INT8:
1594 return "int8";
1595 case SQLITE_VEC_ELEMENT_TYPE_BIT:
1596 return "bit";
1597 }
1598 return "";
1599}
1600
1601static void vec_type(sqlite3_context *context, int argc, sqlite3_value **argv) {
1602 assert(argc == 1)((void) sizeof ((argc == 1) ? 1 : 0), __extension__ ({ if (argc
== 1) ; else __assert_fail ("argc == 1", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1602, __extension__ __PRETTY_FUNCTION__); }))
;
1603 void *vector;
1604 size_t dimensions;
1605 vector_cleanup cleanup;
1606 char *pzError;
1607 enum VectorElementType elementType;
1608 int rc = vector_from_value(argv[0], &vector, &dimensions, &elementType,
1609 &cleanup, &pzError);
1610 if (rc != SQLITE_OK0) {
1611 sqlite3_result_errorsqlite3_api->result_error(context, pzError, -1);
1612 sqlite3_freesqlite3_api->free(pzError);
1613 return;
1614 }
1615 sqlite3_result_textsqlite3_api->result_text(context, vec_type_name(elementType), -1, SQLITE_STATIC((sqlite3_destructor_type)0));
1616 cleanup(vector);
1617}
1618static void vec_quantize_binary(sqlite3_context *context, int argc,
1619 sqlite3_value **argv) {
1620 assert(argc == 1)((void) sizeof ((argc == 1) ? 1 : 0), __extension__ ({ if (argc
== 1) ; else __assert_fail ("argc == 1", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1620, __extension__ __PRETTY_FUNCTION__); }))
;
1621 void *vector;
1622 size_t dimensions;
1623 vector_cleanup vectorCleanup;
1624 char *pzError;
1625 enum VectorElementType elementType;
1626 int rc = vector_from_value(argv[0], &vector, &dimensions, &elementType,
1627 &vectorCleanup, &pzError);
1628 if (rc != SQLITE_OK0) {
1629 sqlite3_result_errorsqlite3_api->result_error(context, pzError, -1);
1630 sqlite3_freesqlite3_api->free(pzError);
1631 return;
1632 }
1633
1634 if (dimensions <= 0) {
1635 sqlite3_result_errorsqlite3_api->result_error(context, "Zero length vectors are not supported.", -1);
1636 goto cleanup;
1637 return;
1638 }
1639 if ((dimensions % CHAR_BIT8) != 0) {
1640 sqlite3_result_errorsqlite3_api->result_error(
1641 context,
1642 "Binary quantization requires vectors with a length divisible by 8",
1643 -1);
1644 goto cleanup;
1645 return;
1646 }
1647
1648 int sz = dimensions / CHAR_BIT8;
1649 u8 *out = sqlite3_mallocsqlite3_api->malloc(sz);
1650 if (!out) {
1651 sqlite3_result_error_codesqlite3_api->result_error_code(context, SQLITE_NOMEM7);
1652 goto cleanup;
1653 return;
1654 }
1655 memset(out, 0, sz);
1656
1657 switch (elementType) {
1658 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32: {
1659
1660 for (size_t i = 0; i < dimensions; i++) {
1661 int res = ((f32 *)vector)[i] > 0.0;
1662 out[i / 8] |= (res << (i % 8));
1663 }
1664 break;
1665 }
1666 case SQLITE_VEC_ELEMENT_TYPE_INT8: {
1667 for (size_t i = 0; i < dimensions; i++) {
1668 int res = ((i8 *)vector)[i] > 0;
1669 out[i / 8] |= (res << (i % 8));
1670 }
1671 break;
1672 }
1673 case SQLITE_VEC_ELEMENT_TYPE_BIT: {
1674 sqlite3_result_errorsqlite3_api->result_error(context,
1675 "Can only binary quantize float or int8 vectors", -1);
1676 sqlite3_freesqlite3_api->free(out);
1677 return;
1678 }
1679 }
1680 sqlite3_result_blobsqlite3_api->result_blob(context, out, sz, sqlite3_freesqlite3_api->free);
1681 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_BIT);
1682
1683cleanup:
1684 vectorCleanup(vector);
1685}
1686
1687static void vec_quantize_int8(sqlite3_context *context, int argc,
1688 sqlite3_value **argv) {
1689 assert(argc == 2)((void) sizeof ((argc == 2) ? 1 : 0), __extension__ ({ if (argc
== 2) ; else __assert_fail ("argc == 2", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1689, __extension__ __PRETTY_FUNCTION__); }))
;
1690 f32 *srcVector;
1691 size_t dimensions;
1692 fvec_cleanup srcCleanup;
1693 char *err;
1694 i8 *out = NULL((void*)0);
1695 int rc = fvec_from_value(argv[0], &srcVector, &dimensions, &srcCleanup, &err);
1696 if (rc != SQLITE_OK0) {
1697 sqlite3_result_errorsqlite3_api->result_error(context, err, -1);
1698 sqlite3_freesqlite3_api->free(err);
1699 return;
1700 }
1701
1702 int sz = dimensions * sizeof(i8);
1703 out = sqlite3_mallocsqlite3_api->malloc(sz);
1704 if (!out) {
1705 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
1706 goto cleanup;
1707 }
1708 memset(out, 0, sz);
1709
1710 if ((sqlite3_value_typesqlite3_api->value_type(argv[1]) != SQLITE_TEXT3) ||
1711 (sqlite3_value_bytessqlite3_api->value_bytes(argv[1]) != strlen("unit")) ||
1712 (sqlite3_stricmpsqlite3_api->stricmp((const char *)sqlite3_value_textsqlite3_api->value_text(argv[1]), "unit") !=
1713 0)) {
1714 sqlite3_result_errorsqlite3_api->result_error(
1715 context, "2nd argument to vec_quantize_int8() must be 'unit'.", -1);
1716 sqlite3_freesqlite3_api->free(out);
1717 goto cleanup;
1718 }
1719 f32 step = (1.0 - (-1.0)) / 255;
1720 for (size_t i = 0; i < dimensions; i++) {
1721 double val = ((srcVector[i] - (-1.0)) / step) - 128;
1722 if (!(val <= 127.0)) val = 127.0; /* also clamps NaN */
1723 if (!(val >= -128.0)) val = -128.0;
1724 out[i] = (i8)val;
1725 }
1726
1727 sqlite3_result_blobsqlite3_api->result_blob(context, out, dimensions * sizeof(i8), sqlite3_freesqlite3_api->free);
1728 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_INT8);
1729
1730cleanup:
1731 srcCleanup(srcVector);
1732}
1733
1734static void vec_add(sqlite3_context *context, int argc, sqlite3_value **argv) {
1735 assert(argc == 2)((void) sizeof ((argc == 2) ? 1 : 0), __extension__ ({ if (argc
== 2) ; else __assert_fail ("argc == 2", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1735, __extension__ __PRETTY_FUNCTION__); }))
;
1736 int rc;
1737 void *a = NULL((void*)0), *b = NULL((void*)0);
1738 size_t dimensions;
1739 vector_cleanup aCleanup, bCleanup;
1740 char *error;
1741 enum VectorElementType elementType;
1742 rc = ensure_vector_match(argv[0], argv[1], &a, &b, &elementType, &dimensions,
1743 &aCleanup, &bCleanup, &error);
1744 if (rc != SQLITE_OK0) {
1745 sqlite3_result_errorsqlite3_api->result_error(context, error, -1);
1746 sqlite3_freesqlite3_api->free(error);
1747 return;
1748 }
1749
1750 switch (elementType) {
1751 case SQLITE_VEC_ELEMENT_TYPE_BIT: {
1752 sqlite3_result_errorsqlite3_api->result_error(context, "Cannot add two bitvectors together.", -1);
1753 goto finish;
1754 }
1755 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32: {
1756 size_t outSize = dimensions * sizeof(f32);
1757 f32 *out = sqlite3_mallocsqlite3_api->malloc(outSize);
1758 if (!out) {
1759 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
1760 goto finish;
1761 }
1762 memset(out, 0, outSize);
1763 for (size_t i = 0; i < dimensions; i++) {
1764 out[i] = ((f32 *)a)[i] + ((f32 *)b)[i];
1765 }
1766 sqlite3_result_blobsqlite3_api->result_blob(context, out, outSize, sqlite3_freesqlite3_api->free);
1767 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_FLOAT32);
1768 goto finish;
1769 }
1770 case SQLITE_VEC_ELEMENT_TYPE_INT8: {
1771 size_t outSize = dimensions * sizeof(i8);
1772 i8 *out = sqlite3_mallocsqlite3_api->malloc(outSize);
1773 if (!out) {
1774 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
1775 goto finish;
1776 }
1777 memset(out, 0, outSize);
1778 for (size_t i = 0; i < dimensions; i++) {
1779 out[i] = ((i8 *)a)[i] + ((i8 *)b)[i];
1780 }
1781 sqlite3_result_blobsqlite3_api->result_blob(context, out, outSize, sqlite3_freesqlite3_api->free);
1782 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_INT8);
1783 goto finish;
1784 }
1785 }
1786finish:
1787 aCleanup(a);
1788 bCleanup(b);
1789 return;
1790}
1791static void vec_sub(sqlite3_context *context, int argc, sqlite3_value **argv) {
1792 assert(argc == 2)((void) sizeof ((argc == 2) ? 1 : 0), __extension__ ({ if (argc
== 2) ; else __assert_fail ("argc == 2", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1792, __extension__ __PRETTY_FUNCTION__); }))
;
1793 int rc;
1794 void *a = NULL((void*)0), *b = NULL((void*)0);
1795 size_t dimensions;
1796 vector_cleanup aCleanup, bCleanup;
1797 char *error;
1798 enum VectorElementType elementType;
1799 rc = ensure_vector_match(argv[0], argv[1], &a, &b, &elementType, &dimensions,
1800 &aCleanup, &bCleanup, &error);
1801 if (rc != SQLITE_OK0) {
1802 sqlite3_result_errorsqlite3_api->result_error(context, error, -1);
1803 sqlite3_freesqlite3_api->free(error);
1804 return;
1805 }
1806
1807 switch (elementType) {
1808 case SQLITE_VEC_ELEMENT_TYPE_BIT: {
1809 sqlite3_result_errorsqlite3_api->result_error(context, "Cannot subtract two bitvectors together.",
1810 -1);
1811 goto finish;
1812 }
1813 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32: {
1814 size_t outSize = dimensions * sizeof(f32);
1815 f32 *out = sqlite3_mallocsqlite3_api->malloc(outSize);
1816 if (!out) {
1817 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
1818 goto finish;
1819 }
1820 memset(out, 0, outSize);
1821 for (size_t i = 0; i < dimensions; i++) {
1822 out[i] = ((f32 *)a)[i] - ((f32 *)b)[i];
1823 }
1824 sqlite3_result_blobsqlite3_api->result_blob(context, out, outSize, sqlite3_freesqlite3_api->free);
1825 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_FLOAT32);
1826 goto finish;
1827 }
1828 case SQLITE_VEC_ELEMENT_TYPE_INT8: {
1829 size_t outSize = dimensions * sizeof(i8);
1830 i8 *out = sqlite3_mallocsqlite3_api->malloc(outSize);
1831 if (!out) {
1832 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
1833 goto finish;
1834 }
1835 memset(out, 0, outSize);
1836 for (size_t i = 0; i < dimensions; i++) {
1837 out[i] = ((i8 *)a)[i] - ((i8 *)b)[i];
1838 }
1839 sqlite3_result_blobsqlite3_api->result_blob(context, out, outSize, sqlite3_freesqlite3_api->free);
1840 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_INT8);
1841 goto finish;
1842 }
1843 }
1844finish:
1845 aCleanup(a);
1846 bCleanup(b);
1847 return;
1848}
1849static void vec_slice(sqlite3_context *context, int argc,
1850 sqlite3_value **argv) {
1851 assert(argc == 3)((void) sizeof ((argc == 3) ? 1 : 0), __extension__ ({ if (argc
== 3) ; else __assert_fail ("argc == 3", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1851, __extension__ __PRETTY_FUNCTION__); }))
;
1852
1853 void *vector;
1854 size_t dimensions;
1855 vector_cleanup cleanup;
1856 char *err;
1857 enum VectorElementType elementType;
1858
1859 int rc = vector_from_value(argv[0], &vector, &dimensions, &elementType,
1860 &cleanup, &err);
1861 if (rc != SQLITE_OK0) {
1862 sqlite3_result_errorsqlite3_api->result_error(context, err, -1);
1863 sqlite3_freesqlite3_api->free(err);
1864 return;
1865 }
1866
1867 int start = sqlite3_value_intsqlite3_api->value_int(argv[1]);
1868 int end = sqlite3_value_intsqlite3_api->value_int(argv[2]);
1869
1870 if (start < 0) {
1871 sqlite3_result_errorsqlite3_api->result_error(context,
1872 "slice 'start' index must be a postive number.", -1);
1873 goto done;
1874 }
1875 if (end < 0) {
1876 sqlite3_result_errorsqlite3_api->result_error(context, "slice 'end' index must be a postive number.",
1877 -1);
1878 goto done;
1879 }
1880 if (((size_t)start) > dimensions) {
1881 sqlite3_result_errorsqlite3_api->result_error(
1882 context, "slice 'start' index is greater than the number of dimensions",
1883 -1);
1884 goto done;
1885 }
1886 if (((size_t)end) > dimensions) {
1887 sqlite3_result_errorsqlite3_api->result_error(
1888 context, "slice 'end' index is greater than the number of dimensions",
1889 -1);
1890 goto done;
1891 }
1892 if (start > end) {
1893 sqlite3_result_errorsqlite3_api->result_error(context,
1894 "slice 'start' index is greater than 'end' index", -1);
1895 goto done;
1896 }
1897 if (start == end) {
1898 sqlite3_result_errorsqlite3_api->result_error(context,
1899 "slice 'start' index is equal to the 'end' index, "
1900 "vectors must have non-zero length",
1901 -1);
1902 goto done;
1903 }
1904 size_t n = end - start;
1905
1906 switch (elementType) {
1907 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32: {
1908 int outSize = n * sizeof(f32);
1909 f32 *out = sqlite3_mallocsqlite3_api->malloc(outSize);
1910 if (!out) {
1911 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
1912 goto done;
1913 }
1914 memset(out, 0, outSize);
1915 for (size_t i = 0; i < n; i++) {
1916 out[i] = ((f32 *)vector)[start + i];
1917 }
1918 sqlite3_result_blobsqlite3_api->result_blob(context, out, outSize, sqlite3_freesqlite3_api->free);
1919 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_FLOAT32);
1920 goto done;
1921 }
1922 case SQLITE_VEC_ELEMENT_TYPE_INT8: {
1923 int outSize = n * sizeof(i8);
1924 i8 *out = sqlite3_mallocsqlite3_api->malloc(outSize);
1925 if (!out) {
1926 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
1927 return;
1928 }
1929 memset(out, 0, outSize);
1930 for (size_t i = 0; i < n; i++) {
1931 out[i] = ((i8 *)vector)[start + i];
1932 }
1933 sqlite3_result_blobsqlite3_api->result_blob(context, out, outSize, sqlite3_freesqlite3_api->free);
1934 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_INT8);
1935 goto done;
1936 }
1937 case SQLITE_VEC_ELEMENT_TYPE_BIT: {
1938 if ((start % CHAR_BIT8) != 0) {
1939 sqlite3_result_errorsqlite3_api->result_error(context, "start index must be divisible by 8.", -1);
1940 goto done;
1941 }
1942 if ((end % CHAR_BIT8) != 0) {
1943 sqlite3_result_errorsqlite3_api->result_error(context, "end index must be divisible by 8.", -1);
1944 goto done;
1945 }
1946 int outSize = n / CHAR_BIT8;
1947 u8 *out = sqlite3_mallocsqlite3_api->malloc(outSize);
1948 if (!out) {
1949 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
1950 return;
1951 }
1952 memset(out, 0, outSize);
1953 for (size_t i = 0; i < n / CHAR_BIT8; i++) {
1954 out[i] = ((u8 *)vector)[(start / CHAR_BIT8) + i];
1955 }
1956 sqlite3_result_blobsqlite3_api->result_blob(context, out, outSize, sqlite3_freesqlite3_api->free);
1957 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_BIT);
1958 goto done;
1959 }
1960 }
1961done:
1962 cleanup(vector);
1963}
1964
1965static void vec_to_json(sqlite3_context *context, int argc,
1966 sqlite3_value **argv) {
1967 assert(argc == 1)((void) sizeof ((argc == 1) ? 1 : 0), __extension__ ({ if (argc
== 1) ; else __assert_fail ("argc == 1", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 1967, __extension__ __PRETTY_FUNCTION__); }))
;
1968 void *vector;
1969 size_t dimensions;
1970 vector_cleanup cleanup;
1971 char *err;
1972 enum VectorElementType elementType;
1973
1974 int rc = vector_from_value(argv[0], &vector, &dimensions, &elementType,
1975 &cleanup, &err);
1976 if (rc != SQLITE_OK0) {
1977 sqlite3_result_errorsqlite3_api->result_error(context, err, -1);
1978 sqlite3_freesqlite3_api->free(err);
1979 return;
1980 }
1981
1982 sqlite3_str *str = sqlite3_str_newsqlite3_api->str_new(sqlite3_context_db_handlesqlite3_api->context_db_handle(context));
1983 sqlite3_str_appendallsqlite3_api->str_appendall(str, "[");
1984 for (size_t i = 0; i < dimensions; i++) {
1985 if (i != 0) {
1986 sqlite3_str_appendallsqlite3_api->str_appendall(str, ",");
1987 }
1988 if (elementType == SQLITE_VEC_ELEMENT_TYPE_FLOAT32) {
1989 f32 value = ((f32 *)vector)[i];
1990 if (isnan(value)__builtin_isnan (value)) {
1991 sqlite3_str_appendallsqlite3_api->str_appendall(str, "null");
1992 } else {
1993 sqlite3_str_appendfsqlite3_api->str_appendf(str, "%f", value);
1994 }
1995
1996 } else if (elementType == SQLITE_VEC_ELEMENT_TYPE_INT8) {
1997 sqlite3_str_appendfsqlite3_api->str_appendf(str, "%d", ((i8 *)vector)[i]);
1998 } else if (elementType == SQLITE_VEC_ELEMENT_TYPE_BIT) {
1999 u8 b = (((u8 *)vector)[i / 8] >> (i % CHAR_BIT8)) & 1;
2000 sqlite3_str_appendfsqlite3_api->str_appendf(str, "%d", b);
2001 }
2002 }
2003 sqlite3_str_appendallsqlite3_api->str_appendall(str, "]");
2004 int len = sqlite3_str_lengthsqlite3_api->str_length(str);
2005 char *s = sqlite3_str_finishsqlite3_api->str_finish(str);
2006 if (s) {
2007 sqlite3_result_textsqlite3_api->result_text(context, s, len, sqlite3_freesqlite3_api->free);
2008 sqlite3_result_subtypesqlite3_api->result_subtype(context, JSON_SUBTYPE74);
2009 } else {
2010 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
2011 }
2012 cleanup(vector);
2013}
2014
2015static void vec_normalize(sqlite3_context *context, int argc,
2016 sqlite3_value **argv) {
2017 assert(argc == 1)((void) sizeof ((argc == 1) ? 1 : 0), __extension__ ({ if (argc
== 1) ; else __assert_fail ("argc == 1", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 2017, __extension__ __PRETTY_FUNCTION__); }))
;
2018 void *vector;
2019 size_t dimensions;
2020 vector_cleanup cleanup;
2021 char *err;
2022 enum VectorElementType elementType;
2023
2024 int rc = vector_from_value(argv[0], &vector, &dimensions, &elementType,
2025 &cleanup, &err);
2026 if (rc != SQLITE_OK0) {
2027 sqlite3_result_errorsqlite3_api->result_error(context, err, -1);
2028 sqlite3_freesqlite3_api->free(err);
2029 return;
2030 }
2031
2032 if (elementType != SQLITE_VEC_ELEMENT_TYPE_FLOAT32) {
2033 sqlite3_result_errorsqlite3_api->result_error(
2034 context, "only float32 vectors are supported when normalizing", -1);
2035 cleanup(vector);
2036 return;
2037 }
2038
2039 int outSize = dimensions * sizeof(f32);
2040 f32 *out = sqlite3_mallocsqlite3_api->malloc(outSize);
2041 if (!out) {
2042 cleanup(vector);
2043 sqlite3_result_error_codesqlite3_api->result_error_code(context, SQLITE_NOMEM7);
2044 return;
2045 }
2046 memset(out, 0, outSize);
2047
2048 f32 *v = (f32 *)vector;
2049
2050 f32 norm = 0;
2051 for (size_t i = 0; i < dimensions; i++) {
2052 norm += v[i] * v[i];
2053 }
2054 norm = sqrt(norm);
2055 for (size_t i = 0; i < dimensions; i++) {
2056 out[i] = v[i] / norm;
2057 }
2058
2059 sqlite3_result_blobsqlite3_api->result_blob(context, out, dimensions * sizeof(f32), sqlite3_freesqlite3_api->free);
2060 sqlite3_result_subtypesqlite3_api->result_subtype(context, SQLITE_VEC_ELEMENT_TYPE_FLOAT32);
2061 cleanup(vector);
2062}
2063
2064static void _static_text_func(sqlite3_context *context, int argc,
2065 sqlite3_value **argv) {
2066 UNUSED_PARAMETER(argc)(void)(argc);
2067 UNUSED_PARAMETER(argv)(void)(argv);
2068 sqlite3_result_textsqlite3_api->result_text(context, sqlite3_user_datasqlite3_api->user_data(context), -1, SQLITE_STATIC((sqlite3_destructor_type)0));
2069}
2070
2071#pragma endregion
2072
2073enum Vec0TokenType {
2074 TOKEN_TYPE_IDENTIFIER,
2075 TOKEN_TYPE_DIGIT,
2076 TOKEN_TYPE_LBRACKET,
2077 TOKEN_TYPE_RBRACKET,
2078 TOKEN_TYPE_PLUS,
2079 TOKEN_TYPE_EQ,
2080 TOKEN_TYPE_LPAREN,
2081 TOKEN_TYPE_RPAREN,
2082 TOKEN_TYPE_COMMA,
2083};
2084struct Vec0Token {
2085 enum Vec0TokenType token_type;
2086 char *start;
2087 char *end;
2088};
2089
2090int is_alpha(char x) {
2091 return (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z');
2092}
2093int is_digit(char x) { return (x >= '0' && x <= '9'); }
2094int is_whitespace(char x) {
2095 return x == ' ' || x == '\t' || x == '\n' || x == '\r';
2096}
2097
2098#define VEC0_TOKEN_RESULT_EOF1 1
2099#define VEC0_TOKEN_RESULT_SOME2 2
2100#define VEC0_TOKEN_RESULT_ERROR3 3
2101
2102int vec0_token_next(char *start, char *end, struct Vec0Token *out) {
2103 char *ptr = start;
2104 while (ptr < end) {
8
Loop condition is false. Execution continues on line 2173
2105 char curr = *ptr;
2106 if (is_whitespace(curr)) {
2107 ptr++;
2108 continue;
2109 } else if (curr == '+') {
2110 ptr++;
2111 out->start = ptr;
2112 out->end = ptr;
2113 out->token_type = TOKEN_TYPE_PLUS;
2114 return VEC0_TOKEN_RESULT_SOME2;
2115 } else if (curr == '[') {
2116 ptr++;
2117 out->start = ptr;
2118 out->end = ptr;
2119 out->token_type = TOKEN_TYPE_LBRACKET;
2120 return VEC0_TOKEN_RESULT_SOME2;
2121 } else if (curr == ']') {
2122 ptr++;
2123 out->start = ptr;
2124 out->end = ptr;
2125 out->token_type = TOKEN_TYPE_RBRACKET;
2126 return VEC0_TOKEN_RESULT_SOME2;
2127 } else if (curr == '=') {
2128 ptr++;
2129 out->start = ptr;
2130 out->end = ptr;
2131 out->token_type = TOKEN_TYPE_EQ;
2132 return VEC0_TOKEN_RESULT_SOME2;
2133 } else if (curr == '(') {
2134 ptr++;
2135 out->start = ptr;
2136 out->end = ptr;
2137 out->token_type = TOKEN_TYPE_LPAREN;
2138 return VEC0_TOKEN_RESULT_SOME2;
2139 } else if (curr == ')') {
2140 ptr++;
2141 out->start = ptr;
2142 out->end = ptr;
2143 out->token_type = TOKEN_TYPE_RPAREN;
2144 return VEC0_TOKEN_RESULT_SOME2;
2145 } else if (curr == ',') {
2146 ptr++;
2147 out->start = ptr;
2148 out->end = ptr;
2149 out->token_type = TOKEN_TYPE_COMMA;
2150 return VEC0_TOKEN_RESULT_SOME2;
2151 } else if (is_alpha(curr)) {
2152 char *start = ptr;
2153 while (ptr < end && (is_alpha(*ptr) || is_digit(*ptr) || *ptr == '_')) {
2154 ptr++;
2155 }
2156 out->start = start;
2157 out->end = ptr;
2158 out->token_type = TOKEN_TYPE_IDENTIFIER;
2159 return VEC0_TOKEN_RESULT_SOME2;
2160 } else if (is_digit(curr)) {
2161 char *start = ptr;
2162 while (ptr < end && (is_digit(*ptr))) {
2163 ptr++;
2164 }
2165 out->start = start;
2166 out->end = ptr;
2167 out->token_type = TOKEN_TYPE_DIGIT;
2168 return VEC0_TOKEN_RESULT_SOME2;
2169 } else {
2170 return VEC0_TOKEN_RESULT_ERROR3;
2171 }
2172 }
2173 return VEC0_TOKEN_RESULT_EOF1;
9
Returning without writing to 'out->token_type'
2174}
2175
2176struct Vec0Scanner {
2177 char *start;
2178 char *end;
2179 char *ptr;
2180};
2181
2182void vec0_scanner_init(struct Vec0Scanner *scanner, const char *source,
2183 int source_length) {
2184 scanner->start = (char *)source;
2185 scanner->end = (char *)source + source_length;
2186 scanner->ptr = (char *)source;
2187}
2188int vec0_scanner_next(struct Vec0Scanner *scanner, struct Vec0Token *out) {
2189 int rc = vec0_token_next(scanner->start, scanner->end, out);
7
Calling 'vec0_token_next'
10
Returning from 'vec0_token_next'
2190 if (rc
10.1
'rc' is not equal to VEC0_TOKEN_RESULT_SOME
== VEC0_TOKEN_RESULT_SOME2) {
11
Taking false branch
2191 scanner->start = out->end;
2192 }
2193 return rc;
12
Returning without writing to 'out->token_type'
2194}
2195
2196int vec0_parse_table_option(const char *source, int source_length,
2197 char **out_key, int *out_key_length,
2198 char **out_value, int *out_value_length) {
2199 int rc;
2200 struct Vec0Scanner scanner;
2201 struct Vec0Token token;
2202 char *key;
2203 char *value;
2204 int keyLength, valueLength;
2205
2206 vec0_scanner_init(&scanner, source, source_length);
2207
2208 rc = vec0_scanner_next(&scanner, &token);
2209 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2210 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2211 return SQLITE_EMPTY16;
2212 }
2213 key = token.start;
2214 keyLength = token.end - token.start;
2215
2216 rc = vec0_scanner_next(&scanner, &token);
2217 if (rc != VEC0_TOKEN_RESULT_SOME2 && token.token_type != TOKEN_TYPE_EQ) {
2218 return SQLITE_EMPTY16;
2219 }
2220
2221 rc = vec0_scanner_next(&scanner, &token);
2222 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2223 !((token.token_type == TOKEN_TYPE_IDENTIFIER) ||
2224 (token.token_type == TOKEN_TYPE_DIGIT))) {
2225 return SQLITE_ERROR1;
2226 }
2227 value = token.start;
2228 valueLength = token.end - token.start;
2229
2230 rc = vec0_scanner_next(&scanner, &token);
2231 if (rc == VEC0_TOKEN_RESULT_EOF1) {
2232 *out_key = key;
2233 *out_key_length = keyLength;
2234 *out_value = value;
2235 *out_value_length = valueLength;
2236 return SQLITE_OK0;
2237 }
2238 return SQLITE_ERROR1;
2239}
2240/**
2241 * @brief Parse an argv[i] entry of a vec0 virtual table definition, and see if
2242 * it's a PARTITION KEY definition.
2243 *
2244 * @param source: argv[i] source string
2245 * @param source_length: length of the source string
2246 * @param out_column_name: If it is a partition key, the output column name. Same lifetime
2247 * as source, points to specific char *
2248 * @param out_column_name_length: Length of out_column_name in bytes
2249 * @param out_column_type: SQLITE_TEXT or SQLITE_INTEGER.
2250 * @return int: SQLITE_EMPTY if not a PK, SQLITE_OK if it is.
2251 */
2252int vec0_parse_partition_key_definition(const char *source, int source_length,
2253 char **out_column_name,
2254 int *out_column_name_length,
2255 int *out_column_type) {
2256 struct Vec0Scanner scanner;
2257 struct Vec0Token token;
2258 char *column_name;
2259 int column_name_length;
2260 int column_type;
2261 vec0_scanner_init(&scanner, source, source_length);
2262
2263 // Check first token is identifier, will be the column name
2264 int rc = vec0_scanner_next(&scanner, &token);
2265 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2266 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2267 return SQLITE_EMPTY16;
2268 }
2269
2270 column_name = token.start;
2271 column_name_length = token.end - token.start;
2272
2273 // Check the next token matches "text" or "integer", as column type
2274 rc = vec0_scanner_next(&scanner, &token);
2275 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2276 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2277 return SQLITE_EMPTY16;
2278 }
2279 if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "text", token.end - token.start) == 0) {
2280 column_type = SQLITE_TEXT3;
2281 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "int", token.end - token.start) ==
2282 0 ||
2283 sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "integer",
2284 token.end - token.start) == 0) {
2285 column_type = SQLITE_INTEGER1;
2286 } else {
2287 return SQLITE_EMPTY16;
2288 }
2289
2290 // Check the next token is identifier and matches "partition"
2291 rc = vec0_scanner_next(&scanner, &token);
2292 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2293 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2294 return SQLITE_EMPTY16;
2295 }
2296 if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "partition", token.end - token.start) != 0) {
2297 return SQLITE_EMPTY16;
2298 }
2299
2300 // Check the next token is identifier and matches "key"
2301 rc = vec0_scanner_next(&scanner, &token);
2302 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2303 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2304 return SQLITE_EMPTY16;
2305 }
2306 if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "key", token.end - token.start) != 0) {
2307 return SQLITE_EMPTY16;
2308 }
2309
2310 *out_column_name = column_name;
2311 *out_column_name_length = column_name_length;
2312 *out_column_type = column_type;
2313
2314 return SQLITE_OK0;
2315}
2316
2317/**
2318 * @brief Parse an argv[i] entry of a vec0 virtual table definition, and see if
2319 * it's an auxiliar column definition, ie `+[name] [type]` like `+contents text`
2320 *
2321 * @param source: argv[i] source string
2322 * @param source_length: length of the source string
2323 * @param out_column_name: If it is a partition key, the output column name. Same lifetime
2324 * as source, points to specific char *
2325 * @param out_column_name_length: Length of out_column_name in bytes
2326 * @param out_column_type: SQLITE_TEXT, SQLITE_INTEGER, SQLITE_FLOAT, or SQLITE_BLOB.
2327 * @return int: SQLITE_EMPTY if not an aux column, SQLITE_OK if it is.
2328 */
2329int vec0_parse_auxiliary_column_definition(const char *source, int source_length,
2330 char **out_column_name,
2331 int *out_column_name_length,
2332 int *out_column_type) {
2333 struct Vec0Scanner scanner;
2334 struct Vec0Token token;
2335 char *column_name;
2336 int column_name_length;
2337 int column_type;
2338 vec0_scanner_init(&scanner, source, source_length);
2339
2340 // Check first token is '+', which denotes aux columns
2341 int rc = vec0_scanner_next(&scanner, &token);
2342 if (rc != VEC0_TOKEN_RESULT_SOME2 ||
2343 token.token_type != TOKEN_TYPE_PLUS) {
2344 return SQLITE_EMPTY16;
2345 }
2346
2347 rc = vec0_scanner_next(&scanner, &token);
2348 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2349 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2350 return SQLITE_EMPTY16;
2351 }
2352
2353 column_name = token.start;
2354 column_name_length = token.end - token.start;
2355
2356 // Check the next token matches "text" or "integer", as column type
2357 rc = vec0_scanner_next(&scanner, &token);
2358 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2359 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2360 return SQLITE_EMPTY16;
2361 }
2362 if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "text", token.end - token.start) == 0) {
2363 column_type = SQLITE_TEXT3;
2364 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "int", token.end - token.start) ==
2365 0 ||
2366 sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "integer",
2367 token.end - token.start) == 0) {
2368 column_type = SQLITE_INTEGER1;
2369 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "float", token.end - token.start) ==
2370 0 ||
2371 sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "double",
2372 token.end - token.start) == 0) {
2373 column_type = SQLITE_FLOAT2;
2374 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "blob", token.end - token.start) ==0) {
2375 column_type = SQLITE_BLOB4;
2376 } else {
2377 return SQLITE_EMPTY16;
2378 }
2379
2380 *out_column_name = column_name;
2381 *out_column_name_length = column_name_length;
2382 *out_column_type = column_type;
2383
2384 return SQLITE_OK0;
2385}
2386
2387typedef enum {
2388 VEC0_METADATA_COLUMN_KIND_BOOLEAN,
2389 VEC0_METADATA_COLUMN_KIND_INTEGER,
2390 VEC0_METADATA_COLUMN_KIND_FLOAT,
2391 VEC0_METADATA_COLUMN_KIND_TEXT,
2392 // future: blob, date, datetime
2393} vec0_metadata_column_kind;
2394
2395/**
2396 * @brief Parse an argv[i] entry of a vec0 virtual table definition, and see if
2397 * it's an metadata column definition, ie `[name] [type]` like `is_released boolean`
2398 *
2399 * @param source: argv[i] source string
2400 * @param source_length: length of the source string
2401 * @param out_column_name: If it is a metadata column, the output column name. Same lifetime
2402 * as source, points to specific char *
2403 * @param out_column_name_length: Length of out_column_name in bytes
2404 * @param out_column_type: one of vec0_metadata_column_kind
2405 * @return int: SQLITE_EMPTY if not an metadata column, SQLITE_OK if it is.
2406 */
2407int vec0_parse_metadata_column_definition(const char *source, int source_length,
2408 char **out_column_name,
2409 int *out_column_name_length,
2410 vec0_metadata_column_kind *out_column_type) {
2411 struct Vec0Scanner scanner;
2412 struct Vec0Token token;
2413 char *column_name;
2414 int column_name_length;
2415 vec0_metadata_column_kind column_type;
2416 int rc;
2417 vec0_scanner_init(&scanner, source, source_length);
2418
2419 rc = vec0_scanner_next(&scanner, &token);
2420 if (rc != VEC0_TOKEN_RESULT_SOME2 ||
2421 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2422 return SQLITE_EMPTY16;
2423 }
2424
2425 column_name = token.start;
2426 column_name_length = token.end - token.start;
2427
2428 // Check the next token matches a valid metadata type
2429 rc = vec0_scanner_next(&scanner, &token);
2430 if (rc != VEC0_TOKEN_RESULT_SOME2 ||
2431 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2432 return SQLITE_EMPTY16;
2433 }
2434 char * t = token.start;
2435 int n = token.end - token.start;
2436 if (sqlite3_strnicmpsqlite3_api->strnicmp(t, "boolean", n) == 0 || sqlite3_strnicmpsqlite3_api->strnicmp(t, "bool", n) == 0) {
2437 column_type = VEC0_METADATA_COLUMN_KIND_BOOLEAN;
2438 }else if (sqlite3_strnicmpsqlite3_api->strnicmp(t, "int64", n) == 0 || sqlite3_strnicmpsqlite3_api->strnicmp(t, "integer64", n) == 0 || sqlite3_strnicmpsqlite3_api->strnicmp(t, "integer", n) == 0 || sqlite3_strnicmpsqlite3_api->strnicmp(t, "int", n) == 0) {
2439 column_type = VEC0_METADATA_COLUMN_KIND_INTEGER;
2440 }else if (sqlite3_strnicmpsqlite3_api->strnicmp(t, "float", n) == 0 || sqlite3_strnicmpsqlite3_api->strnicmp(t, "double", n) == 0 || sqlite3_strnicmpsqlite3_api->strnicmp(t, "float64", n) == 0 || sqlite3_strnicmpsqlite3_api->strnicmp(t, "f64", n) == 0) {
2441 column_type = VEC0_METADATA_COLUMN_KIND_FLOAT;
2442 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(t, "text", n) == 0) {
2443 column_type = VEC0_METADATA_COLUMN_KIND_TEXT;
2444 } else {
2445 return SQLITE_EMPTY16;
2446 }
2447
2448 *out_column_name = column_name;
2449 *out_column_name_length = column_name_length;
2450 *out_column_type = column_type;
2451
2452 return SQLITE_OK0;
2453}
2454
2455/**
2456 * @brief Parse an argv[i] entry of a vec0 virtual table definition, and see if
2457 * it's a PRIMARY KEY definition.
2458 *
2459 * @param source: argv[i] source string
2460 * @param source_length: length of the source string
2461 * @param out_column_name: If it is a PK, the output column name. Same lifetime
2462 * as source, points to specific char *
2463 * @param out_column_name_length: Length of out_column_name in bytes
2464 * @param out_column_type: SQLITE_TEXT or SQLITE_INTEGER.
2465 * @return int: SQLITE_EMPTY if not a PK, SQLITE_OK if it is.
2466 */
2467int vec0_parse_primary_key_definition(const char *source, int source_length,
2468 char **out_column_name,
2469 int *out_column_name_length,
2470 int *out_column_type) {
2471 struct Vec0Scanner scanner;
2472 struct Vec0Token token;
2473 char *column_name;
2474 int column_name_length;
2475 int column_type;
2476 vec0_scanner_init(&scanner, source, source_length);
2477
2478 // Check first token is identifier, will be the column name
2479 int rc = vec0_scanner_next(&scanner, &token);
2480 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2481 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2482 return SQLITE_EMPTY16;
2483 }
2484
2485 column_name = token.start;
2486 column_name_length = token.end - token.start;
2487
2488 // Check the next token matches "text" or "integer", as column type
2489 rc = vec0_scanner_next(&scanner, &token);
2490 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2491 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2492 return SQLITE_EMPTY16;
2493 }
2494 if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "text", token.end - token.start) == 0) {
2495 column_type = SQLITE_TEXT3;
2496 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "int", token.end - token.start) ==
2497 0 ||
2498 sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "integer",
2499 token.end - token.start) == 0) {
2500 column_type = SQLITE_INTEGER1;
2501 } else {
2502 return SQLITE_EMPTY16;
2503 }
2504
2505 // Check the next token is identifier and matches "primary"
2506 rc = vec0_scanner_next(&scanner, &token);
2507 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2508 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2509 return SQLITE_EMPTY16;
2510 }
2511 if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "primary", token.end - token.start) != 0) {
2512 return SQLITE_EMPTY16;
2513 }
2514
2515 // Check the next token is identifier and matches "key"
2516 rc = vec0_scanner_next(&scanner, &token);
2517 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
2518 token.token_type != TOKEN_TYPE_IDENTIFIER) {
2519 return SQLITE_EMPTY16;
2520 }
2521 if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "key", token.end - token.start) != 0) {
2522 return SQLITE_EMPTY16;
2523 }
2524
2525 *out_column_name = column_name;
2526 *out_column_name_length = column_name_length;
2527 *out_column_type = column_type;
2528
2529 return SQLITE_OK0;
2530}
2531
2532enum Vec0DistanceMetrics {
2533 VEC0_DISTANCE_METRIC_L2 = 1,
2534 VEC0_DISTANCE_METRIC_COSINE = 2,
2535 VEC0_DISTANCE_METRIC_L1 = 3,
2536};
2537
2538/**
2539 * Compute distance between two full-precision vectors using the appropriate
2540 * distance function for the given element type and metric.
2541 * Shared utility used by ANN index implementations.
2542 */
2543static f32 vec0_distance_full(
2544 const void *a, const void *b, size_t dimensions,
2545 enum VectorElementType elementType,
2546 enum Vec0DistanceMetrics metric) {
2547 switch (elementType) {
2548 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32:
2549 switch (metric) {
2550 case VEC0_DISTANCE_METRIC_L2:
2551 return distance_l2_sqr_float(a, b, &dimensions);
2552 case VEC0_DISTANCE_METRIC_COSINE:
2553 return distance_cosine_float(a, b, &dimensions);
2554 case VEC0_DISTANCE_METRIC_L1:
2555 return (f32)distance_l1_f32(a, b, &dimensions);
2556 }
2557 break;
2558 case SQLITE_VEC_ELEMENT_TYPE_INT8:
2559 switch (metric) {
2560 case VEC0_DISTANCE_METRIC_L2:
2561 return distance_l2_sqr_int8(a, b, &dimensions);
2562 case VEC0_DISTANCE_METRIC_COSINE:
2563 return distance_cosine_int8(a, b, &dimensions);
2564 case VEC0_DISTANCE_METRIC_L1:
2565 return (f32)distance_l1_int8(a, b, &dimensions);
2566 }
2567 break;
2568 case SQLITE_VEC_ELEMENT_TYPE_BIT:
2569 return distance_hamming(a, b, &dimensions);
2570 }
2571 return 0.0f;
2572}
2573
2574enum Vec0IndexType {
2575 VEC0_INDEX_TYPE_FLAT = 1,
2576#if SQLITE_VEC_ENABLE_RESCORE1
2577 VEC0_INDEX_TYPE_RESCORE = 2,
2578#endif
2579 VEC0_INDEX_TYPE_IVF = 3,
2580 VEC0_INDEX_TYPE_DISKANN = 4,
2581};
2582
2583#if SQLITE_VEC_ENABLE_RESCORE1
2584enum Vec0RescoreQuantizerType {
2585 VEC0_RESCORE_QUANTIZER_BIT = 1,
2586 VEC0_RESCORE_QUANTIZER_INT8 = 2,
2587};
2588
2589struct Vec0RescoreConfig {
2590 enum Vec0RescoreQuantizerType quantizer_type;
2591 int oversample; // CREATE-time default
2592 int oversample_search; // runtime override (0 = use default)
2593};
2594#endif
2595
2596#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
2597enum Vec0IvfQuantizer {
2598 VEC0_IVF_QUANTIZER_NONE = 0,
2599 VEC0_IVF_QUANTIZER_INT8 = 1,
2600 VEC0_IVF_QUANTIZER_BINARY = 2,
2601};
2602
2603struct Vec0IvfConfig {
2604 int nlist; // number of centroids (0 = deferred)
2605 int nprobe; // cells to probe at query time
2606 int quantizer; // VEC0_IVF_QUANTIZER_NONE / INT8 / BINARY
2607 int oversample; // >= 1 (1 = no oversampling)
2608};
2609#else
2610struct Vec0IvfConfig { char _unused; };
2611#endif
2612
2613// ============================================================
2614// DiskANN types and constants
2615// ============================================================
2616
2617#define VEC0_DISKANN_DEFAULT_N_NEIGHBORS72 72
2618#define VEC0_DISKANN_MAX_N_NEIGHBORS256 256
2619#define VEC0_DISKANN_DEFAULT_SEARCH_LIST_SIZE128 128
2620#define VEC0_DISKANN_DEFAULT_ALPHA1.2f 1.2f
2621
2622/**
2623 * Quantizer type used for compressing neighbor vectors in the DiskANN graph.
2624 */
2625enum Vec0DiskannQuantizerType {
2626 VEC0_DISKANN_QUANTIZER_BINARY = 1, // 1 bit per dimension (1/32 compression)
2627 VEC0_DISKANN_QUANTIZER_INT8 = 2, // 1 byte per dimension (1/4 compression)
2628};
2629
2630/**
2631 * Configuration for a DiskANN index on a single vector column.
2632 * Parsed from `INDEXED BY diskann(neighbor_quantizer=binary, n_neighbors=72)`.
2633 */
2634struct Vec0DiskannConfig {
2635 // Quantizer type for neighbor vectors
2636 enum Vec0DiskannQuantizerType quantizer_type;
2637
2638 // Maximum number of neighbors per node (R in the paper). Must be divisible by 8.
2639 int n_neighbors;
2640
2641 // Search list size (L in the paper) — unified default for both insert and query.
2642 int search_list_size;
2643
2644 // Per-path overrides (0 = fall back to search_list_size).
2645 int search_list_size_search;
2646 int search_list_size_insert;
2647
2648 // Alpha parameter for RobustPrune (distance scaling factor, typically 1.0-1.5)
2649 f32 alpha;
2650
2651 // Buffer threshold for batched inserts. When > 0, inserts go into a flat
2652 // buffer table and are flushed into the graph when the buffer reaches this
2653 // size. 0 = disabled (legacy per-row insert behavior).
2654 int buffer_threshold;
2655};
2656
2657/**
2658 * Represents a single candidate during greedy beam search.
2659 * Used in priority queues / sorted arrays during LM-Search.
2660 */
2661struct Vec0DiskannCandidate {
2662 i64 rowid;
2663 f32 distance;
2664 int visited; // 1 if this candidate's neighbors have been explored
2665 int confirmed; // 1 if full-precision vector was successfully read (node exists)
2666};
2667
2668/**
2669 * Returns the byte size of a quantized vector for the given quantizer type
2670 * and number of dimensions.
2671 */
2672size_t diskann_quantized_vector_byte_size(
2673 enum Vec0DiskannQuantizerType quantizer_type, size_t dimensions) {
2674 switch (quantizer_type) {
2675 case VEC0_DISKANN_QUANTIZER_BINARY:
2676 return dimensions / CHAR_BIT8; // 1 bit per dimension
2677 case VEC0_DISKANN_QUANTIZER_INT8:
2678 return dimensions * sizeof(i8); // 1 byte per dimension
2679 }
2680 return 0;
2681}
2682
2683struct VectorColumnDefinition {
2684 char *name;
2685 int name_length;
2686 size_t dimensions;
2687 enum VectorElementType element_type;
2688 enum Vec0DistanceMetrics distance_metric;
2689 enum Vec0IndexType index_type;
2690#if SQLITE_VEC_ENABLE_RESCORE1
2691 struct Vec0RescoreConfig rescore;
2692#endif
2693 struct Vec0IvfConfig ivf;
2694 struct Vec0DiskannConfig diskann;
2695};
2696
2697struct Vec0PartitionColumnDefinition {
2698 int type;
2699 char * name;
2700 int name_length;
2701};
2702
2703struct Vec0AuxiliaryColumnDefinition {
2704 int type;
2705 char * name;
2706 int name_length;
2707};
2708struct Vec0MetadataColumnDefinition {
2709 vec0_metadata_column_kind kind;
2710 char * name;
2711 int name_length;
2712};
2713
2714size_t vector_byte_size(enum VectorElementType element_type,
2715 size_t dimensions) {
2716 switch (element_type) {
2717 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32:
2718 return dimensions * sizeof(f32);
2719 case SQLITE_VEC_ELEMENT_TYPE_INT8:
2720 return dimensions * sizeof(i8);
2721 case SQLITE_VEC_ELEMENT_TYPE_BIT:
2722 return dimensions / CHAR_BIT8;
2723 }
2724 return 0;
2725}
2726
2727size_t vector_column_byte_size(struct VectorColumnDefinition column) {
2728 return vector_byte_size(column.element_type, column.dimensions);
2729}
2730
2731#if SQLITE_VEC_ENABLE_RESCORE1
2732/**
2733 * @brief Parse rescore options from an "INDEXED BY rescore(...)" clause.
2734 *
2735 * @param scanner Scanner positioned right after the opening '(' of rescore(...)
2736 * @param outConfig Output rescore config
2737 * @param pzErr Error message output
2738 * @return int SQLITE_OK on success, SQLITE_ERROR on error.
2739 */
2740static int vec0_parse_rescore_options(struct Vec0Scanner *scanner,
2741 struct Vec0RescoreConfig *outConfig,
2742 char **pzErr) {
2743 struct Vec0Token token;
2744 int rc;
2745 int hasQuantizer = 0;
2746 outConfig->oversample = 8;
2747 outConfig->quantizer_type = 0;
2748
2749 while (1) {
2750 rc = vec0_scanner_next(scanner, &token);
2751 if (rc == VEC0_TOKEN_RESULT_EOF1) {
2752 break;
2753 }
2754 // ')' closes rescore options
2755 if (rc == VEC0_TOKEN_RESULT_SOME2 && token.token_type == TOKEN_TYPE_RPAREN) {
2756 break;
2757 }
2758 if (rc != VEC0_TOKEN_RESULT_SOME2 || token.token_type != TOKEN_TYPE_IDENTIFIER) {
2759 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Expected option name in rescore(...)");
2760 return SQLITE_ERROR1;
2761 }
2762
2763 char *key = token.start;
2764 int keyLength = token.end - token.start;
2765
2766 // expect '='
2767 rc = vec0_scanner_next(scanner, &token);
2768 if (rc != VEC0_TOKEN_RESULT_SOME2 || token.token_type != TOKEN_TYPE_EQ) {
2769 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Expected '=' after option name in rescore(...)");
2770 return SQLITE_ERROR1;
2771 }
2772
2773 // value
2774 rc = vec0_scanner_next(scanner, &token);
2775 if (rc != VEC0_TOKEN_RESULT_SOME2) {
2776 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Expected value after '=' in rescore(...)");
2777 return SQLITE_ERROR1;
2778 }
2779
2780 if (sqlite3_strnicmpsqlite3_api->strnicmp(key, "quantizer", keyLength) == 0) {
2781 if (token.token_type != TOKEN_TYPE_IDENTIFIER) {
2782 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Expected identifier for quantizer value in rescore(...)");
2783 return SQLITE_ERROR1;
2784 }
2785 int valLen = token.end - token.start;
2786 if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "bit", valLen) == 0) {
2787 outConfig->quantizer_type = VEC0_RESCORE_QUANTIZER_BIT;
2788 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "int8", valLen) == 0) {
2789 outConfig->quantizer_type = VEC0_RESCORE_QUANTIZER_INT8;
2790 } else {
2791 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Unknown quantizer type '%.*s' in rescore(...). Expected 'bit' or 'int8'.", valLen, token.start);
2792 return SQLITE_ERROR1;
2793 }
2794 hasQuantizer = 1;
2795 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(key, "oversample", keyLength) == 0) {
2796 if (token.token_type != TOKEN_TYPE_DIGIT) {
2797 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Expected integer for oversample value in rescore(...)");
2798 return SQLITE_ERROR1;
2799 }
2800 outConfig->oversample = atoi(token.start);
2801 if (outConfig->oversample <= 0 || outConfig->oversample > 128) {
2802 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("oversample in rescore(...) must be between 1 and 128, got %d", outConfig->oversample);
2803 return SQLITE_ERROR1;
2804 }
2805 } else {
2806 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Unknown option '%.*s' in rescore(...)", keyLength, key);
2807 return SQLITE_ERROR1;
2808 }
2809
2810 // optional comma between options
2811 rc = vec0_scanner_next(scanner, &token);
2812 if (rc == VEC0_TOKEN_RESULT_EOF1) {
2813 break;
2814 }
2815 if (rc == VEC0_TOKEN_RESULT_SOME2 && token.token_type == TOKEN_TYPE_RPAREN) {
2816 break;
2817 }
2818 if (rc == VEC0_TOKEN_RESULT_SOME2 && token.token_type == TOKEN_TYPE_COMMA) {
2819 continue;
2820 }
2821 // If it's not a comma or rparen, it might be the next key — push back isn't
2822 // possible with this scanner, so we'll treat unexpected tokens as errors
2823 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Unexpected token in rescore(...) options");
2824 return SQLITE_ERROR1;
2825 }
2826
2827 if (!hasQuantizer) {
2828 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("rescore(...) requires a 'quantizer' option (quantizer=bit or quantizer=int8)");
2829 return SQLITE_ERROR1;
2830 }
2831
2832 return SQLITE_OK0;
2833}
2834#endif /* SQLITE_VEC_ENABLE_RESCORE */
2835
2836/**
2837 * @brief Parse an vec0 vtab argv[i] column definition and see if
2838 * it's a vector column defintion, ex `contents_embedding float[768]`.
2839 *
2840 * @param source vec0 argv[i] item
2841 * @param source_length length of source in bytes
2842 * @param outColumn Output the parse vector column to this struct, if success
2843 * @return int SQLITE_OK on success, SQLITE_EMPTY is it's not a vector column
2844 * definition, SQLITE_ERROR on error.
2845 */
2846#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
2847// Forward declaration — defined in sqlite-vec-ivf.c
2848static int vec0_parse_ivf_options(struct Vec0Scanner *scanner,
2849 struct Vec0IvfConfig *config);
2850#endif
2851
2852/**
2853 * Parse the options inside diskann(...) parentheses.
2854 * Scanner should be positioned right before the '(' token.
2855 *
2856 * Recognized options:
2857 * neighbor_quantizer = binary | int8 (required)
2858 * n_neighbors = <integer> (optional, default 72)
2859 * search_list_size = <integer> (optional, default 128)
2860 */
2861static int vec0_parse_diskann_options(struct Vec0Scanner *scanner,
2862 struct Vec0DiskannConfig *config) {
2863 int rc;
2864 struct Vec0Token token;
2865 int hasQuantizer = 0;
2866
2867 // Set defaults
2868 config->n_neighbors = VEC0_DISKANN_DEFAULT_N_NEIGHBORS72;
2869 config->search_list_size = VEC0_DISKANN_DEFAULT_SEARCH_LIST_SIZE128;
2870 config->search_list_size_search = 0;
2871 config->search_list_size_insert = 0;
2872 config->alpha = VEC0_DISKANN_DEFAULT_ALPHA1.2f;
2873 config->buffer_threshold = 0;
2874 int hasSearchListSize = 0;
2875 int hasSearchListSizeSplit = 0;
2876
2877 // Expect '('
2878 rc = vec0_scanner_next(scanner, &token);
2879 if (rc != VEC0_TOKEN_RESULT_SOME2 || token.token_type != TOKEN_TYPE_LPAREN) {
2880 return SQLITE_ERROR1;
2881 }
2882
2883 while (1) {
2884 // key
2885 rc = vec0_scanner_next(scanner, &token);
2886 if (rc == VEC0_TOKEN_RESULT_SOME2 && token.token_type == TOKEN_TYPE_RPAREN) {
2887 break; // empty parens or trailing comma
2888 }
2889 if (rc != VEC0_TOKEN_RESULT_SOME2 || token.token_type != TOKEN_TYPE_IDENTIFIER) {
2890 return SQLITE_ERROR1;
2891 }
2892 char *optKey = token.start;
2893 int optKeyLen = token.end - token.start;
2894
2895 // '='
2896 rc = vec0_scanner_next(scanner, &token);
2897 if (rc != VEC0_TOKEN_RESULT_SOME2 || token.token_type != TOKEN_TYPE_EQ) {
2898 return SQLITE_ERROR1;
2899 }
2900
2901 // value (identifier or digit)
2902 rc = vec0_scanner_next(scanner, &token);
2903 if (rc != VEC0_TOKEN_RESULT_SOME2) {
2904 return SQLITE_ERROR1;
2905 }
2906 char *optVal = token.start;
2907 int optValLen = token.end - token.start;
2908
2909 if (sqlite3_strnicmpsqlite3_api->strnicmp(optKey, "neighbor_quantizer", optKeyLen) == 0) {
2910 if (sqlite3_strnicmpsqlite3_api->strnicmp(optVal, "binary", optValLen) == 0) {
2911 config->quantizer_type = VEC0_DISKANN_QUANTIZER_BINARY;
2912 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(optVal, "int8", optValLen) == 0) {
2913 config->quantizer_type = VEC0_DISKANN_QUANTIZER_INT8;
2914 } else {
2915 return SQLITE_ERROR1; // unknown quantizer
2916 }
2917 hasQuantizer = 1;
2918 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(optKey, "n_neighbors", optKeyLen) == 0) {
2919 config->n_neighbors = atoi(optVal);
2920 if (config->n_neighbors <= 0 || (config->n_neighbors % 8) != 0 ||
2921 config->n_neighbors > VEC0_DISKANN_MAX_N_NEIGHBORS256) {
2922 return SQLITE_ERROR1;
2923 }
2924 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(optKey, "search_list_size_search", optKeyLen) == 0 && optKeyLen == 23) {
2925 config->search_list_size_search = atoi(optVal);
2926 if (config->search_list_size_search <= 0) {
2927 return SQLITE_ERROR1;
2928 }
2929 hasSearchListSizeSplit = 1;
2930 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(optKey, "search_list_size_insert", optKeyLen) == 0 && optKeyLen == 23) {
2931 config->search_list_size_insert = atoi(optVal);
2932 if (config->search_list_size_insert <= 0) {
2933 return SQLITE_ERROR1;
2934 }
2935 hasSearchListSizeSplit = 1;
2936 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(optKey, "search_list_size", optKeyLen) == 0) {
2937 config->search_list_size = atoi(optVal);
2938 if (config->search_list_size <= 0) {
2939 return SQLITE_ERROR1;
2940 }
2941 hasSearchListSize = 1;
2942 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(optKey, "buffer_threshold", optKeyLen) == 0) {
2943 config->buffer_threshold = atoi(optVal);
2944 if (config->buffer_threshold < 0) {
2945 return SQLITE_ERROR1;
2946 }
2947 } else {
2948 return SQLITE_ERROR1; // unknown option
2949 }
2950
2951 // Expect ',' or ')'
2952 rc = vec0_scanner_next(scanner, &token);
2953 if (rc == VEC0_TOKEN_RESULT_SOME2 && token.token_type == TOKEN_TYPE_RPAREN) {
2954 break;
2955 }
2956 if (rc != VEC0_TOKEN_RESULT_SOME2 || token.token_type != TOKEN_TYPE_COMMA) {
2957 return SQLITE_ERROR1;
2958 }
2959 }
2960
2961 if (!hasQuantizer) {
2962 return SQLITE_ERROR1; // neighbor_quantizer is required
2963 }
2964
2965 if (hasSearchListSize && hasSearchListSizeSplit) {
2966 return SQLITE_ERROR1; // cannot mix search_list_size with search_list_size_search/insert
2967 }
2968
2969 return SQLITE_OK0;
2970}
2971
2972int vec0_parse_vector_column(const char *source, int source_length,
2973 struct VectorColumnDefinition *outColumn) {
2974 // parses a vector column definition like so:
2975 // "abc float[123]", "abc_123 bit[1234]", eetc.
2976 // https://github.com/asg017/sqlite-vec/issues/46
2977 int rc;
2978 struct Vec0Scanner scanner;
2979 struct Vec0Token token;
2980
2981 char *name;
2982 int nameLength;
2983 enum VectorElementType elementType;
2984 enum Vec0DistanceMetrics distanceMetric = VEC0_DISTANCE_METRIC_L2;
2985 enum Vec0IndexType indexType = VEC0_INDEX_TYPE_FLAT;
2986#if SQLITE_VEC_ENABLE_RESCORE1
2987 struct Vec0RescoreConfig rescoreConfig;
2988 memset(&rescoreConfig, 0, sizeof(rescoreConfig));
2989#endif
2990 struct Vec0IvfConfig ivfConfig;
2991 memset(&ivfConfig, 0, sizeof(ivfConfig));
2992 struct Vec0DiskannConfig diskannConfig;
2993 memset(&diskannConfig, 0, sizeof(diskannConfig));
2994 int dimensions;
2995 vec0_scanner_init(&scanner, source, source_length);
2996
2997 // starts with an identifier
2998 rc = vec0_scanner_next(&scanner, &token);
6
Calling 'vec0_scanner_next'
13
Returning from 'vec0_scanner_next'
2999
3000 if (rc
13.1
'rc' is not equal to VEC0_TOKEN_RESULT_SOME
!= VEC0_TOKEN_RESULT_SOME2 &&
3001 token.token_type != TOKEN_TYPE_IDENTIFIER) {
14
The left operand of '!=' is a garbage value
3002 return SQLITE_EMPTY16;
3003 }
3004
3005 name = token.start;
3006 nameLength = token.end - token.start;
3007
3008 // vector column type comes next: float, int, or bit
3009 rc = vec0_scanner_next(&scanner, &token);
3010
3011 if (rc != VEC0_TOKEN_RESULT_SOME2 ||
3012 token.token_type != TOKEN_TYPE_IDENTIFIER) {
3013 return SQLITE_EMPTY16;
3014 }
3015 if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "float", 5) == 0 ||
3016 sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "f32", 3) == 0) {
3017 elementType = SQLITE_VEC_ELEMENT_TYPE_FLOAT32;
3018 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "int8", 4) == 0 ||
3019 sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "i8", 2) == 0) {
3020 elementType = SQLITE_VEC_ELEMENT_TYPE_INT8;
3021 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "bit", 3) == 0) {
3022 elementType = SQLITE_VEC_ELEMENT_TYPE_BIT;
3023 } else {
3024 return SQLITE_EMPTY16;
3025 }
3026
3027 // left '[' bracket
3028 rc = vec0_scanner_next(&scanner, &token);
3029 if (rc != VEC0_TOKEN_RESULT_SOME2 && token.token_type != TOKEN_TYPE_LBRACKET) {
3030 return SQLITE_EMPTY16;
3031 }
3032
3033 // digit, for vector dimension length
3034 rc = vec0_scanner_next(&scanner, &token);
3035 if (rc != VEC0_TOKEN_RESULT_SOME2 && token.token_type != TOKEN_TYPE_DIGIT) {
3036 return SQLITE_ERROR1;
3037 }
3038 dimensions = atoi(token.start);
3039 if (dimensions <= 0) {
3040 return SQLITE_ERROR1;
3041 }
3042
3043 // // right ']' bracket
3044 rc = vec0_scanner_next(&scanner, &token);
3045 if (rc != VEC0_TOKEN_RESULT_SOME2 && token.token_type != TOKEN_TYPE_RBRACKET) {
3046 return SQLITE_ERROR1;
3047 }
3048
3049 // any other tokens left should be column-level options , ex `key=value`
3050 // ex `distance_metric=L2 distance_metric=cosine` should error
3051 while (1) {
3052 // should be EOF or identifier (option key)
3053 rc = vec0_scanner_next(&scanner, &token);
3054 if (rc == VEC0_TOKEN_RESULT_EOF1) {
3055 break;
3056 }
3057
3058 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
3059 token.token_type != TOKEN_TYPE_IDENTIFIER) {
3060 return SQLITE_ERROR1;
3061 }
3062
3063 char *key = token.start;
3064 int keyLength = token.end - token.start;
3065
3066 if (sqlite3_strnicmpsqlite3_api->strnicmp(key, "distance_metric", keyLength) == 0) {
3067
3068 if (elementType == SQLITE_VEC_ELEMENT_TYPE_BIT) {
3069 return SQLITE_ERROR1;
3070 }
3071 // ensure equal sign after distance_metric
3072 rc = vec0_scanner_next(&scanner, &token);
3073 if (rc != VEC0_TOKEN_RESULT_SOME2 && token.token_type != TOKEN_TYPE_EQ) {
3074 return SQLITE_ERROR1;
3075 }
3076
3077 // distance_metric value, an identifier (L2, cosine, etc)
3078 rc = vec0_scanner_next(&scanner, &token);
3079 if (rc != VEC0_TOKEN_RESULT_SOME2 &&
3080 token.token_type != TOKEN_TYPE_IDENTIFIER) {
3081 return SQLITE_ERROR1;
3082 }
3083
3084 char *value = token.start;
3085 int valueLength = token.end - token.start;
3086 if (sqlite3_strnicmpsqlite3_api->strnicmp(value, "l2", valueLength) == 0) {
3087 distanceMetric = VEC0_DISTANCE_METRIC_L2;
3088 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(value, "l1", valueLength) == 0) {
3089 distanceMetric = VEC0_DISTANCE_METRIC_L1;
3090 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(value, "cosine", valueLength) == 0) {
3091 distanceMetric = VEC0_DISTANCE_METRIC_COSINE;
3092 } else {
3093 return SQLITE_ERROR1;
3094 }
3095 }
3096 // INDEXED BY flat() | rescore(...)
3097 else if (sqlite3_strnicmpsqlite3_api->strnicmp(key, "indexed", keyLength) == 0) {
3098 // expect "by"
3099 rc = vec0_scanner_next(&scanner, &token);
3100 if (rc != VEC0_TOKEN_RESULT_SOME2 ||
3101 token.token_type != TOKEN_TYPE_IDENTIFIER ||
3102 sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "by", token.end - token.start) != 0) {
3103 return SQLITE_ERROR1;
3104 }
3105 // expect index type name
3106 rc = vec0_scanner_next(&scanner, &token);
3107 if (rc != VEC0_TOKEN_RESULT_SOME2 ||
3108 token.token_type != TOKEN_TYPE_IDENTIFIER) {
3109 return SQLITE_ERROR1;
3110 }
3111 int indexNameLen = token.end - token.start;
3112 if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "flat", indexNameLen) == 0) {
3113 indexType = VEC0_INDEX_TYPE_FLAT;
3114 // expect '('
3115 rc = vec0_scanner_next(&scanner, &token);
3116 if (rc != VEC0_TOKEN_RESULT_SOME2 ||
3117 token.token_type != TOKEN_TYPE_LPAREN) {
3118 return SQLITE_ERROR1;
3119 }
3120 // expect ')'
3121 rc = vec0_scanner_next(&scanner, &token);
3122 if (rc != VEC0_TOKEN_RESULT_SOME2 ||
3123 token.token_type != TOKEN_TYPE_RPAREN) {
3124 return SQLITE_ERROR1;
3125 }
3126 }
3127#if SQLITE_VEC_ENABLE_RESCORE1
3128 else if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "rescore", indexNameLen) == 0) {
3129 indexType = VEC0_INDEX_TYPE_RESCORE;
3130 if (elementType != SQLITE_VEC_ELEMENT_TYPE_FLOAT32) {
3131 return SQLITE_ERROR1;
3132 }
3133 // expect '('
3134 rc = vec0_scanner_next(&scanner, &token);
3135 if (rc != VEC0_TOKEN_RESULT_SOME2 || token.token_type != TOKEN_TYPE_LPAREN) {
3136 return SQLITE_ERROR1;
3137 }
3138 char *rescoreErr = NULL((void*)0);
3139 rc = vec0_parse_rescore_options(&scanner, &rescoreConfig, &rescoreErr);
3140 if (rc != SQLITE_OK0) {
3141 if (rescoreErr) sqlite3_freesqlite3_api->free(rescoreErr);
3142 return SQLITE_ERROR1;
3143 }
3144 // validate dimensions for bit quantizer
3145 if (rescoreConfig.quantizer_type == VEC0_RESCORE_QUANTIZER_BIT &&
3146 (dimensions % CHAR_BIT8) != 0) {
3147 return SQLITE_ERROR1;
3148 }
3149 }
3150#endif
3151 else if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "ivf", indexNameLen) == 0) {
3152#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
3153 indexType = VEC0_INDEX_TYPE_IVF;
3154 memset(&ivfConfig, 0, sizeof(ivfConfig));
3155 rc = vec0_parse_ivf_options(&scanner, &ivfConfig);
3156 if (rc != SQLITE_OK0) {
3157 return SQLITE_ERROR1;
3158 }
3159 if (ivfConfig.quantizer == VEC0_IVF_QUANTIZER_BINARY && (dimensions % 8) != 0) {
3160 return SQLITE_ERROR1;
3161 }
3162#else
3163 return SQLITE_ERROR1; // IVF not compiled in
3164#endif
3165 } else if (sqlite3_strnicmpsqlite3_api->strnicmp(token.start, "diskann", indexNameLen) == 0) {
3166#if SQLITE_VEC_ENABLE_DISKANN0
3167 indexType = VEC0_INDEX_TYPE_DISKANN;
3168 rc = vec0_parse_diskann_options(&scanner, &diskannConfig);
3169 if (rc != SQLITE_OK0) {
3170 return rc;
3171 }
3172#else
3173 return SQLITE_ERROR1;
3174#endif
3175 } else {
3176 // unknown index type
3177 return SQLITE_ERROR1;
3178 }
3179 }
3180 // unknown key
3181 else {
3182 return SQLITE_ERROR1;
3183 }
3184 }
3185
3186 outColumn->name = sqlite3_mprintfsqlite3_api->mprintf("%.*s", nameLength, name);
3187 if (!outColumn->name) {
3188 return SQLITE_ERROR1;
3189 }
3190 outColumn->name_length = nameLength;
3191 outColumn->distance_metric = distanceMetric;
3192 outColumn->element_type = elementType;
3193 outColumn->dimensions = dimensions;
3194 outColumn->index_type = indexType;
3195#if SQLITE_VEC_ENABLE_RESCORE1
3196 outColumn->rescore = rescoreConfig;
3197#endif
3198 outColumn->ivf = ivfConfig;
3199 outColumn->diskann = diskannConfig;
3200 return SQLITE_OK0;
3201}
3202
3203#pragma region vec_each table function
3204
3205typedef struct vec_each_vtab vec_each_vtab;
3206struct vec_each_vtab {
3207 sqlite3_vtab base;
3208};
3209
3210typedef struct vec_each_cursor vec_each_cursor;
3211struct vec_each_cursor {
3212 sqlite3_vtab_cursor base;
3213 i64 iRowid;
3214 enum VectorElementType vector_type;
3215 void *vector;
3216 size_t dimensions;
3217 vector_cleanup cleanup;
3218};
3219
3220static int vec_eachConnect(sqlite3 *db, void *pAux, int argc,
3221 const char *const *argv, sqlite3_vtab **ppVtab,
3222 char **pzErr) {
3223 UNUSED_PARAMETER(pAux)(void)(pAux);
3224 UNUSED_PARAMETER(argc)(void)(argc);
3225 UNUSED_PARAMETER(argv)(void)(argv);
3226 UNUSED_PARAMETER(pzErr)(void)(pzErr);
3227 vec_each_vtab *pNew;
3228 int rc;
3229
3230 rc = sqlite3_declare_vtabsqlite3_api->declare_vtab(db, "CREATE TABLE x(value, vector hidden)");
3231#define VEC_EACH_COLUMN_VALUE0 0
3232#define VEC_EACH_COLUMN_VECTOR1 1
3233 if (rc == SQLITE_OK0) {
3234 pNew = sqlite3_mallocsqlite3_api->malloc(sizeof(*pNew));
3235 *ppVtab = (sqlite3_vtab *)pNew;
3236 if (pNew == 0)
3237 return SQLITE_NOMEM7;
3238 memset(pNew, 0, sizeof(*pNew));
3239 }
3240 return rc;
3241}
3242
3243static int vec_eachDisconnect(sqlite3_vtab *pVtab) {
3244 vec_each_vtab *p = (vec_each_vtab *)pVtab;
3245 sqlite3_freesqlite3_api->free(p);
3246 return SQLITE_OK0;
3247}
3248
3249static int vec_eachOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor) {
3250 UNUSED_PARAMETER(p)(void)(p);
3251 vec_each_cursor *pCur;
3252 pCur = sqlite3_mallocsqlite3_api->malloc(sizeof(*pCur));
3253 if (pCur == 0)
3254 return SQLITE_NOMEM7;
3255 memset(pCur, 0, sizeof(*pCur));
3256 *ppCursor = &pCur->base;
3257 return SQLITE_OK0;
3258}
3259
3260static int vec_eachClose(sqlite3_vtab_cursor *cur) {
3261 vec_each_cursor *pCur = (vec_each_cursor *)cur;
3262 if(pCur->vector) {
3263 pCur->cleanup(pCur->vector);
3264 }
3265 sqlite3_freesqlite3_api->free(pCur);
3266 return SQLITE_OK0;
3267}
3268
3269static int vec_eachBestIndex(sqlite3_vtab *pVTab,
3270 sqlite3_index_info *pIdxInfo) {
3271 UNUSED_PARAMETER(pVTab)(void)(pVTab);
3272 int hasVector = 0;
3273 for (int i = 0; i < pIdxInfo->nConstraint; i++) {
3274 const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
3275 // printf("i=%d iColumn=%d, op=%d, usable=%d\n", i, pCons->iColumn,
3276 // pCons->op, pCons->usable);
3277 switch (pCons->iColumn) {
3278 case VEC_EACH_COLUMN_VECTOR1: {
3279 if (pCons->op == SQLITE_INDEX_CONSTRAINT_EQ2 && pCons->usable) {
3280 hasVector = 1;
3281 pIdxInfo->aConstraintUsage[i].argvIndex = 1;
3282 pIdxInfo->aConstraintUsage[i].omit = 1;
3283 }
3284 break;
3285 }
3286 }
3287 }
3288 if (!hasVector) {
3289 return SQLITE_CONSTRAINT19;
3290 }
3291
3292 pIdxInfo->estimatedCost = (double)100000;
3293 pIdxInfo->estimatedRows = 100000;
3294
3295 return SQLITE_OK0;
3296}
3297
3298static int vec_eachFilter(sqlite3_vtab_cursor *pVtabCursor, int idxNum,
3299 const char *idxStr, int argc, sqlite3_value **argv) {
3300 UNUSED_PARAMETER(idxNum)(void)(idxNum);
3301 UNUSED_PARAMETER(idxStr)(void)(idxStr);
3302 assert(argc == 1)((void) sizeof ((argc == 1) ? 1 : 0), __extension__ ({ if (argc
== 1) ; else __assert_fail ("argc == 1", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 3302, __extension__ __PRETTY_FUNCTION__); }))
;
3303 vec_each_cursor *pCur = (vec_each_cursor *)pVtabCursor;
3304
3305 if (pCur->vector) {
3306 pCur->cleanup(pCur->vector);
3307 pCur->vector = NULL((void*)0);
3308 }
3309
3310 char *pzErrMsg;
3311 int rc = vector_from_value(argv[0], &pCur->vector, &pCur->dimensions,
3312 &pCur->vector_type, &pCur->cleanup, &pzErrMsg);
3313 if (rc != SQLITE_OK0) {
3314 sqlite3_freesqlite3_api->free(pzErrMsg);
3315 return SQLITE_ERROR1;
3316 }
3317 pCur->iRowid = 0;
3318 return SQLITE_OK0;
3319}
3320
3321static int vec_eachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid) {
3322 vec_each_cursor *pCur = (vec_each_cursor *)cur;
3323 *pRowid = pCur->iRowid;
3324 return SQLITE_OK0;
3325}
3326
3327static int vec_eachEof(sqlite3_vtab_cursor *cur) {
3328 vec_each_cursor *pCur = (vec_each_cursor *)cur;
3329 return pCur->iRowid >= (i64)pCur->dimensions;
3330}
3331
3332static int vec_eachNext(sqlite3_vtab_cursor *cur) {
3333 vec_each_cursor *pCur = (vec_each_cursor *)cur;
3334 pCur->iRowid++;
3335 return SQLITE_OK0;
3336}
3337
3338static int vec_eachColumn(sqlite3_vtab_cursor *cur, sqlite3_context *context,
3339 int i) {
3340 vec_each_cursor *pCur = (vec_each_cursor *)cur;
3341 switch (i) {
3342 case VEC_EACH_COLUMN_VALUE0:
3343 switch (pCur->vector_type) {
3344 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32: {
3345 sqlite3_result_doublesqlite3_api->result_double(context, ((f32 *)pCur->vector)[pCur->iRowid]);
3346 break;
3347 }
3348 case SQLITE_VEC_ELEMENT_TYPE_BIT: {
3349 u8 x = ((u8 *)pCur->vector)[pCur->iRowid / CHAR_BIT8];
3350 sqlite3_result_intsqlite3_api->result_int(context,
3351 (x & (0b10000000 >> ((pCur->iRowid % CHAR_BIT8)))) > 0);
3352 break;
3353 }
3354 case SQLITE_VEC_ELEMENT_TYPE_INT8: {
3355 sqlite3_result_intsqlite3_api->result_int(context, ((i8 *)pCur->vector)[pCur->iRowid]);
3356 break;
3357 }
3358 }
3359
3360 break;
3361 }
3362 return SQLITE_OK0;
3363}
3364
3365static sqlite3_module vec_eachModule = {
3366 /* iVersion */ 0,
3367 /* xCreate */ 0,
3368 /* xConnect */ vec_eachConnect,
3369 /* xBestIndex */ vec_eachBestIndex,
3370 /* xDisconnect */ vec_eachDisconnect,
3371 /* xDestroy */ 0,
3372 /* xOpen */ vec_eachOpen,
3373 /* xClose */ vec_eachClose,
3374 /* xFilter */ vec_eachFilter,
3375 /* xNext */ vec_eachNext,
3376 /* xEof */ vec_eachEof,
3377 /* xColumn */ vec_eachColumn,
3378 /* xRowid */ vec_eachRowid,
3379 /* xUpdate */ 0,
3380 /* xBegin */ 0,
3381 /* xSync */ 0,
3382 /* xCommit */ 0,
3383 /* xRollback */ 0,
3384 /* xFindMethod */ 0,
3385 /* xRename */ 0,
3386 /* xSavepoint */ 0,
3387 /* xRelease */ 0,
3388 /* xRollbackTo */ 0,
3389 /* xShadowName */ 0,
3390#if SQLITE_VERSION_NUMBER3053002 >= 3044000
3391 /* xIntegrity */ 0
3392#endif
3393};
3394
3395#pragma endregion
3396
3397
3398
3399#pragma region vec0 virtual table
3400
3401#define VEC0_COLUMN_ID0 0
3402#define VEC0_COLUMN_USERN_START1 1
3403#define VEC0_COLUMN_OFFSET_COMMAND1 1
3404#define VEC0_COLUMN_OFFSET_DISTANCE2 2
3405#define VEC0_COLUMN_OFFSET_K3 3
3406
3407#define VEC0_SHADOW_INFO_NAME"\"%w\".\"%w_info\"" "\"%w\".\"%w_info\""
3408
3409#define VEC0_SHADOW_CHUNKS_NAME"\"%w\".\"%w_chunks\"" "\"%w\".\"%w_chunks\""
3410/// 1) schema, 2) original vtab table name
3411#define VEC0_SHADOW_CHUNKS_CREATE"CREATE TABLE " "\"%w\".\"%w_chunks\"" "(" "chunk_id INTEGER PRIMARY KEY AUTOINCREMENT,"
"size INTEGER NOT NULL," "validity BLOB NOT NULL," "rowids BLOB NOT NULL"
");"
\
3412 "CREATE TABLE " VEC0_SHADOW_CHUNKS_NAME"\"%w\".\"%w_chunks\"" "(" \
3413 "chunk_id INTEGER PRIMARY KEY AUTOINCREMENT," \
3414 "size INTEGER NOT NULL," \
3415 "validity BLOB NOT NULL," \
3416 "rowids BLOB NOT NULL" \
3417 ");"
3418
3419#define VEC0_SHADOW_ROWIDS_NAME"\"%w\".\"%w_rowids\"" "\"%w\".\"%w_rowids\""
3420/// 1) schema, 2) original vtab table name
3421#define VEC0_SHADOW_ROWIDS_CREATE_BASIC"CREATE TABLE " "\"%w\".\"%w_rowids\"" "(" "rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
"id," "chunk_id INTEGER," "chunk_offset INTEGER" ");"
\
3422 "CREATE TABLE " VEC0_SHADOW_ROWIDS_NAME"\"%w\".\"%w_rowids\"" "(" \
3423 "rowid INTEGER PRIMARY KEY AUTOINCREMENT," \
3424 "id," \
3425 "chunk_id INTEGER," \
3426 "chunk_offset INTEGER" \
3427 ");"
3428
3429// vec0 tables with a text primary keys are still backed by int64 primary keys,
3430// since a fixed-length rowid is required for vec0 chunks. But we add a new 'id
3431// text unique' column to emulate a text primary key interface.
3432#define VEC0_SHADOW_ROWIDS_CREATE_PK_TEXT"CREATE TABLE " "\"%w\".\"%w_rowids\"" "(" "rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
"id TEXT UNIQUE NOT NULL," "chunk_id INTEGER," "chunk_offset INTEGER"
");"
\
3433 "CREATE TABLE " VEC0_SHADOW_ROWIDS_NAME"\"%w\".\"%w_rowids\"" "(" \
3434 "rowid INTEGER PRIMARY KEY AUTOINCREMENT," \
3435 "id TEXT UNIQUE NOT NULL," \
3436 "chunk_id INTEGER," \
3437 "chunk_offset INTEGER" \
3438 ");"
3439
3440/// 1) schema, 2) original vtab table name
3441#define VEC0_SHADOW_VECTOR_N_NAME"\"%w\".\"%w_vector_chunks%02d\"" "\"%w\".\"%w_vector_chunks%02d\""
3442
3443/// 1) schema, 2) original vtab table name
3444//
3445// IMPORTANT: "rowid" is declared as PRIMARY KEY but WITHOUT the INTEGER type.
3446// This means it is NOT a true SQLite rowid alias — the user-defined "rowid"
3447// column and the internal SQLite rowid (_rowid_) are two separate values.
3448// When inserting, both must be set explicitly to keep them in sync. See the
3449// _rowid_ bindings in vec0_new_chunk() and the explanation in
3450// SHADOW_TABLE_ROWID_QUIRK below.
3451#define VEC0_SHADOW_VECTOR_N_CREATE"CREATE TABLE " "\"%w\".\"%w_vector_chunks%02d\"" "(" "rowid PRIMARY KEY,"
"vectors BLOB NOT NULL" ");"
\
3452 "CREATE TABLE " VEC0_SHADOW_VECTOR_N_NAME"\"%w\".\"%w_vector_chunks%02d\"" "(" \
3453 "rowid PRIMARY KEY," \
3454 "vectors BLOB NOT NULL" \
3455 ");"
3456
3457#define VEC0_SHADOW_AUXILIARY_NAME"\"%w\".\"%w_auxiliary\"" "\"%w\".\"%w_auxiliary\""
3458
3459#define VEC0_SHADOW_METADATA_N_NAME"\"%w\".\"%w_metadatachunks%02d\"" "\"%w\".\"%w_metadatachunks%02d\""
3460#define VEC0_SHADOW_VECTORS_N_NAME"\"%w\".\"%w_vectors%02d\"" "\"%w\".\"%w_vectors%02d\""
3461#define VEC0_SHADOW_DISKANN_NODES_N_NAME"\"%w\".\"%w_diskann_nodes%02d\"" "\"%w\".\"%w_diskann_nodes%02d\""
3462#define VEC0_SHADOW_DISKANN_BUFFER_N_NAME"\"%w\".\"%w_diskann_buffer%02d\"" "\"%w\".\"%w_diskann_buffer%02d\""
3463#define VEC0_SHADOW_METADATA_TEXT_DATA_NAME"\"%w\".\"%w_metadatatext%02d\"" "\"%w\".\"%w_metadatatext%02d\""
3464
3465#define VEC_INTERAL_ERROR"Internal sqlite-vec error: " "Internal sqlite-vec error: "
3466#define REPORT_URL"https://github.com/asg017/sqlite-vec/issues/new" "https://github.com/asg017/sqlite-vec/issues/new"
3467
3468typedef struct vec0_vtab vec0_vtab;
3469
3470#define VEC0_MAX_VECTOR_COLUMNS16 16
3471#define VEC0_MAX_PARTITION_COLUMNS4 4
3472#define VEC0_MAX_AUXILIARY_COLUMNS16 16
3473#define VEC0_MAX_METADATA_COLUMNS16 16
3474
3475#define SQLITE_VEC_VEC0_MAX_DIMENSIONS8192 8192
3476#define VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16 16
3477#define VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12 12
3478
3479typedef enum {
3480 // vector column, ie "contents_embedding float[1024]"
3481 SQLITE_VEC0_USER_COLUMN_KIND_VECTOR = 1,
3482
3483 // partition key column, ie "user_id integer partition key"
3484 SQLITE_VEC0_USER_COLUMN_KIND_PARTITION = 2,
3485
3486 //
3487 SQLITE_VEC0_USER_COLUMN_KIND_AUXILIARY = 3,
3488
3489 // metadata column that can be filtered, ie "genre text"
3490 SQLITE_VEC0_USER_COLUMN_KIND_METADATA = 4,
3491} vec0_user_column_kind;
3492
3493struct vec0_vtab {
3494 sqlite3_vtab base;
3495
3496 // the SQLite connection of the host database
3497 sqlite3 *db;
3498
3499 // True if the primary key of the vec0 table has a column type TEXT.
3500 // Will change the schema of the _rowids table, and insert/query logic.
3501 int pkIsText;
3502
3503 // True if the hidden command column (named after the table) exists.
3504 // Tables created before v0.1.10 or without _info table don't have it.
3505 int hasCommandColumn;
3506
3507 // number of defined vector columns.
3508 int numVectorColumns;
3509
3510 // number of defined PARTITION KEY columns.
3511 int numPartitionColumns;
3512
3513 // number of defined auxiliary columns
3514 int numAuxiliaryColumns;
3515
3516 // number of defined metadata columns
3517 int numMetadataColumns;
3518
3519
3520 // Name of the schema the table exists on.
3521 // Must be freed with sqlite3_free()
3522 char *schemaName;
3523
3524 // Name of the table the table exists on.
3525 // Must be freed with sqlite3_free()
3526 char *tableName;
3527
3528 // Name of the _rowids shadow table.
3529 // Must be freed with sqlite3_free()
3530 char *shadowRowidsName;
3531
3532 // Name of the _chunks shadow table.
3533 // Must be freed with sqlite3_free()
3534 char *shadowChunksName;
3535
3536 // contains enum vec0_user_column_kind values for up to
3537 // numVectorColumns + numPartitionColumns entries
3538 vec0_user_column_kind user_column_kinds[VEC0_MAX_VECTOR_COLUMNS16 + VEC0_MAX_PARTITION_COLUMNS4 + VEC0_MAX_AUXILIARY_COLUMNS16 + VEC0_MAX_METADATA_COLUMNS16];
3539
3540 uint8_t user_column_idxs[VEC0_MAX_VECTOR_COLUMNS16 + VEC0_MAX_PARTITION_COLUMNS4 + VEC0_MAX_AUXILIARY_COLUMNS16 + VEC0_MAX_METADATA_COLUMNS16];
3541
3542
3543 // Name of all the vector chunk shadow tables.
3544 // Ex '_vector_chunks00'
3545 // Only the first numVectorColumns entries will be available.
3546 // The first numVectorColumns entries must be freed with sqlite3_free()
3547 char *shadowVectorChunksNames[VEC0_MAX_VECTOR_COLUMNS16];
3548
3549#if SQLITE_VEC_ENABLE_RESCORE1
3550 // Name of all rescore chunk shadow tables, ie `_rescore_chunks00`
3551 // Only populated for vector columns with rescore enabled.
3552 // Must be freed with sqlite3_free()
3553 char *shadowRescoreChunksNames[VEC0_MAX_VECTOR_COLUMNS16];
3554
3555 // Name of all rescore vector shadow tables, ie `_rescore_vectors00`
3556 // Rowid-keyed table for fast random-access float vector reads during rescore.
3557 // Only populated for vector columns with rescore enabled.
3558 // Must be freed with sqlite3_free()
3559 char *shadowRescoreVectorsNames[VEC0_MAX_VECTOR_COLUMNS16];
3560#endif
3561
3562 // Name of all metadata chunk shadow tables, ie `_metadatachunks00`
3563 // Only the first numMetadataColumns entries will be available.
3564 // The first numMetadataColumns entries must be freed with sqlite3_free()
3565 char *shadowMetadataChunksNames[VEC0_MAX_METADATA_COLUMNS16];
3566
3567 struct VectorColumnDefinition vector_columns[VEC0_MAX_VECTOR_COLUMNS16];
3568 struct Vec0PartitionColumnDefinition paritition_columns[VEC0_MAX_PARTITION_COLUMNS4];
3569 struct Vec0AuxiliaryColumnDefinition auxiliary_columns[VEC0_MAX_AUXILIARY_COLUMNS16];
3570 struct Vec0MetadataColumnDefinition metadata_columns[VEC0_MAX_METADATA_COLUMNS16];
3571
3572 int chunk_size;
3573
3574#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
3575 // IVF cached state per vector column
3576 char *shadowIvfCellsNames[VEC0_MAX_VECTOR_COLUMNS16]; // table name for blob_open
3577 int ivfTrainedCache[VEC0_MAX_VECTOR_COLUMNS16]; // -1=unknown, 0=no, 1=yes
3578 sqlite3_stmt *stmtIvfCellMeta[VEC0_MAX_VECTOR_COLUMNS16]; // SELECT n_vectors, length(validity)*8 FROM cells WHERE cell_id=?
3579 sqlite3_stmt *stmtIvfCellUpdateN[VEC0_MAX_VECTOR_COLUMNS16]; // UPDATE cells SET n_vectors=n_vectors+? WHERE cell_id=?
3580 sqlite3_stmt *stmtIvfRowidMapInsert[VEC0_MAX_VECTOR_COLUMNS16]; // INSERT INTO rowid_map(rowid,cell_id,slot) VALUES(?,?,?)
3581 sqlite3_stmt *stmtIvfRowidMapLookup[VEC0_MAX_VECTOR_COLUMNS16]; // SELECT cell_id,slot FROM rowid_map WHERE rowid=?
3582 sqlite3_stmt *stmtIvfRowidMapDelete[VEC0_MAX_VECTOR_COLUMNS16]; // DELETE FROM rowid_map WHERE rowid=?
3583 sqlite3_stmt *stmtIvfCentroidsAll[VEC0_MAX_VECTOR_COLUMNS16]; // SELECT centroid_id,centroid FROM centroids
3584#endif
3585
3586 // select latest chunk from _chunks, getting chunk_id
3587 sqlite3_stmt *stmtLatestChunk;
3588
3589 /**
3590 * Statement to insert a row into the _rowids table, with a rowid.
3591 * Parameters:
3592 * 1: int64, rowid to insert
3593 * Result columns: none
3594 * SQL: "INSERT INTO _rowids(rowid) VALUES (?)"
3595 *
3596 * Must be cleaned up with sqlite3_finalize().
3597 */
3598 sqlite3_stmt *stmtRowidsInsertRowid;
3599
3600 /**
3601 * Statement to insert a row into the _rowids table, with an id.
3602 * The id column isn't a tradition primary key, but instead a unique
3603 * column to handle "text primary key" vec0 tables. The true int64 rowid
3604 * can be retrieved after inserting with sqlite3_last_rowid().
3605 *
3606 * Parameters:
3607 * 1: text or null, id to insert
3608 * Result columns: none
3609 *
3610 * Must be cleaned up with sqlite3_finalize().
3611 */
3612 sqlite3_stmt *stmtRowidsInsertId;
3613
3614 /**
3615 * Statement to update the "position" columns chunk_id and chunk_offset for
3616 * a given _rowids row. Used when the "next available" chunk position is found
3617 * for a vector.
3618 *
3619 * Parameters:
3620 * 1: int64, chunk_id value
3621 * 2: int64, chunk_offset value
3622 * 3: int64, rowid value
3623 * Result columns: none
3624 *
3625 * Must be cleaned up with sqlite3_finalize().
3626 */
3627 sqlite3_stmt *stmtRowidsUpdatePosition;
3628
3629 /**
3630 * Statement to quickly find the chunk_id + chunk_offset of a given row.
3631 * Parameters:
3632 * 1: rowid of the row/vector to lookup
3633 * Result columns:
3634 * 0: chunk_id (i64)
3635 * 1: chunk_offset (i64)
3636 * SQL: "SELECT id, chunk_id, chunk_offset FROM _rowids WHERE rowid = ?""
3637 *
3638 * Must be cleaned up with sqlite3_finalize().
3639 */
3640 sqlite3_stmt *stmtRowidsGetChunkPosition;
3641
3642 // === DiskANN additions ===
3643#if SQLITE_VEC_ENABLE_DISKANN0
3644 // Shadow table names for DiskANN, per vector column
3645 // e.g., "{schema}"."{table}_vectors{00..15}"
3646 char *shadowVectorsNames[VEC0_MAX_VECTOR_COLUMNS16];
3647
3648 // e.g., "{schema}"."{table}_diskann_nodes{00..15}"
3649 char *shadowDiskannNodesNames[VEC0_MAX_VECTOR_COLUMNS16];
3650
3651 // Prepared statements for DiskANN operations (per vector column)
3652 // These will be lazily prepared on first use.
3653 sqlite3_stmt *stmtDiskannNodeRead[VEC0_MAX_VECTOR_COLUMNS16];
3654 sqlite3_stmt *stmtDiskannNodeWrite[VEC0_MAX_VECTOR_COLUMNS16];
3655 sqlite3_stmt *stmtDiskannNodeInsert[VEC0_MAX_VECTOR_COLUMNS16];
3656 sqlite3_stmt *stmtVectorsRead[VEC0_MAX_VECTOR_COLUMNS16];
3657 sqlite3_stmt *stmtVectorsInsert[VEC0_MAX_VECTOR_COLUMNS16];
3658#endif
3659};
3660
3661#if SQLITE_VEC_ENABLE_RESCORE1
3662// Forward declarations for rescore functions (defined in sqlite-vec-rescore.c,
3663// included later after all helpers they depend on are defined).
3664static int rescore_create_tables(vec0_vtab *p, sqlite3 *db, char **pzErr);
3665static int rescore_drop_tables(vec0_vtab *p);
3666static int rescore_new_chunk(vec0_vtab *p, i64 chunk_rowid);
3667static int rescore_on_insert(vec0_vtab *p, i64 chunk_rowid, i64 chunk_offset,
3668 i64 rowid, void *vectorDatas[]);
3669static int rescore_on_delete(vec0_vtab *p, i64 chunk_id, u64 chunk_offset, i64 rowid);
3670static int rescore_delete_chunk(vec0_vtab *p, i64 chunk_id);
3671#endif
3672
3673/**
3674 * @brief Finalize all the sqlite3_stmt members in a vec0_vtab.
3675 *
3676 * @param p vec0_vtab pointer
3677 */
3678void vec0_free_resources(vec0_vtab *p) {
3679 sqlite3_finalizesqlite3_api->finalize(p->stmtLatestChunk);
3680 p->stmtLatestChunk = NULL((void*)0);
3681 sqlite3_finalizesqlite3_api->finalize(p->stmtRowidsInsertRowid);
3682 p->stmtRowidsInsertRowid = NULL((void*)0);
3683 sqlite3_finalizesqlite3_api->finalize(p->stmtRowidsInsertId);
3684 p->stmtRowidsInsertId = NULL((void*)0);
3685 sqlite3_finalizesqlite3_api->finalize(p->stmtRowidsUpdatePosition);
3686 p->stmtRowidsUpdatePosition = NULL((void*)0);
3687 sqlite3_finalizesqlite3_api->finalize(p->stmtRowidsGetChunkPosition);
3688 p->stmtRowidsGetChunkPosition = NULL((void*)0);
3689
3690#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
3691 for (int i = 0; i < VEC0_MAX_VECTOR_COLUMNS16; i++) {
3692 sqlite3_finalizesqlite3_api->finalize(p->stmtIvfCellMeta[i]); p->stmtIvfCellMeta[i] = NULL((void*)0);
3693 sqlite3_finalizesqlite3_api->finalize(p->stmtIvfCellUpdateN[i]); p->stmtIvfCellUpdateN[i] = NULL((void*)0);
3694 sqlite3_finalizesqlite3_api->finalize(p->stmtIvfRowidMapInsert[i]); p->stmtIvfRowidMapInsert[i] = NULL((void*)0);
3695 sqlite3_finalizesqlite3_api->finalize(p->stmtIvfRowidMapLookup[i]); p->stmtIvfRowidMapLookup[i] = NULL((void*)0);
3696 sqlite3_finalizesqlite3_api->finalize(p->stmtIvfRowidMapDelete[i]); p->stmtIvfRowidMapDelete[i] = NULL((void*)0);
3697 sqlite3_finalizesqlite3_api->finalize(p->stmtIvfCentroidsAll[i]); p->stmtIvfCentroidsAll[i] = NULL((void*)0);
3698 }
3699#endif
3700#if SQLITE_VEC_ENABLE_DISKANN0
3701 for (int i = 0; i < VEC0_MAX_VECTOR_COLUMNS16; i++) {
3702 sqlite3_finalizesqlite3_api->finalize(p->stmtDiskannNodeRead[i]); p->stmtDiskannNodeRead[i] = NULL((void*)0);
3703 sqlite3_finalizesqlite3_api->finalize(p->stmtDiskannNodeWrite[i]); p->stmtDiskannNodeWrite[i] = NULL((void*)0);
3704 sqlite3_finalizesqlite3_api->finalize(p->stmtDiskannNodeInsert[i]); p->stmtDiskannNodeInsert[i] = NULL((void*)0);
3705 sqlite3_finalizesqlite3_api->finalize(p->stmtVectorsRead[i]); p->stmtVectorsRead[i] = NULL((void*)0);
3706 sqlite3_finalizesqlite3_api->finalize(p->stmtVectorsInsert[i]); p->stmtVectorsInsert[i] = NULL((void*)0);
3707 }
3708#endif
3709}
3710
3711/**
3712 * @brief Free all memory and sqlite3_stmt members of a vec0_vtab
3713 *
3714 * @param p vec0_vtab pointer
3715 */
3716void vec0_free(vec0_vtab *p) {
3717 vec0_free_resources(p);
3718
3719 sqlite3_freesqlite3_api->free(p->schemaName);
3720 p->schemaName = NULL((void*)0);
3721 sqlite3_freesqlite3_api->free(p->tableName);
3722 p->tableName = NULL((void*)0);
3723 sqlite3_freesqlite3_api->free(p->shadowChunksName);
3724 p->shadowChunksName = NULL((void*)0);
3725 sqlite3_freesqlite3_api->free(p->shadowRowidsName);
3726 p->shadowRowidsName = NULL((void*)0);
3727
3728 for (int i = 0; i < p->numVectorColumns; i++) {
3729 sqlite3_freesqlite3_api->free(p->shadowVectorChunksNames[i]);
3730 p->shadowVectorChunksNames[i] = NULL((void*)0);
3731#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
3732 sqlite3_freesqlite3_api->free(p->shadowIvfCellsNames[i]);
3733 p->shadowIvfCellsNames[i] = NULL((void*)0);
3734#endif
3735
3736#if SQLITE_VEC_ENABLE_RESCORE1
3737 sqlite3_freesqlite3_api->free(p->shadowRescoreChunksNames[i]);
3738 p->shadowRescoreChunksNames[i] = NULL((void*)0);
3739
3740 sqlite3_freesqlite3_api->free(p->shadowRescoreVectorsNames[i]);
3741 p->shadowRescoreVectorsNames[i] = NULL((void*)0);
3742#endif
3743
3744#if SQLITE_VEC_ENABLE_DISKANN0
3745 sqlite3_freesqlite3_api->free(p->shadowVectorsNames[i]);
3746 p->shadowVectorsNames[i] = NULL((void*)0);
3747 sqlite3_freesqlite3_api->free(p->shadowDiskannNodesNames[i]);
3748 p->shadowDiskannNodesNames[i] = NULL((void*)0);
3749#endif
3750
3751 sqlite3_freesqlite3_api->free(p->vector_columns[i].name);
3752 p->vector_columns[i].name = NULL((void*)0);
3753 }
3754
3755 for (int i = 0; i < p->numPartitionColumns; i++) {
3756 sqlite3_freesqlite3_api->free(p->paritition_columns[i].name);
3757 p->paritition_columns[i].name = NULL((void*)0);
3758 }
3759
3760 for (int i = 0; i < p->numAuxiliaryColumns; i++) {
3761 sqlite3_freesqlite3_api->free(p->auxiliary_columns[i].name);
3762 p->auxiliary_columns[i].name = NULL((void*)0);
3763 }
3764
3765 for (int i = 0; i < p->numMetadataColumns; i++) {
3766 sqlite3_freesqlite3_api->free(p->metadata_columns[i].name);
3767 p->metadata_columns[i].name = NULL((void*)0);
3768 }
3769}
3770
3771#if SQLITE_VEC_ENABLE_DISKANN0
3772#include "sqlite-vec-diskann.c"
3773#else
3774static int vec0_all_columns_diskann(vec0_vtab *p) { (void)p; return 0; }
3775#endif
3776
3777int vec0_num_defined_user_columns(vec0_vtab *p) {
3778 return p->numVectorColumns + p->numPartitionColumns + p->numAuxiliaryColumns + p->numMetadataColumns;
3779}
3780
3781/**
3782 * @brief Returns the index of the distance hidden column for the given vec0
3783 * table.
3784 *
3785 * @param p vec0 table
3786 * @return int
3787 */
3788int vec0_column_command_idx(vec0_vtab *p) {
3789 // Command column is the first hidden column (right after user columns)
3790 return VEC0_COLUMN_USERN_START1 + vec0_num_defined_user_columns(p);
3791}
3792
3793int vec0_column_distance_idx(vec0_vtab *p) {
3794 int base = VEC0_COLUMN_USERN_START1 + vec0_num_defined_user_columns(p);
3795 return base + (p->hasCommandColumn ? 1 : 0);
3796}
3797
3798int vec0_column_k_idx(vec0_vtab *p) {
3799 int base = VEC0_COLUMN_USERN_START1 + vec0_num_defined_user_columns(p);
3800 return base + (p->hasCommandColumn ? 2 : 1);
3801}
3802
3803/**
3804 * Returns 1 if the given column-based index is a valid vector column,
3805 * 0 otherwise.
3806 */
3807int vec0_column_idx_is_vector(vec0_vtab *pVtab, int column_idx) {
3808 return column_idx >= VEC0_COLUMN_USERN_START1 &&
3809 column_idx <= (VEC0_COLUMN_USERN_START1 + vec0_num_defined_user_columns(pVtab) - 1) &&
3810 pVtab->user_column_kinds[column_idx - VEC0_COLUMN_USERN_START1] == SQLITE_VEC0_USER_COLUMN_KIND_VECTOR;
3811}
3812
3813/**
3814 * Returns the vector index of the given user column index.
3815 * ONLY call if validated with vec0_column_idx_is_vector before
3816 */
3817int vec0_column_idx_to_vector_idx(vec0_vtab *pVtab, int column_idx) {
3818 UNUSED_PARAMETER(pVtab)(void)(pVtab);
3819 return pVtab->user_column_idxs[column_idx - VEC0_COLUMN_USERN_START1];
3820}
3821/**
3822 * Returns 1 if the given column-based index is a "partition key" column,
3823 * 0 otherwise.
3824 */
3825int vec0_column_idx_is_partition(vec0_vtab *pVtab, int column_idx) {
3826 return column_idx >= VEC0_COLUMN_USERN_START1 &&
3827 column_idx <= (VEC0_COLUMN_USERN_START1 + vec0_num_defined_user_columns(pVtab) - 1) &&
3828 pVtab->user_column_kinds[column_idx - VEC0_COLUMN_USERN_START1] == SQLITE_VEC0_USER_COLUMN_KIND_PARTITION;
3829}
3830
3831/**
3832 * Returns the partition column index of the given user column index.
3833 * ONLY call if validated with vec0_column_idx_is_vector before
3834 */
3835int vec0_column_idx_to_partition_idx(vec0_vtab *pVtab, int column_idx) {
3836 UNUSED_PARAMETER(pVtab)(void)(pVtab);
3837 return pVtab->user_column_idxs[column_idx - VEC0_COLUMN_USERN_START1];
3838}
3839
3840/**
3841 * Returns 1 if the given column-based index is a auxiliary column,
3842 * 0 otherwise.
3843 */
3844int vec0_column_idx_is_auxiliary(vec0_vtab *pVtab, int column_idx) {
3845 return column_idx >= VEC0_COLUMN_USERN_START1 &&
3846 column_idx <= (VEC0_COLUMN_USERN_START1 + vec0_num_defined_user_columns(pVtab) - 1) &&
3847 pVtab->user_column_kinds[column_idx - VEC0_COLUMN_USERN_START1] == SQLITE_VEC0_USER_COLUMN_KIND_AUXILIARY;
3848}
3849
3850/**
3851 * Returns the auxiliary column index of the given user column index.
3852 * ONLY call if validated with vec0_column_idx_to_partition_idx before
3853 */
3854int vec0_column_idx_to_auxiliary_idx(vec0_vtab *pVtab, int column_idx) {
3855 UNUSED_PARAMETER(pVtab)(void)(pVtab);
3856 return pVtab->user_column_idxs[column_idx - VEC0_COLUMN_USERN_START1];
3857}
3858
3859/**
3860 * Returns 1 if the given column-based index is a metadata column,
3861 * 0 otherwise.
3862 */
3863int vec0_column_idx_is_metadata(vec0_vtab *pVtab, int column_idx) {
3864 return column_idx >= VEC0_COLUMN_USERN_START1 &&
3865 column_idx <= (VEC0_COLUMN_USERN_START1 + vec0_num_defined_user_columns(pVtab) - 1) &&
3866 pVtab->user_column_kinds[column_idx - VEC0_COLUMN_USERN_START1] == SQLITE_VEC0_USER_COLUMN_KIND_METADATA;
3867}
3868
3869/**
3870 * Returns the metadata column index of the given user column index.
3871 * ONLY call if validated with vec0_column_idx_is_metadata before
3872 */
3873int vec0_column_idx_to_metadata_idx(vec0_vtab *pVtab, int column_idx) {
3874 UNUSED_PARAMETER(pVtab)(void)(pVtab);
3875 return pVtab->user_column_idxs[column_idx - VEC0_COLUMN_USERN_START1];
3876}
3877
3878/**
3879 * @brief Retrieve the chunk_id, chunk_offset, and possible "id" value
3880 * of a vec0_vtab row with the provided rowid
3881 *
3882 * @param p vec0_vtab
3883 * @param rowid the rowid of the row to query
3884 * @param id output, optional sqlite3_value to provide the id.
3885 * Useful for text PK rows. Must be freed with sqlite3_value_free()
3886 * @param chunk_id output, the chunk_id the row belongs to
3887 * @param chunk_offset output, the offset within the chunk the row belongs to
3888 * @return SQLITE_ROW on success, error code otherwise. SQLITE_EMPTY if row DNE
3889 */
3890int vec0_get_chunk_position(vec0_vtab *p, i64 rowid, sqlite3_value **id,
3891 i64 *chunk_id, i64 *chunk_offset) {
3892 int rc;
3893
3894 if (!p->stmtRowidsGetChunkPosition) {
3895 const char *zSql =
3896 sqlite3_mprintfsqlite3_api->mprintf("SELECT id, chunk_id, chunk_offset "
3897 "FROM " VEC0_SHADOW_ROWIDS_NAME"\"%w\".\"%w_rowids\"" " WHERE rowid = ?",
3898 p->schemaName, p->tableName);
3899 if (!zSql) {
3900 rc = SQLITE_NOMEM7;
3901 goto cleanup;
3902 }
3903 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &p->stmtRowidsGetChunkPosition, 0);
3904 sqlite3_freesqlite3_api->free((void *)zSql);
3905 if (rc != SQLITE_OK0) {
3906 vtab_set_error(
3907 &p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: "
3908 "could not initialize 'rowids get chunk position' statement");
3909 goto cleanup;
3910 }
3911 }
3912
3913 sqlite3_bind_int64sqlite3_api->bind_int64(p->stmtRowidsGetChunkPosition, 1, rowid);
3914 rc = sqlite3_stepsqlite3_api->step(p->stmtRowidsGetChunkPosition);
3915 // special case: when no results, return SQLITE_EMPTY to convey "that chunk
3916 // position doesnt exist"
3917 if (rc == SQLITE_DONE101) {
3918 rc = SQLITE_EMPTY16;
3919 goto cleanup;
3920 }
3921 if (rc != SQLITE_ROW100) {
3922 goto cleanup;
3923 }
3924
3925 if (id) {
3926 sqlite3_value *value =
3927 sqlite3_column_valuesqlite3_api->column_value(p->stmtRowidsGetChunkPosition, 0);
3928 *id = sqlite3_value_dupsqlite3_api->value_dup(value);
3929 if (!*id) {
3930 rc = SQLITE_NOMEM7;
3931 goto cleanup;
3932 }
3933 }
3934
3935 if (chunk_id) {
3936 *chunk_id = sqlite3_column_int64sqlite3_api->column_int64(p->stmtRowidsGetChunkPosition, 1);
3937 }
3938 if (chunk_offset) {
3939 *chunk_offset = sqlite3_column_int64sqlite3_api->column_int64(p->stmtRowidsGetChunkPosition, 2);
3940 }
3941
3942 rc = SQLITE_OK0;
3943
3944cleanup:
3945 sqlite3_resetsqlite3_api->reset(p->stmtRowidsGetChunkPosition);
3946 sqlite3_clear_bindingssqlite3_api->clear_bindings(p->stmtRowidsGetChunkPosition);
3947 return rc;
3948}
3949
3950/**
3951 * @brief Return the id value from the _rowids table where _rowids.rowid =
3952 * rowid.
3953 *
3954 * @param pVtab: vec0 table to query
3955 * @param rowid: rowid of the row to query.
3956 * @param out: A dup'ed sqlite3_value of the id column. Might be null.
3957 * Must be cleaned up with sqlite3_value_free().
3958 * @returns SQLITE_OK on success, error code on failure
3959 */
3960int vec0_get_id_value_from_rowid(vec0_vtab *pVtab, i64 rowid,
3961 sqlite3_value **out) {
3962 // PERF: different strategy than get_chunk_position?
3963 return vec0_get_chunk_position((vec0_vtab *)pVtab, rowid, out, NULL((void*)0), NULL((void*)0));
3964}
3965
3966int vec0_rowid_from_id(vec0_vtab *p, sqlite3_value *valueId, i64 *rowid) {
3967 sqlite3_stmt *stmt = NULL((void*)0);
3968 int rc;
3969 char *zSql;
3970 zSql = sqlite3_mprintfsqlite3_api->mprintf("SELECT rowid"
3971 " FROM " VEC0_SHADOW_ROWIDS_NAME"\"%w\".\"%w_rowids\"" " WHERE id = ?",
3972 p->schemaName, p->tableName);
3973 if (!zSql) {
3974 rc = SQLITE_NOMEM7;
3975 goto cleanup;
3976 }
3977 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
3978 sqlite3_freesqlite3_api->free(zSql);
3979 if (rc != SQLITE_OK0) {
3980 goto cleanup;
3981 }
3982 sqlite3_bind_valuesqlite3_api->bind_value(stmt, 1, valueId);
3983 rc = sqlite3_stepsqlite3_api->step(stmt);
3984 if (rc == SQLITE_DONE101) {
3985 rc = SQLITE_EMPTY16;
3986 goto cleanup;
3987 }
3988 if (rc != SQLITE_ROW100) {
3989 goto cleanup;
3990 }
3991 *rowid = sqlite3_column_int64sqlite3_api->column_int64(stmt, 0);
3992 rc = sqlite3_stepsqlite3_api->step(stmt);
3993 if (rc != SQLITE_DONE101) {
3994 goto cleanup;
3995 }
3996
3997 rc = SQLITE_OK0;
3998
3999cleanup:
4000 sqlite3_finalizesqlite3_api->finalize(stmt);
4001 return rc;
4002}
4003
4004int vec0_result_id(vec0_vtab *p, sqlite3_context *context, i64 rowid) {
4005 if (!p->pkIsText) {
4006 sqlite3_result_int64sqlite3_api->result_int64(context, rowid);
4007 return SQLITE_OK0;
4008 }
4009 sqlite3_value *valueId;
4010 int rc = vec0_get_id_value_from_rowid(p, rowid, &valueId);
4011 if (rc != SQLITE_OK0) {
4012 return rc;
4013 }
4014 if (!valueId) {
4015 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
4016 } else {
4017 sqlite3_result_valuesqlite3_api->result_value(context, valueId);
4018 sqlite3_value_freesqlite3_api->value_free(valueId);
4019 }
4020 return SQLITE_OK0;
4021}
4022
4023/**
4024 * @brief
4025 *
4026 * @param pVtab: virtual table to query
4027 * @param rowid: row to lookup
4028 * @param vector_column_idx: which vector column to query
4029 * @param outVector: Output pointer to the vector buffer.
4030 * Must be sqlite3_free()'ed.
4031 * @param outVectorSize: Pointer to a int where the size of outVector
4032 * will be stored.
4033 * @return int SQLITE_OK on success.
4034 */
4035#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
4036// Forward declaration — defined in sqlite-vec-ivf.c (included later)
4037static int ivf_get_vector_data(vec0_vtab *p, i64 rowid, int col_idx,
4038 void **outVector, int *outVectorSize);
4039#endif
4040
4041int vec0_get_vector_data(vec0_vtab *pVtab, i64 rowid, int vector_column_idx,
4042 void **outVector, int *outVectorSize) {
4043 vec0_vtab *p = pVtab;
4044 int rc, brc;
4045
4046#if SQLITE_VEC_ENABLE_DISKANN0
4047 // DiskANN fast path: read from _vectors table
4048 if (p->vector_columns[vector_column_idx].index_type == VEC0_INDEX_TYPE_DISKANN) {
4049 void *vec = NULL((void*)0);
4050 int vecSize;
4051 rc = diskann_vector_read(p, vector_column_idx, rowid, &vec, &vecSize);
4052 if (rc != SQLITE_OK0) {
4053 vtab_set_error(&pVtab->base,
4054 "Could not fetch vector data for %lld from DiskANN vectors table",
4055 rowid);
4056 return SQLITE_ERROR1;
4057 }
4058 *outVector = vec;
4059 if (outVectorSize) *outVectorSize = vecSize;
4060 return SQLITE_OK0;
4061 }
4062#endif
4063
4064 i64 chunk_id;
4065 i64 chunk_offset;
4066
4067#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
4068 // IVF-indexed columns store vectors in _ivf_cells, not _vector_chunks
4069 if (p->vector_columns[vector_column_idx].index_type == VEC0_INDEX_TYPE_IVF) {
4070 return ivf_get_vector_data(p, rowid, vector_column_idx, outVector, outVectorSize);
4071 }
4072#endif
4073 size_t size;
4074 void *buf = NULL((void*)0);
4075 int blobOffset;
4076 sqlite3_blob *vectorBlob = NULL((void*)0);
4077 assert((vector_column_idx >= 0) &&((void) sizeof (((vector_column_idx >= 0) && (vector_column_idx
< pVtab->numVectorColumns)) ? 1 : 0), __extension__ ({
if ((vector_column_idx >= 0) && (vector_column_idx
< pVtab->numVectorColumns)) ; else __assert_fail ("(vector_column_idx >= 0) && (vector_column_idx < pVtab->numVectorColumns)"
, "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 4078, __extension__ __PRETTY_FUNCTION__); }))
4078 (vector_column_idx < pVtab->numVectorColumns))((void) sizeof (((vector_column_idx >= 0) && (vector_column_idx
< pVtab->numVectorColumns)) ? 1 : 0), __extension__ ({
if ((vector_column_idx >= 0) && (vector_column_idx
< pVtab->numVectorColumns)) ; else __assert_fail ("(vector_column_idx >= 0) && (vector_column_idx < pVtab->numVectorColumns)"
, "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 4078, __extension__ __PRETTY_FUNCTION__); }))
;
4079
4080#if SQLITE_VEC_ENABLE_RESCORE1
4081 // Rescore columns store float vectors in _rescore_vectors (rowid-keyed)
4082 if (p->vector_columns[vector_column_idx].index_type == VEC0_INDEX_TYPE_RESCORE) {
4083 size = vector_column_byte_size(p->vector_columns[vector_column_idx]);
4084 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName,
4085 p->shadowRescoreVectorsNames[vector_column_idx],
4086 "vector", rowid, 0, &vectorBlob);
4087 if (rc != SQLITE_OK0) {
4088 vtab_set_error(&pVtab->base,
4089 "Could not fetch vector data for %lld from rescore vectors",
4090 rowid);
4091 rc = SQLITE_ERROR1;
4092 goto cleanup;
4093 }
4094 buf = sqlite3_mallocsqlite3_api->malloc(size);
4095 if (!buf) {
4096 rc = SQLITE_NOMEM7;
4097 goto cleanup;
4098 }
4099 rc = sqlite3_blob_readsqlite3_api->blob_read(vectorBlob, buf, size, 0);
4100 if (rc != SQLITE_OK0) {
4101 sqlite3_freesqlite3_api->free(buf);
4102 buf = NULL((void*)0);
4103 rc = SQLITE_ERROR1;
4104 goto cleanup;
4105 }
4106 *outVector = buf;
4107 if (outVectorSize) {
4108 *outVectorSize = size;
4109 }
4110 rc = SQLITE_OK0;
4111 goto cleanup;
4112 }
4113#endif /* SQLITE_VEC_ENABLE_RESCORE */
4114
4115 rc = vec0_get_chunk_position(pVtab, rowid, NULL((void*)0), &chunk_id, &chunk_offset);
4116 if (rc == SQLITE_EMPTY16) {
4117 vtab_set_error(&pVtab->base, "Could not find a row with rowid %lld", rowid);
4118 goto cleanup;
4119 }
4120 if (rc != SQLITE_OK0) {
4121 goto cleanup;
4122 }
4123
4124 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName,
4125 p->shadowVectorChunksNames[vector_column_idx],
4126 "vectors", chunk_id, 0, &vectorBlob);
4127
4128 if (rc != SQLITE_OK0) {
4129 vtab_set_error(&pVtab->base,
4130 "Could not fetch vector data for %lld, opening blob failed",
4131 rowid);
4132 rc = SQLITE_ERROR1;
4133 goto cleanup;
4134 }
4135
4136 size = vector_column_byte_size(pVtab->vector_columns[vector_column_idx]);
4137 blobOffset = chunk_offset * size;
4138
4139 buf = sqlite3_mallocsqlite3_api->malloc(size);
4140 if (!buf) {
4141 rc = SQLITE_NOMEM7;
4142 goto cleanup;
4143 }
4144
4145 rc = sqlite3_blob_readsqlite3_api->blob_read(vectorBlob, buf, size, blobOffset);
4146 if (rc != SQLITE_OK0) {
4147 sqlite3_freesqlite3_api->free(buf);
4148 buf = NULL((void*)0);
4149 vtab_set_error(
4150 &pVtab->base,
4151 "Could not fetch vector data for %lld, reading from blob failed",
4152 rowid);
4153 rc = SQLITE_ERROR1;
4154 goto cleanup;
4155 }
4156
4157 *outVector = buf;
4158 if (outVectorSize) {
4159 *outVectorSize = size;
4160 }
4161 rc = SQLITE_OK0;
4162
4163cleanup:
4164 brc = sqlite3_blob_closesqlite3_api->blob_close(vectorBlob);
4165 if ((rc == SQLITE_OK0) && (brc != SQLITE_OK0)) {
4166 vtab_set_error(
4167 &p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: "
4168 "unknown error, could not close vector blob, please file an issue");
4169 return brc;
4170 }
4171
4172 return rc;
4173}
4174
4175/**
4176 * @brief Retrieve the sqlite3_value of the i'th partition value for the given row.
4177 *
4178 * @param pVtab - the vec0_vtab in questions
4179 * @param rowid - rowid of target row
4180 * @param partition_idx - which partition column to retrieve
4181 * @param outValue - output sqlite3_value
4182 * @return int - SQLITE_OK on success, otherwise error code
4183 */
4184int vec0_get_partition_value_for_rowid(vec0_vtab *pVtab, i64 rowid, int partition_idx, sqlite3_value ** outValue) {
4185 int rc;
4186 i64 chunk_id;
4187 i64 chunk_offset;
4188 rc = vec0_get_chunk_position(pVtab, rowid, NULL((void*)0), &chunk_id, &chunk_offset);
4189 if(rc != SQLITE_OK0) {
4190 return rc;
4191 }
4192 sqlite3_stmt * stmt = NULL((void*)0);
4193 char * zSql = sqlite3_mprintfsqlite3_api->mprintf("SELECT partition%02d FROM " VEC0_SHADOW_CHUNKS_NAME"\"%w\".\"%w_chunks\"" " WHERE chunk_id = ?", partition_idx, pVtab->schemaName, pVtab->tableName);
4194 if(!zSql) {
4195 return SQLITE_NOMEM7;
4196 }
4197 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(pVtab->db, zSql, -1, &stmt, NULL((void*)0));
4198 sqlite3_freesqlite3_api->free(zSql);
4199 if(rc != SQLITE_OK0) {
4200 return rc;
4201 }
4202 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, chunk_id);
4203 rc = sqlite3_stepsqlite3_api->step(stmt);
4204 if(rc != SQLITE_ROW100) {
4205 rc = SQLITE_ERROR1;
4206 goto done;
4207 }
4208 *outValue = sqlite3_value_dupsqlite3_api->value_dup(sqlite3_column_valuesqlite3_api->column_value(stmt, 0));
4209 if(!*outValue) {
4210 rc = SQLITE_NOMEM7;
4211 goto done;
4212 }
4213 rc = SQLITE_OK0;
4214
4215 done:
4216 sqlite3_finalizesqlite3_api->finalize(stmt);
4217 return rc;
4218
4219}
4220
4221/**
4222 * @brief Get the value of an auxiliary column for the given rowid
4223 *
4224 * @param pVtab vec0_vtab
4225 * @param rowid the rowid of the row to lookup
4226 * @param auxiliary_idx aux index of the column we care about
4227 * @param outValue Output sqlite3_value to store
4228 * @return int SQLITE_OK on success, error code otherwise
4229 */
4230int vec0_get_auxiliary_value_for_rowid(vec0_vtab *pVtab, i64 rowid, int auxiliary_idx, sqlite3_value ** outValue) {
4231 int rc;
4232 sqlite3_stmt * stmt = NULL((void*)0);
4233 char * zSql = sqlite3_mprintfsqlite3_api->mprintf("SELECT value%02d FROM " VEC0_SHADOW_AUXILIARY_NAME"\"%w\".\"%w_auxiliary\"" " WHERE rowid = ?", auxiliary_idx, pVtab->schemaName, pVtab->tableName);
4234 if(!zSql) {
4235 return SQLITE_NOMEM7;
4236 }
4237 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(pVtab->db, zSql, -1, &stmt, NULL((void*)0));
4238 sqlite3_freesqlite3_api->free(zSql);
4239 if(rc != SQLITE_OK0) {
4240 return rc;
4241 }
4242 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, rowid);
4243 rc = sqlite3_stepsqlite3_api->step(stmt);
4244 if(rc != SQLITE_ROW100) {
4245 rc = SQLITE_ERROR1;
4246 goto done;
4247 }
4248 *outValue = sqlite3_value_dupsqlite3_api->value_dup(sqlite3_column_valuesqlite3_api->column_value(stmt, 0));
4249 if(!*outValue) {
4250 rc = SQLITE_NOMEM7;
4251 goto done;
4252 }
4253 rc = SQLITE_OK0;
4254
4255 done:
4256 sqlite3_finalizesqlite3_api->finalize(stmt);
4257 return rc;
4258}
4259
4260/**
4261 * @brief Result the given metadata value for the given row and metadata column index.
4262 * Will traverse the metadatachunksNN table with BLOB I/0 for the given rowid.
4263 *
4264 * @param p
4265 * @param rowid
4266 * @param metadata_idx
4267 * @param context
4268 * @return int
4269 */
4270int vec0_result_metadata_value_for_rowid(vec0_vtab *p, i64 rowid, int metadata_idx, sqlite3_context * context) {
4271 int rc;
4272 i64 chunk_id;
4273 i64 chunk_offset;
4274 rc = vec0_get_chunk_position(p, rowid, NULL((void*)0), &chunk_id, &chunk_offset);
4275 if(rc != SQLITE_OK0) {
4276 return rc;
4277 }
4278 sqlite3_blob * blobValue;
4279 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowMetadataChunksNames[metadata_idx], "data", chunk_id, 0, &blobValue);
4280 if(rc != SQLITE_OK0) {
4281 return rc;
4282 }
4283
4284 switch(p->metadata_columns[metadata_idx].kind) {
4285 case VEC0_METADATA_COLUMN_KIND_BOOLEAN: {
4286 u8 block;
4287 rc = sqlite3_blob_readsqlite3_api->blob_read(blobValue, &block, sizeof(block), chunk_offset / CHAR_BIT8);
4288 if(rc != SQLITE_OK0) {
4289 goto done;
4290 }
4291 int value = block >> ((chunk_offset % CHAR_BIT8)) & 1;
4292 sqlite3_result_intsqlite3_api->result_int(context, value);
4293 break;
4294 }
4295 case VEC0_METADATA_COLUMN_KIND_INTEGER: {
4296 i64 value;
4297 rc = sqlite3_blob_readsqlite3_api->blob_read(blobValue, &value, sizeof(value), chunk_offset * sizeof(i64));
4298 if(rc != SQLITE_OK0) {
4299 goto done;
4300 }
4301 sqlite3_result_int64sqlite3_api->result_int64(context, value);
4302 break;
4303 }
4304 case VEC0_METADATA_COLUMN_KIND_FLOAT: {
4305 double value;
4306 rc = sqlite3_blob_readsqlite3_api->blob_read(blobValue, &value, sizeof(value), chunk_offset * sizeof(double));
4307 if(rc != SQLITE_OK0) {
4308 goto done;
4309 }
4310 sqlite3_result_doublesqlite3_api->result_double(context, value);
4311 break;
4312 }
4313 case VEC0_METADATA_COLUMN_KIND_TEXT: {
4314 u8 view[VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16];
4315 rc = sqlite3_blob_readsqlite3_api->blob_read(blobValue, &view, VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16, chunk_offset * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16);
4316 if(rc != SQLITE_OK0) {
4317 goto done;
4318 }
4319 int length = ((int *)view)[0];
4320 if(length <= VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12) {
4321 sqlite3_result_textsqlite3_api->result_text(context, (const char*) (view + 4), length, SQLITE_TRANSIENT((sqlite3_destructor_type)-1));
4322 }
4323 else {
4324 sqlite3_stmt * stmt;
4325 const char * zSql = sqlite3_mprintfsqlite3_api->mprintf("SELECT data FROM " VEC0_SHADOW_METADATA_TEXT_DATA_NAME"\"%w\".\"%w_metadatatext%02d\"" " WHERE rowid = ?", p->schemaName, p->tableName, metadata_idx);
4326 if(!zSql) {
4327 rc = SQLITE_ERROR1;
4328 goto done;
4329 }
4330 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
4331 sqlite3_freesqlite3_api->free((void *) zSql);
4332 if(rc != SQLITE_OK0) {
4333 goto done;
4334 }
4335 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, rowid);
4336 rc = sqlite3_stepsqlite3_api->step(stmt);
4337 if(rc != SQLITE_ROW100) {
4338 sqlite3_finalizesqlite3_api->finalize(stmt);
4339 rc = SQLITE_ERROR1;
4340 goto done;
4341 }
4342 sqlite3_result_valuesqlite3_api->result_value(context, sqlite3_column_valuesqlite3_api->column_value(stmt, 0));
4343 sqlite3_finalizesqlite3_api->finalize(stmt);
4344 rc = SQLITE_OK0;
4345 }
4346 break;
4347 }
4348 }
4349 done:
4350 // blobValue is read-only, will not fail on close
4351 sqlite3_blob_closesqlite3_api->blob_close(blobValue);
4352 return rc;
4353
4354}
4355
4356int vec0_get_latest_chunk_rowid(vec0_vtab *p, i64 *chunk_rowid, sqlite3_value ** partitionKeyValues) {
4357 int rc;
4358 const char *zSql;
4359 // lazy initialize stmtLatestChunk when needed. May be cleared during xSync()
4360 if (!p->stmtLatestChunk) {
4361 if(p->numPartitionColumns > 0) {
4362 sqlite3_str * s = sqlite3_str_newsqlite3_api->str_new(NULL((void*)0));
4363 sqlite3_str_appendfsqlite3_api->str_appendf(s, "SELECT max(rowid) FROM " VEC0_SHADOW_CHUNKS_NAME"\"%w\".\"%w_chunks\"" " WHERE ",
4364 p->schemaName, p->tableName);
4365
4366 for(int i = 0; i < p->numPartitionColumns; i++) {
4367 if(i != 0) {
4368 sqlite3_str_appendallsqlite3_api->str_appendall(s, " AND ");
4369 }
4370 sqlite3_str_appendfsqlite3_api->str_appendf(s, " partition%02d = ? ", i);
4371 }
4372 zSql = sqlite3_str_finishsqlite3_api->str_finish(s);
4373 }else {
4374 zSql = sqlite3_mprintfsqlite3_api->mprintf("SELECT max(rowid) FROM " VEC0_SHADOW_CHUNKS_NAME"\"%w\".\"%w_chunks\"",
4375 p->schemaName, p->tableName);
4376 }
4377
4378 if (!zSql) {
4379 rc = SQLITE_NOMEM7;
4380 goto cleanup;
4381 }
4382 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &p->stmtLatestChunk, 0);
4383 sqlite3_freesqlite3_api->free((void *)zSql);
4384 if (rc != SQLITE_OK0) {
4385 // IMP: V21406_05476
4386 vtab_set_error(&p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: "
4387 "could not initialize 'latest chunk' statement");
4388 goto cleanup;
4389 }
4390 }
4391
4392 for(int i = 0; i < p->numPartitionColumns; i++) {
4393 sqlite3_bind_valuesqlite3_api->bind_value(p->stmtLatestChunk, i+1, (partitionKeyValues[i]));
4394 }
4395
4396 rc = sqlite3_stepsqlite3_api->step(p->stmtLatestChunk);
4397 if (rc != SQLITE_ROW100) {
4398 // IMP: V31559_15629
4399 vtab_set_error(&p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: " "Could not find latest chunk");
4400 rc = SQLITE_ERROR1;
4401 goto cleanup;
4402 }
4403 if(sqlite3_column_typesqlite3_api->column_type(p->stmtLatestChunk, 0) == SQLITE_NULL5){
4404 rc = SQLITE_EMPTY16;
4405 goto cleanup;
4406 }
4407 *chunk_rowid = sqlite3_column_int64sqlite3_api->column_int64(p->stmtLatestChunk, 0);
4408 rc = sqlite3_stepsqlite3_api->step(p->stmtLatestChunk);
4409 if (rc != SQLITE_DONE101) {
4410 vtab_set_error(&p->base,
4411 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
4412 "unknown result code when closing out stmtLatestChunk. "
4413 "Please file an issue: " REPORT_URL"https://github.com/asg017/sqlite-vec/issues/new",
4414 p->schemaName, p->shadowChunksName);
4415 goto cleanup;
4416 }
4417 rc = SQLITE_OK0;
4418
4419cleanup:
4420 if (p->stmtLatestChunk) {
4421 sqlite3_resetsqlite3_api->reset(p->stmtLatestChunk);
4422 sqlite3_clear_bindingssqlite3_api->clear_bindings(p->stmtLatestChunk);
4423 }
4424 return rc;
4425}
4426
4427int vec0_rowids_insert_rowid(vec0_vtab *p, i64 rowid) {
4428 int rc = SQLITE_OK0;
4429 int entered = 0;
4430 UNUSED_PARAMETER(entered)(void)(entered); // temporary
4431 if (!p->stmtRowidsInsertRowid) {
4432 const char *zSql =
4433 sqlite3_mprintfsqlite3_api->mprintf("INSERT INTO " VEC0_SHADOW_ROWIDS_NAME"\"%w\".\"%w_rowids\"" "(rowid)"
4434 "VALUES (?);",
4435 p->schemaName, p->tableName);
4436 if (!zSql) {
4437 rc = SQLITE_NOMEM7;
4438 goto cleanup;
4439 }
4440 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &p->stmtRowidsInsertRowid, 0);
4441 sqlite3_freesqlite3_api->free((void *)zSql);
4442 if (rc != SQLITE_OK0) {
4443 vtab_set_error(&p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: "
4444 "could not initialize 'insert rowids' statement");
4445 goto cleanup;
4446 }
4447 }
4448
4449#if SQLITE_THREADSAFE
4450 if (sqlite3_mutex_entersqlite3_api->mutex_enter) {
4451 sqlite3_mutex_entersqlite3_api->mutex_enter(sqlite3_db_mutexsqlite3_api->db_mutex(p->db));
4452 entered = 1;
4453 }
4454#endif
4455 sqlite3_bind_int64sqlite3_api->bind_int64(p->stmtRowidsInsertRowid, 1, rowid);
4456 rc = sqlite3_stepsqlite3_api->step(p->stmtRowidsInsertRowid);
4457
4458 if (rc != SQLITE_DONE101) {
4459 if (sqlite3_extended_errcodesqlite3_api->extended_errcode(p->db) == SQLITE_CONSTRAINT_PRIMARYKEY(19 | (6<<8))) {
4460 // IMP: V17090_01160
4461 vtab_set_error(&p->base, "UNIQUE constraint failed on %s primary key",
4462 p->tableName);
4463 } else {
4464 // IMP: V04679_21517
4465 vtab_set_error(&p->base,
4466 "Error inserting rowid into rowids shadow table: %s",
4467 sqlite3_errmsgsqlite3_api->errmsg(sqlite3_db_handlesqlite3_api->db_handle(p->stmtRowidsInsertId)));
4468 }
4469 rc = SQLITE_ERROR1;
4470 goto cleanup;
4471 }
4472
4473 rc = SQLITE_OK0;
4474
4475cleanup:
4476 if (p->stmtRowidsInsertRowid) {
4477 sqlite3_resetsqlite3_api->reset(p->stmtRowidsInsertRowid);
4478 sqlite3_clear_bindingssqlite3_api->clear_bindings(p->stmtRowidsInsertRowid);
4479 }
4480
4481#if SQLITE_THREADSAFE
4482 if (sqlite3_mutex_leavesqlite3_api->mutex_leave && entered) {
4483 sqlite3_mutex_leavesqlite3_api->mutex_leave(sqlite3_db_mutexsqlite3_api->db_mutex(p->db));
4484 }
4485#endif
4486 return rc;
4487}
4488
4489int vec0_rowids_insert_id(vec0_vtab *p, sqlite3_value *idValue, i64 *rowid) {
4490 int rc = SQLITE_OK0;
4491 int entered = 0;
4492 UNUSED_PARAMETER(entered)(void)(entered); // temporary
4493 if (!p->stmtRowidsInsertId) {
4494 const char *zSql =
4495 sqlite3_mprintfsqlite3_api->mprintf("INSERT INTO " VEC0_SHADOW_ROWIDS_NAME"\"%w\".\"%w_rowids\"" "(id)"
4496 "VALUES (?);",
4497 p->schemaName, p->tableName);
4498 if (!zSql) {
4499 rc = SQLITE_NOMEM7;
4500 goto complete;
4501 }
4502 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &p->stmtRowidsInsertId, 0);
4503 sqlite3_freesqlite3_api->free((void *)zSql);
4504 if (rc != SQLITE_OK0) {
4505 vtab_set_error(&p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: "
4506 "could not initialize 'insert rowids id' statement");
4507 goto complete;
4508 }
4509 }
4510
4511#if SQLITE_THREADSAFE
4512 if (sqlite3_mutex_entersqlite3_api->mutex_enter) {
4513 sqlite3_mutex_entersqlite3_api->mutex_enter(sqlite3_db_mutexsqlite3_api->db_mutex(p->db));
4514 entered = 1;
4515 }
4516#endif
4517
4518 if (idValue) {
4519 sqlite3_bind_valuesqlite3_api->bind_value(p->stmtRowidsInsertId, 1, idValue);
4520 }
4521 rc = sqlite3_stepsqlite3_api->step(p->stmtRowidsInsertId);
4522
4523 if (rc != SQLITE_DONE101) {
4524 if (sqlite3_extended_errcodesqlite3_api->extended_errcode(p->db) == SQLITE_CONSTRAINT_UNIQUE(19 | (8<<8))) {
4525 // IMP: V20497_04568
4526 vtab_set_error(&p->base, "UNIQUE constraint failed on %s primary key",
4527 p->tableName);
4528 } else {
4529 // IMP: V24016_08086
4530 // IMP: V15177_32015
4531 vtab_set_error(&p->base,
4532 "Error inserting id into rowids shadow table: %s",
4533 sqlite3_errmsgsqlite3_api->errmsg(sqlite3_db_handlesqlite3_api->db_handle(p->stmtRowidsInsertId)));
4534 }
4535 rc = SQLITE_ERROR1;
4536 goto complete;
4537 }
4538
4539 *rowid = sqlite3_last_insert_rowidsqlite3_api->last_insert_rowid(p->db);
4540 rc = SQLITE_OK0;
4541
4542complete:
4543 if (p->stmtRowidsInsertId) {
4544 sqlite3_resetsqlite3_api->reset(p->stmtRowidsInsertId);
4545 sqlite3_clear_bindingssqlite3_api->clear_bindings(p->stmtRowidsInsertId);
4546 }
4547
4548#if SQLITE_THREADSAFE
4549 if (sqlite3_mutex_leavesqlite3_api->mutex_leave && entered) {
4550 sqlite3_mutex_leavesqlite3_api->mutex_leave(sqlite3_db_mutexsqlite3_api->db_mutex(p->db));
4551 }
4552#endif
4553 return rc;
4554}
4555
4556int vec0_metadata_chunk_size(vec0_metadata_column_kind kind, int chunk_size) {
4557 switch(kind) {
4558 case VEC0_METADATA_COLUMN_KIND_BOOLEAN:
4559 return chunk_size / 8;
4560 case VEC0_METADATA_COLUMN_KIND_INTEGER:
4561 return chunk_size * sizeof(i64);
4562 case VEC0_METADATA_COLUMN_KIND_FLOAT:
4563 return chunk_size * sizeof(double);
4564 case VEC0_METADATA_COLUMN_KIND_TEXT:
4565 return chunk_size * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16;
4566 }
4567 return 0;
4568}
4569
4570int vec0_rowids_update_position(vec0_vtab *p, i64 rowid, i64 chunk_rowid,
4571 i64 chunk_offset) {
4572 int rc = SQLITE_OK0;
4573
4574 if (!p->stmtRowidsUpdatePosition) {
4575 const char *zSql = sqlite3_mprintfsqlite3_api->mprintf(" UPDATE " VEC0_SHADOW_ROWIDS_NAME"\"%w\".\"%w_rowids\""
4576 " SET chunk_id = ?, chunk_offset = ?"
4577 " WHERE rowid = ?",
4578 p->schemaName, p->tableName);
4579 if (!zSql) {
4580 rc = SQLITE_NOMEM7;
4581 goto cleanup;
4582 }
4583 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &p->stmtRowidsUpdatePosition, 0);
4584 sqlite3_freesqlite3_api->free((void *)zSql);
4585 if (rc != SQLITE_OK0) {
4586 vtab_set_error(&p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: "
4587 "could not initialize 'update rowids position' statement");
4588 goto cleanup;
4589 }
4590 }
4591
4592 sqlite3_bind_int64sqlite3_api->bind_int64(p->stmtRowidsUpdatePosition, 1, chunk_rowid);
4593 sqlite3_bind_int64sqlite3_api->bind_int64(p->stmtRowidsUpdatePosition, 2, chunk_offset);
4594 sqlite3_bind_int64sqlite3_api->bind_int64(p->stmtRowidsUpdatePosition, 3, rowid);
4595
4596 rc = sqlite3_stepsqlite3_api->step(p->stmtRowidsUpdatePosition);
4597 if (rc != SQLITE_DONE101) {
4598 // IMP: V21925_05995
4599 vtab_set_error(&p->base,
4600 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
4601 "could not update rowids position for rowid=%lld, "
4602 "chunk_rowid=%lld, chunk_offset=%lld",
4603 rowid, chunk_rowid, chunk_offset);
4604 rc = SQLITE_ERROR1;
4605 goto cleanup;
4606 }
4607 rc = SQLITE_OK0;
4608
4609cleanup:
4610 if (p->stmtRowidsUpdatePosition) {
4611 sqlite3_resetsqlite3_api->reset(p->stmtRowidsUpdatePosition);
4612 sqlite3_clear_bindingssqlite3_api->clear_bindings(p->stmtRowidsUpdatePosition);
4613 }
4614
4615 return rc;
4616}
4617
4618/**
4619 * @brief Adds a new chunk for the vec0 table, and the corresponding vector
4620 * chunks.
4621 *
4622 * Inserts a new row into the _chunks table, with blank data, and uses that new
4623 * rowid to insert new blank rows into _vector_chunksXX tables.
4624 *
4625 * @param p: vec0 table to add new chunk
4626 * @param paritionKeyValues: Array of partition key valeus for the new chunk, if available
4627 * @param chunk_rowid: Output pointer, if not NULL, then will be filled with the
4628 * new chunk rowid.
4629 * @return int SQLITE_OK on success, error code otherwise.
4630 */
4631int vec0_new_chunk(vec0_vtab *p, sqlite3_value ** partitionKeyValues, i64 *chunk_rowid) {
4632 int rc;
4633 char *zSql;
4634 sqlite3_stmt *stmt;
4635 i64 rowid;
4636
4637 // Step 1: Insert a new row in _chunks, capture that new rowid
4638 if(p->numPartitionColumns > 0) {
4639 sqlite3_str * s = sqlite3_str_newsqlite3_api->str_new(NULL((void*)0));
4640 sqlite3_str_appendfsqlite3_api->str_appendf(s, "INSERT INTO " VEC0_SHADOW_CHUNKS_NAME"\"%w\".\"%w_chunks\"", p->schemaName, p->tableName);
4641 sqlite3_str_appendallsqlite3_api->str_appendall(s, "(size, validity, rowids");
4642 for(int i = 0; i < p->numPartitionColumns; i++) {
4643 sqlite3_str_appendfsqlite3_api->str_appendf(s, ", partition%02d", i);
4644 }
4645 sqlite3_str_appendallsqlite3_api->str_appendall(s, ") VALUES (?, ?, ?");
4646 for(int i = 0; i < p->numPartitionColumns; i++) {
4647 sqlite3_str_appendallsqlite3_api->str_appendall(s, ", ?");
4648 }
4649 sqlite3_str_appendallsqlite3_api->str_appendall(s, ")");
4650
4651 zSql = sqlite3_str_finishsqlite3_api->str_finish(s);
4652 }else {
4653 zSql = sqlite3_mprintfsqlite3_api->mprintf("INSERT INTO " VEC0_SHADOW_CHUNKS_NAME"\"%w\".\"%w_chunks\""
4654 "(size, validity, rowids) "
4655 "VALUES (?, ?, ?);",
4656 p->schemaName, p->tableName);
4657 }
4658
4659 if (!zSql) {
4660 return SQLITE_NOMEM7;
4661 }
4662 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
4663 sqlite3_freesqlite3_api->free(zSql);
4664 if (rc != SQLITE_OK0) {
4665 sqlite3_finalizesqlite3_api->finalize(stmt);
4666 return rc;
4667 }
4668
4669#if SQLITE_THREADSAFE
4670 if (sqlite3_mutex_entersqlite3_api->mutex_enter) {
4671 sqlite3_mutex_entersqlite3_api->mutex_enter(sqlite3_db_mutexsqlite3_api->db_mutex(p->db));
4672 }
4673#endif
4674
4675 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, p->chunk_size); // size
4676 sqlite3_bind_zeroblobsqlite3_api->bind_zeroblob(stmt, 2, p->chunk_size / CHAR_BIT8); // validity bitmap
4677 sqlite3_bind_zeroblobsqlite3_api->bind_zeroblob(stmt, 3, p->chunk_size * sizeof(i64)); // rowids
4678
4679 for(int i = 0; i < p->numPartitionColumns; i++) {
4680 sqlite3_bind_valuesqlite3_api->bind_value(stmt, 4 + i, partitionKeyValues[i]);
4681 }
4682
4683 rc = sqlite3_stepsqlite3_api->step(stmt);
4684 int failed = rc != SQLITE_DONE101;
4685 rowid = sqlite3_last_insert_rowidsqlite3_api->last_insert_rowid(p->db);
4686#if SQLITE_THREADSAFE
4687 if (sqlite3_mutex_leavesqlite3_api->mutex_leave) {
4688 sqlite3_mutex_leavesqlite3_api->mutex_leave(sqlite3_db_mutexsqlite3_api->db_mutex(p->db));
4689 }
4690#endif
4691 sqlite3_finalizesqlite3_api->finalize(stmt);
4692 if (failed) {
4693 return SQLITE_ERROR1;
4694 }
4695
4696 // Step 2: Create new vector chunks for each vector column, with
4697 // that new chunk_rowid.
4698 //
4699 // SHADOW_TABLE_ROWID_QUIRK: The _vector_chunksNN and _metadatachunksNN
4700 // shadow tables declare "rowid PRIMARY KEY" without the INTEGER type, so
4701 // the user-defined "rowid" column is NOT an alias for the internal SQLite
4702 // rowid (_rowid_). When only appending rows these two happen to stay in
4703 // sync, but after a chunk is deleted (vec0Update_Delete_DeleteChunkIfEmpty)
4704 // and a new one is created, the auto-assigned _rowid_ can diverge from the
4705 // user "rowid" value. Since sqlite3_blob_open() addresses rows by internal
4706 // _rowid_, we must explicitly set BOTH _rowid_ and "rowid" to the same
4707 // value so that later blob operations can find the row.
4708 //
4709 // The correct long-term fix is changing the schema to
4710 // "rowid INTEGER PRIMARY KEY"
4711 // which makes it a true alias, but that would break existing databases.
4712
4713 for (int i = 0; i < vec0_num_defined_user_columns(p); i++) {
4714 if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_VECTOR) {
4715 continue;
4716 }
4717 int vector_column_idx = p->user_column_idxs[i];
4718
4719 // Non-FLAT columns (rescore, IVF, DiskANN) don't use _vector_chunks
4720 if (p->vector_columns[vector_column_idx].index_type != VEC0_INDEX_TYPE_FLAT) {
4721 continue;
4722 }
4723
4724 i64 vectorsSize =
4725 p->chunk_size * vector_column_byte_size(p->vector_columns[vector_column_idx]);
4726
4727 // See SHADOW_TABLE_ROWID_QUIRK above for why _rowid_ and rowid are both set.
4728 zSql = sqlite3_mprintfsqlite3_api->mprintf("INSERT INTO " VEC0_SHADOW_VECTOR_N_NAME"\"%w\".\"%w_vector_chunks%02d\""
4729 "(_rowid_, rowid, vectors)"
4730 "VALUES (?, ?, ?)",
4731 p->schemaName, p->tableName, vector_column_idx);
4732 if (!zSql) {
4733 return SQLITE_NOMEM7;
4734 }
4735 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
4736 sqlite3_freesqlite3_api->free(zSql);
4737
4738 if (rc != SQLITE_OK0) {
4739 sqlite3_finalizesqlite3_api->finalize(stmt);
4740 return rc;
4741 }
4742
4743 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, rowid); // _rowid_ (internal SQLite rowid)
4744 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 2, rowid); // rowid (user-defined column)
4745 sqlite3_bind_zeroblob64sqlite3_api->bind_zeroblob64(stmt, 3, vectorsSize);
4746
4747 rc = sqlite3_stepsqlite3_api->step(stmt);
4748 sqlite3_finalizesqlite3_api->finalize(stmt);
4749 if (rc != SQLITE_DONE101) {
4750 return rc;
4751 }
4752 }
4753
4754#if SQLITE_VEC_ENABLE_RESCORE1
4755 // Create new rescore chunks for each rescore-enabled vector column
4756 rc = rescore_new_chunk(p, rowid);
4757 if (rc != SQLITE_OK0) {
4758 return rc;
4759 }
4760#endif
4761
4762 // Step 3: Create new metadata chunks for each metadata column
4763 for (int i = 0; i < vec0_num_defined_user_columns(p); i++) {
4764 if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_METADATA) {
4765 continue;
4766 }
4767 int metadata_column_idx = p->user_column_idxs[i];
4768 // See SHADOW_TABLE_ROWID_QUIRK above for why _rowid_ and rowid are both set.
4769 zSql = sqlite3_mprintfsqlite3_api->mprintf("INSERT INTO " VEC0_SHADOW_METADATA_N_NAME"\"%w\".\"%w_metadatachunks%02d\""
4770 "(_rowid_, rowid, data)"
4771 "VALUES (?, ?, ?)",
4772 p->schemaName, p->tableName, metadata_column_idx);
4773 if (!zSql) {
4774 return SQLITE_NOMEM7;
4775 }
4776 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
4777 sqlite3_freesqlite3_api->free(zSql);
4778
4779 if (rc != SQLITE_OK0) {
4780 sqlite3_finalizesqlite3_api->finalize(stmt);
4781 return rc;
4782 }
4783
4784 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, rowid); // _rowid_ (internal SQLite rowid)
4785 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 2, rowid); // rowid (user-defined column)
4786 sqlite3_bind_zeroblob64sqlite3_api->bind_zeroblob64(stmt, 3, vec0_metadata_chunk_size(p->metadata_columns[metadata_column_idx].kind, p->chunk_size));
4787
4788 rc = sqlite3_stepsqlite3_api->step(stmt);
4789 sqlite3_finalizesqlite3_api->finalize(stmt);
4790 if (rc != SQLITE_DONE101) {
4791 return rc;
4792 }
4793 }
4794
4795
4796 if (chunk_rowid) {
4797 *chunk_rowid = rowid;
4798 }
4799
4800 return SQLITE_OK0;
4801}
4802
4803struct vec0_query_fullscan_data {
4804 sqlite3_stmt *rowids_stmt;
4805 i8 done;
4806};
4807void vec0_query_fullscan_data_clear(
4808 struct vec0_query_fullscan_data *fullscan_data) {
4809 if (!fullscan_data)
4810 return;
4811
4812 if (fullscan_data->rowids_stmt) {
4813 sqlite3_finalizesqlite3_api->finalize(fullscan_data->rowids_stmt);
4814 fullscan_data->rowids_stmt = NULL((void*)0);
4815 }
4816}
4817
4818struct vec0_query_knn_data {
4819 i64 k;
4820 i64 k_used;
4821 // Array of rowids of size k. Must be freed with sqlite3_free().
4822 i64 *rowids;
4823 // Array of distances of size k. Must be freed with sqlite3_free().
4824 f32 *distances;
4825 i64 current_idx;
4826};
4827void vec0_query_knn_data_clear(struct vec0_query_knn_data *knn_data) {
4828 if (!knn_data)
4829 return;
4830
4831 if (knn_data->rowids) {
4832 sqlite3_freesqlite3_api->free(knn_data->rowids);
4833 knn_data->rowids = NULL((void*)0);
4834 }
4835 if (knn_data->distances) {
4836 sqlite3_freesqlite3_api->free(knn_data->distances);
4837 knn_data->distances = NULL((void*)0);
4838 }
4839}
4840
4841struct vec0_query_point_data {
4842 i64 rowid;
4843 void *vectors[VEC0_MAX_VECTOR_COLUMNS16];
4844 int done;
4845};
4846void vec0_query_point_data_clear(struct vec0_query_point_data *point_data) {
4847 if (!point_data)
4848 return;
4849 for (int i = 0; i < VEC0_MAX_VECTOR_COLUMNS16; i++) {
4850 sqlite3_freesqlite3_api->free(point_data->vectors[i]);
4851 point_data->vectors[i] = NULL((void*)0);
4852 }
4853}
4854
4855typedef enum {
4856 // If any values are updated, please update the ARCHITECTURE.md docs accordingly!
4857
4858 VEC0_QUERY_PLAN_FULLSCAN = '1',
4859 VEC0_QUERY_PLAN_POINT = '2',
4860 VEC0_QUERY_PLAN_KNN = '3',
4861} vec0_query_plan;
4862
4863typedef struct vec0_cursor vec0_cursor;
4864struct vec0_cursor {
4865 sqlite3_vtab_cursor base;
4866
4867 vec0_query_plan query_plan;
4868 struct vec0_query_fullscan_data *fullscan_data;
4869 struct vec0_query_knn_data *knn_data;
4870 struct vec0_query_point_data *point_data;
4871};
4872
4873void vec0_cursor_clear(vec0_cursor *pCur) {
4874 if (pCur->fullscan_data) {
4875 vec0_query_fullscan_data_clear(pCur->fullscan_data);
4876 sqlite3_freesqlite3_api->free(pCur->fullscan_data);
4877 pCur->fullscan_data = NULL((void*)0);
4878 }
4879 if (pCur->knn_data) {
4880 vec0_query_knn_data_clear(pCur->knn_data);
4881 sqlite3_freesqlite3_api->free(pCur->knn_data);
4882 pCur->knn_data = NULL((void*)0);
4883 }
4884 if (pCur->point_data) {
4885 vec0_query_point_data_clear(pCur->point_data);
4886 sqlite3_freesqlite3_api->free(pCur->point_data);
4887 pCur->point_data = NULL((void*)0);
4888 }
4889}
4890
4891// IVF index implementation — #include'd here after all struct/helper definitions
4892#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
4893#include "sqlite-vec-ivf-kmeans.c"
4894#include "sqlite-vec-ivf.c"
4895#endif
4896
4897#define VEC_CONSTRUCTOR_ERROR"vec0 constructor error: " "vec0 constructor error: "
4898static int vec0_init(sqlite3 *db, void *pAux, int argc, const char *const *argv,
4899 sqlite3_vtab **ppVtab, char **pzErr, bool_Bool isCreate) {
4900 UNUSED_PARAMETER(pAux)(void)(pAux);
4901 vec0_vtab *pNew;
4902 int rc;
4903 const char *zSql;
4904
4905 pNew = sqlite3_mallocsqlite3_api->malloc(sizeof(*pNew));
4906 if (pNew == 0)
1
Assuming 'pNew' is not equal to null
2
Taking false branch
4907 return SQLITE_NOMEM7;
4908 memset(pNew, 0, sizeof(*pNew));
4909
4910 // Declared chunk_size=N for entire table.
4911 // -1 to use the defualt, otherwise will get re-assigned on `chunk_size=N`
4912 // option
4913 int chunk_size = -1;
4914 int numVectorColumns = 0;
4915 int numPartitionColumns = 0;
4916 int numAuxiliaryColumns = 0;
4917 int numMetadataColumns = 0;
4918 int user_column_idx = 0;
4919
4920 // track if a "primary key" column is defined
4921 char *pkColumnName = NULL((void*)0);
4922 int pkColumnNameLength;
4923 int pkColumnType = SQLITE_INTEGER1;
4924
4925 for (int i = 3; i < argc; i++) {
3
Assuming 'i' is < 'argc'
4
Loop condition is true. Entering loop body
4926 struct VectorColumnDefinition vecColumn;
4927 struct Vec0PartitionColumnDefinition partitionColumn;
4928 struct Vec0AuxiliaryColumnDefinition auxColumn;
4929 struct Vec0MetadataColumnDefinition metadataColumn;
4930 char *cName = NULL((void*)0);
4931 int cNameLength;
4932 int cType;
4933
4934 // Scenario #1: Constructor argument is a vector column definition, ie `foo float[1024]`
4935 rc = vec0_parse_vector_column(argv[i], strlen(argv[i]), &vecColumn);
5
Calling 'vec0_parse_vector_column'
4936 if (rc == SQLITE_ERROR1) {
4937 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
4938 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: " "could not parse vector column '%s'", argv[i]);
4939 goto error;
4940 }
4941 if (rc == SQLITE_OK0) {
4942 if (numVectorColumns >= VEC0_MAX_VECTOR_COLUMNS16) {
4943 sqlite3_freesqlite3_api->free(vecColumn.name);
4944 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
4945 "Too many provided vector columns, maximum %d",
4946 VEC0_MAX_VECTOR_COLUMNS16);
4947 goto error;
4948 }
4949
4950 if (vecColumn.dimensions > SQLITE_VEC_VEC0_MAX_DIMENSIONS8192) {
4951 sqlite3_freesqlite3_api->free(vecColumn.name);
4952 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
4953 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
4954 "Dimension on vector column too large, provided %lld, maximum %lld",
4955 (i64)vecColumn.dimensions, SQLITE_VEC_VEC0_MAX_DIMENSIONS8192);
4956 goto error;
4957 }
4958
4959 // DiskANN validation
4960 if (vecColumn.index_type == VEC0_INDEX_TYPE_DISKANN) {
4961 if (vecColumn.element_type == SQLITE_VEC_ELEMENT_TYPE_BIT) {
4962 sqlite3_freesqlite3_api->free(vecColumn.name);
4963 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
4964 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
4965 "DiskANN index is not supported on bit vector columns");
4966 goto error;
4967 }
4968 if (vecColumn.diskann.quantizer_type == VEC0_DISKANN_QUANTIZER_BINARY &&
4969 (vecColumn.dimensions % CHAR_BIT8) != 0) {
4970 sqlite3_freesqlite3_api->free(vecColumn.name);
4971 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
4972 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
4973 "DiskANN with binary quantizer requires dimensions divisible by 8");
4974 goto error;
4975 }
4976 }
4977
4978 pNew->user_column_kinds[user_column_idx] = SQLITE_VEC0_USER_COLUMN_KIND_VECTOR;
4979 pNew->user_column_idxs[user_column_idx] = numVectorColumns;
4980 memcpy(&pNew->vector_columns[numVectorColumns], &vecColumn, sizeof(vecColumn));
4981 numVectorColumns++;
4982 pNew->numVectorColumns = numVectorColumns;
4983 user_column_idx++;
4984
4985 continue;
4986 }
4987
4988 // Scenario #2: Constructor argument is a partition key column definition, ie `user_id text partition key`
4989 rc = vec0_parse_partition_key_definition(argv[i], strlen(argv[i]), &cName,
4990 &cNameLength, &cType);
4991 if (rc == SQLITE_OK0) {
4992 if (numPartitionColumns >= VEC0_MAX_PARTITION_COLUMNS4) {
4993 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
4994 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
4995 "More than %d partition key columns were provided",
4996 VEC0_MAX_PARTITION_COLUMNS4);
4997 goto error;
4998 }
4999 partitionColumn.type = cType;
5000 partitionColumn.name_length = cNameLength;
5001 partitionColumn.name = sqlite3_mprintfsqlite3_api->mprintf("%.*s", cNameLength, cName);
5002 if(!partitionColumn.name) {
5003 rc = SQLITE_NOMEM7;
5004 goto error;
5005 }
5006
5007 pNew->user_column_kinds[user_column_idx] = SQLITE_VEC0_USER_COLUMN_KIND_PARTITION;
5008 pNew->user_column_idxs[user_column_idx] = numPartitionColumns;
5009 memcpy(&pNew->paritition_columns[numPartitionColumns], &partitionColumn, sizeof(partitionColumn));
5010 numPartitionColumns++;
5011 pNew->numPartitionColumns = numPartitionColumns;
5012 user_column_idx++;
5013 continue;
5014 }
5015
5016 // Scenario #3: Constructor argument is a primary key column definition, ie `article_id text primary key`
5017 rc = vec0_parse_primary_key_definition(argv[i], strlen(argv[i]), &cName,
5018 &cNameLength, &cType);
5019 if (rc == SQLITE_OK0) {
5020 if (pkColumnName) {
5021 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5022 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5023 "More than one primary key definition was provided, vec0 only "
5024 "suports a single primary key column",
5025 argv[i]);
5026 goto error;
5027 }
5028 pkColumnName = cName;
5029 pkColumnNameLength = cNameLength;
5030 pkColumnType = cType;
5031 continue;
5032 }
5033
5034 // Scenario #4: Constructor argument is a auxiliary column definition, ie `+contents text`
5035 rc = vec0_parse_auxiliary_column_definition(argv[i], strlen(argv[i]), &cName,
5036 &cNameLength, &cType);
5037 if(rc == SQLITE_OK0) {
5038 if (numAuxiliaryColumns >= VEC0_MAX_AUXILIARY_COLUMNS16) {
5039 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5040 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5041 "More than %d auxiliary columns were provided",
5042 VEC0_MAX_AUXILIARY_COLUMNS16);
5043 goto error;
5044 }
5045 auxColumn.type = cType;
5046 auxColumn.name_length = cNameLength;
5047 auxColumn.name = sqlite3_mprintfsqlite3_api->mprintf("%.*s", cNameLength, cName);
5048 if(!auxColumn.name) {
5049 rc = SQLITE_NOMEM7;
5050 goto error;
5051 }
5052
5053 pNew->user_column_kinds[user_column_idx] = SQLITE_VEC0_USER_COLUMN_KIND_AUXILIARY;
5054 pNew->user_column_idxs[user_column_idx] = numAuxiliaryColumns;
5055 memcpy(&pNew->auxiliary_columns[numAuxiliaryColumns], &auxColumn, sizeof(auxColumn));
5056 numAuxiliaryColumns++;
5057 pNew->numAuxiliaryColumns = numAuxiliaryColumns;
5058 user_column_idx++;
5059 continue;
5060 }
5061
5062 vec0_metadata_column_kind kind;
5063 rc = vec0_parse_metadata_column_definition(argv[i], strlen(argv[i]), &cName,
5064 &cNameLength, &kind);
5065 if(rc == SQLITE_OK0) {
5066 if (numMetadataColumns >= VEC0_MAX_METADATA_COLUMNS16) {
5067 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5068 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5069 "More than %d metadata columns were provided",
5070 VEC0_MAX_METADATA_COLUMNS16);
5071 goto error;
5072 }
5073 metadataColumn.kind = kind;
5074 metadataColumn.name_length = cNameLength;
5075 metadataColumn.name = sqlite3_mprintfsqlite3_api->mprintf("%.*s", cNameLength, cName);
5076 if(!metadataColumn.name) {
5077 rc = SQLITE_NOMEM7;
5078 goto error;
5079 }
5080
5081 pNew->user_column_kinds[user_column_idx] = SQLITE_VEC0_USER_COLUMN_KIND_METADATA;
5082 pNew->user_column_idxs[user_column_idx] = numMetadataColumns;
5083 memcpy(&pNew->metadata_columns[numMetadataColumns], &metadataColumn, sizeof(metadataColumn));
5084 numMetadataColumns++;
5085 pNew->numMetadataColumns = numMetadataColumns;
5086 user_column_idx++;
5087 continue;
5088 }
5089
5090 // Scenario #4: Constructor argument is a table-level option, ie `chunk_size`
5091
5092 char *key;
5093 char *value;
5094 int keyLength, valueLength;
5095 rc = vec0_parse_table_option(argv[i], strlen(argv[i]), &key, &keyLength,
5096 &value, &valueLength);
5097 if (rc == SQLITE_ERROR1) {
5098 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5099 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: " "could not parse table option '%s'", argv[i]);
5100 goto error;
5101 }
5102 if (rc == SQLITE_OK0) {
5103 if (sqlite3_strnicmpsqlite3_api->strnicmp(key, "chunk_size", keyLength) == 0) {
5104 chunk_size = atoi(value);
5105 if (chunk_size <= 0) {
5106 // IMP: V01931_18769
5107 *pzErr =
5108 sqlite3_mprintfsqlite3_api->mprintf(VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5109 "chunk_size must be a non-zero positive integer");
5110 goto error;
5111 }
5112 if ((chunk_size % 8) != 0) {
5113 // IMP: V14110_30948
5114 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5115 "chunk_size must be divisible by 8");
5116 goto error;
5117 }
5118#define SQLITE_VEC_CHUNK_SIZE_MAX4096 4096
5119 if (chunk_size > SQLITE_VEC_CHUNK_SIZE_MAX4096) {
5120 *pzErr =
5121 sqlite3_mprintfsqlite3_api->mprintf(VEC_CONSTRUCTOR_ERROR"vec0 constructor error: " "chunk_size too large");
5122 goto error;
5123 }
5124 } else {
5125 // IMP: V27642_11712
5126 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5127 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: " "Unknown table option: %.*s", keyLength, key);
5128 goto error;
5129 }
5130 continue;
5131 }
5132
5133 // Scenario #5: Unknown constructor argument
5134 *pzErr =
5135 sqlite3_mprintfsqlite3_api->mprintf(VEC_CONSTRUCTOR_ERROR"vec0 constructor error: " "Could not parse '%s'", argv[i]);
5136 goto error;
5137 }
5138
5139 if (chunk_size < 0) {
5140 chunk_size = 1024;
5141 }
5142
5143 if (numVectorColumns <= 0) {
5144 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5145 "At least one vector column is required");
5146 goto error;
5147 }
5148
5149#if SQLITE_VEC_ENABLE_RESCORE1
5150 {
5151 int hasRescore = 0;
5152 for (int i = 0; i < numVectorColumns; i++) {
5153 if (pNew->vector_columns[i].index_type == VEC0_INDEX_TYPE_RESCORE) {
5154 hasRescore = 1;
5155 break;
5156 }
5157 }
5158 if (hasRescore) {
5159 if (numMetadataColumns > 0) {
5160 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5161 "Metadata columns are not supported with rescore indexes");
5162 goto error;
5163 }
5164 if (numPartitionColumns > 0) {
5165 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5166 "Partition key columns are not supported with rescore indexes");
5167 goto error;
5168 }
5169 }
5170 }
5171#endif
5172
5173 // IVF indexes do not support auxiliary, metadata, or partition key columns.
5174 {
5175 int has_ivf = 0;
5176 for (int i = 0; i < numVectorColumns; i++) {
5177 if (pNew->vector_columns[i].index_type == VEC0_INDEX_TYPE_IVF) {
5178 has_ivf = 1;
5179 break;
5180 }
5181 }
5182 if (has_ivf) {
5183 if (numPartitionColumns > 0) {
5184 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5185 "partition key columns are not supported with IVF indexes");
5186 goto error;
5187 }
5188 if (numMetadataColumns > 0) {
5189 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5190 "metadata columns are not supported with IVF indexes");
5191 goto error;
5192 }
5193 }
5194 }
5195
5196 // DiskANN columns cannot coexist with aux/metadata/partition columns
5197 for (int i = 0; i < numVectorColumns; i++) {
5198 if (pNew->vector_columns[i].index_type == VEC0_INDEX_TYPE_DISKANN) {
5199 if (numMetadataColumns > 0) {
5200 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5201 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5202 "Metadata columns are not supported with DiskANN-indexed vector columns");
5203 goto error;
5204 }
5205 if (numPartitionColumns > 0) {
5206 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5207 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5208 "Partition key columns are not supported with DiskANN-indexed vector columns");
5209 goto error;
5210 }
5211 break;
5212 }
5213 }
5214
5215 // Determine whether to add the FTS5-style hidden command column.
5216 // New tables (isCreate) always get it; existing tables only if created
5217 // with v0.1.10+ (which validated no column name == table name).
5218 int hasCommandColumn = 0;
5219 if (isCreate) {
5220 // Validate no user column name conflicts with the table name
5221 const char *tblName = argv[2];
5222 int tblNameLen = (int)strlen(tblName);
5223 for (int i = 0; i < numVectorColumns; i++) {
5224 if (pNew->vector_columns[i].name_length == tblNameLen &&
5225 sqlite3_strnicmpsqlite3_api->strnicmp(pNew->vector_columns[i].name, tblName, tblNameLen) == 0) {
5226 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5227 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5228 "column name '%s' conflicts with table name (reserved for command column)",
5229 tblName);
5230 goto error;
5231 }
5232 }
5233 for (int i = 0; i < numPartitionColumns; i++) {
5234 if (pNew->paritition_columns[i].name_length == tblNameLen &&
5235 sqlite3_strnicmpsqlite3_api->strnicmp(pNew->paritition_columns[i].name, tblName, tblNameLen) == 0) {
5236 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5237 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5238 "column name '%s' conflicts with table name (reserved for command column)",
5239 tblName);
5240 goto error;
5241 }
5242 }
5243 for (int i = 0; i < numAuxiliaryColumns; i++) {
5244 if (pNew->auxiliary_columns[i].name_length == tblNameLen &&
5245 sqlite3_strnicmpsqlite3_api->strnicmp(pNew->auxiliary_columns[i].name, tblName, tblNameLen) == 0) {
5246 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5247 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5248 "column name '%s' conflicts with table name (reserved for command column)",
5249 tblName);
5250 goto error;
5251 }
5252 }
5253 for (int i = 0; i < numMetadataColumns; i++) {
5254 if (pNew->metadata_columns[i].name_length == tblNameLen &&
5255 sqlite3_strnicmpsqlite3_api->strnicmp(pNew->metadata_columns[i].name, tblName, tblNameLen) == 0) {
5256 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5257 VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5258 "column name '%s' conflicts with table name (reserved for command column)",
5259 tblName);
5260 goto error;
5261 }
5262 }
5263 hasCommandColumn = 1;
5264 } else {
5265 // xConnect: check _info shadow table for version
5266 sqlite3_stmt *stmtInfo = NULL((void*)0);
5267 char *zInfoSql = sqlite3_mprintfsqlite3_api->mprintf(
5268 "SELECT value FROM " VEC0_SHADOW_INFO_NAME"\"%w\".\"%w_info\"" " WHERE key = 'CREATE_VERSION_PATCH'",
5269 argv[1], argv[2]);
5270 if (zInfoSql) {
5271 int infoRc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zInfoSql, -1, &stmtInfo, NULL((void*)0));
5272 sqlite3_freesqlite3_api->free(zInfoSql);
5273 if (infoRc == SQLITE_OK0 && sqlite3_stepsqlite3_api->step(stmtInfo) == SQLITE_ROW100) {
5274 int patch = sqlite3_column_intsqlite3_api->column_int(stmtInfo, 0);
5275 hasCommandColumn = (patch >= 10); // v0.1.10+
5276 }
5277 // If _info doesn't exist or has no version, assume old table
5278 sqlite3_finalizesqlite3_api->finalize(stmtInfo);
5279 }
5280 }
5281 pNew->hasCommandColumn = hasCommandColumn;
5282
5283 sqlite3_str *createStr = sqlite3_str_newsqlite3_api->str_new(NULL((void*)0));
5284 sqlite3_str_appendallsqlite3_api->str_appendall(createStr, "CREATE TABLE x(");
5285 if (pkColumnName) {
5286 sqlite3_str_appendfsqlite3_api->str_appendf(createStr, "\"%.*w\" primary key, ", pkColumnNameLength,
5287 pkColumnName);
5288 } else {
5289 sqlite3_str_appendallsqlite3_api->str_appendall(createStr, "rowid, ");
5290 }
5291 for (int i = 0; i < numVectorColumns + numPartitionColumns + numAuxiliaryColumns + numMetadataColumns; i++) {
5292 switch(pNew->user_column_kinds[i]) {
5293 case SQLITE_VEC0_USER_COLUMN_KIND_VECTOR: {
5294 int vector_idx = pNew->user_column_idxs[i];
5295 sqlite3_str_appendfsqlite3_api->str_appendf(createStr, "\"%.*w\", ",
5296 pNew->vector_columns[vector_idx].name_length,
5297 pNew->vector_columns[vector_idx].name);
5298 break;
5299 }
5300 case SQLITE_VEC0_USER_COLUMN_KIND_PARTITION: {
5301 int partition_idx = pNew->user_column_idxs[i];
5302 sqlite3_str_appendfsqlite3_api->str_appendf(createStr, "\"%.*w\", ",
5303 pNew->paritition_columns[partition_idx].name_length,
5304 pNew->paritition_columns[partition_idx].name);
5305 break;
5306 }
5307 case SQLITE_VEC0_USER_COLUMN_KIND_AUXILIARY: {
5308 int auxiliary_idx = pNew->user_column_idxs[i];
5309 sqlite3_str_appendfsqlite3_api->str_appendf(createStr, "\"%.*w\", ",
5310 pNew->auxiliary_columns[auxiliary_idx].name_length,
5311 pNew->auxiliary_columns[auxiliary_idx].name);
5312 break;
5313 }
5314 case SQLITE_VEC0_USER_COLUMN_KIND_METADATA: {
5315 int metadata_idx = pNew->user_column_idxs[i];
5316 sqlite3_str_appendfsqlite3_api->str_appendf(createStr, "\"%.*w\", ",
5317 pNew->metadata_columns[metadata_idx].name_length,
5318 pNew->metadata_columns[metadata_idx].name);
5319 break;
5320 }
5321 }
5322
5323 }
5324 if (hasCommandColumn) {
5325 sqlite3_str_appendfsqlite3_api->str_appendf(createStr, " \"%w\" hidden, distance hidden, k hidden) ", argv[2]);
5326 } else {
5327 sqlite3_str_appendallsqlite3_api->str_appendall(createStr, " distance hidden, k hidden) ");
5328 }
5329 if (pkColumnName) {
5330 sqlite3_str_appendallsqlite3_api->str_appendall(createStr, "without rowid ");
5331 }
5332 zSql = sqlite3_str_finishsqlite3_api->str_finish(createStr);
5333 if (!zSql) {
5334 goto error;
5335 }
5336 rc = sqlite3_declare_vtabsqlite3_api->declare_vtab(db, zSql);
5337 sqlite3_freesqlite3_api->free((void *)zSql);
5338 if (rc != SQLITE_OK0) {
5339 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(VEC_CONSTRUCTOR_ERROR"vec0 constructor error: "
5340 "could not declare virtual table, '%s'",
5341 sqlite3_errmsgsqlite3_api->errmsg(db));
5342 goto error;
5343 }
5344
5345 const char *schemaName = argv[1];
5346 const char *tableName = argv[2];
5347
5348 pNew->db = db;
5349 pNew->pkIsText = pkColumnType == SQLITE_TEXT3;
5350 pNew->schemaName = sqlite3_mprintfsqlite3_api->mprintf("%s", schemaName);
5351 if (!pNew->schemaName) {
5352 goto error;
5353 }
5354 pNew->tableName = sqlite3_mprintfsqlite3_api->mprintf("%s", tableName);
5355 if (!pNew->tableName) {
5356 goto error;
5357 }
5358 pNew->shadowRowidsName = sqlite3_mprintfsqlite3_api->mprintf("%s_rowids", tableName);
5359 if (!pNew->shadowRowidsName) {
5360 goto error;
5361 }
5362 pNew->shadowChunksName = sqlite3_mprintfsqlite3_api->mprintf("%s_chunks", tableName);
5363 if (!pNew->shadowChunksName) {
5364 goto error;
5365 }
5366 pNew->numVectorColumns = numVectorColumns;
5367 pNew->numPartitionColumns = numPartitionColumns;
5368 pNew->numAuxiliaryColumns = numAuxiliaryColumns;
5369 pNew->numMetadataColumns = numMetadataColumns;
5370
5371 for (int i = 0; i < pNew->numVectorColumns; i++) {
5372 pNew->shadowVectorChunksNames[i] =
5373 sqlite3_mprintfsqlite3_api->mprintf("%s_vector_chunks%02d", tableName, i);
5374 if (!pNew->shadowVectorChunksNames[i]) {
5375 goto error;
5376 }
5377#if SQLITE_VEC_ENABLE_RESCORE1
5378 if (pNew->vector_columns[i].index_type == VEC0_INDEX_TYPE_RESCORE) {
5379 pNew->shadowRescoreChunksNames[i] =
5380 sqlite3_mprintfsqlite3_api->mprintf("%s_rescore_chunks%02d", tableName, i);
5381 if (!pNew->shadowRescoreChunksNames[i]) {
5382 goto error;
5383 }
5384 pNew->shadowRescoreVectorsNames[i] =
5385 sqlite3_mprintfsqlite3_api->mprintf("%s_rescore_vectors%02d", tableName, i);
5386 if (!pNew->shadowRescoreVectorsNames[i]) {
5387 goto error;
5388 }
5389 }
5390#endif
5391#if SQLITE_VEC_ENABLE_DISKANN0
5392 if (pNew->vector_columns[i].index_type == VEC0_INDEX_TYPE_DISKANN) {
5393 pNew->shadowVectorsNames[i] =
5394 sqlite3_mprintfsqlite3_api->mprintf("%s_vectors%02d", tableName, i);
5395 if (!pNew->shadowVectorsNames[i]) {
5396 goto error;
5397 }
5398 pNew->shadowDiskannNodesNames[i] =
5399 sqlite3_mprintfsqlite3_api->mprintf("%s_diskann_nodes%02d", tableName, i);
5400 if (!pNew->shadowDiskannNodesNames[i]) {
5401 goto error;
5402 }
5403 }
5404#endif
5405 }
5406#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
5407 for (int i = 0; i < pNew->numVectorColumns; i++) {
5408 if (pNew->vector_columns[i].index_type != VEC0_INDEX_TYPE_IVF) continue;
5409 pNew->shadowIvfCellsNames[i] =
5410 sqlite3_mprintfsqlite3_api->mprintf("%s_ivf_cells%02d", tableName, i);
5411 if (!pNew->shadowIvfCellsNames[i]) goto error;
5412 pNew->ivfTrainedCache[i] = -1; // unknown
5413 }
5414#endif
5415 for (int i = 0; i < pNew->numMetadataColumns; i++) {
5416 pNew->shadowMetadataChunksNames[i] =
5417 sqlite3_mprintfsqlite3_api->mprintf("%s_metadatachunks%02d", tableName, i);
5418 if (!pNew->shadowMetadataChunksNames[i]) {
5419 goto error;
5420 }
5421 }
5422 pNew->chunk_size = chunk_size;
5423
5424 // if xCreate, then create the necessary shadow tables
5425 if (isCreate) {
5426 sqlite3_stmt *stmt;
5427 int rc;
5428
5429 char * zCreateInfo = sqlite3_mprintfsqlite3_api->mprintf("CREATE TABLE "VEC0_SHADOW_INFO_NAME"\"%w\".\"%w_info\"" " (key text primary key, value any)", pNew->schemaName, pNew->tableName);
5430 if(!zCreateInfo) {
5431 goto error;
5432 }
5433 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zCreateInfo, -1, &stmt, NULL((void*)0));
5434
5435 sqlite3_freesqlite3_api->free((void *) zCreateInfo);
5436 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5437 // TODO(IMP)
5438 sqlite3_finalizesqlite3_api->finalize(stmt);
5439 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Could not create '_info' shadow table: %s",
5440 sqlite3_errmsgsqlite3_api->errmsg(db));
5441 goto error;
5442 }
5443 sqlite3_finalizesqlite3_api->finalize(stmt);
5444
5445 char * zSeedInfo = sqlite3_mprintfsqlite3_api->mprintf(
5446 "INSERT INTO "VEC0_SHADOW_INFO_NAME"\"%w\".\"%w_info\"" "(key, value) VALUES "
5447 "(?1, ?2), (?3, ?4), (?5, ?6), (?7, ?8) ",
5448 pNew->schemaName, pNew->tableName
5449 );
5450 if(!zSeedInfo) {
5451 goto error;
5452 }
5453 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zSeedInfo, -1, &stmt, NULL((void*)0));
5454 sqlite3_freesqlite3_api->free((void *) zSeedInfo);
5455 if (rc != SQLITE_OK0) {
5456 // TODO(IMP)
5457 sqlite3_finalizesqlite3_api->finalize(stmt);
5458 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Could not seed '_info' shadow table: %s",
5459 sqlite3_errmsgsqlite3_api->errmsg(db));
5460 goto error;
5461 }
5462 sqlite3_bind_textsqlite3_api->bind_text(stmt, 1, "CREATE_VERSION", -1, SQLITE_STATIC((sqlite3_destructor_type)0));
5463 sqlite3_bind_textsqlite3_api->bind_text(stmt, 2, SQLITE_VEC_VERSION"v0.1.10-alpha.4", -1, SQLITE_STATIC((sqlite3_destructor_type)0));
5464 sqlite3_bind_textsqlite3_api->bind_text(stmt, 3, "CREATE_VERSION_MAJOR", -1, SQLITE_STATIC((sqlite3_destructor_type)0));
5465 sqlite3_bind_intsqlite3_api->bind_int(stmt, 4, SQLITE_VEC_VERSION_MAJOR0);
5466 sqlite3_bind_textsqlite3_api->bind_text(stmt, 5, "CREATE_VERSION_MINOR", -1, SQLITE_STATIC((sqlite3_destructor_type)0));
5467 sqlite3_bind_intsqlite3_api->bind_int(stmt, 6, SQLITE_VEC_VERSION_MINOR1);
5468 sqlite3_bind_textsqlite3_api->bind_text(stmt, 7, "CREATE_VERSION_PATCH", -1, SQLITE_STATIC((sqlite3_destructor_type)0));
5469 sqlite3_bind_intsqlite3_api->bind_int(stmt, 8, SQLITE_VEC_VERSION_PATCH10);
5470
5471 if(sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101) {
5472 // TODO(IMP)
5473 sqlite3_finalizesqlite3_api->finalize(stmt);
5474 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Could not seed '_info' shadow table: %s",
5475 sqlite3_errmsgsqlite3_api->errmsg(db));
5476 goto error;
5477 }
5478 sqlite3_finalizesqlite3_api->finalize(stmt);
5479
5480#if SQLITE_VEC_ENABLE_DISKANN0
5481 // Seed medoid entries for DiskANN-indexed columns
5482 for (int i = 0; i < pNew->numVectorColumns; i++) {
5483 if (pNew->vector_columns[i].index_type != VEC0_INDEX_TYPE_DISKANN) {
5484 continue;
5485 }
5486 char *key = sqlite3_mprintfsqlite3_api->mprintf("diskann_medoid_%02d", i);
5487 char *zInsert = sqlite3_mprintfsqlite3_api->mprintf(
5488 "INSERT INTO " VEC0_SHADOW_INFO_NAME"\"%w\".\"%w_info\"" "(key, value) VALUES (?1, ?2)",
5489 pNew->schemaName, pNew->tableName);
5490 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zInsert, -1, &stmt, NULL((void*)0));
5491 sqlite3_freesqlite3_api->free(zInsert);
5492 if (rc != SQLITE_OK0) {
5493 sqlite3_freesqlite3_api->free(key);
5494 sqlite3_finalizesqlite3_api->finalize(stmt);
5495 goto error;
5496 }
5497 sqlite3_bind_textsqlite3_api->bind_text(stmt, 1, key, -1, sqlite3_freesqlite3_api->free);
5498 sqlite3_bind_nullsqlite3_api->bind_null(stmt, 2); // NULL means empty graph
5499 if (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101) {
5500 sqlite3_finalizesqlite3_api->finalize(stmt);
5501 goto error;
5502 }
5503 sqlite3_finalizesqlite3_api->finalize(stmt);
5504 }
5505#endif
5506
5507 // create the _chunks shadow table
5508 char *zCreateShadowChunks = NULL((void*)0);
5509 if(pNew->numPartitionColumns) {
5510 sqlite3_str * s = sqlite3_str_newsqlite3_api->str_new(NULL((void*)0));
5511 sqlite3_str_appendfsqlite3_api->str_appendf(s, "CREATE TABLE " VEC0_SHADOW_CHUNKS_NAME"\"%w\".\"%w_chunks\"" "(", pNew->schemaName, pNew->tableName);
5512 sqlite3_str_appendallsqlite3_api->str_appendall(s, "chunk_id INTEGER PRIMARY KEY AUTOINCREMENT," "size INTEGER NOT NULL,");
5513 sqlite3_str_appendallsqlite3_api->str_appendall(s, "sequence_id integer,");
5514 for(int i = 0; i < pNew->numPartitionColumns;i++) {
5515 sqlite3_str_appendfsqlite3_api->str_appendf(s, "partition%02d,", i);
5516 }
5517 sqlite3_str_appendallsqlite3_api->str_appendall(s, "validity BLOB NOT NULL, rowids BLOB NOT NULL);");
5518 zCreateShadowChunks = sqlite3_str_finishsqlite3_api->str_finish(s);
5519 }else {
5520 zCreateShadowChunks = sqlite3_mprintfsqlite3_api->mprintf(VEC0_SHADOW_CHUNKS_CREATE"CREATE TABLE " "\"%w\".\"%w_chunks\"" "(" "chunk_id INTEGER PRIMARY KEY AUTOINCREMENT,"
"size INTEGER NOT NULL," "validity BLOB NOT NULL," "rowids BLOB NOT NULL"
");"
,
5521 pNew->schemaName, pNew->tableName);
5522 }
5523 if (!zCreateShadowChunks) {
5524 goto error;
5525 }
5526 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zCreateShadowChunks, -1, &stmt, 0);
5527 sqlite3_freesqlite3_api->free((void *)zCreateShadowChunks);
5528 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5529 // IMP: V17740_01811
5530 sqlite3_finalizesqlite3_api->finalize(stmt);
5531 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Could not create '_chunks' shadow table: %s",
5532 sqlite3_errmsgsqlite3_api->errmsg(db));
5533 goto error;
5534 }
5535 sqlite3_finalizesqlite3_api->finalize(stmt);
5536
5537 // create the _rowids shadow table
5538 char *zCreateShadowRowids;
5539 if (pNew->pkIsText) {
5540 // adds a "text unique not null" constraint to the id column
5541 zCreateShadowRowids = sqlite3_mprintfsqlite3_api->mprintf(VEC0_SHADOW_ROWIDS_CREATE_PK_TEXT"CREATE TABLE " "\"%w\".\"%w_rowids\"" "(" "rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
"id TEXT UNIQUE NOT NULL," "chunk_id INTEGER," "chunk_offset INTEGER"
");"
,
5542 pNew->schemaName, pNew->tableName);
5543 } else {
5544 zCreateShadowRowids = sqlite3_mprintfsqlite3_api->mprintf(VEC0_SHADOW_ROWIDS_CREATE_BASIC"CREATE TABLE " "\"%w\".\"%w_rowids\"" "(" "rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
"id," "chunk_id INTEGER," "chunk_offset INTEGER" ");"
,
5545 pNew->schemaName, pNew->tableName);
5546 }
5547 if (!zCreateShadowRowids) {
5548 goto error;
5549 }
5550 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zCreateShadowRowids, -1, &stmt, 0);
5551 sqlite3_freesqlite3_api->free((void *)zCreateShadowRowids);
5552 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5553 // IMP: V11631_28470
5554 sqlite3_finalizesqlite3_api->finalize(stmt);
5555 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Could not create '_rowids' shadow table: %s",
5556 sqlite3_errmsgsqlite3_api->errmsg(db));
5557 goto error;
5558 }
5559 sqlite3_finalizesqlite3_api->finalize(stmt);
5560
5561 for (int i = 0; i < pNew->numVectorColumns; i++) {
5562 // Non-FLAT columns (rescore, IVF, DiskANN) don't use _vector_chunks
5563 if (pNew->vector_columns[i].index_type != VEC0_INDEX_TYPE_FLAT)
5564 continue;
5565 char *zSql = sqlite3_mprintfsqlite3_api->mprintf(VEC0_SHADOW_VECTOR_N_CREATE"CREATE TABLE " "\"%w\".\"%w_vector_chunks%02d\"" "(" "rowid PRIMARY KEY,"
"vectors BLOB NOT NULL" ");"
,
5566 pNew->schemaName, pNew->tableName, i);
5567 if (!zSql) {
5568 goto error;
5569 }
5570 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zSql, -1, &stmt, 0);
5571 sqlite3_freesqlite3_api->free((void *)zSql);
5572 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5573 // IMP: V25919_09989
5574 sqlite3_finalizesqlite3_api->finalize(stmt);
5575 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5576 "Could not create '_vector_chunks%02d' shadow table: %s", i,
5577 sqlite3_errmsgsqlite3_api->errmsg(db));
5578 goto error;
5579 }
5580 sqlite3_finalizesqlite3_api->finalize(stmt);
5581 }
5582
5583#if SQLITE_VEC_ENABLE_RESCORE1
5584 rc = rescore_create_tables(pNew, db, pzErr);
5585 if (rc != SQLITE_OK0) {
5586 goto error;
5587 }
5588#endif
5589
5590#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
5591 // Create IVF shadow tables for IVF-indexed vector columns
5592 for (int i = 0; i < pNew->numVectorColumns; i++) {
5593 if (pNew->vector_columns[i].index_type != VEC0_INDEX_TYPE_IVF) continue;
5594 rc = ivf_create_shadow_tables(pNew, i);
5595 if (rc != SQLITE_OK0) {
5596 *pzErr = sqlite3_mprintfsqlite3_api->mprintf("Could not create IVF shadow tables for column %d", i);
5597 goto error;
5598 }
5599 }
5600#endif
5601
5602#if SQLITE_VEC_ENABLE_DISKANN0
5603 // Create DiskANN shadow tables for indexed vector columns
5604 for (int i = 0; i < pNew->numVectorColumns; i++) {
5605 if (pNew->vector_columns[i].index_type != VEC0_INDEX_TYPE_DISKANN) {
5606 continue;
5607 }
5608
5609 // Create _vectors{NN} table
5610 {
5611 char *zSql = sqlite3_mprintfsqlite3_api->mprintf(
5612 "CREATE TABLE " VEC0_SHADOW_VECTORS_N_NAME"\"%w\".\"%w_vectors%02d\""
5613 " (rowid INTEGER PRIMARY KEY, vector BLOB NOT NULL);",
5614 pNew->schemaName, pNew->tableName, i);
5615 if (!zSql) {
5616 goto error;
5617 }
5618 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zSql, -1, &stmt, 0);
5619 sqlite3_freesqlite3_api->free(zSql);
5620 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5621 sqlite3_finalizesqlite3_api->finalize(stmt);
5622 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5623 "Could not create '_vectors%02d' shadow table: %s", i,
5624 sqlite3_errmsgsqlite3_api->errmsg(db));
5625 goto error;
5626 }
5627 sqlite3_finalizesqlite3_api->finalize(stmt);
5628 }
5629
5630 // Create _diskann_nodes{NN} table
5631 {
5632 char *zSql = sqlite3_mprintfsqlite3_api->mprintf(
5633 "CREATE TABLE " VEC0_SHADOW_DISKANN_NODES_N_NAME"\"%w\".\"%w_diskann_nodes%02d\"" " ("
5634 "rowid INTEGER PRIMARY KEY, "
5635 "neighbors_validity BLOB NOT NULL, "
5636 "neighbor_ids BLOB NOT NULL, "
5637 "neighbor_quantized_vectors BLOB NOT NULL"
5638 ");",
5639 pNew->schemaName, pNew->tableName, i);
5640 if (!zSql) {
5641 goto error;
5642 }
5643 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zSql, -1, &stmt, 0);
5644 sqlite3_freesqlite3_api->free(zSql);
5645 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5646 sqlite3_finalizesqlite3_api->finalize(stmt);
5647 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5648 "Could not create '_diskann_nodes%02d' shadow table: %s", i,
5649 sqlite3_errmsgsqlite3_api->errmsg(db));
5650 goto error;
5651 }
5652 sqlite3_finalizesqlite3_api->finalize(stmt);
5653 }
5654
5655 // Create _diskann_buffer{NN} table (for batched inserts)
5656 {
5657 char *zSql = sqlite3_mprintfsqlite3_api->mprintf(
5658 "CREATE TABLE " VEC0_SHADOW_DISKANN_BUFFER_N_NAME"\"%w\".\"%w_diskann_buffer%02d\"" " ("
5659 "rowid INTEGER PRIMARY KEY, "
5660 "vector BLOB NOT NULL"
5661 ");",
5662 pNew->schemaName, pNew->tableName, i);
5663 if (!zSql) {
5664 goto error;
5665 }
5666 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zSql, -1, &stmt, 0);
5667 sqlite3_freesqlite3_api->free(zSql);
5668 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5669 sqlite3_finalizesqlite3_api->finalize(stmt);
5670 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5671 "Could not create '_diskann_buffer%02d' shadow table: %s", i,
5672 sqlite3_errmsgsqlite3_api->errmsg(db));
5673 goto error;
5674 }
5675 sqlite3_finalizesqlite3_api->finalize(stmt);
5676 }
5677 }
5678#endif
5679
5680 // See SHADOW_TABLE_ROWID_QUIRK in vec0_new_chunk() — same "rowid PRIMARY KEY"
5681 // without INTEGER type issue applies here.
5682 for (int i = 0; i < pNew->numMetadataColumns; i++) {
5683 char *zSql = sqlite3_mprintfsqlite3_api->mprintf("CREATE TABLE " VEC0_SHADOW_METADATA_N_NAME"\"%w\".\"%w_metadatachunks%02d\"" "(rowid PRIMARY KEY, data BLOB NOT NULL);",
5684 pNew->schemaName, pNew->tableName, i);
5685 if (!zSql) {
5686 goto error;
5687 }
5688 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zSql, -1, &stmt, 0);
5689 sqlite3_freesqlite3_api->free((void *)zSql);
5690 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5691 sqlite3_finalizesqlite3_api->finalize(stmt);
5692 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5693 "Could not create '_metata_chunks%02d' shadow table: %s", i,
5694 sqlite3_errmsgsqlite3_api->errmsg(db));
5695 goto error;
5696 }
5697 sqlite3_finalizesqlite3_api->finalize(stmt);
5698
5699 if(pNew->metadata_columns[i].kind == VEC0_METADATA_COLUMN_KIND_TEXT) {
5700 char *zSql = sqlite3_mprintfsqlite3_api->mprintf("CREATE TABLE " VEC0_SHADOW_METADATA_TEXT_DATA_NAME"\"%w\".\"%w_metadatatext%02d\"" "(rowid PRIMARY KEY, data TEXT);",
5701 pNew->schemaName, pNew->tableName, i);
5702 if (!zSql) {
5703 goto error;
5704 }
5705 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zSql, -1, &stmt, 0);
5706 sqlite3_freesqlite3_api->free((void *)zSql);
5707 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5708 sqlite3_finalizesqlite3_api->finalize(stmt);
5709 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5710 "Could not create '_metadatatext%02d' shadow table: %s", i,
5711 sqlite3_errmsgsqlite3_api->errmsg(db));
5712 goto error;
5713 }
5714 sqlite3_finalizesqlite3_api->finalize(stmt);
5715
5716 }
5717 }
5718
5719 if(pNew->numAuxiliaryColumns > 0) {
5720 sqlite3_stmt * stmt;
5721 sqlite3_str * s = sqlite3_str_newsqlite3_api->str_new(NULL((void*)0));
5722 sqlite3_str_appendfsqlite3_api->str_appendf(s, "CREATE TABLE " VEC0_SHADOW_AUXILIARY_NAME"\"%w\".\"%w_auxiliary\"" "( rowid integer PRIMARY KEY ", pNew->schemaName, pNew->tableName);
5723 for(int i = 0; i < pNew->numAuxiliaryColumns; i++) {
5724 sqlite3_str_appendfsqlite3_api->str_appendf(s, ", value%02d", i);
5725 }
5726 sqlite3_str_appendallsqlite3_api->str_appendall(s, ")");
5727 char *zSql = sqlite3_str_finishsqlite3_api->str_finish(s);
5728 if(!zSql) {
5729 goto error;
5730 }
5731 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(db, zSql, -1, &stmt, NULL((void*)0));
5732 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5733 sqlite3_finalizesqlite3_api->finalize(stmt);
5734 *pzErr = sqlite3_mprintfsqlite3_api->mprintf(
5735 "Could not create auxiliary shadow table: %s",
5736 sqlite3_errmsgsqlite3_api->errmsg(db));
5737
5738 goto error;
5739 }
5740 sqlite3_finalizesqlite3_api->finalize(stmt);
5741 }
5742 }
5743
5744 *ppVtab = (sqlite3_vtab *)pNew;
5745 return SQLITE_OK0;
5746
5747error:
5748 vec0_free(pNew);
5749 sqlite3_freesqlite3_api->free(pNew);
5750 return SQLITE_ERROR1;
5751}
5752
5753static int vec0Create(sqlite3 *db, void *pAux, int argc,
5754 const char *const *argv, sqlite3_vtab **ppVtab,
5755 char **pzErr) {
5756 return vec0_init(db, pAux, argc, argv, ppVtab, pzErr, true1);
5757}
5758static int vec0Connect(sqlite3 *db, void *pAux, int argc,
5759 const char *const *argv, sqlite3_vtab **ppVtab,
5760 char **pzErr) {
5761 return vec0_init(db, pAux, argc, argv, ppVtab, pzErr, false0);
5762}
5763
5764static int vec0Disconnect(sqlite3_vtab *pVtab) {
5765 vec0_vtab *p = (vec0_vtab *)pVtab;
5766 vec0_free(p);
5767 sqlite3_freesqlite3_api->free(p);
5768 return SQLITE_OK0;
5769}
5770static int vec0Destroy(sqlite3_vtab *pVtab) {
5771 vec0_vtab *p = (vec0_vtab *)pVtab;
5772 sqlite3_stmt *stmt;
5773 int rc;
5774 const char *zSql;
5775
5776 // Free up any sqlite3_stmt, otherwise DROPs on those tables will fail
5777 vec0_free_resources(p);
5778
5779 // TODO(test) later: can't evidence-of here, bc always gives "SQL logic error" instead of
5780 // provided error
5781 zSql = sqlite3_mprintfsqlite3_api->mprintf("DROP TABLE " VEC0_SHADOW_CHUNKS_NAME"\"%w\".\"%w_chunks\"", p->schemaName,
5782 p->tableName);
5783 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, 0);
5784 sqlite3_freesqlite3_api->free((void *)zSql);
5785 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5786 rc = SQLITE_ERROR1;
5787 vtab_set_error(pVtab, "could not drop chunks shadow table");
5788 goto done;
5789 }
5790 sqlite3_finalizesqlite3_api->finalize(stmt);
5791
5792 zSql = sqlite3_mprintfsqlite3_api->mprintf("DROP TABLE " VEC0_SHADOW_INFO_NAME"\"%w\".\"%w_info\"", p->schemaName,
5793 p->tableName);
5794 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, 0);
5795 sqlite3_freesqlite3_api->free((void *)zSql);
5796 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5797 rc = SQLITE_ERROR1;
5798 vtab_set_error(pVtab, "could not drop info shadow table");
5799 goto done;
5800 }
5801 sqlite3_finalizesqlite3_api->finalize(stmt);
5802
5803 zSql = sqlite3_mprintfsqlite3_api->mprintf("DROP TABLE " VEC0_SHADOW_ROWIDS_NAME"\"%w\".\"%w_rowids\"", p->schemaName,
5804 p->tableName);
5805 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, 0);
5806 sqlite3_freesqlite3_api->free((void *)zSql);
5807 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5808 rc = SQLITE_ERROR1;
5809 goto done;
5810 }
5811 sqlite3_finalizesqlite3_api->finalize(stmt);
5812
5813 for (int i = 0; i < p->numVectorColumns; i++) {
5814#if SQLITE_VEC_ENABLE_DISKANN0
5815 if (p->vector_columns[i].index_type == VEC0_INDEX_TYPE_DISKANN) {
5816 // Drop DiskANN shadow tables
5817 zSql = sqlite3_mprintfsqlite3_api->mprintf("DROP TABLE IF EXISTS " VEC0_SHADOW_VECTORS_N_NAME"\"%w\".\"%w_vectors%02d\"",
5818 p->schemaName, p->tableName, i);
5819 if (zSql) {
5820 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, 0);
5821 sqlite3_freesqlite3_api->free((void *)zSql);
5822 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5823 rc = SQLITE_ERROR1;
5824 goto done;
5825 }
5826 sqlite3_finalizesqlite3_api->finalize(stmt);
5827 }
5828 zSql = sqlite3_mprintfsqlite3_api->mprintf("DROP TABLE IF EXISTS " VEC0_SHADOW_DISKANN_NODES_N_NAME"\"%w\".\"%w_diskann_nodes%02d\"",
5829 p->schemaName, p->tableName, i);
5830 if (zSql) {
5831 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, 0);
5832 sqlite3_freesqlite3_api->free((void *)zSql);
5833 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5834 rc = SQLITE_ERROR1;
5835 goto done;
5836 }
5837 sqlite3_finalizesqlite3_api->finalize(stmt);
5838 }
5839 zSql = sqlite3_mprintfsqlite3_api->mprintf("DROP TABLE IF EXISTS " VEC0_SHADOW_DISKANN_BUFFER_N_NAME"\"%w\".\"%w_diskann_buffer%02d\"",
5840 p->schemaName, p->tableName, i);
5841 if (zSql) {
5842 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, 0);
5843 sqlite3_freesqlite3_api->free((void *)zSql);
5844 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5845 rc = SQLITE_ERROR1;
5846 goto done;
5847 }
5848 sqlite3_finalizesqlite3_api->finalize(stmt);
5849 }
5850 continue;
5851 }
5852#endif
5853 // Non-FLAT columns (rescore, IVF, DiskANN) don't use _vector_chunks
5854 if (p->vector_columns[i].index_type != VEC0_INDEX_TYPE_FLAT)
5855 continue;
5856 zSql = sqlite3_mprintfsqlite3_api->mprintf("DROP TABLE \"%w\".\"%w\"", p->schemaName,
5857 p->shadowVectorChunksNames[i]);
5858 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, 0);
5859 sqlite3_freesqlite3_api->free((void *)zSql);
5860 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5861 rc = SQLITE_ERROR1;
5862 goto done;
5863 }
5864 sqlite3_finalizesqlite3_api->finalize(stmt);
5865 }
5866
5867#if SQLITE_VEC_ENABLE_RESCORE1
5868 rc = rescore_drop_tables(p);
5869 if (rc != SQLITE_OK0) {
5870 goto done;
5871 }
5872#endif
5873
5874#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
5875 // Drop IVF shadow tables
5876 for (int i = 0; i < p->numVectorColumns; i++) {
5877 if (p->vector_columns[i].index_type != VEC0_INDEX_TYPE_IVF) continue;
5878 ivf_drop_shadow_tables(p, i);
5879 }
5880#endif
5881
5882 if(p->numAuxiliaryColumns > 0) {
5883 zSql = sqlite3_mprintfsqlite3_api->mprintf("DROP TABLE " VEC0_SHADOW_AUXILIARY_NAME"\"%w\".\"%w_auxiliary\"", p->schemaName, p->tableName);
5884 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, 0);
5885 sqlite3_freesqlite3_api->free((void *)zSql);
5886 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5887 rc = SQLITE_ERROR1;
5888 goto done;
5889 }
5890 sqlite3_finalizesqlite3_api->finalize(stmt);
5891 }
5892
5893
5894 for (int i = 0; i < p->numMetadataColumns; i++) {
5895 zSql = sqlite3_mprintfsqlite3_api->mprintf("DROP TABLE " VEC0_SHADOW_METADATA_N_NAME"\"%w\".\"%w_metadatachunks%02d\"", p->schemaName,p->tableName, i);
5896 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, 0);
5897 sqlite3_freesqlite3_api->free((void *)zSql);
5898 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5899 rc = SQLITE_ERROR1;
5900 goto done;
5901 }
5902 sqlite3_finalizesqlite3_api->finalize(stmt);
5903
5904 if(p->metadata_columns[i].kind == VEC0_METADATA_COLUMN_KIND_TEXT) {
5905 zSql = sqlite3_mprintfsqlite3_api->mprintf("DROP TABLE " VEC0_SHADOW_METADATA_TEXT_DATA_NAME"\"%w\".\"%w_metadatatext%02d\"", p->schemaName,p->tableName, i);
5906 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, 0);
5907 sqlite3_freesqlite3_api->free((void *)zSql);
5908 if ((rc != SQLITE_OK0) || (sqlite3_stepsqlite3_api->step(stmt) != SQLITE_DONE101)) {
5909 rc = SQLITE_ERROR1;
5910 goto done;
5911 }
5912 sqlite3_finalizesqlite3_api->finalize(stmt);
5913 }
5914 }
5915
5916 stmt = NULL((void*)0);
5917 rc = SQLITE_OK0;
5918
5919done:
5920 sqlite3_finalizesqlite3_api->finalize(stmt);
5921 vec0_free(p);
5922 // If there was an error
5923 if (rc == SQLITE_OK0) {
5924 sqlite3_freesqlite3_api->free(p);
5925 }
5926 return rc;
5927}
5928
5929static int vec0Open(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor) {
5930 UNUSED_PARAMETER(p)(void)(p);
5931 vec0_cursor *pCur;
5932 pCur = sqlite3_mallocsqlite3_api->malloc(sizeof(*pCur));
5933 if (pCur == 0)
5934 return SQLITE_NOMEM7;
5935 memset(pCur, 0, sizeof(*pCur));
5936 *ppCursor = &pCur->base;
5937 return SQLITE_OK0;
5938}
5939
5940static int vec0Close(sqlite3_vtab_cursor *cur) {
5941 vec0_cursor *pCur = (vec0_cursor *)cur;
5942 vec0_cursor_clear(pCur);
5943 sqlite3_freesqlite3_api->free(pCur);
5944 return SQLITE_OK0;
5945}
5946
5947// All the different type of "values" provided to argv/argc in vec0Filter.
5948// These enums denote the use and purpose of all of them.
5949typedef enum {
5950 // If any values are updated, please update the ARCHITECTURE.md docs accordingly!
5951
5952 // ~~~ KNN QUERIES ~~~ //
5953 VEC0_IDXSTR_KIND_KNN_MATCH = '{',
5954 VEC0_IDXSTR_KIND_KNN_K = '}',
5955 VEC0_IDXSTR_KIND_KNN_ROWID_IN = '[',
5956 // argv[i] is a constraint on a PARTITON KEY column in a KNN query
5957 //
5958 VEC0_IDXSTR_KIND_KNN_PARTITON_CONSTRAINT = ']',
5959
5960 // argv[i] is a constraint on the distance column in a KNN query
5961 VEC0_IDXSTR_KIND_KNN_DISTANCE_CONSTRAINT = '*',
5962
5963 // ~~~ POINT QUERIES ~~~ //
5964 VEC0_IDXSTR_KIND_POINT_ID = '!',
5965
5966 // ~~~ ??? ~~~ //
5967 VEC0_IDXSTR_KIND_METADATA_CONSTRAINT = '&',
5968} vec0_idxstr_kind;
5969
5970// The different SQLITE_INDEX_CONSTRAINT values that vec0 partition key columns
5971// support, but as characters that fit nicely in idxstr.
5972typedef enum {
5973 // If any values are updated, please update the ARCHITECTURE.md docs accordingly!
5974
5975 // Equality constraint on a PARTITON KEY column, ex `user_id = 123`
5976 VEC0_PARTITION_OPERATOR_EQ = 'a',
5977
5978 // "Greater than" constraint on a PARTITON KEY column, ex `year > 2024`
5979 VEC0_PARTITION_OPERATOR_GT = 'b',
5980
5981 // "Less than or equal to" constraint on a PARTITON KEY column, ex `year <= 2024`
5982 VEC0_PARTITION_OPERATOR_LE = 'c',
5983
5984 // "Less than" constraint on a PARTITON KEY column, ex `year < 2024`
5985 VEC0_PARTITION_OPERATOR_LT = 'd',
5986
5987 // "Greater than or equal to" constraint on a PARTITON KEY column, ex `year >= 2024`
5988 VEC0_PARTITION_OPERATOR_GE = 'e',
5989
5990 // "Not equal to" constraint on a PARTITON KEY column, ex `year != 2024`
5991 VEC0_PARTITION_OPERATOR_NE = 'f',
5992} vec0_partition_operator;
5993typedef enum {
5994 VEC0_METADATA_OPERATOR_EQ = 'a',
5995 VEC0_METADATA_OPERATOR_GT = 'b',
5996 VEC0_METADATA_OPERATOR_LE = 'c',
5997 VEC0_METADATA_OPERATOR_LT = 'd',
5998 VEC0_METADATA_OPERATOR_GE = 'e',
5999 VEC0_METADATA_OPERATOR_NE = 'f',
6000 VEC0_METADATA_OPERATOR_IN = 'g',
6001} vec0_metadata_operator;
6002
6003
6004typedef enum {
6005
6006 VEC0_DISTANCE_CONSTRAINT_GT = 'a',
6007 VEC0_DISTANCE_CONSTRAINT_GE = 'b',
6008 VEC0_DISTANCE_CONSTRAINT_LT = 'c',
6009 VEC0_DISTANCE_CONSTRAINT_LE = 'd',
6010} vec0_distance_constraint_operator;
6011
6012static int vec0BestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pIdxInfo) {
6013 vec0_vtab *p = (vec0_vtab *)pVTab;
6014 /**
6015 * Possible query plans are:
6016 * 1. KNN when:
6017 * a) An `MATCH` op on vector column
6018 * b) ORDER BY on distance column
6019 * c) LIMIT
6020 * d) rowid in (...) OPTIONAL
6021 * 2. Point when:
6022 * a) An `EQ` op on rowid column
6023 * 3. else: fullscan
6024 *
6025 */
6026 int iMatchTerm = -1;
6027 int iMatchVectorTerm = -1;
6028 int iLimitTerm = -1;
6029 int iRowidTerm = -1;
6030 int iKTerm = -1;
6031 int iRowidInTerm = -1;
6032 int hasAuxConstraint = 0;
6033
6034#ifdef SQLITE_VEC_DEBUG
6035 printf("pIdxInfo->nOrderBy=%d, pIdxInfo->nConstraint=%d\n", pIdxInfo->nOrderBy, pIdxInfo->nConstraint);
6036#endif
6037
6038 for (int i = 0; i < pIdxInfo->nConstraint; i++) {
6039 u8 vtabIn = 0;
6040
6041#if COMPILER_SUPPORTS_VTAB_IN1
6042 if (sqlite3_libversion_numbersqlite3_api->libversion_number() >= 3038000) {
6043 vtabIn = sqlite3_vtab_insqlite3_api->vtab_in(pIdxInfo, i, -1);
6044 }
6045#endif
6046
6047#ifdef SQLITE_VEC_DEBUG
6048 printf("xBestIndex [%d] usable=%d iColumn=%d op=%d vtabin=%d\n", i,
6049 pIdxInfo->aConstraint[i].usable, pIdxInfo->aConstraint[i].iColumn,
6050 pIdxInfo->aConstraint[i].op, vtabIn);
6051#endif
6052 if (!pIdxInfo->aConstraint[i].usable)
6053 continue;
6054
6055 int iColumn = pIdxInfo->aConstraint[i].iColumn;
6056 int op = pIdxInfo->aConstraint[i].op;
6057
6058 if (op == SQLITE_INDEX_CONSTRAINT_LIMIT73) {
6059 iLimitTerm = i;
6060 }
6061 if (op == SQLITE_INDEX_CONSTRAINT_MATCH64 &&
6062 vec0_column_idx_is_vector(p, iColumn)) {
6063 if (iMatchTerm > -1) {
6064 vtab_set_error(
6065 pVTab, "only 1 MATCH operator is allowed in a single vec0 query");
6066 return SQLITE_ERROR1;
6067 }
6068 iMatchTerm = i;
6069 iMatchVectorTerm = vec0_column_idx_to_vector_idx(p, iColumn);
6070 }
6071 if (op == SQLITE_INDEX_CONSTRAINT_EQ2 && iColumn == VEC0_COLUMN_ID0) {
6072 if (vtabIn) {
6073 if (iRowidInTerm != -1) {
6074 vtab_set_error(pVTab, "only 1 'rowid in (..)' operator is allowed in "
6075 "a single vec0 query");
6076 return SQLITE_ERROR1;
6077 }
6078 iRowidInTerm = i;
6079
6080 } else {
6081 iRowidTerm = i;
6082 }
6083 }
6084 if (op == SQLITE_INDEX_CONSTRAINT_EQ2 && iColumn == vec0_column_k_idx(p)) {
6085 iKTerm = i;
6086 }
6087 if(
6088 (op != SQLITE_INDEX_CONSTRAINT_LIMIT73 && op != SQLITE_INDEX_CONSTRAINT_OFFSET74)
6089 && vec0_column_idx_is_auxiliary(p, iColumn)) {
6090 hasAuxConstraint = 1;
6091 }
6092 }
6093
6094 sqlite3_str *idxStr = sqlite3_str_newsqlite3_api->str_new(NULL((void*)0));
6095 int rc;
6096
6097 if (iMatchTerm >= 0) {
6098 if (iLimitTerm < 0 && iKTerm < 0) {
6099 vtab_set_error(
6100 pVTab,
6101 "A LIMIT or 'k = ?' constraint is required on vec0 knn queries.");
6102 rc = SQLITE_ERROR1;
6103 goto done;
6104 }
6105 if (iLimitTerm >= 0 && iKTerm >= 0) {
6106 vtab_set_error(pVTab, "Only LIMIT or 'k =?' can be provided, not both");
6107 rc = SQLITE_ERROR1;
6108 goto done;
6109 }
6110
6111 if (pIdxInfo->nOrderBy) {
6112 if (pIdxInfo->nOrderBy > 1) {
6113 vtab_set_error(pVTab, "Only a single 'ORDER BY distance' clause is "
6114 "allowed on vec0 KNN queries");
6115 rc = SQLITE_ERROR1;
6116 goto done;
6117 }
6118 if (pIdxInfo->aOrderBy[0].iColumn != vec0_column_distance_idx(p)) {
6119 vtab_set_error(pVTab,
6120 "Only a single 'ORDER BY distance' clause is allowed on "
6121 "vec0 KNN queries, not on other columns");
6122 rc = SQLITE_ERROR1;
6123 goto done;
6124 }
6125 if (pIdxInfo->aOrderBy[0].desc) {
6126 vtab_set_error(
6127 pVTab, "Only ascending in ORDER BY distance clause is supported, "
6128 "DESC is not supported yet.");
6129 rc = SQLITE_ERROR1;
6130 goto done;
6131 }
6132 }
6133
6134 if(hasAuxConstraint) {
6135 // IMP: V25623_09693
6136 vtab_set_error(pVTab, "An illegal WHERE constraint was provided on a vec0 auxiliary column in a KNN query.");
6137 rc = SQLITE_ERROR1;
6138 goto done;
6139 }
6140
6141 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, VEC0_QUERY_PLAN_KNN);
6142
6143 int argvIndex = 1;
6144 pIdxInfo->aConstraintUsage[iMatchTerm].argvIndex = argvIndex++;
6145 pIdxInfo->aConstraintUsage[iMatchTerm].omit = 1;
6146 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, VEC0_IDXSTR_KIND_KNN_MATCH);
6147 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 3, '_');
6148
6149 if (iLimitTerm >= 0) {
6150 pIdxInfo->aConstraintUsage[iLimitTerm].argvIndex = argvIndex++;
6151 pIdxInfo->aConstraintUsage[iLimitTerm].omit = 1;
6152 } else {
6153 pIdxInfo->aConstraintUsage[iKTerm].argvIndex = argvIndex++;
6154 pIdxInfo->aConstraintUsage[iKTerm].omit = 1;
6155 }
6156 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, VEC0_IDXSTR_KIND_KNN_K);
6157 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 3, '_');
6158
6159#if COMPILER_SUPPORTS_VTAB_IN1
6160 if (iRowidInTerm >= 0) {
6161 // already validated as >= SQLite 3.38 bc iRowidInTerm is only >= 0 when
6162 // vtabIn == 1
6163 sqlite3_vtab_insqlite3_api->vtab_in(pIdxInfo, iRowidInTerm, 1);
6164 pIdxInfo->aConstraintUsage[iRowidInTerm].argvIndex = argvIndex++;
6165 pIdxInfo->aConstraintUsage[iRowidInTerm].omit = 1;
6166 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, VEC0_IDXSTR_KIND_KNN_ROWID_IN);
6167 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 3, '_');
6168 }
6169#endif
6170
6171 // find any PARTITION KEY column constraints
6172 for (int i = 0; i < pIdxInfo->nConstraint; i++) {
6173 if (!pIdxInfo->aConstraint[i].usable)
6174 continue;
6175
6176 int iColumn = pIdxInfo->aConstraint[i].iColumn;
6177 int op = pIdxInfo->aConstraint[i].op;
6178 if(op == SQLITE_INDEX_CONSTRAINT_LIMIT73 || op == SQLITE_INDEX_CONSTRAINT_OFFSET74) {
6179 continue;
6180 }
6181 if(!vec0_column_idx_is_partition(p, iColumn)) {
6182 continue;
6183 }
6184
6185 int partition_idx = vec0_column_idx_to_partition_idx(p, iColumn);
6186 char value = 0;
6187
6188 switch(op) {
6189 case SQLITE_INDEX_CONSTRAINT_EQ2: {
6190 value = VEC0_PARTITION_OPERATOR_EQ;
6191 break;
6192 }
6193 case SQLITE_INDEX_CONSTRAINT_GT4: {
6194 value = VEC0_PARTITION_OPERATOR_GT;
6195 break;
6196 }
6197 case SQLITE_INDEX_CONSTRAINT_LE8: {
6198 value = VEC0_PARTITION_OPERATOR_LE;
6199 break;
6200 }
6201 case SQLITE_INDEX_CONSTRAINT_LT16: {
6202 value = VEC0_PARTITION_OPERATOR_LT;
6203 break;
6204 }
6205 case SQLITE_INDEX_CONSTRAINT_GE32: {
6206 value = VEC0_PARTITION_OPERATOR_GE;
6207 break;
6208 }
6209 case SQLITE_INDEX_CONSTRAINT_NE68: {
6210 value = VEC0_PARTITION_OPERATOR_NE;
6211 break;
6212 }
6213 }
6214
6215 if(value) {
6216 pIdxInfo->aConstraintUsage[i].argvIndex = argvIndex++;
6217 pIdxInfo->aConstraintUsage[i].omit = 1;
6218 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, VEC0_IDXSTR_KIND_KNN_PARTITON_CONSTRAINT);
6219 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, 'A' + partition_idx);
6220 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, value);
6221 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, '_');
6222 }
6223
6224 }
6225
6226 // find any metadata column constraints
6227 for (int i = 0; i < pIdxInfo->nConstraint; i++) {
6228 if (!pIdxInfo->aConstraint[i].usable)
6229 continue;
6230
6231 int iColumn = pIdxInfo->aConstraint[i].iColumn;
6232 int op = pIdxInfo->aConstraint[i].op;
6233 if(op == SQLITE_INDEX_CONSTRAINT_LIMIT73 || op == SQLITE_INDEX_CONSTRAINT_OFFSET74) {
6234 continue;
6235 }
6236 if(!vec0_column_idx_is_metadata(p, iColumn)) {
6237 continue;
6238 }
6239
6240 int metadata_idx = vec0_column_idx_to_metadata_idx(p, iColumn);
6241 char value = 0;
6242
6243 switch(op) {
6244 case SQLITE_INDEX_CONSTRAINT_EQ2: {
6245 int vtabIn = 0;
6246 #if COMPILER_SUPPORTS_VTAB_IN1
6247 if (sqlite3_libversion_numbersqlite3_api->libversion_number() >= 3038000) {
6248 vtabIn = sqlite3_vtab_insqlite3_api->vtab_in(pIdxInfo, i, -1);
6249 }
6250 if(vtabIn) {
6251 switch(p->metadata_columns[metadata_idx].kind) {
6252 case VEC0_METADATA_COLUMN_KIND_FLOAT:
6253 case VEC0_METADATA_COLUMN_KIND_BOOLEAN: {
6254 // IMP: V15248_32086
6255 rc = SQLITE_ERROR1;
6256 vtab_set_error(pVTab, "'xxx in (...)' is only available on INTEGER or TEXT metadata columns.");
6257 goto done;
6258 break;
6259 }
6260 case VEC0_METADATA_COLUMN_KIND_INTEGER:
6261 case VEC0_METADATA_COLUMN_KIND_TEXT: {
6262 break;
6263 }
6264 }
6265 value = VEC0_METADATA_OPERATOR_IN;
6266 sqlite3_vtab_insqlite3_api->vtab_in(pIdxInfo, i, 1);
6267 }else
6268 #endif
6269 {
6270 value = VEC0_PARTITION_OPERATOR_EQ;
6271 }
6272 break;
6273 }
6274 case SQLITE_INDEX_CONSTRAINT_GT4: {
6275 value = VEC0_METADATA_OPERATOR_GT;
6276 break;
6277 }
6278 case SQLITE_INDEX_CONSTRAINT_LE8: {
6279 value = VEC0_METADATA_OPERATOR_LE;
6280 break;
6281 }
6282 case SQLITE_INDEX_CONSTRAINT_LT16: {
6283 value = VEC0_METADATA_OPERATOR_LT;
6284 break;
6285 }
6286 case SQLITE_INDEX_CONSTRAINT_GE32: {
6287 value = VEC0_METADATA_OPERATOR_GE;
6288 break;
6289 }
6290 case SQLITE_INDEX_CONSTRAINT_NE68: {
6291 value = VEC0_METADATA_OPERATOR_NE;
6292 break;
6293 }
6294 default: {
6295 // IMP: V16511_00582
6296 rc = SQLITE_ERROR1;
6297 vtab_set_error(pVTab,
6298 "An illegal WHERE constraint was provided on a vec0 metadata column in a KNN query. "
6299 "Only one of EQUALS, GREATER_THAN, LESS_THAN_OR_EQUAL, LESS_THAN, GREATER_THAN_OR_EQUAL, NOT_EQUALS is allowed."
6300 );
6301 goto done;
6302 }
6303 }
6304
6305 if(p->metadata_columns[metadata_idx].kind == VEC0_METADATA_COLUMN_KIND_BOOLEAN) {
6306 if(!(value == VEC0_METADATA_OPERATOR_EQ || value == VEC0_METADATA_OPERATOR_NE)) {
6307 // IMP: V10145_26984
6308 rc = SQLITE_ERROR1;
6309 vtab_set_error(pVTab, "ONLY EQUALS (=) or NOT_EQUALS (!=) operators are allowed on boolean metadata columns.");
6310 goto done;
6311 }
6312 }
6313
6314 pIdxInfo->aConstraintUsage[i].argvIndex = argvIndex++;
6315 pIdxInfo->aConstraintUsage[i].omit = 1;
6316 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, VEC0_IDXSTR_KIND_METADATA_CONSTRAINT);
6317 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, 'A' + metadata_idx);
6318 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, value);
6319 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, '_');
6320
6321 }
6322
6323 // find any distance column constraints
6324 for (int i = 0; i < pIdxInfo->nConstraint; i++) {
6325 if (!pIdxInfo->aConstraint[i].usable)
6326 continue;
6327
6328 int iColumn = pIdxInfo->aConstraint[i].iColumn;
6329 int op = pIdxInfo->aConstraint[i].op;
6330 if(op == SQLITE_INDEX_CONSTRAINT_LIMIT73 || op == SQLITE_INDEX_CONSTRAINT_OFFSET74) {
6331 continue;
6332 }
6333 if(vec0_column_distance_idx(p) != iColumn) {
6334 continue;
6335 }
6336
6337 char value = 0;
6338 switch(op) {
6339 case SQLITE_INDEX_CONSTRAINT_GT4: {
6340 value = VEC0_DISTANCE_CONSTRAINT_GT;
6341 break;
6342 }
6343 case SQLITE_INDEX_CONSTRAINT_GE32: {
6344 value = VEC0_DISTANCE_CONSTRAINT_GE;
6345 break;
6346 }
6347 case SQLITE_INDEX_CONSTRAINT_LT16: {
6348 value = VEC0_DISTANCE_CONSTRAINT_LT;
6349 break;
6350 }
6351 case SQLITE_INDEX_CONSTRAINT_LE8: {
6352 value = VEC0_DISTANCE_CONSTRAINT_LE;
6353 break;
6354 }
6355 default: {
6356 // IMP TODO
6357 rc = SQLITE_ERROR1;
6358 vtab_set_error(
6359 pVTab,
6360 "Illegal WHERE constraint on distance column in a KNN query. "
6361 "Only one of GT, GE, LT, LE constraints are allowed."
6362 );
6363 goto done;
6364 }
6365 }
6366
6367 pIdxInfo->aConstraintUsage[i].argvIndex = argvIndex++;
6368 pIdxInfo->aConstraintUsage[i].omit = 1;
6369 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, VEC0_IDXSTR_KIND_KNN_DISTANCE_CONSTRAINT);
6370 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, value);
6371 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, '_');
6372 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, '_');
6373 }
6374
6375
6376
6377 pIdxInfo->idxNum = iMatchVectorTerm;
6378 pIdxInfo->estimatedCost = 30.0;
6379 pIdxInfo->estimatedRows = 10;
6380
6381 } else if (iRowidTerm >= 0) {
6382 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, VEC0_QUERY_PLAN_POINT);
6383 pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1;
6384 pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1;
6385 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, VEC0_IDXSTR_KIND_POINT_ID);
6386 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 3, '_');
6387 pIdxInfo->idxNum = pIdxInfo->colUsed;
6388 pIdxInfo->estimatedCost = 10.0;
6389 pIdxInfo->estimatedRows = 1;
6390 } else {
6391 sqlite3_str_appendcharsqlite3_api->str_appendchar(idxStr, 1, VEC0_QUERY_PLAN_FULLSCAN);
6392 pIdxInfo->estimatedCost = 3000000.0;
6393 pIdxInfo->estimatedRows = 100000;
6394 }
6395 pIdxInfo->idxStr = sqlite3_str_finishsqlite3_api->str_finish(idxStr);
6396 idxStr = NULL((void*)0);
6397 if (!pIdxInfo->idxStr) {
6398 rc = SQLITE_OK0;
6399 goto done;
6400 }
6401 pIdxInfo->needToFreeIdxStr = 1;
6402
6403 rc = SQLITE_OK0;
6404
6405 done:
6406 if(idxStr) {
6407 sqlite3_str_finishsqlite3_api->str_finish(idxStr);
6408 }
6409 return rc;
6410}
6411
6412// forward delcaration bc vec0Filter uses it
6413static int vec0Next(sqlite3_vtab_cursor *cur);
6414
6415void merge_sorted_lists(f32 *a, i64 *a_rowids, i64 a_length, f32 *b,
6416 i64 *b_rowids, i32 *b_top_idxs, i64 b_length, f32 *out,
6417 i64 *out_rowids, i64 out_length, i64 *out_used) {
6418 // assert((a_length >= out_length) || (b_length >= out_length));
6419 i64 ptrA = 0;
6420 i64 ptrB = 0;
6421 for (int i = 0; i < out_length; i++) {
6422 if ((ptrA >= a_length) && (ptrB >= b_length)) {
6423 *out_used = i;
6424 return;
6425 }
6426 if (ptrA >= a_length) {
6427 out[i] = b[b_top_idxs[ptrB]];
6428 out_rowids[i] = b_rowids[b_top_idxs[ptrB]];
6429 ptrB++;
6430 } else if (ptrB >= b_length) {
6431 out[i] = a[ptrA];
6432 out_rowids[i] = a_rowids[ptrA];
6433 ptrA++;
6434 } else {
6435 if (a[ptrA] <= b[b_top_idxs[ptrB]]) {
6436 out[i] = a[ptrA];
6437 out_rowids[i] = a_rowids[ptrA];
6438 ptrA++;
6439 } else {
6440 out[i] = b[b_top_idxs[ptrB]];
6441 out_rowids[i] = b_rowids[b_top_idxs[ptrB]];
6442 ptrB++;
6443 }
6444 }
6445 }
6446
6447 *out_used = out_length;
6448}
6449
6450u8 *bitmap_new(i32 n) {
6451 assert(n % 8 == 0)((void) sizeof ((n % 8 == 0) ? 1 : 0), __extension__ ({ if (n
% 8 == 0) ; else __assert_fail ("n % 8 == 0", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 6451, __extension__ __PRETTY_FUNCTION__); }))
;
6452 u8 *p = sqlite3_mallocsqlite3_api->malloc(n * sizeof(u8) / CHAR_BIT8);
6453 if (p) {
6454 memset(p, 0, n * sizeof(u8) / CHAR_BIT8);
6455 }
6456 return p;
6457}
6458u8 *bitmap_new_from(i32 n, u8 *from) {
6459 assert(n % 8 == 0)((void) sizeof ((n % 8 == 0) ? 1 : 0), __extension__ ({ if (n
% 8 == 0) ; else __assert_fail ("n % 8 == 0", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 6459, __extension__ __PRETTY_FUNCTION__); }))
;
6460 u8 *p = sqlite3_mallocsqlite3_api->malloc(n * sizeof(u8) / CHAR_BIT8);
6461 if (p) {
6462 memcpy(p, from, n / CHAR_BIT8);
6463 }
6464 return p;
6465}
6466
6467void bitmap_copy(u8 *base, u8 *from, i32 n) {
6468 assert(n % 8 == 0)((void) sizeof ((n % 8 == 0) ? 1 : 0), __extension__ ({ if (n
% 8 == 0) ; else __assert_fail ("n % 8 == 0", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 6468, __extension__ __PRETTY_FUNCTION__); }))
;
6469 memcpy(base, from, n / CHAR_BIT8);
6470}
6471
6472void bitmap_and_inplace(u8 *base, u8 *other, i32 n) {
6473 assert((n % 8) == 0)((void) sizeof (((n % 8) == 0) ? 1 : 0), __extension__ ({ if (
(n % 8) == 0) ; else __assert_fail ("(n % 8) == 0", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 6473, __extension__ __PRETTY_FUNCTION__); }))
;
6474 for (int i = 0; i < n / CHAR_BIT8; i++) {
6475 base[i] = base[i] & other[i];
6476 }
6477}
6478
6479void bitmap_set(u8 *bitmap, i32 position, int value) {
6480 if (value) {
6481 bitmap[position / CHAR_BIT8] |= 1 << (position % CHAR_BIT8);
6482 } else {
6483 bitmap[position / CHAR_BIT8] &= ~(1 << (position % CHAR_BIT8));
6484 }
6485}
6486
6487int bitmap_get(u8 *bitmap, i32 position) {
6488 return (((bitmap[position / CHAR_BIT8]) >> (position % CHAR_BIT8)) & 1);
6489}
6490
6491void bitmap_clear(u8 *bitmap, i32 n) {
6492 assert((n % 8) == 0)((void) sizeof (((n % 8) == 0) ? 1 : 0), __extension__ ({ if (
(n % 8) == 0) ; else __assert_fail ("(n % 8) == 0", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 6492, __extension__ __PRETTY_FUNCTION__); }))
;
6493 memset(bitmap, 0, n / CHAR_BIT8);
6494}
6495
6496void bitmap_fill(u8 *bitmap, i32 n) {
6497 assert((n % 8) == 0)((void) sizeof (((n % 8) == 0) ? 1 : 0), __extension__ ({ if (
(n % 8) == 0) ; else __assert_fail ("(n % 8) == 0", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 6497, __extension__ __PRETTY_FUNCTION__); }))
;
6498 memset(bitmap, 0xFF, n / CHAR_BIT8);
6499}
6500
6501/**
6502 * @brief Finds the minimum k items in distances, and writes the indicies to
6503 * out.
6504 *
6505 * @param distances input f32 array of size n, the items to consider.
6506 * @param n: size of distances array.
6507 * @param out: Output array of size k, will contain at most k element indicies
6508 * @param k: Size of output array
6509 * @return int
6510 */
6511int min_idx(const f32 *distances, i32 n, u8 *candidates, i32 *out, i32 k,
6512 u8 *bTaken, i32 *k_used) {
6513 assert(k > 0)((void) sizeof ((k > 0) ? 1 : 0), __extension__ ({ if (k >
0) ; else __assert_fail ("k > 0", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 6513, __extension__ __PRETTY_FUNCTION__); }))
;
6514 assert(k <= n)((void) sizeof ((k <= n) ? 1 : 0), __extension__ ({ if (k <=
n) ; else __assert_fail ("k <= n", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 6514, __extension__ __PRETTY_FUNCTION__); }))
;
6515
6516#ifdef SQLITE_VEC_EXPERIMENTAL_MIN_IDX
6517 // Max-heap variant: O(n log k) single-pass.
6518 // out[0..heap_size-1] stores indices; heap ordered by distances descending
6519 // so out[0] is always the index of the LARGEST distance in the top-k.
6520 (void)bTaken;
6521 int heap_size = 0;
6522
6523 #define HEAP_SIFT_UP(pos) do { \
6524 int _c = (pos); \
6525 while (_c > 0) { \
6526 int _p = (_c - 1) / 2; \
6527 if (distances[out[_p]] < distances[out[_c]]) { \
6528 i32 _tmp = out[_p]; out[_p] = out[_c]; out[_c] = _tmp; \
6529 _c = _p; \
6530 } else break; \
6531 } \
6532 } while(0)
6533
6534 #define HEAP_SIFT_DOWN(pos, sz) do { \
6535 int _p = (pos); \
6536 for (;;) { \
6537 int _l = 2*_p + 1, _r = 2*_p + 2, _largest = _p; \
6538 if (_l < (sz) && distances[out[_l]] > distances[out[_largest]]) \
6539 _largest = _l; \
6540 if (_r < (sz) && distances[out[_r]] > distances[out[_largest]]) \
6541 _largest = _r; \
6542 if (_largest == _p) break; \
6543 i32 _tmp = out[_p]; out[_p] = out[_largest]; out[_largest] = _tmp; \
6544 _p = _largest; \
6545 } \
6546 } while(0)
6547
6548 for (int i = 0; i < n; i++) {
6549 if (!bitmap_get(candidates, i))
6550 continue;
6551 if (heap_size < k) {
6552 out[heap_size] = i;
6553 heap_size++;
6554 HEAP_SIFT_UP(heap_size - 1);
6555 } else if (distances[i] < distances[out[0]]) {
6556 out[0] = i;
6557 HEAP_SIFT_DOWN(0, heap_size);
6558 }
6559 }
6560
6561 // Heapsort to produce ascending order.
6562 for (int i = heap_size - 1; i > 0; i--) {
6563 i32 tmp = out[0]; out[0] = out[i]; out[i] = tmp;
6564 HEAP_SIFT_DOWN(0, i);
6565 }
6566
6567 #undef HEAP_SIFT_UP
6568 #undef HEAP_SIFT_DOWN
6569
6570 *k_used = heap_size;
6571 return SQLITE_OK0;
6572
6573#else
6574 // Original: O(n*k) repeated linear scan with bitmap.
6575 bitmap_clear(bTaken, n);
6576
6577 for (int ik = 0; ik < k; ik++) {
6578 int min_idx = 0;
6579 while (min_idx < n &&
6580 (bitmap_get(bTaken, min_idx) || !bitmap_get(candidates, min_idx))) {
6581 min_idx++;
6582 }
6583 if (min_idx >= n) {
6584 *k_used = ik;
6585 return SQLITE_OK0;
6586 }
6587
6588 for (int i = 0; i < n; i++) {
6589 if (distances[i] <= distances[min_idx] && !bitmap_get(bTaken, i) &&
6590 (bitmap_get(candidates, i))) {
6591 min_idx = i;
6592 }
6593 }
6594
6595 out[ik] = min_idx;
6596 bitmap_set(bTaken, min_idx, 1);
6597 }
6598 *k_used = k;
6599 return SQLITE_OK0;
6600#endif
6601}
6602
6603int vec0_get_metadata_text_long_value(
6604 vec0_vtab * p,
6605 sqlite3_stmt ** stmt,
6606 int metadata_idx,
6607 i64 rowid,
6608 int *n,
6609 char ** s) {
6610 int rc;
6611 if(!(*stmt)) {
6612 const char * zSql = sqlite3_mprintfsqlite3_api->mprintf("select data from " VEC0_SHADOW_METADATA_TEXT_DATA_NAME"\"%w\".\"%w_metadatatext%02d\"" " where rowid = ?", p->schemaName, p->tableName, metadata_idx);
6613 if(!zSql) {
6614 rc = SQLITE_NOMEM7;
6615 goto done;
6616 }
6617 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, stmt, NULL((void*)0));
6618 sqlite3_freesqlite3_api->free( (void *) zSql);
6619 if(rc != SQLITE_OK0) {
6620 goto done;
6621 }
6622 }
6623
6624 sqlite3_resetsqlite3_api->reset(*stmt);
6625 sqlite3_bind_int64sqlite3_api->bind_int64(*stmt, 1, rowid);
6626 rc = sqlite3_stepsqlite3_api->step(*stmt);
6627 if(rc != SQLITE_ROW100) {
6628 rc = SQLITE_ERROR1;
6629 goto done;
6630 }
6631 *s = (char *) sqlite3_column_textsqlite3_api->column_text(*stmt, 0);
6632 *n = sqlite3_column_bytessqlite3_api->column_bytes(*stmt, 0);
6633 rc = SQLITE_OK0;
6634 done:
6635 return rc;
6636}
6637
6638/**
6639 * @brief Crete at "iterator" (sqlite3_stmt) of chunks with the given constraints
6640 *
6641 * Any VEC0_IDXSTR_KIND_KNN_PARTITON_CONSTRAINT values in idxStr/argv will be applied
6642 * as WHERE constraints in the underlying stmt SQL, and any consumer of the stmt
6643 * can freely step through the stmt with all constraints satisfied.
6644 *
6645 * @param p - vec0_vtab
6646 * @param idxStr - the xBestIndex/xFilter idxstr containing VEC0_IDXSTR values
6647 * @param argc - number of argv values from xFilter
6648 * @param argv - array of sqlite3_value from xFilter
6649 * @param outStmt - output sqlite3_stmt of chunks with all filters applied
6650 * @return int SQLITE_OK on success, error code otherwise
6651 */
6652int vec0_chunks_iter(vec0_vtab * p, const char * idxStr, int argc, sqlite3_value ** argv, sqlite3_stmt** outStmt) {
6653 // always null terminated, enforced by SQLite
6654 int idxStrLength = strlen(idxStr);
6655 // "1" refers to the initial vec0_query_plan char, 4 is the number of chars per "element"
6656 int numValueEntries = (idxStrLength-1) / 4;
6657 assert(argc == numValueEntries)((void) sizeof ((argc == numValueEntries) ? 1 : 0), __extension__
({ if (argc == numValueEntries) ; else __assert_fail ("argc == numValueEntries"
, "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 6657, __extension__ __PRETTY_FUNCTION__); }))
;
6658
6659 int rc;
6660 sqlite3_str * s = sqlite3_str_newsqlite3_api->str_new(NULL((void*)0));
6661 sqlite3_str_appendfsqlite3_api->str_appendf(s, "select chunk_id, validity, rowids "
6662 " from " VEC0_SHADOW_CHUNKS_NAME"\"%w\".\"%w_chunks\"",
6663 p->schemaName, p->tableName);
6664
6665 int appendedWhere = 0;
6666 for(int i = 0; i < numValueEntries; i++) {
6667 int idx = 1 + (i * 4);
6668 char kind = idxStr[idx + 0];
6669 if(kind != VEC0_IDXSTR_KIND_KNN_PARTITON_CONSTRAINT) {
6670 continue;
6671 }
6672
6673 int partition_idx = idxStr[idx + 1] - 'A';
6674 int operator = idxStr[idx + 2];
6675 // idxStr[idx + 3] is just null, a '_' placeholder
6676
6677 if(!appendedWhere) {
6678 sqlite3_str_appendallsqlite3_api->str_appendall(s, " WHERE ");
6679 appendedWhere = 1;
6680 }else {
6681 sqlite3_str_appendallsqlite3_api->str_appendall(s, " AND ");
6682 }
6683 switch(operator) {
6684 case VEC0_PARTITION_OPERATOR_EQ:
6685 sqlite3_str_appendfsqlite3_api->str_appendf(s, " partition%02d = ? ", partition_idx);
6686 break;
6687 case VEC0_PARTITION_OPERATOR_GT:
6688 sqlite3_str_appendfsqlite3_api->str_appendf(s, " partition%02d > ? ", partition_idx);
6689 break;
6690 case VEC0_PARTITION_OPERATOR_LE:
6691 sqlite3_str_appendfsqlite3_api->str_appendf(s, " partition%02d <= ? ", partition_idx);
6692 break;
6693 case VEC0_PARTITION_OPERATOR_LT:
6694 sqlite3_str_appendfsqlite3_api->str_appendf(s, " partition%02d < ? ", partition_idx);
6695 break;
6696 case VEC0_PARTITION_OPERATOR_GE:
6697 sqlite3_str_appendfsqlite3_api->str_appendf(s, " partition%02d >= ? ", partition_idx);
6698 break;
6699 case VEC0_PARTITION_OPERATOR_NE:
6700 sqlite3_str_appendfsqlite3_api->str_appendf(s, " partition%02d != ? ", partition_idx);
6701 break;
6702 default: {
6703 char * zSql = sqlite3_str_finishsqlite3_api->str_finish(s);
6704 sqlite3_freesqlite3_api->free(zSql);
6705 return SQLITE_ERROR1;
6706 }
6707
6708 }
6709
6710 }
6711
6712 char *zSql = sqlite3_str_finishsqlite3_api->str_finish(s);
6713 if (!zSql) {
6714 return SQLITE_NOMEM7;
6715 }
6716
6717 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, outStmt, NULL((void*)0));
6718 sqlite3_freesqlite3_api->free(zSql);
6719 if(rc != SQLITE_OK0) {
6720 return rc;
6721 }
6722
6723 int n = 1;
6724 for(int i = 0; i < numValueEntries; i++) {
6725 int idx = 1 + (i * 4);
6726 char kind = idxStr[idx + 0];
6727 if(kind != VEC0_IDXSTR_KIND_KNN_PARTITON_CONSTRAINT) {
6728 continue;
6729 }
6730 sqlite3_bind_valuesqlite3_api->bind_value(*outStmt, n++, argv[i]);
6731 }
6732
6733 return rc;
6734}
6735
6736// a single `xxx in (...)` constraint on a metadata column. TEXT or INTEGER only for now.
6737struct Vec0MetadataIn{
6738 // index of argv[i]` the constraint is on
6739 int argv_idx;
6740 // metadata column index of the constraint, derived from idxStr + argv_idx
6741 int metadata_idx;
6742 // array of the copied `(...)` values from sqlite3_vtab_in_first()/sqlite3_vtab_in_next()
6743 struct Array array;
6744};
6745
6746// Array elements for `xxx in (...)` values for a text column. basically just a string
6747struct Vec0MetadataInTextEntry {
6748 int n;
6749 char * zString;
6750};
6751
6752
6753int vec0_metadata_filter_text(vec0_vtab * p, sqlite3_value * value, const void * buffer, int size, vec0_metadata_operator op, u8* b, int metadata_idx, int chunk_rowid, struct Array * aMetadataIn, int argv_idx) {
6754 int rc;
6755 sqlite3_stmt * stmt = NULL((void*)0);
6756 i64 * rowids = NULL((void*)0);
6757 sqlite3_blob * rowidsBlob;
6758 const char * sTarget = (const char *) sqlite3_value_textsqlite3_api->value_text(value);
6759 int nTarget = sqlite3_value_bytessqlite3_api->value_bytes(value);
6760
6761
6762 // TODO(perf): only text metadata news the rowids BLOB. Make it so that
6763 // rowids BLOB is re-used when multiple fitlers on text columns,
6764 // ex "name BETWEEN 'a' and 'b'""
6765 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowChunksName, "rowids", chunk_rowid, 0, &rowidsBlob);
6766 if(rc != SQLITE_OK0) {
6767 return rc;
6768 }
6769 assert(sqlite3_blob_bytes(rowidsBlob) % sizeof(i64) == 0)((void) sizeof ((sqlite3_api->blob_bytes(rowidsBlob) % sizeof
(i64) == 0) ? 1 : 0), __extension__ ({ if (sqlite3_api->blob_bytes
(rowidsBlob) % sizeof(i64) == 0) ; else __assert_fail ("sqlite3_blob_bytes(rowidsBlob) % sizeof(i64) == 0"
, "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 6769, __extension__ __PRETTY_FUNCTION__); }))
;
6770 assert((sqlite3_blob_bytes(rowidsBlob) / sizeof(i64)) == size)((void) sizeof (((sqlite3_api->blob_bytes(rowidsBlob) / sizeof
(i64)) == size) ? 1 : 0), __extension__ ({ if ((sqlite3_api->
blob_bytes(rowidsBlob) / sizeof(i64)) == size) ; else __assert_fail
("(sqlite3_blob_bytes(rowidsBlob) / sizeof(i64)) == size", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 6770, __extension__ __PRETTY_FUNCTION__); }))
;
6771
6772 rowids = sqlite3_mallocsqlite3_api->malloc(sqlite3_blob_bytessqlite3_api->blob_bytes(rowidsBlob));
6773 if(!rowids) {
6774 sqlite3_blob_closesqlite3_api->blob_close(rowidsBlob);
6775 return SQLITE_NOMEM7;
6776 }
6777
6778 rc = sqlite3_blob_readsqlite3_api->blob_read(rowidsBlob, rowids, sqlite3_blob_bytessqlite3_api->blob_bytes(rowidsBlob), 0);
6779 if(rc != SQLITE_OK0) {
6780 sqlite3_blob_closesqlite3_api->blob_close(rowidsBlob);
6781 return rc;
6782 }
6783 sqlite3_blob_closesqlite3_api->blob_close(rowidsBlob);
6784
6785 switch(op) {
6786 int nPrefix;
6787 char * sPrefix;
6788 char *sFull;
6789 int nFull;
6790 u8 * view;
6791 case VEC0_METADATA_OPERATOR_EQ: {
6792 for(int i = 0; i < size; i++) {
6793 view = &((u8*) buffer)[i * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16];
6794 nPrefix = ((int*) view)[0];
6795 sPrefix = (char *) &view[4];
6796
6797 // for EQ the text lengths must match
6798 if(nPrefix != nTarget) {
6799 bitmap_set(b, i, 0);
6800 continue;
6801 }
6802 int cmpPrefix = strncmp(sPrefix, sTarget, min(nPrefix, VEC0_METADATA_TEXT_VIEW_DATA_LENGTH)(((nPrefix) <= (12)) ? (nPrefix) : (12)));
6803
6804 // for short strings, use the prefix comparison direclty
6805 if(nPrefix <= VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12) {
6806 bitmap_set(b, i, cmpPrefix == 0);
6807 continue;
6808 }
6809 // for EQ on longs strings, the prefix must match
6810 if(cmpPrefix) {
6811 bitmap_set(b, i, 0);
6812 continue;
6813 }
6814 // consult the full string
6815 rc = vec0_get_metadata_text_long_value(p, &stmt, metadata_idx, rowids[i], &nFull, &sFull);
6816 if(rc != SQLITE_OK0) {
6817 goto done;
6818 }
6819 if(nPrefix != nFull) {
6820 rc = SQLITE_ERROR1;
6821 goto done;
6822 }
6823 bitmap_set(b, i, strncmp(sFull, sTarget, nFull) == 0);
6824 }
6825 break;
6826 }
6827 case VEC0_METADATA_OPERATOR_NE: {
6828 for(int i = 0; i < size; i++) {
6829 view = &((u8*) buffer)[i * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16];
6830 nPrefix = ((int*) view)[0];
6831 sPrefix = (char *) &view[4];
6832
6833 // for NE if text lengths dont match, it never will
6834 if(nPrefix != nTarget) {
6835 bitmap_set(b, i, 1);
6836 continue;
6837 }
6838
6839 int cmpPrefix = strncmp(sPrefix, sTarget, min(nPrefix, VEC0_METADATA_TEXT_VIEW_DATA_LENGTH)(((nPrefix) <= (12)) ? (nPrefix) : (12)));
6840
6841 // for short strings, use the prefix comparison direclty
6842 if(nPrefix <= VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12) {
6843 bitmap_set(b, i, cmpPrefix != 0);
6844 continue;
6845 }
6846 // for NE on longs strings, if prefixes dont match, then long string wont
6847 if(cmpPrefix) {
6848 bitmap_set(b, i, 1);
6849 continue;
6850 }
6851 // consult the full string
6852 rc = vec0_get_metadata_text_long_value(p, &stmt, metadata_idx, rowids[i], &nFull, &sFull);
6853 if(rc != SQLITE_OK0) {
6854 goto done;
6855 }
6856 if(nPrefix != nFull) {
6857 rc = SQLITE_ERROR1;
6858 goto done;
6859 }
6860 bitmap_set(b, i, strncmp(sFull, sTarget, nFull) != 0);
6861 }
6862 break;
6863 }
6864 case VEC0_METADATA_OPERATOR_GT: {
6865 for(int i = 0; i < size; i++) {
6866 view = &((u8*) buffer)[i * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16];
6867 nPrefix = ((int*) view)[0];
6868 sPrefix = (char *) &view[4];
6869 int cmpPrefix = strncmp(sPrefix, sTarget, min(min(nPrefix, VEC0_METADATA_TEXT_VIEW_DATA_LENGTH), nTarget)((((((nPrefix) <= (12)) ? (nPrefix) : (12))) <= (nTarget
)) ? ((((nPrefix) <= (12)) ? (nPrefix) : (12))) : (nTarget
))
);
6870
6871 if(nPrefix < VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12) {
6872 // if prefix match, check which is longer
6873 if(cmpPrefix == 0) {
6874 bitmap_set(b, i, nPrefix > nTarget);
6875 }
6876 else {
6877 bitmap_set(b, i, cmpPrefix > 0);
6878 }
6879 continue;
6880 }
6881 // TODO(perf): may not need to compare full text in some cases
6882
6883 rc = vec0_get_metadata_text_long_value(p, &stmt, metadata_idx, rowids[i], &nFull, &sFull);
6884 if(rc != SQLITE_OK0) {
6885 goto done;
6886 }
6887 if(nPrefix != nFull) {
6888 rc = SQLITE_ERROR1;
6889 goto done;
6890 }
6891 bitmap_set(b, i, strncmp(sFull, sTarget, nFull) > 0);
6892 }
6893 break;
6894 }
6895 case VEC0_METADATA_OPERATOR_GE: {
6896 for(int i = 0; i < size; i++) {
6897 view = &((u8*) buffer)[i * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16];
6898 nPrefix = ((int*) view)[0];
6899 sPrefix = (char *) &view[4];
6900 int cmpPrefix = strncmp(sPrefix, sTarget, min(min(nPrefix, VEC0_METADATA_TEXT_VIEW_DATA_LENGTH), nTarget)((((((nPrefix) <= (12)) ? (nPrefix) : (12))) <= (nTarget
)) ? ((((nPrefix) <= (12)) ? (nPrefix) : (12))) : (nTarget
))
);
6901
6902 if(nPrefix < VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12) {
6903 // if prefix match, check which is longer
6904 if(cmpPrefix == 0) {
6905 bitmap_set(b, i, nPrefix >= nTarget);
6906 }
6907 else {
6908 bitmap_set(b, i, cmpPrefix >= 0);
6909 }
6910 continue;
6911 }
6912 // TODO(perf): may not need to compare full text in some cases
6913
6914 rc = vec0_get_metadata_text_long_value(p, &stmt, metadata_idx, rowids[i], &nFull, &sFull);
6915 if(rc != SQLITE_OK0) {
6916 goto done;
6917 }
6918 if(nPrefix != nFull) {
6919 rc = SQLITE_ERROR1;
6920 goto done;
6921 }
6922 bitmap_set(b, i, strncmp(sFull, sTarget, nFull) >= 0);
6923 }
6924 break;
6925 }
6926 case VEC0_METADATA_OPERATOR_LE: {
6927 for(int i = 0; i < size; i++) {
6928 view = &((u8*) buffer)[i * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16];
6929 nPrefix = ((int*) view)[0];
6930 sPrefix = (char *) &view[4];
6931 int cmpPrefix = strncmp(sPrefix, sTarget, min(min(nPrefix, VEC0_METADATA_TEXT_VIEW_DATA_LENGTH), nTarget)((((((nPrefix) <= (12)) ? (nPrefix) : (12))) <= (nTarget
)) ? ((((nPrefix) <= (12)) ? (nPrefix) : (12))) : (nTarget
))
);
6932
6933 if(nPrefix < VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12) {
6934 // if prefix match, check which is longer
6935 if(cmpPrefix == 0) {
6936 bitmap_set(b, i, nPrefix <= nTarget);
6937 }
6938 else {
6939 bitmap_set(b, i, cmpPrefix <= 0);
6940 }
6941 continue;
6942 }
6943 // TODO(perf): may not need to compare full text in some cases
6944
6945 rc = vec0_get_metadata_text_long_value(p, &stmt, metadata_idx, rowids[i], &nFull, &sFull);
6946 if(rc != SQLITE_OK0) {
6947 goto done;
6948 }
6949 if(nPrefix != nFull) {
6950 rc = SQLITE_ERROR1;
6951 goto done;
6952 }
6953 bitmap_set(b, i, strncmp(sFull, sTarget, nFull) <= 0);
6954 }
6955 break;
6956 }
6957 case VEC0_METADATA_OPERATOR_LT: {
6958 for(int i = 0; i < size; i++) {
6959 view = &((u8*) buffer)[i * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16];
6960 nPrefix = ((int*) view)[0];
6961 sPrefix = (char *) &view[4];
6962 int cmpPrefix = strncmp(sPrefix, sTarget, min(min(nPrefix, VEC0_METADATA_TEXT_VIEW_DATA_LENGTH), nTarget)((((((nPrefix) <= (12)) ? (nPrefix) : (12))) <= (nTarget
)) ? ((((nPrefix) <= (12)) ? (nPrefix) : (12))) : (nTarget
))
);
6963
6964 if(nPrefix < VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12) {
6965 // if prefix match, check which is longer
6966 if(cmpPrefix == 0) {
6967 bitmap_set(b, i, nPrefix < nTarget);
6968 }
6969 else {
6970 bitmap_set(b, i, cmpPrefix < 0);
6971 }
6972 continue;
6973 }
6974 // TODO(perf): may not need to compare full text in some cases
6975
6976 rc = vec0_get_metadata_text_long_value(p, &stmt, metadata_idx, rowids[i], &nFull, &sFull);
6977 if(rc != SQLITE_OK0) {
6978 goto done;
6979 }
6980 if(nPrefix != nFull) {
6981 rc = SQLITE_ERROR1;
6982 goto done;
6983 }
6984 bitmap_set(b, i, strncmp(sFull, sTarget, nFull) < 0);
6985 }
6986 break;
6987 }
6988
6989 case VEC0_METADATA_OPERATOR_IN: {
6990 size_t metadataInIdx = -1;
6991 for(size_t i = 0; i < aMetadataIn->length; i++) {
6992 struct Vec0MetadataIn * metadataIn = &(((struct Vec0MetadataIn *) aMetadataIn->z)[i]);
6993 if(metadataIn->argv_idx == argv_idx) {
6994 metadataInIdx = i;
6995 break;
6996 }
6997 }
6998 if(metadataInIdx < 0) {
6999 rc = SQLITE_ERROR1;
7000 goto done;
7001 }
7002
7003 struct Vec0MetadataIn * metadataIn = &((struct Vec0MetadataIn *) aMetadataIn->z)[metadataInIdx];
7004 struct Array * aTarget = &(metadataIn->array);
7005
7006
7007 int nPrefix;
7008 char * sPrefix;
7009 char *sFull;
7010 int nFull;
7011 u8 * view;
7012 for(int i = 0; i < size; i++) {
7013 view = &((u8*) buffer)[i * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16];
7014 nPrefix = ((int*) view)[0];
7015 sPrefix = (char *) &view[4];
7016 for(size_t target_idx = 0; target_idx < aTarget->length; target_idx++) {
7017 struct Vec0MetadataInTextEntry * entry = &(((struct Vec0MetadataInTextEntry*)aTarget->z)[target_idx]);
7018 if(entry->n != nPrefix) {
7019 continue;
7020 }
7021 int cmpPrefix = strncmp(sPrefix, entry->zString, min(nPrefix, VEC0_METADATA_TEXT_VIEW_DATA_LENGTH)(((nPrefix) <= (12)) ? (nPrefix) : (12)));
7022 if(nPrefix <= VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12) {
7023 if(cmpPrefix == 0) {
7024 bitmap_set(b, i, 1);
7025 break;
7026 }
7027 continue;
7028 }
7029 if(cmpPrefix) {
7030 continue;
7031 }
7032
7033 rc = vec0_get_metadata_text_long_value(p, &stmt, metadata_idx, rowids[i], &nFull, &sFull);
7034 if(rc != SQLITE_OK0) {
7035 goto done;
7036 }
7037 if(nPrefix != nFull) {
7038 rc = SQLITE_ERROR1;
7039 goto done;
7040 }
7041 if(strncmp(sFull, entry->zString, nFull) == 0) {
7042 bitmap_set(b, i, 1);
7043 break;
7044 }
7045 }
7046 }
7047 break;
7048 }
7049
7050 }
7051 rc = SQLITE_OK0;
7052
7053 done:
7054 sqlite3_finalizesqlite3_api->finalize(stmt);
7055 sqlite3_freesqlite3_api->free(rowids);
7056 return rc;
7057
7058}
7059
7060/**
7061 * @brief Fill in bitmap of chunk values, whether or not the values match a metadata constraint
7062 *
7063 * @param p vec0_vtab
7064 * @param metadata_idx index of the metatadata column to perfrom constraints on
7065 * @param value sqlite3_value of the constraints value
7066 * @param blob sqlite3_blob that is already opened on the metdata column's shadow chunk table
7067 * @param chunk_rowid rowid of the chunk to calculate on
7068 * @param b pre-allocated and zero'd out bitmap to write results to
7069 * @param size size of the chunk
7070 * @return int SQLITE_OK on success, error code otherwise
7071 */
7072int vec0_set_metadata_filter_bitmap(
7073 vec0_vtab *p,
7074 int metadata_idx,
7075 vec0_metadata_operator op,
7076 sqlite3_value * value,
7077 sqlite3_blob * blob,
7078 i64 chunk_rowid,
7079 u8* b,
7080 int size,
7081 struct Array * aMetadataIn, int argv_idx) {
7082 // TODO: shouldn't this skip in-valid entries from the chunk's validity bitmap?
7083
7084 int rc;
7085 rc = sqlite3_blob_reopensqlite3_api->blob_reopen(blob, chunk_rowid);
7086 if(rc != SQLITE_OK0) {
7087 return rc;
7088 }
7089
7090 vec0_metadata_column_kind kind = p->metadata_columns[metadata_idx].kind;
7091 int szMatch = 0;
7092 int blobSize = sqlite3_blob_bytessqlite3_api->blob_bytes(blob);
7093 switch(kind) {
7094 case VEC0_METADATA_COLUMN_KIND_BOOLEAN: {
7095 szMatch = blobSize == size / CHAR_BIT8;
7096 break;
7097 }
7098 case VEC0_METADATA_COLUMN_KIND_INTEGER: {
7099 szMatch = blobSize == size * sizeof(i64);
7100 break;
7101 }
7102 case VEC0_METADATA_COLUMN_KIND_FLOAT: {
7103 szMatch = blobSize == size * sizeof(double);
7104 break;
7105 }
7106 case VEC0_METADATA_COLUMN_KIND_TEXT: {
7107 szMatch = blobSize == size * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16;
7108 break;
7109 }
7110 }
7111 if(!szMatch) {
7112 return SQLITE_ERROR1;
7113 }
7114 void * buffer = sqlite3_mallocsqlite3_api->malloc(blobSize);
7115 if(!buffer) {
7116 return SQLITE_NOMEM7;
7117 }
7118 rc = sqlite3_blob_readsqlite3_api->blob_read(blob, buffer, blobSize, 0);
7119 if(rc != SQLITE_OK0) {
7120 goto done;
7121 }
7122 switch(kind) {
7123 case VEC0_METADATA_COLUMN_KIND_BOOLEAN: {
7124 int target = sqlite3_value_intsqlite3_api->value_int(value);
7125 if( (target && op == VEC0_METADATA_OPERATOR_EQ) || (!target && op == VEC0_METADATA_OPERATOR_NE)) {
7126 for(int i = 0; i < size; i++) { bitmap_set(b, i, bitmap_get((u8*) buffer, i)); }
7127 }
7128 else {
7129 for(int i = 0; i < size; i++) { bitmap_set(b, i, !bitmap_get((u8*) buffer, i)); }
7130 }
7131 break;
7132 }
7133 case VEC0_METADATA_COLUMN_KIND_INTEGER: {
7134 i64 * array = (i64*) buffer;
7135 i64 target = sqlite3_value_int64sqlite3_api->value_int64(value);
7136 switch(op) {
7137 case VEC0_METADATA_OPERATOR_EQ: {
7138 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] == target); }
7139 break;
7140 }
7141 case VEC0_METADATA_OPERATOR_GT: {
7142 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] > target); }
7143 break;
7144 }
7145 case VEC0_METADATA_OPERATOR_LE: {
7146 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] <= target); }
7147 break;
7148 }
7149 case VEC0_METADATA_OPERATOR_LT: {
7150 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] < target); }
7151 break;
7152 }
7153 case VEC0_METADATA_OPERATOR_GE: {
7154 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] >= target); }
7155 break;
7156 }
7157 case VEC0_METADATA_OPERATOR_NE: {
7158 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] != target); }
7159 break;
7160 }
7161 case VEC0_METADATA_OPERATOR_IN: {
7162 int metadataInIdx = -1;
7163 for(size_t i = 0; i < aMetadataIn->length; i++) {
7164 struct Vec0MetadataIn * metadataIn = &((struct Vec0MetadataIn *) aMetadataIn->z)[i];
7165 if(metadataIn->argv_idx == argv_idx) {
7166 metadataInIdx = i;
7167 break;
7168 }
7169 }
7170 if(metadataInIdx < 0) {
7171 rc = SQLITE_ERROR1;
7172 goto done;
7173 }
7174 struct Vec0MetadataIn * metadataIn = &((struct Vec0MetadataIn *) aMetadataIn->z)[metadataInIdx];
7175 struct Array * aTarget = &(metadataIn->array);
7176
7177 for(int i = 0; i < size; i++) {
7178 for(size_t target_idx = 0; target_idx < aTarget->length; target_idx++) {
7179 if( ((i64*)aTarget->z)[target_idx] == array[i]) {
7180 bitmap_set(b, i, 1);
7181 break;
7182 }
7183 }
7184 }
7185 break;
7186 }
7187 }
7188 break;
7189 }
7190 case VEC0_METADATA_COLUMN_KIND_FLOAT: {
7191 double * array = (double*) buffer;
7192 double target = sqlite3_value_doublesqlite3_api->value_double(value);
7193 switch(op) {
7194 case VEC0_METADATA_OPERATOR_EQ: {
7195 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] == target); }
7196 break;
7197 }
7198 case VEC0_METADATA_OPERATOR_GT: {
7199 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] > target); }
7200 break;
7201 }
7202 case VEC0_METADATA_OPERATOR_LE: {
7203 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] <= target); }
7204 break;
7205 }
7206 case VEC0_METADATA_OPERATOR_LT: {
7207 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] < target); }
7208 break;
7209 }
7210 case VEC0_METADATA_OPERATOR_GE: {
7211 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] >= target); }
7212 break;
7213 }
7214 case VEC0_METADATA_OPERATOR_NE: {
7215 for(int i = 0; i < size; i++) { bitmap_set(b, i, array[i] != target); }
7216 break;
7217 }
7218 case VEC0_METADATA_OPERATOR_IN: {
7219 // should never be reached
7220 break;
7221 }
7222 }
7223 break;
7224 }
7225 case VEC0_METADATA_COLUMN_KIND_TEXT: {
7226 rc = vec0_metadata_filter_text(p, value, buffer, size, op, b, metadata_idx, chunk_rowid, aMetadataIn, argv_idx);
7227 if(rc != SQLITE_OK0) {
7228 goto done;
7229 }
7230 break;
7231 }
7232 }
7233 done:
7234 sqlite3_freesqlite3_api->free(buffer);
7235 return rc;
7236}
7237
7238int vec0Filter_knn_chunks_iter(vec0_vtab *p, sqlite3_stmt *stmtChunks,
7239 struct VectorColumnDefinition *vector_column,
7240 int vectorColumnIdx, struct Array *arrayRowidsIn,
7241 struct Array * aMetadataIn,
7242 const char * idxStr, int argc, sqlite3_value ** argv,
7243 void *queryVector, i64 k, i64 **out_topk_rowids,
7244 f32 **out_topk_distances, i64 *out_used) {
7245 // for each chunk, get top min(k, chunk_size) rowid + distances to query vec.
7246 // then reconcile all topk_chunks for a true top k.
7247 // output only rowids + distances for now
7248
7249 int rc = SQLITE_OK0;
7250 sqlite3_blob *blobVectors = NULL((void*)0);
7251
7252 void *baseVectors = NULL((void*)0); // memory: chunk_size * dimensions * element_size
7253
7254 // OWNED BY CALLER ON SUCCESS
7255 i64 *topk_rowids = NULL((void*)0); // memory: k * 4
7256 // OWNED BY CALLER ON SUCCESS
7257 f32 *topk_distances = NULL((void*)0); // memory: k * 4
7258
7259 i64 *tmp_topk_rowids = NULL((void*)0); // memory: k * 4
7260 f32 *tmp_topk_distances = NULL((void*)0); // memory: k * 4
7261 f32 *chunk_distances = NULL((void*)0); // memory: chunk_size * 4
7262 u8 *b = NULL((void*)0); // memory: chunk_size / 8
7263 u8 *bTaken = NULL((void*)0); // memory: chunk_size / 8
7264 i32 *chunk_topk_idxs = NULL((void*)0); // memory: k * 4
7265 u8 *bmRowids = NULL((void*)0); // memory: chunk_size / 8
7266 u8 *bmMetadata = NULL((void*)0); // memory: chunk_size / 8
7267 // // total: a lot???
7268
7269 // 6 * (k * 4) + (k * 2) + (chunk_size / 8) + (chunk_size * dimensions * 4)
7270
7271 topk_rowids = sqlite3_mallocsqlite3_api->malloc(k * sizeof(i64));
7272 if (!topk_rowids) {
7273 rc = SQLITE_NOMEM7;
7274 goto cleanup;
7275 }
7276 memset(topk_rowids, 0, k * sizeof(i64));
7277
7278 topk_distances = sqlite3_mallocsqlite3_api->malloc(k * sizeof(f32));
7279 if (!topk_distances) {
7280 rc = SQLITE_NOMEM7;
7281 goto cleanup;
7282 }
7283 memset(topk_distances, 0, k * sizeof(f32));
7284
7285 tmp_topk_rowids = sqlite3_mallocsqlite3_api->malloc(k * sizeof(i64));
7286 if (!tmp_topk_rowids) {
7287 rc = SQLITE_NOMEM7;
7288 goto cleanup;
7289 }
7290 memset(tmp_topk_rowids, 0, k * sizeof(i64));
7291
7292 tmp_topk_distances = sqlite3_mallocsqlite3_api->malloc(k * sizeof(f32));
7293 if (!tmp_topk_distances) {
7294 rc = SQLITE_NOMEM7;
7295 goto cleanup;
7296 }
7297 memset(tmp_topk_distances, 0, k * sizeof(f32));
7298
7299 i64 k_used = 0;
7300 i64 baseVectorsSize = p->chunk_size * vector_column_byte_size(*vector_column);
7301 baseVectors = sqlite3_mallocsqlite3_api->malloc(baseVectorsSize);
7302 if (!baseVectors) {
7303 rc = SQLITE_NOMEM7;
7304 goto cleanup;
7305 }
7306
7307 chunk_distances = sqlite3_mallocsqlite3_api->malloc(p->chunk_size * sizeof(f32));
7308 if (!chunk_distances) {
7309 rc = SQLITE_NOMEM7;
7310 goto cleanup;
7311 }
7312
7313 b = bitmap_new(p->chunk_size);
7314 if (!b) {
7315 rc = SQLITE_NOMEM7;
7316 goto cleanup;
7317 }
7318
7319 bTaken = bitmap_new(p->chunk_size);
7320 if (!bTaken) {
7321 rc = SQLITE_NOMEM7;
7322 goto cleanup;
7323 }
7324
7325 chunk_topk_idxs = sqlite3_mallocsqlite3_api->malloc(k * sizeof(i32));
7326 if (!chunk_topk_idxs) {
7327 rc = SQLITE_NOMEM7;
7328 goto cleanup;
7329 }
7330
7331 bmRowids = arrayRowidsIn ? bitmap_new(p->chunk_size) : NULL((void*)0);
7332 if (arrayRowidsIn && !bmRowids) {
7333 rc = SQLITE_NOMEM7;
7334 goto cleanup;
7335 }
7336
7337 sqlite3_blob * metadataBlobs[VEC0_MAX_METADATA_COLUMNS16];
7338 memset(metadataBlobs, 0, sizeof(sqlite3_blob*) * VEC0_MAX_METADATA_COLUMNS16);
7339
7340 bmMetadata = bitmap_new(p->chunk_size);
7341 if(!bmMetadata) {
7342 rc = SQLITE_NOMEM7;
7343 goto cleanup;
7344 }
7345
7346 int idxStrLength = strlen(idxStr);
7347 int numValueEntries = (idxStrLength-1) / 4;
7348 assert(numValueEntries == argc)((void) sizeof ((numValueEntries == argc) ? 1 : 0), __extension__
({ if (numValueEntries == argc) ; else __assert_fail ("numValueEntries == argc"
, "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 7348, __extension__ __PRETTY_FUNCTION__); }))
;
7349 int hasMetadataFilters = 0;
7350 int hasDistanceConstraints = 0;
7351 for(int i = 0; i < argc; i++) {
7352 int idx = 1 + (i * 4);
7353 char kind = idxStr[idx + 0];
7354 if(kind == VEC0_IDXSTR_KIND_METADATA_CONSTRAINT) {
7355 hasMetadataFilters = 1;
7356 }
7357 else if(kind == VEC0_IDXSTR_KIND_KNN_DISTANCE_CONSTRAINT) {
7358 hasDistanceConstraints = 1;
7359 }
7360 }
7361
7362 while (true1) {
7363 rc = sqlite3_stepsqlite3_api->step(stmtChunks);
7364 if (rc == SQLITE_DONE101) {
7365 break;
7366 }
7367 if (rc != SQLITE_ROW100) {
7368 vtab_set_error(&p->base, "chunks iter error");
7369 rc = SQLITE_ERROR1;
7370 goto cleanup;
7371 }
7372 memset(chunk_distances, 0, p->chunk_size * sizeof(f32));
7373 memset(chunk_topk_idxs, 0, k * sizeof(i32));
7374 bitmap_clear(b, p->chunk_size);
7375
7376 i64 chunk_id = sqlite3_column_int64sqlite3_api->column_int64(stmtChunks, 0);
7377 unsigned char *chunkValidity =
7378 (unsigned char *)sqlite3_column_blobsqlite3_api->column_blob(stmtChunks, 1);
7379 i64 validitySize = sqlite3_column_bytessqlite3_api->column_bytes(stmtChunks, 1);
7380 if (validitySize != p->chunk_size / CHAR_BIT8) {
7381 // IMP: V05271_22109
7382 vtab_set_error(
7383 &p->base,
7384 "chunk validity size doesn't match - expected %lld, found %lld",
7385 p->chunk_size / CHAR_BIT8, validitySize);
7386 rc = SQLITE_ERROR1;
7387 goto cleanup;
7388 }
7389
7390 i64 *chunkRowids = (i64 *)sqlite3_column_blobsqlite3_api->column_blob(stmtChunks, 2);
7391 i64 rowidsSize = sqlite3_column_bytessqlite3_api->column_bytes(stmtChunks, 2);
7392 if (rowidsSize != p->chunk_size * sizeof(i64)) {
7393 // IMP: V02796_19635
7394 vtab_set_error(&p->base, "rowids size doesn't match");
7395 vtab_set_error(
7396 &p->base,
7397 "chunk rowids size doesn't match - expected %lld, found %lld",
7398 p->chunk_size * sizeof(i64), rowidsSize);
7399 rc = SQLITE_ERROR1;
7400 goto cleanup;
7401 }
7402
7403 // open the vector chunk blob for the current chunk
7404 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName,
7405 p->shadowVectorChunksNames[vectorColumnIdx],
7406 "vectors", chunk_id, 0, &blobVectors);
7407 if (rc != SQLITE_OK0) {
7408 vtab_set_error(&p->base, "could not open vectors blob for chunk %lld",
7409 chunk_id);
7410 rc = SQLITE_ERROR1;
7411 goto cleanup;
7412 }
7413
7414 i64 currentBaseVectorsSize = sqlite3_blob_bytessqlite3_api->blob_bytes(blobVectors);
7415 i64 expectedBaseVectorsSize =
7416 p->chunk_size * vector_column_byte_size(*vector_column);
7417 if (currentBaseVectorsSize != expectedBaseVectorsSize) {
7418 // IMP: V16465_00535
7419 vtab_set_error(
7420 &p->base,
7421 "vectors blob size doesn't match - expected %lld, found %lld",
7422 expectedBaseVectorsSize, currentBaseVectorsSize);
7423 rc = SQLITE_ERROR1;
7424 goto cleanup;
7425 }
7426 rc = sqlite3_blob_readsqlite3_api->blob_read(blobVectors, baseVectors, currentBaseVectorsSize, 0);
7427
7428 if (rc != SQLITE_OK0) {
7429 vtab_set_error(&p->base, "vectors blob read error for %lld", chunk_id);
7430 rc = SQLITE_ERROR1;
7431 goto cleanup;
7432 }
7433
7434 bitmap_copy(b, chunkValidity, p->chunk_size);
7435 if (arrayRowidsIn) {
7436 bitmap_clear(bmRowids, p->chunk_size);
7437
7438 for (int i = 0; i < p->chunk_size; i++) {
7439 if (!bitmap_get(chunkValidity, i)) {
7440 continue;
7441 }
7442 i64 rowid = chunkRowids[i];
7443 void *in = bsearch(&rowid, arrayRowidsIn->z, arrayRowidsIn->length,
7444 sizeof(i64), _cmp);
7445 bitmap_set(bmRowids, i, in ? 1 : 0);
7446 }
7447 bitmap_and_inplace(b, bmRowids, p->chunk_size);
7448 }
7449
7450 if(hasMetadataFilters) {
7451 for(int i = 0; i < argc; i++) {
7452 int idx = 1 + (i * 4);
7453 char kind = idxStr[idx + 0];
7454 if(kind != VEC0_IDXSTR_KIND_METADATA_CONSTRAINT) {
7455 continue;
7456 }
7457 int metadata_idx = idxStr[idx + 1] - 'A';
7458 int operator = idxStr[idx + 2];
7459
7460 if(!metadataBlobs[metadata_idx]) {
7461 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowMetadataChunksNames[metadata_idx], "data", chunk_id, 0, &metadataBlobs[metadata_idx]);
7462 vtab_set_error(&p->base, "Could not open metadata blob");
7463 if(rc != SQLITE_OK0) {
7464 goto cleanup;
7465 }
7466 }
7467
7468 bitmap_clear(bmMetadata, p->chunk_size);
7469 rc = vec0_set_metadata_filter_bitmap(p, metadata_idx, operator, argv[i], metadataBlobs[metadata_idx], chunk_id, bmMetadata, p->chunk_size, aMetadataIn, i);
7470 if(rc != SQLITE_OK0) {
7471 vtab_set_error(&p->base, "Could not filter metadata fields");
7472 if(rc != SQLITE_OK0) {
7473 goto cleanup;
7474 }
7475 }
7476 bitmap_and_inplace(b, bmMetadata, p->chunk_size);
7477 }
7478 }
7479
7480
7481 for (int i = 0; i < p->chunk_size; i++) {
7482 if (!bitmap_get(b, i)) {
7483 continue;
7484 };
7485
7486 f32 result;
7487 switch (vector_column->element_type) {
7488 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32: {
7489 const f32 *base_i =
7490 ((f32 *)baseVectors) + (i * vector_column->dimensions);
7491 switch (vector_column->distance_metric) {
7492 case VEC0_DISTANCE_METRIC_L2: {
7493 result = distance_l2_sqr_float(base_i, (f32 *)queryVector,
7494 &vector_column->dimensions);
7495 break;
7496 }
7497 case VEC0_DISTANCE_METRIC_L1: {
7498 result = distance_l1_f32(base_i, (f32 *)queryVector,
7499 &vector_column->dimensions);
7500 break;
7501 }
7502 case VEC0_DISTANCE_METRIC_COSINE: {
7503 result = distance_cosine_float(base_i, (f32 *)queryVector,
7504 &vector_column->dimensions);
7505 break;
7506 }
7507 }
7508 break;
7509 }
7510 case SQLITE_VEC_ELEMENT_TYPE_INT8: {
7511 const i8 *base_i =
7512 ((i8 *)baseVectors) + (i * vector_column->dimensions);
7513 switch (vector_column->distance_metric) {
7514 case VEC0_DISTANCE_METRIC_L2: {
7515 result = distance_l2_sqr_int8(base_i, (i8 *)queryVector,
7516 &vector_column->dimensions);
7517 break;
7518 }
7519 case VEC0_DISTANCE_METRIC_L1: {
7520 result = distance_l1_int8(base_i, (i8 *)queryVector,
7521 &vector_column->dimensions);
7522 break;
7523 }
7524 case VEC0_DISTANCE_METRIC_COSINE: {
7525 result = distance_cosine_int8(base_i, (i8 *)queryVector,
7526 &vector_column->dimensions);
7527 break;
7528 }
7529 }
7530
7531 break;
7532 }
7533 case SQLITE_VEC_ELEMENT_TYPE_BIT: {
7534 const u8 *base_i =
7535 ((u8 *)baseVectors) + (i * (vector_column->dimensions / CHAR_BIT8));
7536 result = distance_hamming(base_i, (u8 *)queryVector,
7537 &vector_column->dimensions);
7538 break;
7539 }
7540 }
7541
7542 chunk_distances[i] = result;
7543 }
7544
7545 if(hasDistanceConstraints) {
7546 for(int i = 0; i < argc; i++) {
7547 int idx = 1 + (i * 4);
7548 char kind = idxStr[idx + 0];
7549 // TODO casts f64 to f32, is that a problem?
7550 f32 target = (f32) sqlite3_value_doublesqlite3_api->value_double(argv[i]);
7551
7552 if(kind != VEC0_IDXSTR_KIND_KNN_DISTANCE_CONSTRAINT) {
7553 continue;
7554 }
7555 vec0_distance_constraint_operator op = idxStr[idx + 1];
7556
7557 switch(op) {
7558 case VEC0_DISTANCE_CONSTRAINT_GE: {
7559 for(int i = 0; i < p->chunk_size;i++) {
7560 if(bitmap_get(b, i) && !(chunk_distances[i] >= target)) {
7561 bitmap_set(b, i, 0);
7562 }
7563 }
7564 break;
7565 }
7566 case VEC0_DISTANCE_CONSTRAINT_GT: {
7567 for(int i = 0; i < p->chunk_size;i++) {
7568 if(bitmap_get(b, i) && !(chunk_distances[i] > target)) {
7569 bitmap_set(b, i, 0);
7570 }
7571 }
7572 break;
7573 }
7574 case VEC0_DISTANCE_CONSTRAINT_LE: {
7575 for(int i = 0; i < p->chunk_size;i++) {
7576 if(bitmap_get(b, i) && !(chunk_distances[i] <= target)) {
7577 bitmap_set(b, i, 0);
7578 }
7579 }
7580 break;
7581 }
7582 case VEC0_DISTANCE_CONSTRAINT_LT: {
7583 for(int i = 0; i < p->chunk_size;i++) {
7584 if(bitmap_get(b, i) && !(chunk_distances[i] < target)) {
7585 bitmap_set(b, i, 0);
7586 }
7587 }
7588 break;
7589 }
7590 }
7591 }
7592 }
7593
7594 int used1;
7595 min_idx(chunk_distances, p->chunk_size, b, chunk_topk_idxs,
7596 min(k, p->chunk_size)(((k) <= (p->chunk_size)) ? (k) : (p->chunk_size)), bTaken, &used1);
7597
7598 i64 used;
7599 merge_sorted_lists(topk_distances, topk_rowids, k_used, chunk_distances,
7600 chunkRowids, chunk_topk_idxs,
7601 min(min(k, p->chunk_size), used1)((((((k) <= (p->chunk_size)) ? (k) : (p->chunk_size)
)) <= (used1)) ? ((((k) <= (p->chunk_size)) ? (k) : (
p->chunk_size))) : (used1))
, tmp_topk_distances,
7602 tmp_topk_rowids, k, &used);
7603
7604 for (int i = 0; i < used; i++) {
7605 topk_rowids[i] = tmp_topk_rowids[i];
7606 topk_distances[i] = tmp_topk_distances[i];
7607 }
7608 k_used = used;
7609 // blobVectors is always opened with read-only permissions, so this never
7610 // fails.
7611 sqlite3_blob_closesqlite3_api->blob_close(blobVectors);
7612 blobVectors = NULL((void*)0);
7613 }
7614
7615 *out_topk_rowids = topk_rowids;
7616 *out_topk_distances = topk_distances;
7617 *out_used = k_used;
7618 rc = SQLITE_OK0;
7619
7620cleanup:
7621 if (rc != SQLITE_OK0) {
7622 sqlite3_freesqlite3_api->free(topk_rowids);
7623 sqlite3_freesqlite3_api->free(topk_distances);
7624 }
7625 sqlite3_freesqlite3_api->free(chunk_topk_idxs);
7626 sqlite3_freesqlite3_api->free(tmp_topk_rowids);
7627 sqlite3_freesqlite3_api->free(tmp_topk_distances);
7628 sqlite3_freesqlite3_api->free(b);
7629 sqlite3_freesqlite3_api->free(bTaken);
7630 sqlite3_freesqlite3_api->free(bmRowids);
7631 sqlite3_freesqlite3_api->free(baseVectors);
7632 sqlite3_freesqlite3_api->free(chunk_distances);
7633 sqlite3_freesqlite3_api->free(bmMetadata);
7634 for(int i = 0; i < VEC0_MAX_METADATA_COLUMNS16; i++) {
7635 sqlite3_blob_closesqlite3_api->blob_close(metadataBlobs[i]);
7636 }
7637 // blobVectors is always opened with read-only permissions, so this never
7638 // fails.
7639 sqlite3_blob_closesqlite3_api->blob_close(blobVectors);
7640 return rc;
7641}
7642
7643#if SQLITE_VEC_ENABLE_RESCORE1
7644#include "sqlite-vec-rescore.c"
7645#endif
7646
7647#if SQLITE_VEC_ENABLE_DISKANN0
7648/**
7649 * Handle a KNN query using the DiskANN graph search.
7650 */
7651static int vec0Filter_knn_diskann(
7652 vec0_cursor *pCur, vec0_vtab *p, int idxNum,
7653 const char *idxStr, int argc, sqlite3_value **argv) {
7654
7655 int rc;
7656 int vectorColumnIdx = idxNum;
7657 struct VectorColumnDefinition *vector_column = &p->vector_columns[vectorColumnIdx];
7658 struct vec0_query_knn_data *knn_data;
7659
7660 knn_data = sqlite3_mallocsqlite3_api->malloc(sizeof(*knn_data));
7661 if (!knn_data) return SQLITE_NOMEM7;
7662 memset(knn_data, 0, sizeof(*knn_data));
7663
7664 // Parse query_idx and k_idx from idxStr
7665 int query_idx = -1;
7666 int k_idx = -1;
7667 for (int i = 0; i < argc; i++) {
7668 if (idxStr[1 + (i * 4)] == VEC0_IDXSTR_KIND_KNN_MATCH) {
7669 query_idx = i;
7670 }
7671 if (idxStr[1 + (i * 4)] == VEC0_IDXSTR_KIND_KNN_K) {
7672 k_idx = i;
7673 }
7674 }
7675 assert(query_idx >= 0)((void) sizeof ((query_idx >= 0) ? 1 : 0), __extension__ (
{ if (query_idx >= 0) ; else __assert_fail ("query_idx >= 0"
, "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 7675, __extension__ __PRETTY_FUNCTION__); }))
;
7676 assert(k_idx >= 0)((void) sizeof ((k_idx >= 0) ? 1 : 0), __extension__ ({ if
(k_idx >= 0) ; else __assert_fail ("k_idx >= 0", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 7676, __extension__ __PRETTY_FUNCTION__); }))
;
7677
7678 // Extract query vector
7679 void *queryVector;
7680 size_t dimensions;
7681 enum VectorElementType elementType;
7682 vector_cleanup queryVectorCleanup = vector_cleanup_noop;
7683 char *pzError;
7684
7685 rc = vector_from_value(argv[query_idx], &queryVector, &dimensions,
7686 &elementType, &queryVectorCleanup, &pzError);
7687 if (rc != SQLITE_OK0) {
7688 vtab_set_error(&p->base, "Invalid query vector: %z", pzError);
7689 sqlite3_freesqlite3_api->free(knn_data);
7690 return SQLITE_ERROR1;
7691 }
7692
7693 if (elementType != vector_column->element_type ||
7694 dimensions != vector_column->dimensions) {
7695 vtab_set_error(&p->base, "Query vector type/dimension mismatch");
7696 queryVectorCleanup(queryVector);
7697 sqlite3_freesqlite3_api->free(knn_data);
7698 return SQLITE_ERROR1;
7699 }
7700
7701 i64 k = sqlite3_value_int64sqlite3_api->value_int64(argv[k_idx]);
7702 if (k <= 0) {
7703 knn_data->k = 0;
7704 knn_data->k_used = 0;
7705 pCur->knn_data = knn_data;
7706 pCur->query_plan = VEC0_QUERY_PLAN_KNN;
7707 queryVectorCleanup(queryVector);
7708 return SQLITE_OK0;
7709 }
7710
7711 // Run DiskANN search
7712 i64 *resultRowids = sqlite3_mallocsqlite3_api->malloc(k * sizeof(i64));
7713 f32 *resultDistances = sqlite3_mallocsqlite3_api->malloc(k * sizeof(f32));
7714 if (!resultRowids || !resultDistances) {
7715 sqlite3_freesqlite3_api->free(resultRowids);
7716 sqlite3_freesqlite3_api->free(resultDistances);
7717 queryVectorCleanup(queryVector);
7718 sqlite3_freesqlite3_api->free(knn_data);
7719 return SQLITE_NOMEM7;
7720 }
7721
7722 int resultCount;
7723 rc = diskann_search(p, vectorColumnIdx, queryVector, dimensions,
7724 elementType, (int)k, 0,
7725 resultRowids, resultDistances, &resultCount);
7726
7727 if (rc != SQLITE_OK0) {
7728 queryVectorCleanup(queryVector);
7729 sqlite3_freesqlite3_api->free(resultRowids);
7730 sqlite3_freesqlite3_api->free(resultDistances);
7731 sqlite3_freesqlite3_api->free(knn_data);
7732 return rc;
7733 }
7734
7735 // Scan _diskann_buffer for any buffered (unflushed) vectors and merge
7736 // with graph results. This ensures no recall loss for buffered vectors.
7737 {
7738 sqlite3_stmt *bufStmt = NULL((void*)0);
7739 char *zSql = sqlite3_mprintfsqlite3_api->mprintf(
7740 "SELECT rowid, vector FROM " VEC0_SHADOW_DISKANN_BUFFER_N_NAME"\"%w\".\"%w_diskann_buffer%02d\"",
7741 p->schemaName, p->tableName, vectorColumnIdx);
7742 if (!zSql) {
7743 queryVectorCleanup(queryVector);
7744 sqlite3_freesqlite3_api->free(resultRowids);
7745 sqlite3_freesqlite3_api->free(resultDistances);
7746 sqlite3_freesqlite3_api->free(knn_data);
7747 return SQLITE_NOMEM7;
7748 }
7749 int bufRc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &bufStmt, NULL((void*)0));
7750 sqlite3_freesqlite3_api->free(zSql);
7751 if (bufRc == SQLITE_OK0) {
7752 while (sqlite3_stepsqlite3_api->step(bufStmt) == SQLITE_ROW100) {
7753 i64 bufRowid = sqlite3_column_int64sqlite3_api->column_int64(bufStmt, 0);
7754 const void *bufVec = sqlite3_column_blobsqlite3_api->column_blob(bufStmt, 1);
7755 f32 dist = vec0_distance_full(
7756 queryVector, bufVec, dimensions, elementType,
7757 vector_column->distance_metric);
7758
7759 // Check if this buffer vector should replace the worst graph result
7760 if (resultCount < (int)k) {
7761 // Still have room, just add it
7762 resultRowids[resultCount] = bufRowid;
7763 resultDistances[resultCount] = dist;
7764 resultCount++;
7765 } else {
7766 // Find worst (largest distance) in results
7767 int worstIdx = 0;
7768 for (int wi = 1; wi < resultCount; wi++) {
7769 if (resultDistances[wi] > resultDistances[worstIdx]) {
7770 worstIdx = wi;
7771 }
7772 }
7773 if (dist < resultDistances[worstIdx]) {
7774 resultRowids[worstIdx] = bufRowid;
7775 resultDistances[worstIdx] = dist;
7776 }
7777 }
7778 }
7779 sqlite3_finalizesqlite3_api->finalize(bufStmt);
7780 }
7781 }
7782
7783 queryVectorCleanup(queryVector);
7784
7785 // Sort results by distance (ascending)
7786 for (int si = 0; si < resultCount - 1; si++) {
7787 for (int sj = si + 1; sj < resultCount; sj++) {
7788 if (resultDistances[sj] < resultDistances[si]) {
7789 f32 tmpD = resultDistances[si];
7790 resultDistances[si] = resultDistances[sj];
7791 resultDistances[sj] = tmpD;
7792 i64 tmpR = resultRowids[si];
7793 resultRowids[si] = resultRowids[sj];
7794 resultRowids[sj] = tmpR;
7795 }
7796 }
7797 }
7798
7799 knn_data->k = resultCount;
7800 knn_data->k_used = resultCount;
7801 knn_data->rowids = resultRowids;
7802 knn_data->distances = resultDistances;
7803 knn_data->current_idx = 0;
7804
7805 pCur->knn_data = knn_data;
7806 pCur->query_plan = VEC0_QUERY_PLAN_KNN;
7807
7808 return SQLITE_OK0;
7809}
7810#endif /* SQLITE_VEC_ENABLE_DISKANN */
7811
7812int vec0Filter_knn(vec0_cursor *pCur, vec0_vtab *p, int idxNum,
7813 const char *idxStr, int argc, sqlite3_value **argv) {
7814 assert(argc == (strlen(idxStr)-1) / 4)((void) sizeof ((argc == (strlen(idxStr)-1) / 4) ? 1 : 0), __extension__
({ if (argc == (strlen(idxStr)-1) / 4) ; else __assert_fail (
"argc == (strlen(idxStr)-1) / 4", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 7814, __extension__ __PRETTY_FUNCTION__); }))
;
7815 int rc;
7816 struct vec0_query_knn_data *knn_data;
7817
7818 int vectorColumnIdx = idxNum;
7819 struct VectorColumnDefinition *vector_column =
7820 &p->vector_columns[vectorColumnIdx];
7821
7822#if SQLITE_VEC_ENABLE_DISKANN0
7823 // DiskANN dispatch
7824 if (vector_column->index_type == VEC0_INDEX_TYPE_DISKANN) {
7825 return vec0Filter_knn_diskann(pCur, p, idxNum, idxStr, argc, argv);
7826 }
7827#endif
7828
7829 struct Array *arrayRowidsIn = NULL((void*)0);
7830 sqlite3_stmt *stmtChunks = NULL((void*)0);
7831 void *queryVector;
7832 size_t dimensions;
7833 enum VectorElementType elementType;
7834 vector_cleanup queryVectorCleanup = vector_cleanup_noop;
7835 char *pzError;
7836 knn_data = sqlite3_mallocsqlite3_api->malloc(sizeof(*knn_data));
7837 if (!knn_data) {
7838 return SQLITE_NOMEM7;
7839 }
7840 memset(knn_data, 0, sizeof(*knn_data));
7841 // array of `struct Vec0MetadataIn`, IF there are any `xxx in (...)` metadata constraints
7842 struct Array * aMetadataIn = NULL((void*)0);
7843
7844 int query_idx =-1;
7845 int k_idx = -1;
7846 int rowid_in_idx = -1;
7847 for(int i = 0; i < argc; i++) {
7848 if(idxStr[1 + (i*4)] == VEC0_IDXSTR_KIND_KNN_MATCH) {
7849 query_idx = i;
7850 }
7851 if(idxStr[1 + (i*4)] == VEC0_IDXSTR_KIND_KNN_K) {
7852 k_idx = i;
7853 }
7854 if(idxStr[1 + (i*4)] == VEC0_IDXSTR_KIND_KNN_ROWID_IN) {
7855 rowid_in_idx = i;
7856 }
7857 }
7858 assert(query_idx >= 0)((void) sizeof ((query_idx >= 0) ? 1 : 0), __extension__ (
{ if (query_idx >= 0) ; else __assert_fail ("query_idx >= 0"
, "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 7858, __extension__ __PRETTY_FUNCTION__); }))
;
7859 assert(k_idx >= 0)((void) sizeof ((k_idx >= 0) ? 1 : 0), __extension__ ({ if
(k_idx >= 0) ; else __assert_fail ("k_idx >= 0", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 7859, __extension__ __PRETTY_FUNCTION__); }))
;
7860
7861 // make sure the query vector matches the vector column (type dimensions etc.)
7862 rc = vector_from_value(argv[query_idx], &queryVector, &dimensions, &elementType,
7863 &queryVectorCleanup, &pzError);
7864
7865 if (rc != SQLITE_OK0) {
7866 vtab_set_error(&p->base,
7867 "Query vector on the \"%.*s\" column is invalid: %z",
7868 vector_column->name_length, vector_column->name, pzError);
7869 rc = SQLITE_ERROR1;
7870 goto cleanup;
7871 }
7872 if (elementType != vector_column->element_type) {
7873 vtab_set_error(
7874 &p->base,
7875 "Query vector for the \"%.*s\" column is expected to be of type "
7876 "%s, but a %s vector was provided.",
7877 vector_column->name_length, vector_column->name,
7878 vector_subtype_name(vector_column->element_type),
7879 vector_subtype_name(elementType));
7880 rc = SQLITE_ERROR1;
7881 goto cleanup;
7882 }
7883 if (dimensions != vector_column->dimensions) {
7884 vtab_set_error(
7885 &p->base,
7886 "Dimension mismatch for query vector for the \"%.*s\" column. "
7887 "Expected %d dimensions but received %d.",
7888 vector_column->name_length, vector_column->name,
7889 vector_column->dimensions, dimensions);
7890 rc = SQLITE_ERROR1;
7891 goto cleanup;
7892 }
7893
7894 i64 k = sqlite3_value_int64sqlite3_api->value_int64(argv[k_idx]);
7895 if (k < 0) {
7896 vtab_set_error(
7897 &p->base, "k value in knn queries must be greater than or equal to 0.");
7898 rc = SQLITE_ERROR1;
7899 goto cleanup;
7900 }
7901#define SQLITE_VEC_VEC0_K_MAX4096 4096
7902 if (k > SQLITE_VEC_VEC0_K_MAX4096) {
7903 vtab_set_error(
7904 &p->base,
7905 "k value in knn query too large, provided %lld and the limit is %lld",
7906 k, SQLITE_VEC_VEC0_K_MAX4096);
7907 rc = SQLITE_ERROR1;
7908 goto cleanup;
7909 }
7910
7911 if (k == 0) {
7912 knn_data->k = 0;
7913 pCur->knn_data = knn_data;
7914 pCur->query_plan = VEC0_QUERY_PLAN_KNN;
7915 rc = SQLITE_OK0;
7916 goto cleanup;
7917 }
7918
7919// handle when a `rowid in (...)` operation was provided
7920// Array of all the rowids that appear in any `rowid in (...)` constraint.
7921// NULL if none were provided, which means a "full" scan.
7922#if COMPILER_SUPPORTS_VTAB_IN1
7923 if (rowid_in_idx >= 0) {
7924 sqlite3_value *item;
7925 int rc;
7926 arrayRowidsIn = sqlite3_mallocsqlite3_api->malloc(sizeof(*arrayRowidsIn));
7927 if (!arrayRowidsIn) {
7928 rc = SQLITE_NOMEM7;
7929 goto cleanup;
7930 }
7931 memset(arrayRowidsIn, 0, sizeof(*arrayRowidsIn));
7932
7933 rc = array_init(arrayRowidsIn, sizeof(i64), 32);
7934 if (rc != SQLITE_OK0) {
7935 goto cleanup;
7936 }
7937 for (rc = sqlite3_vtab_in_firstsqlite3_api->vtab_in_first(argv[rowid_in_idx], &item); rc == SQLITE_OK0 && item;
7938 rc = sqlite3_vtab_in_nextsqlite3_api->vtab_in_next(argv[rowid_in_idx], &item)) {
7939 i64 rowid;
7940 if (p->pkIsText) {
7941 rc = vec0_rowid_from_id(p, item, &rowid);
7942 if (rc != SQLITE_OK0) {
7943 goto cleanup;
7944 }
7945 } else {
7946 rowid = sqlite3_value_int64sqlite3_api->value_int64(item);
7947 }
7948 rc = array_append(arrayRowidsIn, &rowid);
7949 if (rc != SQLITE_OK0) {
7950 goto cleanup;
7951 }
7952 }
7953 if (rc != SQLITE_DONE101) {
7954 vtab_set_error(&p->base, "error processing rowid in (...) array");
7955 goto cleanup;
7956 }
7957 qsort(arrayRowidsIn->z, arrayRowidsIn->length, arrayRowidsIn->element_size,
7958 _cmp);
7959 }
7960#endif
7961
7962 #if COMPILER_SUPPORTS_VTAB_IN1
7963 for(int i = 0; i < argc; i++) {
7964 if(!(idxStr[1 + (i*4)] == VEC0_IDXSTR_KIND_METADATA_CONSTRAINT && idxStr[1 + (i*4) + 2] == VEC0_METADATA_OPERATOR_IN)) {
7965 continue;
7966 }
7967 int metadata_idx = idxStr[1 + (i*4) + 1] - 'A';
7968 if(!aMetadataIn) {
7969 aMetadataIn = sqlite3_mallocsqlite3_api->malloc(sizeof(*aMetadataIn));
7970 if(!aMetadataIn) {
7971 rc = SQLITE_NOMEM7;
7972 goto cleanup;
7973 }
7974 memset(aMetadataIn, 0, sizeof(*aMetadataIn));
7975 rc = array_init(aMetadataIn, sizeof(struct Vec0MetadataIn), 8);
7976 if(rc != SQLITE_OK0) {
7977 goto cleanup;
7978 }
7979 }
7980
7981 struct Vec0MetadataIn item;
7982 memset(&item, 0, sizeof(item));
7983 item.metadata_idx=metadata_idx;
7984 item.argv_idx = i;
7985
7986 switch(p->metadata_columns[metadata_idx].kind) {
7987 case VEC0_METADATA_COLUMN_KIND_INTEGER: {
7988 rc = array_init(&item.array, sizeof(i64), 16);
7989 if(rc != SQLITE_OK0) {
7990 goto cleanup;
7991 }
7992 sqlite3_value *entry;
7993 for (rc = sqlite3_vtab_in_firstsqlite3_api->vtab_in_first(argv[i], &entry); rc == SQLITE_OK0 && entry; rc = sqlite3_vtab_in_nextsqlite3_api->vtab_in_next(argv[i], &entry)) {
7994 i64 v = sqlite3_value_int64sqlite3_api->value_int64(entry);
7995 rc = array_append(&item.array, &v);
7996 if (rc != SQLITE_OK0) {
7997 goto cleanup;
7998 }
7999 }
8000
8001 if (rc != SQLITE_DONE101) {
8002 vtab_set_error(&p->base, "Error fetching next value in `x in (...)` integer expression");
8003 goto cleanup;
8004 }
8005
8006 break;
8007 }
8008 case VEC0_METADATA_COLUMN_KIND_TEXT: {
8009 rc = array_init(&item.array, sizeof(struct Vec0MetadataInTextEntry), 16);
8010 if(rc != SQLITE_OK0) {
8011 goto cleanup;
8012 }
8013 sqlite3_value *entry;
8014 for (rc = sqlite3_vtab_in_firstsqlite3_api->vtab_in_first(argv[i], &entry); rc == SQLITE_OK0 && entry; rc = sqlite3_vtab_in_nextsqlite3_api->vtab_in_next(argv[i], &entry)) {
8015 const char * s = (const char *) sqlite3_value_textsqlite3_api->value_text(entry);
8016 int n = sqlite3_value_bytessqlite3_api->value_bytes(entry);
8017
8018 struct Vec0MetadataInTextEntry entry;
8019 entry.zString = sqlite3_mprintfsqlite3_api->mprintf("%.*s", n, s);
8020 if(!entry.zString) {
8021 rc = SQLITE_NOMEM7;
8022 goto cleanup;
8023 }
8024 entry.n = n;
8025 rc = array_append(&item.array, &entry);
8026 if (rc != SQLITE_OK0) {
8027 goto cleanup;
8028 }
8029 }
8030
8031 if (rc != SQLITE_DONE101) {
8032 vtab_set_error(&p->base, "Error fetching next value in `x in (...)` text expression");
8033 goto cleanup;
8034 }
8035
8036 break;
8037 }
8038 default: {
8039 vtab_set_error(&p->base, "Internal sqlite-vec error");
8040 goto cleanup;
8041 }
8042 }
8043
8044 rc = array_append(aMetadataIn, &item);
8045 if(rc != SQLITE_OK0) {
8046 goto cleanup;
8047 }
8048 }
8049 #endif
8050
8051#if SQLITE_VEC_ENABLE_RESCORE1
8052 // Dispatch to rescore KNN path if this vector column has rescore enabled
8053 if (vector_column->index_type == VEC0_INDEX_TYPE_RESCORE) {
8054 rc = rescore_knn(p, pCur, vector_column, vectorColumnIdx, arrayRowidsIn,
8055 aMetadataIn, idxStr, argc, argv, queryVector, k, knn_data);
8056 if (rc != SQLITE_OK0) {
8057 goto cleanup;
8058 }
8059 pCur->knn_data = knn_data;
8060 pCur->query_plan = VEC0_QUERY_PLAN_KNN;
8061 rc = SQLITE_OK0;
8062 goto cleanup;
8063 }
8064#endif
8065
8066#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
8067 // IVF dispatch: if vector column has IVF, use IVF query instead of chunk scan
8068 if (vector_column->index_type == VEC0_INDEX_TYPE_IVF) {
8069 rc = ivf_query_knn(p, vectorColumnIdx, queryVector,
8070 (int)vector_column_byte_size(*vector_column), k, knn_data);
8071 if (rc != SQLITE_OK0) {
8072 goto cleanup;
8073 }
8074 pCur->knn_data = knn_data;
8075 pCur->query_plan = VEC0_QUERY_PLAN_KNN;
8076 rc = SQLITE_OK0;
8077 goto cleanup;
8078 }
8079#endif
8080
8081 rc = vec0_chunks_iter(p, idxStr, argc, argv, &stmtChunks);
8082 if (rc != SQLITE_OK0) {
8083 // IMP: V06942_23781
8084 vtab_set_error(&p->base, "Error preparing stmtChunk: %s",
8085 sqlite3_errmsgsqlite3_api->errmsg(p->db));
8086 goto cleanup;
8087 }
8088
8089 i64 *topk_rowids = NULL((void*)0);
8090 f32 *topk_distances = NULL((void*)0);
8091 i64 k_used = 0;
8092 rc = vec0Filter_knn_chunks_iter(p, stmtChunks, vector_column, vectorColumnIdx,
8093 arrayRowidsIn, aMetadataIn, idxStr, argc, argv, queryVector, k, &topk_rowids,
8094 &topk_distances, &k_used);
8095 if (rc != SQLITE_OK0) {
8096 goto cleanup;
8097 }
8098
8099 knn_data->current_idx = 0;
8100 knn_data->k = k;
8101 knn_data->rowids = topk_rowids;
8102 knn_data->distances = topk_distances;
8103 knn_data->k_used = k_used;
8104
8105 pCur->knn_data = knn_data;
8106 pCur->query_plan = VEC0_QUERY_PLAN_KNN;
8107 rc = SQLITE_OK0;
8108
8109cleanup:
8110 sqlite3_finalizesqlite3_api->finalize(stmtChunks);
8111 array_cleanup(arrayRowidsIn);
8112 sqlite3_freesqlite3_api->free(arrayRowidsIn);
8113 queryVectorCleanup(queryVector);
8114 if(aMetadataIn) {
8115 for(size_t i = 0; i < aMetadataIn->length; i++) {
8116 struct Vec0MetadataIn* item = &((struct Vec0MetadataIn *) aMetadataIn->z)[i];
8117 for(size_t j = 0; j < item->array.length; j++) {
8118 if(p->metadata_columns[item->metadata_idx].kind == VEC0_METADATA_COLUMN_KIND_TEXT) {
8119 struct Vec0MetadataInTextEntry entry = ((struct Vec0MetadataInTextEntry*)item->array.z)[j];
8120 sqlite3_freesqlite3_api->free(entry.zString);
8121 }
8122 }
8123 array_cleanup(&item->array);
8124 }
8125 array_cleanup(aMetadataIn);
8126 }
8127
8128 sqlite3_freesqlite3_api->free(aMetadataIn);
8129
8130 if (rc != SQLITE_OK0) {
8131 sqlite3_freesqlite3_api->free(knn_data);
8132 }
8133
8134 return rc;
8135}
8136
8137int vec0Filter_fullscan(vec0_vtab *p, vec0_cursor *pCur) {
8138 int rc;
8139 char *zSql;
8140 struct vec0_query_fullscan_data *fullscan_data;
8141
8142 fullscan_data = sqlite3_mallocsqlite3_api->malloc(sizeof(*fullscan_data));
8143 if (!fullscan_data) {
8144 return SQLITE_NOMEM7;
8145 }
8146 memset(fullscan_data, 0, sizeof(*fullscan_data));
8147
8148 zSql = sqlite3_mprintfsqlite3_api->mprintf(" SELECT rowid "
8149 " FROM " VEC0_SHADOW_ROWIDS_NAME"\"%w\".\"%w_rowids\""
8150 " ORDER by chunk_id, chunk_offset ",
8151 p->schemaName, p->tableName);
8152 if (!zSql) {
8153 rc = SQLITE_NOMEM7;
8154 goto error;
8155 }
8156 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &fullscan_data->rowids_stmt, NULL((void*)0));
8157 sqlite3_freesqlite3_api->free(zSql);
8158 if (rc != SQLITE_OK0) {
8159 // IMP: V09901_26739
8160 vtab_set_error(&p->base, "Error preparing rowid scan: %s",
8161 sqlite3_errmsgsqlite3_api->errmsg(p->db));
8162 goto error;
8163 }
8164
8165 rc = sqlite3_stepsqlite3_api->step(fullscan_data->rowids_stmt);
8166
8167 // DONE when there's no rowids, ROW when there are, both "success"
8168 if (!(rc == SQLITE_ROW100 || rc == SQLITE_DONE101)) {
8169 goto error;
8170 }
8171
8172 fullscan_data->done = rc == SQLITE_DONE101;
8173 pCur->query_plan = VEC0_QUERY_PLAN_FULLSCAN;
8174 pCur->fullscan_data = fullscan_data;
8175 return SQLITE_OK0;
8176
8177error:
8178 vec0_query_fullscan_data_clear(fullscan_data);
8179 sqlite3_freesqlite3_api->free(fullscan_data);
8180 return rc;
8181}
8182
8183int vec0Filter_point(vec0_cursor *pCur, vec0_vtab *p, int argc,
8184 sqlite3_value **argv) {
8185 int rc;
8186 assert(argc == 1)((void) sizeof ((argc == 1) ? 1 : 0), __extension__ ({ if (argc
== 1) ; else __assert_fail ("argc == 1", "/root/firefox-clang/third_party/sqlite3/ext/sqlite-vec/sqlite-vec.c"
, 8186, __extension__ __PRETTY_FUNCTION__); }))
;
8187 i64 rowid;
8188 struct vec0_query_point_data *point_data = NULL((void*)0);
8189
8190 point_data = sqlite3_mallocsqlite3_api->malloc(sizeof(*point_data));
8191 if (!point_data) {
8192 rc = SQLITE_NOMEM7;
8193 goto error;
8194 }
8195 memset(point_data, 0, sizeof(*point_data));
8196
8197 if (p->pkIsText) {
8198 rc = vec0_rowid_from_id(p, argv[0], &rowid);
8199 if (rc == SQLITE_EMPTY16) {
8200 goto eof;
8201 }
8202 if (rc != SQLITE_OK0) {
8203 goto error;
8204 }
8205 } else {
8206 rowid = sqlite3_value_int64sqlite3_api->value_int64(argv[0]);
8207 }
8208
8209 for (int i = 0; i < p->numVectorColumns; i++) {
8210 rc = vec0_get_vector_data(p, rowid, i, &point_data->vectors[i], NULL((void*)0));
8211 if (rc == SQLITE_EMPTY16) {
8212 goto eof;
8213 }
8214 if (rc != SQLITE_OK0) {
8215 goto error;
8216 }
8217 }
8218
8219 point_data->rowid = rowid;
8220 point_data->done = 0;
8221 pCur->point_data = point_data;
8222 pCur->query_plan = VEC0_QUERY_PLAN_POINT;
8223 return SQLITE_OK0;
8224
8225eof:
8226 point_data->rowid = rowid;
8227 point_data->done = 1;
8228 pCur->point_data = point_data;
8229 pCur->query_plan = VEC0_QUERY_PLAN_POINT;
8230 return SQLITE_OK0;
8231
8232error:
8233 vec0_query_point_data_clear(point_data);
8234 sqlite3_freesqlite3_api->free(point_data);
8235 return rc;
8236}
8237
8238static int vec0Filter(sqlite3_vtab_cursor *pVtabCursor, int idxNum,
8239 const char *idxStr, int argc, sqlite3_value **argv) {
8240 vec0_vtab *p = (vec0_vtab *)pVtabCursor->pVtab;
8241 vec0_cursor *pCur = (vec0_cursor *)pVtabCursor;
8242 vec0_cursor_clear(pCur);
8243
8244 int idxStrLength = strlen(idxStr);
8245 if(idxStrLength <= 0) {
8246 return SQLITE_ERROR1;
8247 }
8248 if((idxStrLength-1) % 4 != 0) {
8249 return SQLITE_ERROR1;
8250 }
8251 int numValueEntries = (idxStrLength-1) / 4;
8252 if(numValueEntries != argc) {
8253 return SQLITE_ERROR1;
8254 }
8255
8256 char query_plan = idxStr[0];
8257 switch(query_plan) {
8258 case VEC0_QUERY_PLAN_FULLSCAN:
8259 return vec0Filter_fullscan(p, pCur);
8260 case VEC0_QUERY_PLAN_KNN:
8261 return vec0Filter_knn(pCur, p, idxNum, idxStr, argc, argv);
8262 case VEC0_QUERY_PLAN_POINT:
8263 return vec0Filter_point(pCur, p, argc, argv);
8264 default:
8265 vtab_set_error(pVtabCursor->pVtab, "unknown idxStr '%s'", idxStr);
8266 return SQLITE_ERROR1;
8267 }
8268}
8269
8270static int vec0Rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid) {
8271 vec0_cursor *pCur = (vec0_cursor *)cur;
8272 switch (pCur->query_plan) {
8273 case VEC0_QUERY_PLAN_FULLSCAN: {
8274 *pRowid = sqlite3_column_int64sqlite3_api->column_int64(pCur->fullscan_data->rowids_stmt, 0);
8275 return SQLITE_OK0;
8276 }
8277 case VEC0_QUERY_PLAN_POINT: {
8278 *pRowid = pCur->point_data->rowid;
8279 return SQLITE_OK0;
8280 }
8281 case VEC0_QUERY_PLAN_KNN: {
8282 vtab_set_error(cur->pVtab,
8283 "Internal sqlite-vec error: expected point query plan in "
8284 "vec0Rowid, found %d",
8285 pCur->query_plan);
8286 return SQLITE_ERROR1;
8287 }
8288 }
8289 return SQLITE_ERROR1;
8290}
8291
8292static int vec0Next(sqlite3_vtab_cursor *cur) {
8293 vec0_cursor *pCur = (vec0_cursor *)cur;
8294 switch (pCur->query_plan) {
8295 case VEC0_QUERY_PLAN_FULLSCAN: {
8296 if (!pCur->fullscan_data) {
8297 return SQLITE_ERROR1;
8298 }
8299 int rc = sqlite3_stepsqlite3_api->step(pCur->fullscan_data->rowids_stmt);
8300 if (rc == SQLITE_DONE101) {
8301 pCur->fullscan_data->done = 1;
8302 return SQLITE_OK0;
8303 }
8304 if (rc == SQLITE_ROW100) {
8305 return SQLITE_OK0;
8306 }
8307 return SQLITE_ERROR1;
8308 }
8309 case VEC0_QUERY_PLAN_KNN: {
8310 if (!pCur->knn_data) {
8311 return SQLITE_ERROR1;
8312 }
8313
8314 pCur->knn_data->current_idx++;
8315 return SQLITE_OK0;
8316 }
8317 case VEC0_QUERY_PLAN_POINT: {
8318 if (!pCur->point_data) {
8319 return SQLITE_ERROR1;
8320 }
8321 pCur->point_data->done = 1;
8322 return SQLITE_OK0;
8323 }
8324 }
8325 return SQLITE_ERROR1;
8326}
8327
8328static int vec0Eof(sqlite3_vtab_cursor *cur) {
8329 vec0_cursor *pCur = (vec0_cursor *)cur;
8330 switch (pCur->query_plan) {
8331 case VEC0_QUERY_PLAN_FULLSCAN: {
8332 if (!pCur->fullscan_data) {
8333 return 1;
8334 }
8335 return pCur->fullscan_data->done;
8336 }
8337 case VEC0_QUERY_PLAN_KNN: {
8338 if (!pCur->knn_data) {
8339 return 1;
8340 }
8341 // return (pCur->knn_data->current_idx >= pCur->knn_data->k) ||
8342 // (pCur->knn_data->distances[pCur->knn_data->current_idx] == FLT_MAX);
8343 return (pCur->knn_data->current_idx >= pCur->knn_data->k_used);
8344 }
8345 case VEC0_QUERY_PLAN_POINT: {
8346 if (!pCur->point_data) {
8347 return 1;
8348 }
8349 return pCur->point_data->done;
8350 }
8351 }
8352 return 1;
8353}
8354
8355static int vec0Column_fullscan(vec0_vtab *pVtab, vec0_cursor *pCur,
8356 sqlite3_context *context, int i) {
8357 if (!pCur->fullscan_data) {
8358 sqlite3_result_errorsqlite3_api->result_error(
8359 context, "Internal sqlite-vec error: fullscan_data is NULL.", -1);
8360 return SQLITE_ERROR1;
8361 }
8362 i64 rowid = sqlite3_column_int64sqlite3_api->column_int64(pCur->fullscan_data->rowids_stmt, 0);
8363 if (i == VEC0_COLUMN_ID0) {
8364 return vec0_result_id(pVtab, context, rowid);
8365 }
8366 else if (vec0_column_idx_is_vector(pVtab, i)) {
8367 void *v;
8368 int sz;
8369 int vector_idx = vec0_column_idx_to_vector_idx(pVtab, i);
8370 int rc = vec0_get_vector_data(pVtab, rowid, vector_idx, &v, &sz);
8371 if (rc != SQLITE_OK0) {
8372 return rc;
8373 }
8374 sqlite3_result_blobsqlite3_api->result_blob(context, v, sz, sqlite3_freesqlite3_api->free);
8375 sqlite3_result_subtypesqlite3_api->result_subtype(context,
8376 pVtab->vector_columns[vector_idx].element_type);
8377
8378 }
8379 else if (i == vec0_column_distance_idx(pVtab)) {
8380 sqlite3_result_nullsqlite3_api->result_null(context);
8381 }
8382 else if(vec0_column_idx_is_partition(pVtab, i)) {
8383 int partition_idx = vec0_column_idx_to_partition_idx(pVtab, i);
8384 sqlite3_value * v;
8385 int rc = vec0_get_partition_value_for_rowid(pVtab, rowid, partition_idx, &v);
8386 if(rc == SQLITE_OK0) {
8387 sqlite3_result_valuesqlite3_api->result_value(context, v);
8388 sqlite3_value_freesqlite3_api->value_free(v);
8389 }else {
8390 sqlite3_result_error_codesqlite3_api->result_error_code(context, rc);
8391 }
8392 }
8393 else if(vec0_column_idx_is_auxiliary(pVtab, i)) {
8394 int auxiliary_idx = vec0_column_idx_to_auxiliary_idx(pVtab, i);
8395 sqlite3_value * v;
8396 int rc = vec0_get_auxiliary_value_for_rowid(pVtab, rowid, auxiliary_idx, &v);
8397 if(rc == SQLITE_OK0) {
8398 sqlite3_result_valuesqlite3_api->result_value(context, v);
8399 sqlite3_value_freesqlite3_api->value_free(v);
8400 }else {
8401 sqlite3_result_error_codesqlite3_api->result_error_code(context, rc);
8402 }
8403 }
8404
8405 else if(vec0_column_idx_is_metadata(pVtab, i)) {
8406 if(sqlite3_vtab_nochangesqlite3_api->vtab_nochange(context)) {
8407 return SQLITE_OK0;
8408 }
8409 int metadata_idx = vec0_column_idx_to_metadata_idx(pVtab, i);
8410 int rc = vec0_result_metadata_value_for_rowid(pVtab, rowid, metadata_idx, context);
8411 if(rc != SQLITE_OK0) {
8412 // IMP: V15466_32305
8413 const char * zErr = sqlite3_mprintfsqlite3_api->mprintf(
8414 "Could not extract metadata value for column %.*s at rowid %lld",
8415 pVtab->metadata_columns[metadata_idx].name_length,
8416 pVtab->metadata_columns[metadata_idx].name, rowid
8417 );
8418 if(zErr) {
8419 sqlite3_result_errorsqlite3_api->result_error(context, zErr, -1);
8420 sqlite3_freesqlite3_api->free((void *) zErr);
8421 }else {
8422 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
8423 }
8424 }
8425 }
8426
8427 return SQLITE_OK0;
8428}
8429
8430static int vec0Column_point(vec0_vtab *pVtab, vec0_cursor *pCur,
8431 sqlite3_context *context, int i) {
8432 if (!pCur->point_data) {
8433 sqlite3_result_errorsqlite3_api->result_error(context,
8434 "Internal sqlite-vec error: point_data is NULL.", -1);
8435 return SQLITE_ERROR1;
8436 }
8437 if (i == VEC0_COLUMN_ID0) {
8438 return vec0_result_id(pVtab, context, pCur->point_data->rowid);
8439 }
8440 else if (i == vec0_column_distance_idx(pVtab)) {
8441 sqlite3_result_nullsqlite3_api->result_null(context);
8442 return SQLITE_OK0;
8443 }
8444 else if (vec0_column_idx_is_vector(pVtab, i)) {
8445 if (sqlite3_vtab_nochangesqlite3_api->vtab_nochange(context)) {
8446 sqlite3_result_nullsqlite3_api->result_null(context);
8447 return SQLITE_OK0;
8448 }
8449 int vector_idx = vec0_column_idx_to_vector_idx(pVtab, i);
8450 sqlite3_result_blobsqlite3_api->result_blob(
8451 context, pCur->point_data->vectors[vector_idx],
8452 vector_column_byte_size(pVtab->vector_columns[vector_idx]),
8453 SQLITE_TRANSIENT((sqlite3_destructor_type)-1));
8454 sqlite3_result_subtypesqlite3_api->result_subtype(context,
8455 pVtab->vector_columns[vector_idx].element_type);
8456 return SQLITE_OK0;
8457 }
8458 else if(vec0_column_idx_is_partition(pVtab, i)) {
8459 if(sqlite3_vtab_nochangesqlite3_api->vtab_nochange(context)) {
8460 return SQLITE_OK0;
8461 }
8462 int partition_idx = vec0_column_idx_to_partition_idx(pVtab, i);
8463 i64 rowid = pCur->point_data->rowid;
8464 sqlite3_value * v;
8465 int rc = vec0_get_partition_value_for_rowid(pVtab, rowid, partition_idx, &v);
8466 if(rc == SQLITE_OK0) {
8467 sqlite3_result_valuesqlite3_api->result_value(context, v);
8468 sqlite3_value_freesqlite3_api->value_free(v);
8469 }else {
8470 sqlite3_result_error_codesqlite3_api->result_error_code(context, rc);
8471 }
8472 }
8473 else if(vec0_column_idx_is_auxiliary(pVtab, i)) {
8474 if(sqlite3_vtab_nochangesqlite3_api->vtab_nochange(context)) {
8475 return SQLITE_OK0;
8476 }
8477 i64 rowid = pCur->point_data->rowid;
8478 int auxiliary_idx = vec0_column_idx_to_auxiliary_idx(pVtab, i);
8479 sqlite3_value * v;
8480 int rc = vec0_get_auxiliary_value_for_rowid(pVtab, rowid, auxiliary_idx, &v);
8481 if(rc == SQLITE_OK0) {
8482 sqlite3_result_valuesqlite3_api->result_value(context, v);
8483 sqlite3_value_freesqlite3_api->value_free(v);
8484 }else {
8485 sqlite3_result_error_codesqlite3_api->result_error_code(context, rc);
8486 }
8487 }
8488
8489 else if(vec0_column_idx_is_metadata(pVtab, i)) {
8490 if(sqlite3_vtab_nochangesqlite3_api->vtab_nochange(context)) {
8491 return SQLITE_OK0;
8492 }
8493 i64 rowid = pCur->point_data->rowid;
8494 int metadata_idx = vec0_column_idx_to_metadata_idx(pVtab, i);
8495 int rc = vec0_result_metadata_value_for_rowid(pVtab, rowid, metadata_idx, context);
8496 if(rc != SQLITE_OK0) {
8497 const char * zErr = sqlite3_mprintfsqlite3_api->mprintf(
8498 "Could not extract metadata value for column %.*s at rowid %lld",
8499 pVtab->metadata_columns[metadata_idx].name_length,
8500 pVtab->metadata_columns[metadata_idx].name, rowid
8501 );
8502 if(zErr) {
8503 sqlite3_result_errorsqlite3_api->result_error(context, zErr, -1);
8504 sqlite3_freesqlite3_api->free((void *) zErr);
8505 }else {
8506 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
8507 }
8508 }
8509 }
8510
8511 return SQLITE_OK0;
8512}
8513
8514static int vec0Column_knn(vec0_vtab *pVtab, vec0_cursor *pCur,
8515 sqlite3_context *context, int i) {
8516 if (!pCur->knn_data) {
8517 sqlite3_result_errorsqlite3_api->result_error(context,
8518 "Internal sqlite-vec error: knn_data is NULL.", -1);
8519 return SQLITE_ERROR1;
8520 }
8521 if (i == VEC0_COLUMN_ID0) {
8522 i64 rowid = pCur->knn_data->rowids[pCur->knn_data->current_idx];
8523 return vec0_result_id(pVtab, context, rowid);
8524 }
8525 else if (i == vec0_column_distance_idx(pVtab)) {
8526 sqlite3_result_doublesqlite3_api->result_double(
8527 context, pCur->knn_data->distances[pCur->knn_data->current_idx]);
8528 return SQLITE_OK0;
8529 }
8530 else if (vec0_column_idx_is_vector(pVtab, i)) {
8531 void *out;
8532 int sz;
8533 int vector_idx = vec0_column_idx_to_vector_idx(pVtab, i);
8534 int rc = vec0_get_vector_data(
8535 pVtab, pCur->knn_data->rowids[pCur->knn_data->current_idx], vector_idx,
8536 &out, &sz);
8537 if (rc != SQLITE_OK0) {
8538 return rc;
8539 }
8540 sqlite3_result_blobsqlite3_api->result_blob(context, out, sz, sqlite3_freesqlite3_api->free);
8541 sqlite3_result_subtypesqlite3_api->result_subtype(context,
8542 pVtab->vector_columns[vector_idx].element_type);
8543 return SQLITE_OK0;
8544 }
8545 else if(vec0_column_idx_is_partition(pVtab, i)) {
8546 int partition_idx = vec0_column_idx_to_partition_idx(pVtab, i);
8547 i64 rowid = pCur->knn_data->rowids[pCur->knn_data->current_idx];
8548 sqlite3_value * v;
8549 int rc = vec0_get_partition_value_for_rowid(pVtab, rowid, partition_idx, &v);
8550 if(rc == SQLITE_OK0) {
8551 sqlite3_result_valuesqlite3_api->result_value(context, v);
8552 sqlite3_value_freesqlite3_api->value_free(v);
8553 }else {
8554 sqlite3_result_error_codesqlite3_api->result_error_code(context, rc);
8555 }
8556 }
8557 else if(vec0_column_idx_is_auxiliary(pVtab, i)) {
8558 int auxiliary_idx = vec0_column_idx_to_auxiliary_idx(pVtab, i);
8559 i64 rowid = pCur->knn_data->rowids[pCur->knn_data->current_idx];
8560 sqlite3_value * v;
8561 int rc = vec0_get_auxiliary_value_for_rowid(pVtab, rowid, auxiliary_idx, &v);
8562 if(rc == SQLITE_OK0) {
8563 sqlite3_result_valuesqlite3_api->result_value(context, v);
8564 sqlite3_value_freesqlite3_api->value_free(v);
8565 }else {
8566 sqlite3_result_error_codesqlite3_api->result_error_code(context, rc);
8567 }
8568 }
8569
8570 else if(vec0_column_idx_is_metadata(pVtab, i)) {
8571 int metadata_idx = vec0_column_idx_to_metadata_idx(pVtab, i);
8572 i64 rowid = pCur->knn_data->rowids[pCur->knn_data->current_idx];
8573 int rc = vec0_result_metadata_value_for_rowid(pVtab, rowid, metadata_idx, context);
8574 if(rc != SQLITE_OK0) {
8575 const char * zErr = sqlite3_mprintfsqlite3_api->mprintf(
8576 "Could not extract metadata value for column %.*s at rowid %lld",
8577 pVtab->metadata_columns[metadata_idx].name_length,
8578 pVtab->metadata_columns[metadata_idx].name, rowid
8579 );
8580 if(zErr) {
8581 sqlite3_result_errorsqlite3_api->result_error(context, zErr, -1);
8582 sqlite3_freesqlite3_api->free((void *) zErr);
8583 }else {
8584 sqlite3_result_error_nomemsqlite3_api->result_error_nomem(context);
8585 }
8586 }
8587 }
8588
8589 return SQLITE_OK0;
8590}
8591
8592static int vec0Column(sqlite3_vtab_cursor *cur, sqlite3_context *context,
8593 int i) {
8594 vec0_cursor *pCur = (vec0_cursor *)cur;
8595 vec0_vtab *pVtab = (vec0_vtab *)cur->pVtab;
8596 switch (pCur->query_plan) {
8597 case VEC0_QUERY_PLAN_FULLSCAN: {
8598 return vec0Column_fullscan(pVtab, pCur, context, i);
8599 }
8600 case VEC0_QUERY_PLAN_KNN: {
8601 return vec0Column_knn(pVtab, pCur, context, i);
8602 }
8603 case VEC0_QUERY_PLAN_POINT: {
8604 return vec0Column_point(pVtab, pCur, context, i);
8605 }
8606 }
8607 return SQLITE_OK0;
8608}
8609
8610/**
8611 * @brief Handles the "insert rowid" step of a row insert operation of a vec0
8612 * table.
8613 *
8614 * This function will insert a new row into the _rowids vec0 shadow table.
8615 *
8616 * @param p: virtual table
8617 * @param idValue: Value containing the inserted rowid/id value.
8618 * @param rowid: Output rowid, will point to the "real" i64 rowid
8619 * value that was inserted
8620 * @return int SQLITE_OK on success, error code on failure
8621 */
8622int vec0Update_InsertRowidStep(vec0_vtab *p, sqlite3_value *idValue,
8623 i64 *rowid) {
8624
8625 /**
8626 * An insert into a vec0 table can happen a few different ways:
8627 * 1) With default INTEGER primary key: With a supplied i64 rowid
8628 * 2) With default INTEGER primary key: WITHOUT a supplied rowid
8629 * 3) With TEXT primary key: supplied text rowid
8630 */
8631
8632 int rc;
8633
8634 // Option 3: vtab has a user-defined TEXT primary key, so ensure a text value
8635 // is provided.
8636 if (p->pkIsText) {
8637 if (sqlite3_value_typesqlite3_api->value_type(idValue) != SQLITE_TEXT3) {
8638 // IMP: V04200_21039
8639 vtab_set_error(&p->base,
8640 "The %s virtual table was declared with a TEXT primary "
8641 "key, but a non-TEXT value was provided in an INSERT.",
8642 p->tableName);
8643 return SQLITE_ERROR1;
8644 }
8645
8646 return vec0_rowids_insert_id(p, idValue, rowid);
8647 }
8648
8649 // Option 1: User supplied a i64 rowid
8650 if (sqlite3_value_typesqlite3_api->value_type(idValue) == SQLITE_INTEGER1) {
8651 i64 suppliedRowid = sqlite3_value_int64sqlite3_api->value_int64(idValue);
8652 rc = vec0_rowids_insert_rowid(p, suppliedRowid);
8653 if (rc == SQLITE_OK0) {
8654 *rowid = suppliedRowid;
8655 }
8656 return rc;
8657 }
8658
8659 // Option 2: User did not suppled a rowid
8660
8661 if (sqlite3_value_typesqlite3_api->value_type(idValue) != SQLITE_NULL5) {
8662 // IMP: V30855_14925
8663 vtab_set_error(&p->base,
8664 "Only integers are allows for primary key values on %s",
8665 p->tableName);
8666 return SQLITE_ERROR1;
8667 }
8668 // NULL to get next auto-incremented value
8669 return vec0_rowids_insert_id(p, NULL((void*)0), rowid);
8670}
8671
8672/**
8673 * @brief Determines the "next available" chunk position for a newly inserted
8674 * vec0 row.
8675 *
8676 * This operation may insert a new "blank" chunk the _chunks table, if there is
8677 * no more space in previous chunks.
8678 *
8679 * @param p: virtual table
8680 * @param partitionKeyValues: array of partition key column values, to constrain
8681 * against any partition key columns.
8682 * @param chunk_rowid: Output rowid of the chunk in the _chunks virtual table
8683 * that has the avialabiity.
8684 * @param chunk_offset: Output the index of the available space insert the
8685 * chunk, based on the index of the first available validity bit.
8686 * @param pBlobValidity: Output blob of the validity column of the available
8687 * chunk. Will be opened with read/write permissions.
8688 * @param pValidity: Output buffer of the original chunk's validity column.
8689 * Needs to be cleaned up with sqlite3_free().
8690 * @return int SQLITE_OK on success, error code on failure
8691 */
8692int vec0Update_InsertNextAvailableStep(
8693 vec0_vtab *p,
8694 sqlite3_value ** partitionKeyValues,
8695 i64 *chunk_rowid, i64 *chunk_offset,
8696 sqlite3_blob **blobChunksValidity,
8697 const unsigned char **bufferChunksValidity) {
8698
8699 int rc;
8700 i64 validitySize;
8701 *chunk_offset = -1;
8702
8703 rc = vec0_get_latest_chunk_rowid(p, chunk_rowid, partitionKeyValues);
8704 if(rc == SQLITE_EMPTY16) {
8705 goto done;
8706 }
8707 if (rc != SQLITE_OK0) {
8708 goto cleanup;
8709 }
8710
8711 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowChunksName, "validity",
8712 *chunk_rowid, 1, blobChunksValidity);
8713 if (rc != SQLITE_OK0) {
8714 // IMP: V22053_06123
8715 vtab_set_error(&p->base,
8716 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8717 "could not open validity blob on %s.%s.%lld",
8718 p->schemaName, p->shadowChunksName, *chunk_rowid);
8719 goto cleanup;
8720 }
8721
8722 validitySize = sqlite3_blob_bytessqlite3_api->blob_bytes(*blobChunksValidity);
8723 if (validitySize != p->chunk_size / CHAR_BIT8) {
8724 // IMP: V29362_13432
8725 vtab_set_error(&p->base,
8726 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8727 "validity blob size mismatch on "
8728 "%s.%s.%lld, expected %lld but received %lld.",
8729 p->schemaName, p->shadowChunksName, *chunk_rowid,
8730 (i64)(p->chunk_size / CHAR_BIT8), validitySize);
8731 rc = SQLITE_ERROR1;
8732 goto cleanup;
8733 }
8734
8735 *bufferChunksValidity = sqlite3_mallocsqlite3_api->malloc(validitySize);
8736 if (!(*bufferChunksValidity)) {
8737 vtab_set_error(&p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8738 "Could not allocate memory for validity bitmap");
8739 rc = SQLITE_NOMEM7;
8740 goto cleanup;
8741 }
8742
8743 rc = sqlite3_blob_readsqlite3_api->blob_read(*blobChunksValidity, (void *)*bufferChunksValidity,
8744 validitySize, 0);
8745
8746 if (rc != SQLITE_OK0) {
8747 vtab_set_error(&p->base,
8748 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8749 "Could not read validity bitmap for %s.%s.%lld",
8750 p->schemaName, p->shadowChunksName, *chunk_rowid);
8751 goto cleanup;
8752 }
8753
8754 // find the next available offset, ie first `0` in the bitmap.
8755 for (int i = 0; i < validitySize; i++) {
8756 if ((*bufferChunksValidity)[i] == 0b11111111)
8757 continue;
8758 for (int j = 0; j < CHAR_BIT8; j++) {
8759 if (((((*bufferChunksValidity)[i] >> j) & 1) == 0)) {
8760 *chunk_offset = (i * CHAR_BIT8) + j;
8761 goto done;
8762 }
8763 }
8764 }
8765
8766done:
8767 // latest chunk was full, so need to create a new one
8768 if (*chunk_offset == -1) {
8769 rc = vec0_new_chunk(p, partitionKeyValues, chunk_rowid);
8770 if (rc != SQLITE_OK0) {
8771 // IMP: V08441_25279
8772 vtab_set_error(&p->base,
8773 VEC_INTERAL_ERROR"Internal sqlite-vec error: " "Could not insert a new vector chunk");
8774 rc = SQLITE_ERROR1; // otherwise raises a DatabaseError and not operational
8775 // error?
8776 goto cleanup;
8777 }
8778 *chunk_offset = 0;
8779
8780 // blobChunksValidity and pValidity are stale, pointing to the previous
8781 // (full) chunk. to re-assign them
8782 rc = sqlite3_blob_closesqlite3_api->blob_close(*blobChunksValidity);
8783 sqlite3_freesqlite3_api->free((void *)*bufferChunksValidity);
8784 *blobChunksValidity = NULL((void*)0);
8785 *bufferChunksValidity = NULL((void*)0);
8786 if (rc != SQLITE_OK0) {
8787 vtab_set_error(&p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8788 "unknown error, blobChunksValidity could not be closed, "
8789 "please file an issue.");
8790 rc = SQLITE_ERROR1;
8791 goto cleanup;
8792 }
8793
8794 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowChunksName,
8795 "validity", *chunk_rowid, 1, blobChunksValidity);
8796 if (rc != SQLITE_OK0) {
8797 vtab_set_error(
8798 &p->base,
8799 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8800 "Could not open validity blob for newly created chunk %s.%s.%lld",
8801 p->schemaName, p->shadowChunksName, *chunk_rowid);
8802 goto cleanup;
8803 }
8804 validitySize = sqlite3_blob_bytessqlite3_api->blob_bytes(*blobChunksValidity);
8805 if (validitySize != p->chunk_size / CHAR_BIT8) {
8806 vtab_set_error(&p->base,
8807 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8808 "validity blob size mismatch for newly created chunk "
8809 "%s.%s.%lld. Exepcted %lld, got %lld",
8810 p->schemaName, p->shadowChunksName, *chunk_rowid,
8811 p->chunk_size / CHAR_BIT8, validitySize);
8812 goto cleanup;
8813 }
8814 *bufferChunksValidity = sqlite3_mallocsqlite3_api->malloc(validitySize);
8815 rc = sqlite3_blob_readsqlite3_api->blob_read(*blobChunksValidity, (void *)*bufferChunksValidity,
8816 validitySize, 0);
8817 if (rc != SQLITE_OK0) {
8818 vtab_set_error(&p->base,
8819 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8820 "could not read validity blob newly created chunk "
8821 "%s.%s.%lld",
8822 p->schemaName, p->shadowChunksName, *chunk_rowid);
8823 goto cleanup;
8824 }
8825 }
8826
8827 rc = SQLITE_OK0;
8828
8829cleanup:
8830 return rc;
8831}
8832
8833/**
8834 * @brief Write the vector data into the provided vector blob at the given
8835 * offset
8836 *
8837 * @param blobVectors SQLite BLOB to write to
8838 * @param chunk_offset the "offset" (ie validity bitmap position) to write the
8839 * vector to
8840 * @param bVector pointer to the vector containing data
8841 * @param dimensions how many dimensions the vector has
8842 * @param element_type the vector type
8843 * @return result of sqlite3_blob_write, SQLITE_OK on success, otherwise failure
8844 */
8845static int
8846vec0_write_vector_to_vector_blob(sqlite3_blob *blobVectors, i64 chunk_offset,
8847 const void *bVector, size_t dimensions,
8848 enum VectorElementType element_type) {
8849 int n;
8850 int offset;
8851
8852 switch (element_type) {
8853 case SQLITE_VEC_ELEMENT_TYPE_FLOAT32:
8854 n = dimensions * sizeof(f32);
8855 offset = chunk_offset * dimensions * sizeof(f32);
8856 break;
8857 case SQLITE_VEC_ELEMENT_TYPE_INT8:
8858 n = dimensions * sizeof(i8);
8859 offset = chunk_offset * dimensions * sizeof(i8);
8860 break;
8861 case SQLITE_VEC_ELEMENT_TYPE_BIT:
8862 n = dimensions / CHAR_BIT8;
8863 offset = chunk_offset * dimensions / CHAR_BIT8;
8864 break;
8865 }
8866
8867 return sqlite3_blob_writesqlite3_api->blob_write(blobVectors, bVector, n, offset);
8868}
8869
8870/**
8871 * @brief
8872 *
8873 * @param p vec0 virtual table
8874 * @param chunk_rowid: which chunk to write to
8875 * @param chunk_offset: the offset inside the chunk to write the vector to.
8876 * @param rowid: the rowid of the inserting row
8877 * @param vectorDatas: array of the vector data to insert
8878 * @param blobValidity: writeable validity blob of the row's assigned chunk.
8879 * @param validity: snapshot buffer of the valdity column from the row's
8880 * assigned chunk.
8881 * @return int SQLITE_OK on success, error code on failure
8882 */
8883int vec0Update_InsertWriteFinalStep(vec0_vtab *p, i64 chunk_rowid,
8884 i64 chunk_offset, i64 rowid,
8885 void *vectorDatas[],
8886 sqlite3_blob *blobChunksValidity,
8887 const unsigned char *bufferChunksValidity) {
8888 int rc, brc;
8889 sqlite3_blob *blobChunksRowids = NULL((void*)0);
8890
8891 // mark the validity bit for this row in the chunk's validity bitmap
8892 // Get the byte offset of the bitmap
8893 char unsigned bx = bufferChunksValidity[chunk_offset / CHAR_BIT8];
8894 // set the bit at the chunk_offset position inside that byte
8895 bx = bx | (1 << (chunk_offset % CHAR_BIT8));
8896 // write that 1 byte
8897 rc = sqlite3_blob_writesqlite3_api->blob_write(blobChunksValidity, &bx, 1, chunk_offset / CHAR_BIT8);
8898 if (rc != SQLITE_OK0) {
8899 vtab_set_error(&p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: " "could not mark validity bit ");
8900 return rc;
8901 }
8902
8903 // Go insert the vector data into the vector chunk shadow tables
8904 for (int i = 0; i < p->numVectorColumns; i++) {
8905 // Non-FLAT columns (rescore, IVF, DiskANN) don't use _vector_chunks
8906 if (p->vector_columns[i].index_type != VEC0_INDEX_TYPE_FLAT)
8907 continue;
8908
8909 sqlite3_blob *blobVectors;
8910 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowVectorChunksNames[i],
8911 "vectors", chunk_rowid, 1, &blobVectors);
8912 if (rc != SQLITE_OK0) {
8913 vtab_set_error(&p->base, "Error opening vector blob at %s.%s.%lld",
8914 p->schemaName, p->shadowVectorChunksNames[i], chunk_rowid);
8915 goto cleanup;
8916 }
8917
8918 i64 expected =
8919 p->chunk_size * vector_column_byte_size(p->vector_columns[i]);
8920 i64 actual = sqlite3_blob_bytessqlite3_api->blob_bytes(blobVectors);
8921
8922 if (actual != expected) {
8923 // IMP: V16386_00456
8924 vtab_set_error(
8925 &p->base,
8926 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8927 "vector blob size mismatch on %s.%s.%lld. Expected %lld, actual %lld",
8928 p->schemaName, p->shadowVectorChunksNames[i], chunk_rowid, expected,
8929 actual);
8930 rc = SQLITE_ERROR1;
8931 // already error, can ignore result code
8932 sqlite3_blob_closesqlite3_api->blob_close(blobVectors);
8933 goto cleanup;
8934 };
8935
8936 rc = vec0_write_vector_to_vector_blob(
8937 blobVectors, chunk_offset, vectorDatas[i],
8938 p->vector_columns[i].dimensions, p->vector_columns[i].element_type);
8939 if (rc != SQLITE_OK0) {
8940 vtab_set_error(&p->base,
8941 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8942 "could not write vector blob on %s.%s.%lld",
8943 p->schemaName, p->shadowVectorChunksNames[i], chunk_rowid);
8944 rc = SQLITE_ERROR1;
8945 // already error, can ignore result code
8946 sqlite3_blob_closesqlite3_api->blob_close(blobVectors);
8947 goto cleanup;
8948 }
8949 rc = sqlite3_blob_closesqlite3_api->blob_close(blobVectors);
8950 if (rc != SQLITE_OK0) {
8951 vtab_set_error(&p->base,
8952 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8953 "could not close vector blob on %s.%s.%lld",
8954 p->schemaName, p->shadowVectorChunksNames[i], chunk_rowid);
8955 rc = SQLITE_ERROR1;
8956 goto cleanup;
8957 }
8958 }
8959
8960 // write the new rowid to the rowids column of the _chunks table
8961 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowChunksName, "rowids",
8962 chunk_rowid, 1, &blobChunksRowids);
8963 if (rc != SQLITE_OK0) {
8964 // IMP: V09221_26060
8965 vtab_set_error(&p->base,
8966 VEC_INTERAL_ERROR"Internal sqlite-vec error: " "could not open rowids blob on %s.%s.%lld",
8967 p->schemaName, p->shadowChunksName, chunk_rowid);
8968 goto cleanup;
8969 }
8970 i64 expected = p->chunk_size * sizeof(i64);
8971 i64 actual = sqlite3_blob_bytessqlite3_api->blob_bytes(blobChunksRowids);
8972 if (expected != actual) {
8973 // IMP: V12779_29618
8974 vtab_set_error(
8975 &p->base,
8976 VEC_INTERAL_ERROR"Internal sqlite-vec error: "
8977 "rowids blob size mismatch on %s.%s.%lld. Expected %lld, actual %lld",
8978 p->schemaName, p->shadowChunksName, chunk_rowid, expected, actual);
8979 rc = SQLITE_ERROR1;
8980 goto cleanup;
8981 }
8982 rc = sqlite3_blob_writesqlite3_api->blob_write(blobChunksRowids, &rowid, sizeof(i64),
8983 chunk_offset * sizeof(i64));
8984 if (rc != SQLITE_OK0) {
8985 vtab_set_error(
8986 &p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: " "could not write rowids blob on %s.%s.%lld",
8987 p->schemaName, p->shadowChunksName, chunk_rowid);
8988 rc = SQLITE_ERROR1;
8989 goto cleanup;
8990 }
8991
8992 // Now with all the vectors inserted, go back and update the _rowids table
8993 // with the new chunk_rowid/chunk_offset values
8994 rc = vec0_rowids_update_position(p, rowid, chunk_rowid, chunk_offset);
8995
8996cleanup:
8997 brc = sqlite3_blob_closesqlite3_api->blob_close(blobChunksRowids);
8998 if ((rc == SQLITE_OK0) && (brc != SQLITE_OK0)) {
8999 vtab_set_error(
9000 &p->base, VEC_INTERAL_ERROR"Internal sqlite-vec error: " "could not close rowids blob on %s.%s.%lld",
9001 p->schemaName, p->shadowChunksName, chunk_rowid);
9002 return brc;
9003 }
9004 return rc;
9005}
9006
9007int vec0_write_metadata_value(vec0_vtab *p, int metadata_column_idx, i64 rowid, i64 chunk_id, i64 chunk_offset, sqlite3_value * v, int isupdate) {
9008 int rc;
9009 struct Vec0MetadataColumnDefinition * metadata_column = &p->metadata_columns[metadata_column_idx];
9010 vec0_metadata_column_kind kind = metadata_column->kind;
9011
9012 // verify input value matches column type
9013 switch(kind) {
9014 case VEC0_METADATA_COLUMN_KIND_BOOLEAN: {
9015 if(sqlite3_value_typesqlite3_api->value_type(v) != SQLITE_INTEGER1 || ((sqlite3_value_intsqlite3_api->value_int(v) != 0) && (sqlite3_value_intsqlite3_api->value_int(v) != 1))) {
9016 rc = SQLITE_ERROR1;
9017 vtab_set_error(&p->base, "Expected 0 or 1 for BOOLEAN metadata column %.*s", metadata_column->name_length, metadata_column->name);
9018 goto done;
9019 }
9020 break;
9021 }
9022 case VEC0_METADATA_COLUMN_KIND_INTEGER: {
9023 if(sqlite3_value_typesqlite3_api->value_type(v) != SQLITE_INTEGER1) {
9024 rc = SQLITE_ERROR1;
9025 vtab_set_error(&p->base, "Expected integer for INTEGER metadata column %.*s, received %s", metadata_column->name_length, metadata_column->name, type_name(sqlite3_value_typesqlite3_api->value_type(v)));
9026 goto done;
9027 }
9028 break;
9029 }
9030 case VEC0_METADATA_COLUMN_KIND_FLOAT: {
9031 if(sqlite3_value_typesqlite3_api->value_type(v) != SQLITE_FLOAT2) {
9032 rc = SQLITE_ERROR1;
9033 vtab_set_error(&p->base, "Expected float for FLOAT metadata column %.*s, received %s", metadata_column->name_length, metadata_column->name, type_name(sqlite3_value_typesqlite3_api->value_type(v)));
9034 goto done;
9035 }
9036 break;
9037 }
9038 case VEC0_METADATA_COLUMN_KIND_TEXT: {
9039 if(sqlite3_value_typesqlite3_api->value_type(v) != SQLITE_TEXT3) {
9040 rc = SQLITE_ERROR1;
9041 vtab_set_error(&p->base, "Expected text for TEXT metadata column %.*s, received %s", metadata_column->name_length, metadata_column->name, type_name(sqlite3_value_typesqlite3_api->value_type(v)));
9042 goto done;
9043 }
9044 break;
9045 }
9046 }
9047
9048 sqlite3_blob * blobValue = NULL((void*)0);
9049 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowMetadataChunksNames[metadata_column_idx], "data", chunk_id, 1, &blobValue);
9050 if(rc != SQLITE_OK0) {
9051 goto done;
9052 }
9053
9054 switch(kind) {
9055 case VEC0_METADATA_COLUMN_KIND_BOOLEAN: {
9056 u8 block;
9057 int value = sqlite3_value_intsqlite3_api->value_int(v);
9058 rc = sqlite3_blob_readsqlite3_api->blob_read(blobValue, &block, sizeof(u8), (int) (chunk_offset / CHAR_BIT8));
9059 if(rc != SQLITE_OK0) {
9060 goto done;
9061 }
9062
9063 if (value) {
9064 block |= 1 << (chunk_offset % CHAR_BIT8);
9065 } else {
9066 block &= ~(1 << (chunk_offset % CHAR_BIT8));
9067 }
9068
9069 rc = sqlite3_blob_writesqlite3_api->blob_write(blobValue, &block, sizeof(u8), chunk_offset / CHAR_BIT8);
9070 break;
9071 }
9072 case VEC0_METADATA_COLUMN_KIND_INTEGER: {
9073 i64 value = sqlite3_value_int64sqlite3_api->value_int64(v);
9074 rc = sqlite3_blob_writesqlite3_api->blob_write(blobValue, &value, sizeof(value), chunk_offset * sizeof(i64));
9075 break;
9076 }
9077 case VEC0_METADATA_COLUMN_KIND_FLOAT: {
9078 double value = sqlite3_value_doublesqlite3_api->value_double(v);
9079 rc = sqlite3_blob_writesqlite3_api->blob_write(blobValue, &value, sizeof(value), chunk_offset * sizeof(double));
9080 break;
9081 }
9082 case VEC0_METADATA_COLUMN_KIND_TEXT: {
9083 int prev_n;
9084 rc = sqlite3_blob_readsqlite3_api->blob_read(blobValue, &prev_n, sizeof(int), chunk_offset * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16);
9085 if(rc != SQLITE_OK0) {
9086 goto done;
9087 }
9088
9089 const char * s = (const char *) sqlite3_value_textsqlite3_api->value_text(v);
9090 int n = sqlite3_value_bytessqlite3_api->value_bytes(v);
9091 u8 view[VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16];
9092 memset(view, 0, VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16);
9093 memcpy(view, &n, sizeof(int));
9094 memcpy(view+4, s, min(n, VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH-4)(((n) <= (16 -4)) ? (n) : (16 -4)));
9095
9096 rc = sqlite3_blob_writesqlite3_api->blob_write(blobValue, &view, VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16, chunk_offset * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16);
9097 if(n > VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12) {
9098 const char * zSql;
9099
9100 if(isupdate && (prev_n > VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12)) {
9101 zSql = sqlite3_mprintfsqlite3_api->mprintf("UPDATE " VEC0_SHADOW_METADATA_TEXT_DATA_NAME"\"%w\".\"%w_metadatatext%02d\"" " SET data = ?2 WHERE rowid = ?1", p->schemaName, p->tableName, metadata_column_idx);
9102 }else {
9103 zSql = sqlite3_mprintfsqlite3_api->mprintf("INSERT INTO " VEC0_SHADOW_METADATA_TEXT_DATA_NAME"\"%w\".\"%w_metadatatext%02d\"" " (rowid, data) VALUES (?1, ?2)", p->schemaName, p->tableName, metadata_column_idx);
9104 }
9105 if(!zSql) {
9106 rc = SQLITE_NOMEM7;
9107 goto done;
9108 }
9109 sqlite3_stmt * stmt;
9110 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
9111 if(rc != SQLITE_OK0) {
9112 goto done;
9113 }
9114 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, rowid);
9115 sqlite3_bind_textsqlite3_api->bind_text(stmt, 2, s, n, SQLITE_STATIC((sqlite3_destructor_type)0));
9116 rc = sqlite3_stepsqlite3_api->step(stmt);
9117 sqlite3_finalizesqlite3_api->finalize(stmt);
9118
9119 if(rc != SQLITE_DONE101) {
9120 rc = SQLITE_ERROR1;
9121 goto done;
9122 }
9123 }
9124 else if(prev_n > VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12) {
9125 const char * zSql = sqlite3_mprintfsqlite3_api->mprintf("DELETE FROM " VEC0_SHADOW_METADATA_TEXT_DATA_NAME"\"%w\".\"%w_metadatatext%02d\"" " WHERE rowid = ?", p->schemaName, p->tableName, metadata_column_idx);
9126 if(!zSql) {
9127 rc = SQLITE_NOMEM7;
9128 goto done;
9129 }
9130 sqlite3_stmt * stmt;
9131 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
9132 if(rc != SQLITE_OK0) {
9133 goto done;
9134 }
9135 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, rowid);
9136 rc = sqlite3_stepsqlite3_api->step(stmt);
9137 sqlite3_finalizesqlite3_api->finalize(stmt);
9138
9139 if(rc != SQLITE_DONE101) {
9140 rc = SQLITE_ERROR1;
9141 goto done;
9142 }
9143 }
9144 break;
9145 }
9146 }
9147
9148 if(rc != SQLITE_OK0) {
9149
9150 }
9151 rc = sqlite3_blob_closesqlite3_api->blob_close(blobValue);
9152 if(rc != SQLITE_OK0) {
9153 goto done;
9154 }
9155
9156 done:
9157 return rc;
9158}
9159
9160
9161/**
9162 * @brief Handles INSERT INTO operations on a vec0 table.
9163 *
9164 * @return int SQLITE_OK on success, otherwise error code on failure
9165 */
9166// Forward declaration: needed for INSERT OR REPLACE handling in vec0Update_Insert
9167int vec0Update_Delete(sqlite3_vtab *pVTab, sqlite3_value *idValue);
9168
9169int vec0Update_Insert(sqlite3_vtab *pVTab, int argc, sqlite3_value **argv,
9170 sqlite_int64 *pRowid) {
9171 UNUSED_PARAMETER(argc)(void)(argc);
9172 vec0_vtab *p = (vec0_vtab *)pVTab;
9173 int rc;
9174 // Rowid for the inserted row, deterimined by the inserted ID + _rowids shadow
9175 // table
9176 i64 rowid;
9177
9178 // Array to hold the vector data of the inserted row. Individual elements will
9179 // have a lifetime bound to the argv[..] values.
9180 void *vectorDatas[VEC0_MAX_VECTOR_COLUMNS16];
9181 // Array to hold cleanup functions for vectorDatas[]
9182 vector_cleanup cleanups[VEC0_MAX_VECTOR_COLUMNS16];
9183
9184 sqlite3_value * partitionKeyValues[VEC0_MAX_PARTITION_COLUMNS4];
9185
9186 // Rowid of the chunk in the _chunks shadow table that the row will be a part
9187 // of.
9188 i64 chunk_rowid;
9189 // offset within the chunk where the rowid belongs
9190 i64 chunk_offset;
9191
9192 // a write-able blob of the validity column for the given chunk. Used to mark
9193 // validity bit
9194 sqlite3_blob *blobChunksValidity = NULL((void*)0);
9195 // buffer for the valididty column for the given chunk. Maybe not needed here?
9196 const unsigned char *bufferChunksValidity = NULL((void*)0);
9197 int numReadVectors = 0;
9198
9199 // Read all provided partition key values into partitionKeyValues
9200 for (int i = 0; i < vec0_num_defined_user_columns(p); i++) {
9201 if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_PARTITION) {
9202 continue;
9203 }
9204 int partition_key_idx = p->user_column_idxs[i];
9205 partitionKeyValues[partition_key_idx] = argv[2+VEC0_COLUMN_USERN_START1 + i];
9206
9207 int new_value_type = sqlite3_value_typesqlite3_api->value_type(partitionKeyValues[partition_key_idx]);
9208 if((new_value_type != SQLITE_NULL5) && (new_value_type != p->paritition_columns[partition_key_idx].type)) {
9209 // IMP: V11454_28292
9210 vtab_set_error(
9211 pVTab,
9212 "Parition key type mismatch: The partition key column %.*s has type %s, but %s was provided.",
9213 p->paritition_columns[partition_key_idx].name_length,
9214 p->paritition_columns[partition_key_idx].name,
9215 type_name(p->paritition_columns[partition_key_idx].type),
9216 type_name(new_value_type)
9217 );
9218 rc = SQLITE_ERROR1;
9219 goto cleanup;
9220 }
9221 }
9222
9223 // read all the inserted vectors into vectorDatas, validate their lengths.
9224 for (int i = 0; i < vec0_num_defined_user_columns(p); i++) {
9225 if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_VECTOR) {
9226 continue;
9227 }
9228 int vector_column_idx = p->user_column_idxs[i];
9229 sqlite3_value *valueVector = argv[2 + VEC0_COLUMN_USERN_START1 + i];
9230 size_t dimensions;
9231
9232 char *pzError;
9233 enum VectorElementType elementType;
9234 rc = vector_from_value(valueVector, &vectorDatas[vector_column_idx], &dimensions,
9235 &elementType, &cleanups[vector_column_idx], &pzError);
9236 if (rc != SQLITE_OK0) {
9237 // IMP: V06519_23358
9238 vtab_set_error(
9239 pVTab, "Inserted vector for the \"%.*s\" column is invalid: %z",
9240 p->vector_columns[vector_column_idx].name_length, p->vector_columns[vector_column_idx].name, pzError);
9241 rc = SQLITE_ERROR1;
9242 goto cleanup;
9243 }
9244
9245 numReadVectors++;
9246 if (elementType != p->vector_columns[vector_column_idx].element_type) {
9247 // IMP: V08221_25059
9248 vtab_set_error(
9249 pVTab,
9250 "Inserted vector for the \"%.*s\" column is expected to be of type "
9251 "%s, but a %s vector was provided.",
9252 p->vector_columns[i].name_length, p->vector_columns[i].name,
9253 vector_subtype_name(p->vector_columns[i].element_type),
9254 vector_subtype_name(elementType));
9255 rc = SQLITE_ERROR1;
9256 goto cleanup;
9257 }
9258
9259 if (dimensions != p->vector_columns[vector_column_idx].dimensions) {
9260 // IMP: V01145_17984
9261 vtab_set_error(
9262 pVTab,
9263 "Dimension mismatch for inserted vector for the \"%.*s\" column. "
9264 "Expected %d dimensions but received %d.",
9265 p->vector_columns[vector_column_idx].name_length, p->vector_columns[vector_column_idx].name,
9266 p->vector_columns[vector_column_idx].dimensions, dimensions);
9267 rc = SQLITE_ERROR1;
9268 goto cleanup;
9269 }
9270 }
9271
9272 // Cannot insert a value in the hidden "distance" column
9273 if (sqlite3_value_typesqlite3_api->value_type(argv[2 + vec0_column_distance_idx(p)]) !=
9274 SQLITE_NULL5) {
9275 // IMP: V24228_08298
9276 vtab_set_error(pVTab,
9277 "A value was provided for the hidden \"distance\" column.");
9278 rc = SQLITE_ERROR1;
9279 goto cleanup;
9280 }
9281 // Cannot insert a value in the hidden "k" column
9282 if (sqlite3_value_typesqlite3_api->value_type(argv[2 + vec0_column_k_idx(p)]) != SQLITE_NULL5) {
9283 // IMP: V11875_28713
9284 vtab_set_error(pVTab, "A value was provided for the hidden \"k\" column.");
9285 rc = SQLITE_ERROR1;
9286 goto cleanup;
9287 }
9288
9289 // Handle INSERT OR REPLACE: if the conflict resolution is REPLACE and the
9290 // row already exists, delete the existing row first before inserting.
9291 if (sqlite3_vtab_on_conflictsqlite3_api->vtab_on_conflict(p->db) == SQLITE_REPLACE5) {
9292 sqlite3_value *idValue = argv[2 + VEC0_COLUMN_ID0];
9293 int idType = sqlite3_value_typesqlite3_api->value_type(idValue);
9294 int existingRowExists = 0;
9295
9296 if (p->pkIsText && idType == SQLITE_TEXT3) {
9297 i64 existingRowid;
9298 rc = vec0_rowid_from_id(p, idValue, &existingRowid);
9299 if (rc == SQLITE_OK0) {
9300 existingRowExists = 1;
9301 } else if (rc == SQLITE_EMPTY16) {
9302 rc = SQLITE_OK0; // row doesn't exist, proceed with normal insert
9303 } else {
9304 goto cleanup;
9305 }
9306 } else if (!p->pkIsText && idType == SQLITE_INTEGER1) {
9307 i64 existingRowid = sqlite3_value_int64sqlite3_api->value_int64(idValue);
9308 i64 chunk_id_tmp, chunk_offset_tmp;
9309 rc = vec0_get_chunk_position(p, existingRowid, NULL((void*)0), &chunk_id_tmp, &chunk_offset_tmp);
9310 if (rc == SQLITE_OK0) {
9311 existingRowExists = 1;
9312 } else if (rc == SQLITE_EMPTY16) {
9313 rc = SQLITE_OK0; // row doesn't exist, proceed with normal insert
9314 } else {
9315 goto cleanup;
9316 }
9317 }
9318
9319 if (existingRowExists) {
9320 rc = vec0Update_Delete(pVTab, idValue);
9321 if (rc != SQLITE_OK0) {
9322 goto cleanup;
9323 }
9324 }
9325 }
9326
9327 // Step #1: Insert/get a rowid for this row, from the _rowids table.
9328 rc = vec0Update_InsertRowidStep(p, argv[2 + VEC0_COLUMN_ID0], &rowid);
9329 if (rc != SQLITE_OK0) {
9330 goto cleanup;
9331 }
9332
9333 if (!vec0_all_columns_diskann(p)) {
9334 // Step #2: Find the next "available" position in the _chunks table for this
9335 // row.
9336 rc = vec0Update_InsertNextAvailableStep(p, partitionKeyValues,
9337 &chunk_rowid, &chunk_offset,
9338 &blobChunksValidity,
9339 &bufferChunksValidity);
9340 if (rc != SQLITE_OK0) {
9341 goto cleanup;
9342 }
9343
9344 // Step #3: With the next available chunk position, write out all the vectors
9345 // to their specified location.
9346 rc = vec0Update_InsertWriteFinalStep(p, chunk_rowid, chunk_offset, rowid,
9347 vectorDatas, blobChunksValidity,
9348 bufferChunksValidity);
9349 if (rc != SQLITE_OK0) {
9350 goto cleanup;
9351 }
9352 }
9353
9354#if SQLITE_VEC_ENABLE_DISKANN0
9355 // Step #4: Insert into DiskANN graph for indexed vector columns
9356 for (int i = 0; i < p->numVectorColumns; i++) {
9357 if (p->vector_columns[i].index_type != VEC0_INDEX_TYPE_DISKANN) continue;
9358 rc = diskann_insert(p, i, rowid, vectorDatas[i]);
9359 if (rc != SQLITE_OK0) {
9360 goto cleanup;
9361 }
9362 }
9363#endif
9364
9365#if SQLITE_VEC_ENABLE_RESCORE1
9366 rc = rescore_on_insert(p, chunk_rowid, chunk_offset, rowid, vectorDatas);
9367 if (rc != SQLITE_OK0) {
9368 goto cleanup;
9369 }
9370#endif
9371
9372#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
9373 // Step #4: IVF index insert (if any vector column uses IVF)
9374 for (int i = 0; i < p->numVectorColumns; i++) {
9375 if (p->vector_columns[i].index_type != VEC0_INDEX_TYPE_IVF) continue;
9376 int vecSize = (int)vector_column_byte_size(p->vector_columns[i]);
9377 rc = ivf_insert(p, i, rowid, vectorDatas[i], vecSize);
9378 if (rc != SQLITE_OK0) {
9379 goto cleanup;
9380 }
9381 }
9382#endif
9383
9384 if(p->numAuxiliaryColumns > 0) {
9385 sqlite3_stmt *stmt;
9386 sqlite3_str * s = sqlite3_str_newsqlite3_api->str_new(NULL((void*)0));
9387 sqlite3_str_appendfsqlite3_api->str_appendf(s, "INSERT INTO " VEC0_SHADOW_AUXILIARY_NAME"\"%w\".\"%w_auxiliary\"" "(rowid ", p->schemaName, p->tableName);
9388 for(int i = 0; i < p->numAuxiliaryColumns; i++) {
9389 sqlite3_str_appendfsqlite3_api->str_appendf(s, ", value%02d", i);
9390 }
9391 sqlite3_str_appendallsqlite3_api->str_appendall(s, ") VALUES (? ");
9392 for(int i = 0; i < p->numAuxiliaryColumns; i++) {
9393 sqlite3_str_appendallsqlite3_api->str_appendall(s, ", ?");
9394 }
9395 sqlite3_str_appendallsqlite3_api->str_appendall(s, ")");
9396 char * zSql = sqlite3_str_finishsqlite3_api->str_finish(s);
9397 // TODO double check error handling ehre
9398 if(!zSql) {
9399 rc = SQLITE_NOMEM7;
9400 goto cleanup;
9401 }
9402 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
9403 if(rc != SQLITE_OK0) {
9404 goto cleanup;
9405 }
9406 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, rowid);
9407
9408 for (int i = 0; i < vec0_num_defined_user_columns(p); i++) {
9409 if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_AUXILIARY) {
9410 continue;
9411 }
9412 int auxiliary_key_idx = p->user_column_idxs[i];
9413 sqlite3_value * v = argv[2+VEC0_COLUMN_USERN_START1 + i];
9414 int v_type = sqlite3_value_typesqlite3_api->value_type(v);
9415 if(v_type != SQLITE_NULL5 && (v_type != p->auxiliary_columns[auxiliary_key_idx].type)) {
9416 sqlite3_finalizesqlite3_api->finalize(stmt);
9417 rc = SQLITE_CONSTRAINT19;
9418 vtab_set_error(
9419 pVTab,
9420 "Auxiliary column type mismatch: The auxiliary column %.*s has type %s, but %s was provided.",
9421 p->auxiliary_columns[auxiliary_key_idx].name_length,
9422 p->auxiliary_columns[auxiliary_key_idx].name,
9423 type_name(p->auxiliary_columns[auxiliary_key_idx].type),
9424 type_name(v_type)
9425 );
9426 goto cleanup;
9427 }
9428 // first 1 is for 1-based indexing on sqlite3_bind_*, second 1 is to account for initial rowid parameter
9429 sqlite3_bind_valuesqlite3_api->bind_value(stmt, 1 + 1 + auxiliary_key_idx, v);
9430 }
9431
9432 rc = sqlite3_stepsqlite3_api->step(stmt);
9433 if(rc != SQLITE_DONE101) {
9434 sqlite3_finalizesqlite3_api->finalize(stmt);
9435 rc = SQLITE_ERROR1;
9436 goto cleanup;
9437 }
9438 sqlite3_finalizesqlite3_api->finalize(stmt);
9439 }
9440
9441
9442 for(int i = 0; i < vec0_num_defined_user_columns(p); i++) {
9443 if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_METADATA) {
9444 continue;
9445 }
9446 int metadata_idx = p->user_column_idxs[i];
9447 sqlite3_value *v = argv[2 + VEC0_COLUMN_USERN_START1 + i];
9448 rc = vec0_write_metadata_value(p, metadata_idx, rowid, chunk_rowid, chunk_offset, v, 0);
9449 if(rc != SQLITE_OK0) {
9450 goto cleanup;
9451 }
9452 }
9453
9454 *pRowid = rowid;
9455 rc = SQLITE_OK0;
9456
9457cleanup:
9458 for (int i = 0; i < numReadVectors; i++) {
9459 cleanups[i](vectorDatas[i]);
9460 }
9461 sqlite3_freesqlite3_api->free((void *)bufferChunksValidity);
9462 int brc = sqlite3_blob_closesqlite3_api->blob_close(blobChunksValidity);
9463 if ((rc == SQLITE_OK0) && (brc != SQLITE_OK0)) {
9464 vtab_set_error(&p->base,
9465 VEC_INTERAL_ERROR"Internal sqlite-vec error: " "unknown error, blobChunksValidity could "
9466 "not be closed, please file an issue");
9467 return brc;
9468 }
9469 return rc;
9470}
9471
9472int vec0Update_Delete_ClearValidity(vec0_vtab *p, i64 chunk_id,
9473 u64 chunk_offset) {
9474 int rc, brc;
9475 sqlite3_blob *blobChunksValidity = NULL((void*)0);
9476 char unsigned bx;
9477 int validityOffset = chunk_offset / CHAR_BIT8;
9478
9479 // 2. ensure chunks.validity bit is 1, then set to 0
9480 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowChunksName, "validity",
9481 chunk_id, 1, &blobChunksValidity);
9482 if (rc != SQLITE_OK0) {
9483 // IMP: V26002_10073
9484 vtab_set_error(&p->base, "could not open validity blob for %s.%s.%lld",
9485 p->schemaName, p->shadowChunksName, chunk_id);
9486 return SQLITE_ERROR1;
9487 }
9488 // will skip the sqlite3_blob_bytes(blobChunksValidity) check for now,
9489 // the read below would catch it
9490
9491 rc = sqlite3_blob_readsqlite3_api->blob_read(blobChunksValidity, &bx, sizeof(bx), validityOffset);
9492 if (rc != SQLITE_OK0) {
9493 // IMP: V21193_05263
9494 vtab_set_error(
9495 &p->base, "could not read validity blob for %s.%s.%lld at %d",
9496 p->schemaName, p->shadowChunksName, chunk_id, validityOffset);
9497 goto cleanup;
9498 }
9499 if (!(bx >> (chunk_offset % CHAR_BIT8))) {
9500 // IMP: V21193_05263
9501 rc = SQLITE_ERROR1;
9502 vtab_set_error(
9503 &p->base,
9504 "vec0 deletion error: validity bit is not set for %s.%s.%lld at %d",
9505 p->schemaName, p->shadowChunksName, chunk_id, validityOffset);
9506 goto cleanup;
9507 }
9508 char unsigned mask = ~(1 << (chunk_offset % CHAR_BIT8));
9509 char result = bx & mask;
9510 rc = sqlite3_blob_writesqlite3_api->blob_write(blobChunksValidity, &result, sizeof(bx),
9511 validityOffset);
9512 if (rc != SQLITE_OK0) {
9513 vtab_set_error(
9514 &p->base, "could not write to validity blob for %s.%s.%lld at %d",
9515 p->schemaName, p->shadowChunksName, chunk_id, validityOffset);
9516 goto cleanup;
9517 }
9518
9519cleanup:
9520
9521 brc = sqlite3_blob_closesqlite3_api->blob_close(blobChunksValidity);
9522 if (rc != SQLITE_OK0)
9523 return rc;
9524 if (brc != SQLITE_OK0) {
9525 vtab_set_error(&p->base,
9526 "vec0 deletion error: Error commiting validity blob "
9527 "transaction on %s.%s.%lld at %d",
9528 p->schemaName, p->shadowChunksName, chunk_id,
9529 validityOffset);
9530 return brc;
9531 }
9532 return SQLITE_OK0;
9533}
9534
9535int vec0Update_Delete_ClearRowid(vec0_vtab *p, i64 chunk_id,
9536 u64 chunk_offset) {
9537 int rc, brc;
9538 sqlite3_blob *blobChunksRowids = NULL((void*)0);
9539 i64 zero = 0;
9540
9541 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowChunksName, "rowids",
9542 chunk_id, 1, &blobChunksRowids);
9543 if (rc != SQLITE_OK0) {
9544 vtab_set_error(&p->base, "could not open rowids blob for %s.%s.%lld",
9545 p->schemaName, p->shadowChunksName, chunk_id);
9546 return SQLITE_ERROR1;
9547 }
9548
9549 rc = sqlite3_blob_writesqlite3_api->blob_write(blobChunksRowids, &zero, sizeof(zero),
9550 chunk_offset * sizeof(i64));
9551 if (rc != SQLITE_OK0) {
9552 vtab_set_error(&p->base,
9553 "could not write to rowids blob for %s.%s.%lld at %llu",
9554 p->schemaName, p->shadowChunksName, chunk_id, chunk_offset);
9555 }
9556
9557 brc = sqlite3_blob_closesqlite3_api->blob_close(blobChunksRowids);
9558 if (rc != SQLITE_OK0)
9559 return rc;
9560 if (brc != SQLITE_OK0) {
9561 vtab_set_error(&p->base,
9562 "vec0 deletion error: Error commiting rowids blob "
9563 "transaction on %s.%s.%lld at %llu",
9564 p->schemaName, p->shadowChunksName, chunk_id, chunk_offset);
9565 return brc;
9566 }
9567 return SQLITE_OK0;
9568}
9569
9570int vec0Update_Delete_ClearVectors(vec0_vtab *p, i64 chunk_id,
9571 u64 chunk_offset) {
9572 int rc, brc;
9573 for (int i = 0; i < p->numVectorColumns; i++) {
9574 // Non-FLAT columns (rescore, IVF, DiskANN) don't use _vector_chunks
9575 if (p->vector_columns[i].index_type != VEC0_INDEX_TYPE_FLAT)
9576 continue;
9577 sqlite3_blob *blobVectors = NULL((void*)0);
9578 size_t n = vector_column_byte_size(p->vector_columns[i]);
9579
9580 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName,
9581 p->shadowVectorChunksNames[i], "vectors",
9582 chunk_id, 1, &blobVectors);
9583 if (rc != SQLITE_OK0) {
9584 vtab_set_error(&p->base,
9585 "could not open vector blob for %s.%s.%lld column %d",
9586 p->schemaName, p->shadowVectorChunksNames[i], chunk_id, i);
9587 return SQLITE_ERROR1;
9588 }
9589
9590 void *zeroBuf = sqlite3_mallocsqlite3_api->malloc(n);
9591 if (!zeroBuf) {
9592 sqlite3_blob_closesqlite3_api->blob_close(blobVectors);
9593 return SQLITE_NOMEM7;
9594 }
9595 memset(zeroBuf, 0, n);
9596
9597 rc = sqlite3_blob_writesqlite3_api->blob_write(blobVectors, zeroBuf, n, chunk_offset * n);
9598 sqlite3_freesqlite3_api->free(zeroBuf);
9599 if (rc != SQLITE_OK0) {
9600 vtab_set_error(
9601 &p->base,
9602 "could not write to vector blob for %s.%s.%lld at %llu column %d",
9603 p->schemaName, p->shadowVectorChunksNames[i], chunk_id,
9604 chunk_offset, i);
9605 }
9606
9607 brc = sqlite3_blob_closesqlite3_api->blob_close(blobVectors);
9608 if (rc != SQLITE_OK0)
9609 return rc;
9610 if (brc != SQLITE_OK0) {
9611 vtab_set_error(&p->base,
9612 "vec0 deletion error: Error commiting vector blob "
9613 "transaction on %s.%s.%lld column %d",
9614 p->schemaName, p->shadowVectorChunksNames[i], chunk_id, i);
9615 return brc;
9616 }
9617 }
9618 return SQLITE_OK0;
9619}
9620
9621int vec0Update_Delete_DeleteChunkIfEmpty(vec0_vtab *p, i64 chunk_id,
9622 int *deleted) {
9623 int rc, brc;
9624 sqlite3_blob *blobValidity = NULL((void*)0);
9625 *deleted = 0;
9626
9627 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowChunksName, "validity",
9628 chunk_id, 0, &blobValidity);
9629 if (rc != SQLITE_OK0) {
9630 vtab_set_error(&p->base,
9631 "could not open validity blob for chunk %lld", chunk_id);
9632 return SQLITE_ERROR1;
9633 }
9634
9635 int validitySize = sqlite3_blob_bytessqlite3_api->blob_bytes(blobValidity);
9636 unsigned char *validityBuf = sqlite3_mallocsqlite3_api->malloc(validitySize);
9637 if (!validityBuf) {
9638 sqlite3_blob_closesqlite3_api->blob_close(blobValidity);
9639 return SQLITE_NOMEM7;
9640 }
9641
9642 rc = sqlite3_blob_readsqlite3_api->blob_read(blobValidity, validityBuf, validitySize, 0);
9643 brc = sqlite3_blob_closesqlite3_api->blob_close(blobValidity);
9644 if (rc != SQLITE_OK0) {
9645 sqlite3_freesqlite3_api->free(validityBuf);
9646 return rc;
9647 }
9648 if (brc != SQLITE_OK0) {
9649 sqlite3_freesqlite3_api->free(validityBuf);
9650 return brc;
9651 }
9652
9653 int allZero = 1;
9654 for (int i = 0; i < validitySize; i++) {
9655 if (validityBuf[i] != 0) {
9656 allZero = 0;
9657 break;
9658 }
9659 }
9660 sqlite3_freesqlite3_api->free(validityBuf);
9661
9662 if (!allZero) {
9663 return SQLITE_OK0;
9664 }
9665
9666 // All validity bits are zero — delete this chunk and its associated data
9667 char *zSql;
9668 sqlite3_stmt *stmt;
9669
9670 // Delete from _chunks
9671 zSql = sqlite3_mprintfsqlite3_api->mprintf(
9672 "DELETE FROM " VEC0_SHADOW_CHUNKS_NAME"\"%w\".\"%w_chunks\"" " WHERE rowid = ?",
9673 p->schemaName, p->tableName);
9674 if (!zSql)
9675 return SQLITE_NOMEM7;
9676 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
9677 sqlite3_freesqlite3_api->free(zSql);
9678 if (rc != SQLITE_OK0)
9679 return rc;
9680 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, chunk_id);
9681 rc = sqlite3_stepsqlite3_api->step(stmt);
9682 sqlite3_finalizesqlite3_api->finalize(stmt);
9683 if (rc != SQLITE_DONE101)
9684 return SQLITE_ERROR1;
9685
9686 // Delete from each _vector_chunksNN
9687 for (int i = 0; i < p->numVectorColumns; i++) {
9688 // Non-FLAT columns (rescore, IVF, DiskANN) don't use _vector_chunks
9689 if (p->vector_columns[i].index_type != VEC0_INDEX_TYPE_FLAT)
9690 continue;
9691 zSql = sqlite3_mprintfsqlite3_api->mprintf(
9692 "DELETE FROM " VEC0_SHADOW_VECTOR_N_NAME"\"%w\".\"%w_vector_chunks%02d\"" " WHERE rowid = ?",
9693 p->schemaName, p->tableName, i);
9694 if (!zSql)
9695 return SQLITE_NOMEM7;
9696 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
9697 sqlite3_freesqlite3_api->free(zSql);
9698 if (rc != SQLITE_OK0)
9699 return rc;
9700 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, chunk_id);
9701 rc = sqlite3_stepsqlite3_api->step(stmt);
9702 sqlite3_finalizesqlite3_api->finalize(stmt);
9703 if (rc != SQLITE_DONE101)
9704 return SQLITE_ERROR1;
9705 }
9706
9707#if SQLITE_VEC_ENABLE_RESCORE1
9708 rc = rescore_delete_chunk(p, chunk_id);
9709 if (rc != SQLITE_OK0)
9710 return rc;
9711#endif
9712
9713 // Delete from each _metadatachunksNN
9714 for (int i = 0; i < p->numMetadataColumns; i++) {
9715 zSql = sqlite3_mprintfsqlite3_api->mprintf(
9716 "DELETE FROM " VEC0_SHADOW_METADATA_N_NAME"\"%w\".\"%w_metadatachunks%02d\"" " WHERE rowid = ?",
9717 p->schemaName, p->tableName, i);
9718 if (!zSql)
9719 return SQLITE_NOMEM7;
9720 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
9721 sqlite3_freesqlite3_api->free(zSql);
9722 if (rc != SQLITE_OK0)
9723 return rc;
9724 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, chunk_id);
9725 rc = sqlite3_stepsqlite3_api->step(stmt);
9726 sqlite3_finalizesqlite3_api->finalize(stmt);
9727 if (rc != SQLITE_DONE101)
9728 return SQLITE_ERROR1;
9729 }
9730
9731 // Invalidate cached stmtLatestChunk so it gets re-prepared on next insert
9732 if (p->stmtLatestChunk) {
9733 sqlite3_finalizesqlite3_api->finalize(p->stmtLatestChunk);
9734 p->stmtLatestChunk = NULL((void*)0);
9735 }
9736
9737 *deleted = 1;
9738 return SQLITE_OK0;
9739}
9740
9741int vec0Update_Delete_DeleteRowids(vec0_vtab *p, i64 rowid) {
9742 int rc;
9743 sqlite3_stmt *stmt = NULL((void*)0);
9744
9745 char *zSql =
9746 sqlite3_mprintfsqlite3_api->mprintf("DELETE FROM " VEC0_SHADOW_ROWIDS_NAME"\"%w\".\"%w_rowids\"" " WHERE rowid = ?",
9747 p->schemaName, p->tableName);
9748 if (!zSql) {
9749 return SQLITE_NOMEM7;
9750 }
9751
9752 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
9753 sqlite3_freesqlite3_api->free(zSql);
9754 if (rc != SQLITE_OK0) {
9755 goto cleanup;
9756 }
9757 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, rowid);
9758 rc = sqlite3_stepsqlite3_api->step(stmt);
9759 if (rc != SQLITE_DONE101) {
9760 goto cleanup;
9761 }
9762 rc = SQLITE_OK0;
9763
9764cleanup:
9765 sqlite3_finalizesqlite3_api->finalize(stmt);
9766 return rc;
9767}
9768
9769int vec0Update_Delete_DeleteAux(vec0_vtab *p, i64 rowid) {
9770 int rc;
9771 sqlite3_stmt *stmt = NULL((void*)0);
9772
9773 char *zSql =
9774 sqlite3_mprintfsqlite3_api->mprintf("DELETE FROM " VEC0_SHADOW_AUXILIARY_NAME"\"%w\".\"%w_auxiliary\"" " WHERE rowid = ?",
9775 p->schemaName, p->tableName);
9776 if (!zSql) {
9777 return SQLITE_NOMEM7;
9778 }
9779
9780 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
9781 sqlite3_freesqlite3_api->free(zSql);
9782 if (rc != SQLITE_OK0) {
9783 goto cleanup;
9784 }
9785 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, rowid);
9786 rc = sqlite3_stepsqlite3_api->step(stmt);
9787 if (rc != SQLITE_DONE101) {
9788 goto cleanup;
9789 }
9790 rc = SQLITE_OK0;
9791
9792cleanup:
9793 sqlite3_finalizesqlite3_api->finalize(stmt);
9794 return rc;
9795}
9796
9797int vec0Update_Delete_ClearMetadata(vec0_vtab *p, int metadata_idx, i64 rowid, i64 chunk_id,
9798 u64 chunk_offset) {
9799 int rc;
9800 sqlite3_blob * blobValue;
9801 vec0_metadata_column_kind kind = p->metadata_columns[metadata_idx].kind;
9802 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowMetadataChunksNames[metadata_idx], "data", chunk_id, 1, &blobValue);
9803 if(rc != SQLITE_OK0) {
9804 return rc;
9805 }
9806
9807 switch(kind) {
9808 case VEC0_METADATA_COLUMN_KIND_BOOLEAN: {
9809 u8 block;
9810 rc = sqlite3_blob_readsqlite3_api->blob_read(blobValue, &block, sizeof(u8), (int) (chunk_offset / CHAR_BIT8));
9811 if(rc != SQLITE_OK0) {
9812 goto done;
9813 }
9814
9815 block &= ~(1 << (chunk_offset % CHAR_BIT8));
9816 rc = sqlite3_blob_writesqlite3_api->blob_write(blobValue, &block, sizeof(u8), chunk_offset / CHAR_BIT8);
9817 break;
9818 }
9819 case VEC0_METADATA_COLUMN_KIND_INTEGER: {
9820 i64 v = 0;
9821 rc = sqlite3_blob_writesqlite3_api->blob_write(blobValue, &v, sizeof(v), chunk_offset * sizeof(i64));
9822 break;
9823 }
9824 case VEC0_METADATA_COLUMN_KIND_FLOAT: {
9825 double v = 0;
9826 rc = sqlite3_blob_writesqlite3_api->blob_write(blobValue, &v, sizeof(v), chunk_offset * sizeof(double));
9827 break;
9828 }
9829 case VEC0_METADATA_COLUMN_KIND_TEXT: {
9830 int n;
9831 rc = sqlite3_blob_readsqlite3_api->blob_read(blobValue, &n, sizeof(int), chunk_offset * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16);
9832 if(rc != SQLITE_OK0) {
9833 goto done;
9834 }
9835
9836 u8 view[VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16];
9837 memset(view, 0, VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16);
9838 rc = sqlite3_blob_writesqlite3_api->blob_write(blobValue, &view, sizeof(view), chunk_offset * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH16);
9839 if(rc != SQLITE_OK0) {
9840 goto done;
9841 }
9842
9843 if(n > VEC0_METADATA_TEXT_VIEW_DATA_LENGTH12) {
9844 const char * zSql = sqlite3_mprintfsqlite3_api->mprintf("DELETE FROM " VEC0_SHADOW_METADATA_TEXT_DATA_NAME"\"%w\".\"%w_metadatatext%02d\"" " WHERE rowid = ?", p->schemaName, p->tableName, metadata_idx);
9845 if(!zSql) {
9846 rc = SQLITE_NOMEM7;
9847 goto done;
9848 }
9849 sqlite3_stmt * stmt;
9850 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
9851 if(rc != SQLITE_OK0) {
9852 goto done;
9853 }
9854 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 1, rowid);
9855 rc = sqlite3_stepsqlite3_api->step(stmt);
9856 sqlite3_finalizesqlite3_api->finalize(stmt);
9857 if(rc != SQLITE_DONE101) {
9858 rc = SQLITE_ERROR1;
9859 goto done;
9860 }
9861 // Fix for https://github.com/asg017/sqlite-vec/issues/274
9862 // sqlite3_step returns SQLITE_DONE (101) on DML success, but the
9863 // `done:` epilogue treats anything other than SQLITE_OK as an error.
9864 // Without this, SQLITE_DONE propagates up to vec0Update_Delete,
9865 // which aborts the DELETE scan and silently drops remaining rows.
9866 rc = SQLITE_OK0;
9867 }
9868 break;
9869 }
9870 }
9871 int rc2;
9872 done:
9873 rc2 = sqlite3_blob_closesqlite3_api->blob_close(blobValue);
9874 if(rc == SQLITE_OK0) {
9875 return rc2;
9876 }
9877 return rc;
9878}
9879
9880int vec0Update_Delete(sqlite3_vtab *pVTab, sqlite3_value *idValue) {
9881 vec0_vtab *p = (vec0_vtab *)pVTab;
9882 int rc;
9883 i64 rowid;
9884 i64 chunk_id = 0;
9885 i64 chunk_offset = 0;
9886
9887 if (p->pkIsText) {
9888 rc = vec0_rowid_from_id(p, idValue, &rowid);
9889 if (rc != SQLITE_OK0) {
9890 return rc;
9891 }
9892 } else {
9893 rowid = sqlite3_value_int64sqlite3_api->value_int64(idValue);
9894 }
9895
9896 // 1. Find chunk position for given rowid
9897 // 2. Ensure that validity bit for position is 1, then set to 0
9898 // 3. Zero out rowid in chunks.rowid
9899 // 4. Zero out vector data in all vector column chunks
9900 // 5. Delete value in _rowids table
9901
9902#if SQLITE_VEC_ENABLE_DISKANN0
9903 // DiskANN graph deletion for indexed columns
9904 for (int i = 0; i < p->numVectorColumns; i++) {
9905 if (p->vector_columns[i].index_type != VEC0_INDEX_TYPE_DISKANN) continue;
9906 rc = diskann_delete(p, i, rowid);
9907 if (rc != SQLITE_OK0) {
9908 return rc;
9909 }
9910 }
9911#endif
9912
9913 if (!vec0_all_columns_diskann(p)) {
9914 // 1. get chunk_id and chunk_offset from _rowids
9915 rc = vec0_get_chunk_position(p, rowid, NULL((void*)0), &chunk_id, &chunk_offset);
9916 if (rc != SQLITE_OK0) {
9917 return rc;
9918 }
9919
9920 // 2. clear validity bit
9921 rc = vec0Update_Delete_ClearValidity(p, chunk_id, chunk_offset);
9922 if (rc != SQLITE_OK0) {
9923 return rc;
9924 }
9925
9926 // 3. zero out rowid in chunks.rowids
9927 rc = vec0Update_Delete_ClearRowid(p, chunk_id, chunk_offset);
9928 if (rc != SQLITE_OK0) {
9929 return rc;
9930 }
9931
9932 // 4. zero out any data in vector chunks tables
9933 rc = vec0Update_Delete_ClearVectors(p, chunk_id, chunk_offset);
9934 if (rc != SQLITE_OK0) {
9935 return rc;
9936 }
9937
9938#if SQLITE_VEC_ENABLE_RESCORE1
9939 // 4b. zero out quantized data in rescore chunk tables, delete from rescore vectors
9940 rc = rescore_on_delete(p, chunk_id, chunk_offset, rowid);
9941 if (rc != SQLITE_OK0) {
9942 return rc;
9943 }
9944#endif
9945 }
9946
9947 // 5. delete from _rowids table
9948 rc = vec0Update_Delete_DeleteRowids(p, rowid);
9949 if (rc != SQLITE_OK0) {
9950 return rc;
9951 }
9952
9953 // 6. delete any auxiliary rows
9954 if(p->numAuxiliaryColumns > 0) {
9955 rc = vec0Update_Delete_DeleteAux(p, rowid);
9956 if (rc != SQLITE_OK0) {
9957 return rc;
9958 }
9959 }
9960
9961 // 7. delete metadata and reclaim chunk (only when using chunk-based storage)
9962 if (!vec0_all_columns_diskann(p)) {
9963 for(int i = 0; i < p->numMetadataColumns; i++) {
9964 rc = vec0Update_Delete_ClearMetadata(p, i, rowid, chunk_id, chunk_offset);
9965 if (rc != SQLITE_OK0) {
9966 return rc;
9967 }
9968 }
9969
9970 // 8. reclaim chunk if fully empty
9971 {
9972 int chunkDeleted;
9973 rc = vec0Update_Delete_DeleteChunkIfEmpty(p, chunk_id, &chunkDeleted);
9974 if (rc != SQLITE_OK0) {
9975 return rc;
9976 }
9977 }
9978 }
9979
9980#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
9981 // 7. delete from IVF index
9982 for (int i = 0; i < p->numVectorColumns; i++) {
9983 if (p->vector_columns[i].index_type != VEC0_INDEX_TYPE_IVF) continue;
9984 rc = ivf_delete(p, i, rowid);
9985 if (rc != SQLITE_OK0) return rc;
9986 }
9987#endif
9988
9989 return SQLITE_OK0;
9990}
9991
9992int vec0Update_UpdateAuxColumn(vec0_vtab *p, int auxiliary_column_idx, sqlite3_value * value, i64 rowid) {
9993 int rc;
9994 sqlite3_stmt *stmt;
9995 const char * zSql = sqlite3_mprintfsqlite3_api->mprintf("UPDATE " VEC0_SHADOW_AUXILIARY_NAME"\"%w\".\"%w_auxiliary\"" " SET value%02d = ? WHERE rowid = ?", p->schemaName, p->tableName, auxiliary_column_idx);
9996 if(!zSql) {
9997 return SQLITE_NOMEM7;
9998 }
9999 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmt, NULL((void*)0));
10000 if(rc != SQLITE_OK0) {
10001 return rc;
10002 }
10003 sqlite3_bind_valuesqlite3_api->bind_value(stmt, 1, value);
10004 sqlite3_bind_int64sqlite3_api->bind_int64(stmt, 2, rowid);
10005 rc = sqlite3_stepsqlite3_api->step(stmt);
10006 if(rc != SQLITE_DONE101) {
10007 sqlite3_finalizesqlite3_api->finalize(stmt);
10008 return SQLITE_ERROR1;
10009 }
10010 sqlite3_finalizesqlite3_api->finalize(stmt);
10011 return SQLITE_OK0;
10012}
10013
10014int vec0Update_UpdateVectorColumn(vec0_vtab *p, i64 chunk_id, i64 chunk_offset,
10015 int i, sqlite3_value *valueVector, i64 rowid) {
10016 int rc;
10017#if !SQLITE_VEC_ENABLE_RESCORE1
10018 UNUSED_PARAMETER(rowid)(void)(rowid);
10019#endif
10020
10021 sqlite3_blob *blobVectors = NULL((void*)0);
10022
10023 char *pzError;
10024 size_t dimensions;
10025 enum VectorElementType elementType;
10026 void *vector;
10027 vector_cleanup cleanup = vector_cleanup_noop;
10028 // https://github.com/asg017/sqlite-vec/issues/53
10029 rc = vector_from_value(valueVector, &vector, &dimensions, &elementType,
10030 &cleanup, &pzError);
10031 if (rc != SQLITE_OK0) {
10032 // IMP: V15203_32042
10033 vtab_set_error(
10034 &p->base, "Updated vector for the \"%.*s\" column is invalid: %z",
10035 p->vector_columns[i].name_length, p->vector_columns[i].name, pzError);
10036 rc = SQLITE_ERROR1;
10037 goto cleanup;
10038 }
10039 if (elementType != p->vector_columns[i].element_type) {
10040 // IMP: V03643_20481
10041 vtab_set_error(
10042 &p->base,
10043 "Updated vector for the \"%.*s\" column is expected to be of type "
10044 "%s, but a %s vector was provided.",
10045 p->vector_columns[i].name_length, p->vector_columns[i].name,
10046 vector_subtype_name(p->vector_columns[i].element_type),
10047 vector_subtype_name(elementType));
10048 rc = SQLITE_ERROR1;
10049 goto cleanup;
10050 }
10051 if (dimensions != p->vector_columns[i].dimensions) {
10052 // IMP: V25739_09810
10053 vtab_set_error(
10054 &p->base,
10055 "Dimension mismatch for new updated vector for the \"%.*s\" column. "
10056 "Expected %d dimensions but received %d.",
10057 p->vector_columns[i].name_length, p->vector_columns[i].name,
10058 p->vector_columns[i].dimensions, dimensions);
10059 rc = SQLITE_ERROR1;
10060 goto cleanup;
10061 }
10062
10063#if SQLITE_VEC_ENABLE_RESCORE1
10064 if (p->vector_columns[i].index_type == VEC0_INDEX_TYPE_RESCORE) {
10065 // For rescore columns, update _rescore_vectors and _rescore_chunks
10066 struct VectorColumnDefinition *col = &p->vector_columns[i];
10067 size_t qsize = rescore_quantized_byte_size(col);
10068 size_t fsize = vector_column_byte_size(*col);
10069
10070 // 1. Update quantized chunk
10071 {
10072 void *qbuf = sqlite3_mallocsqlite3_api->malloc(qsize);
10073 if (!qbuf) { rc = SQLITE_NOMEM7; goto cleanup; }
10074 switch (col->rescore.quantizer_type) {
10075 case VEC0_RESCORE_QUANTIZER_BIT:
10076 rescore_quantize_float_to_bit((const float *)vector, (uint8_t *)qbuf, col->dimensions);
10077 break;
10078 case VEC0_RESCORE_QUANTIZER_INT8:
10079 rescore_quantize_float_to_int8((const float *)vector, (int8_t *)qbuf, col->dimensions);
10080 break;
10081 }
10082 sqlite3_blob *blobQ = NULL((void*)0);
10083 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName,
10084 p->shadowRescoreChunksNames[i], "vectors",
10085 chunk_id, 1, &blobQ);
10086 if (rc != SQLITE_OK0) { sqlite3_freesqlite3_api->free(qbuf); goto cleanup; }
10087 rc = sqlite3_blob_writesqlite3_api->blob_write(blobQ, qbuf, qsize, chunk_offset * qsize);
10088 sqlite3_freesqlite3_api->free(qbuf);
10089 int brc2 = sqlite3_blob_closesqlite3_api->blob_close(blobQ);
10090 if (rc != SQLITE_OK0) goto cleanup;
10091 if (brc2 != SQLITE_OK0) { rc = brc2; goto cleanup; }
10092 }
10093
10094 // 2. Update float vector in _rescore_vectors (keyed by user rowid)
10095 {
10096 char *zSql = sqlite3_mprintfsqlite3_api->mprintf(
10097 "UPDATE \"%w\".\"%w\" SET vector = ? WHERE rowid = ?",
10098 p->schemaName, p->shadowRescoreVectorsNames[i]);
10099 if (!zSql) { rc = SQLITE_NOMEM7; goto cleanup; }
10100 sqlite3_stmt *stmtUp;
10101 rc = sqlite3_prepare_v2sqlite3_api->prepare_v2(p->db, zSql, -1, &stmtUp, NULL((void*)0));
10102 sqlite3_freesqlite3_api->free(zSql);
10103 if (rc != SQLITE_OK0) goto cleanup;
10104 sqlite3_bind_blobsqlite3_api->bind_blob(stmtUp, 1, vector, fsize, SQLITE_TRANSIENT((sqlite3_destructor_type)-1));
10105 sqlite3_bind_int64sqlite3_api->bind_int64(stmtUp, 2, rowid);
10106 rc = sqlite3_stepsqlite3_api->step(stmtUp);
10107 sqlite3_finalizesqlite3_api->finalize(stmtUp);
10108 if (rc != SQLITE_DONE101) { rc = SQLITE_ERROR1; goto cleanup; }
10109 }
10110
10111 rc = SQLITE_OK0;
10112 goto cleanup;
10113 }
10114#endif
10115
10116 rc = sqlite3_blob_opensqlite3_api->blob_open(p->db, p->schemaName, p->shadowVectorChunksNames[i],
10117 "vectors", chunk_id, 1, &blobVectors);
10118 if (rc != SQLITE_OK0) {
10119 vtab_set_error(&p->base, "Could not open vectors blob for %s.%s.%lld",
10120 p->schemaName, p->shadowVectorChunksNames[i], chunk_id);
10121 goto cleanup;
10122 }
10123 rc = vec0_write_vector_to_vector_blob(blobVectors, chunk_offset, vector,
10124 p->vector_columns[i].dimensions,
10125 p->vector_columns[i].element_type);
10126 if (rc != SQLITE_OK0) {
10127 vtab_set_error(&p->base, "Could not write to vectors blob for %s.%s.%lld",
10128 p->schemaName, p->shadowVectorChunksNames[i], chunk_id);
10129 goto cleanup;
10130 }
10131
10132cleanup:
10133 cleanup(vector);
10134 int brc = sqlite3_blob_closesqlite3_api->blob_close(blobVectors);
10135 if (rc != SQLITE_OK0) {
10136 return rc;
10137 }
10138 if (brc != SQLITE_OK0) {
10139 vtab_set_error(
10140 &p->base,
10141 "Could not commit blob transaction for vectors blob for %s.%s.%lld",
10142 p->schemaName, p->shadowVectorChunksNames[i], chunk_id);
10143 return brc;
10144 }
10145 return SQLITE_OK0;
10146}
10147
10148int vec0Update_Update(sqlite3_vtab *pVTab, int argc, sqlite3_value **argv) {
10149 UNUSED_PARAMETER(argc)(void)(argc);
10150 vec0_vtab *p = (vec0_vtab *)pVTab;
10151 int rc;
10152 i64 chunk_id;
10153 i64 chunk_offset;
10154
10155 i64 rowid;
10156 if (p->pkIsText) {
10157 const char *a = (const char *)sqlite3_value_textsqlite3_api->value_text(argv[0]);
10158 const char *b = (const char *)sqlite3_value_textsqlite3_api->value_text(argv[1]);
10159 // IMP: V08886_25725
10160 if ((sqlite3_value_bytessqlite3_api->value_bytes(argv[0]) != sqlite3_value_bytessqlite3_api->value_bytes(argv[1])) ||
10161 strncmp(a, b, sqlite3_value_bytessqlite3_api->value_bytes(argv[0])) != 0) {
10162 vtab_set_error(pVTab,
10163 "UPDATEs on vec0 primary key values are not allowed.");
10164 return SQLITE_ERROR1;
10165 }
10166 rc = vec0_rowid_from_id(p, argv[0], &rowid);
10167 if (rc != SQLITE_OK0) {
10168 return rc;
10169 }
10170 } else {
10171 rowid = sqlite3_value_int64sqlite3_api->value_int64(argv[0]);
10172 }
10173
10174 // 1) get chunk_id and chunk_offset from _rowids
10175 rc = vec0_get_chunk_position(p, rowid, NULL((void*)0), &chunk_id, &chunk_offset);
10176 if (rc != SQLITE_OK0) {
10177 return rc;
10178 }
10179
10180 // 2) update any partition key values
10181 for (int i = 0; i < vec0_num_defined_user_columns(p); i++) {
10182 if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_PARTITION) {
10183 continue;
10184 }
10185 sqlite3_value * value = argv[2+VEC0_COLUMN_USERN_START1 + i];
10186 if(sqlite3_value_nochangesqlite3_api->value_nochange(value)) {
10187 continue;
10188 }
10189 vtab_set_error(pVTab, "UPDATE on partition key columns are not supported yet. ");
10190 return SQLITE_ERROR1;
10191 }
10192
10193 // 3) handle auxiliary column updates
10194 for (int i = 0; i < vec0_num_defined_user_columns(p); i++) {
10195 if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_AUXILIARY) {
10196 continue;
10197 }
10198 int auxiliary_column_idx = p->user_column_idxs[i];
10199 sqlite3_value * value = argv[2+VEC0_COLUMN_USERN_START1 + i];
10200 if(sqlite3_value_nochangesqlite3_api->value_nochange(value)) {
10201 continue;
10202 }
10203 rc = vec0Update_UpdateAuxColumn(p, auxiliary_column_idx, value, rowid);
10204 if(rc != SQLITE_OK0) {
10205 return SQLITE_ERROR1;
10206 }
10207 }
10208
10209 // 4) handle metadata column updates
10210 for (int i = 0; i < vec0_num_defined_user_columns(p); i++) {
10211 if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_METADATA) {
10212 continue;
10213 }
10214 int metadata_column_idx = p->user_column_idxs[i];
10215 sqlite3_value * value = argv[2+VEC0_COLUMN_USERN_START1 + i];
10216 if(sqlite3_value_nochangesqlite3_api->value_nochange(value)) {
10217 continue;
10218 }
10219 rc = vec0_write_metadata_value(p, metadata_column_idx, rowid, chunk_id, chunk_offset, value, 1);
10220 if(rc != SQLITE_OK0) {
10221 return rc;
10222 }
10223 }
10224
10225 // 5) iterate over all new vectors, update the vectors
10226 for (int i = 0; i < vec0_num_defined_user_columns(p); i++) {
10227 if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_VECTOR) {
10228 continue;
10229 }
10230 int vector_idx = p->user_column_idxs[i];
10231 sqlite3_value *valueVector = argv[2 + VEC0_COLUMN_USERN_START1 + i];
10232 // in vec0Column, we check sqlite3_vtab_nochange() on vector columns.
10233 // If the vector column isn't being changed, we return NULL;
10234 // That's not great, that means vector columns can never be NULLABLE
10235 // (bc we cant distinguish if an updated vector is truly NULL or nochange).
10236 // Also it means that if someone tries to run `UPDATE v SET X = NULL`,
10237 // we can't effectively detect and raise an error.
10238 // A better solution would be to use a custom result_type for "empty",
10239 // but subtypes don't appear to survive xColumn -> xUpdate, it's always 0.
10240 // So for now, we'll just use NULL and warn people to not SET X = NULL
10241 // in the docs.
10242 if (sqlite3_value_typesqlite3_api->value_type(valueVector) == SQLITE_NULL5) {
10243 continue;
10244 }
10245
10246 // Block vector UPDATE for index types that don't implement it —
10247 // the DiskANN graph / IVF lists would become stale.
10248 {
10249 enum Vec0IndexType idx_type = p->vector_columns[vector_idx].index_type;
10250 const char *idx_name = NULL((void*)0);
10251 if (idx_type == VEC0_INDEX_TYPE_DISKANN) idx_name = "DiskANN";
10252#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
10253 else if (idx_type == VEC0_INDEX_TYPE_IVF) idx_name = "IVF";
10254#endif
10255 if (idx_name) {
10256 vtab_set_error(
10257 &p->base,
10258 "UPDATE on vector column \"%.*s\" is not supported for %s indexes.",
10259 p->vector_columns[vector_idx].name_length,
10260 p->vector_columns[vector_idx].name,
10261 idx_name);
10262 return SQLITE_ERROR1;
10263 }
10264 }
10265
10266 rc = vec0Update_UpdateVectorColumn(p, chunk_id, chunk_offset, vector_idx,
10267 valueVector, rowid);
10268 if (rc != SQLITE_OK0) {
10269 return SQLITE_ERROR1;
10270 }
10271 }
10272
10273 return SQLITE_OK0;
10274}
10275
10276static int vec0Update(sqlite3_vtab *pVTab, int argc, sqlite3_value **argv,
10277 sqlite_int64 *pRowid) {
10278 // DELETE operation
10279 if (argc == 1 && sqlite3_value_typesqlite3_api->value_type(argv[0]) != SQLITE_NULL5) {
10280 return vec0Update_Delete(pVTab, argv[0]);
10281 }
10282 // INSERT operation
10283 else if (argc > 1 && sqlite3_value_typesqlite3_api->value_type(argv[0]) == SQLITE_NULL5) {
10284 vec0_vtab *p = (vec0_vtab *)pVTab;
10285 // FTS5-style command dispatch via hidden column named after table
10286 if (p->hasCommandColumn) {
10287 sqlite3_value *cmdVal = argv[2 + vec0_column_command_idx(p)];
10288 if (sqlite3_value_typesqlite3_api->value_type(cmdVal) == SQLITE_TEXT3) {
10289 const char *cmd = (const char *)sqlite3_value_textsqlite3_api->value_text(cmdVal);
10290 int cmdRc = SQLITE_EMPTY16;
10291#if SQLITE_VEC_ENABLE_RESCORE1
10292 cmdRc = rescore_handle_command(p, cmd);
10293#endif
10294#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
10295 if (cmdRc == SQLITE_EMPTY16)
10296 cmdRc = ivf_handle_command(p, cmd, argc, argv);
10297#endif
10298#if SQLITE_VEC_ENABLE_DISKANN0
10299 if (cmdRc == SQLITE_EMPTY16)
10300 cmdRc = diskann_handle_command(p, cmd);
10301#endif
10302 if (cmdRc == SQLITE_EMPTY16) {
10303 vtab_set_error(pVTab, "unknown vec0 command: '%s'", cmd);
10304 return SQLITE_ERROR1;
10305 }
10306 return cmdRc;
10307 }
10308 }
10309 return vec0Update_Insert(pVTab, argc, argv, pRowid);
10310 }
10311 // UPDATE operation
10312 else if (argc > 1 && sqlite3_value_typesqlite3_api->value_type(argv[0]) != SQLITE_NULL5) {
10313 return vec0Update_Update(pVTab, argc, argv);
10314 } else {
10315 vtab_set_error(pVTab, "Unrecognized xUpdate operation provided for vec0.");
10316 return SQLITE_ERROR1;
10317 }
10318}
10319
10320static int vec0ShadowName(const char *zName) {
10321 static const char *azName[] = {
10322 "rowids", "chunks", "auxiliary", "info",
10323
10324 // Up to VEC0_MAX_METADATA_COLUMNS
10325 // TODO be smarter about this man
10326 "metadatachunks00",
10327 "metadatachunks01",
10328 "metadatachunks02",
10329 "metadatachunks03",
10330 "metadatachunks04",
10331 "metadatachunks05",
10332 "metadatachunks06",
10333 "metadatachunks07",
10334 "metadatachunks08",
10335 "metadatachunks09",
10336 "metadatachunks10",
10337 "metadatachunks11",
10338 "metadatachunks12",
10339 "metadatachunks13",
10340 "metadatachunks14",
10341 "metadatachunks15",
10342
10343 // Up to
10344 "metadatatext00",
10345 "metadatatext01",
10346 "metadatatext02",
10347 "metadatatext03",
10348 "metadatatext04",
10349 "metadatatext05",
10350 "metadatatext06",
10351 "metadatatext07",
10352 "metadatatext08",
10353 "metadatatext09",
10354 "metadatatext10",
10355 "metadatatext11",
10356 "metadatatext12",
10357 "metadatatext13",
10358 "metadatatext14",
10359 "metadatatext15",
10360 };
10361
10362 for (size_t i = 0; i < sizeof(azName) / sizeof(azName[0]); i++) {
10363 if (sqlite3_stricmpsqlite3_api->stricmp(zName, azName[i]) == 0)
10364 return 1;
10365 }
10366 //for(size_t i = 0; i < )"vector_chunks", "metadatachunks"
10367 return 0;
10368}
10369
10370static int vec0Begin(sqlite3_vtab *pVTab) {
10371 UNUSED_PARAMETER(pVTab)(void)(pVTab);
10372 return SQLITE_OK0;
10373}
10374static int vec0Sync(sqlite3_vtab *pVTab) {
10375 vec0_free_resources((vec0_vtab *)pVTab);
10376 return SQLITE_OK0;
10377}
10378static int vec0Commit(sqlite3_vtab *pVTab) {
10379 UNUSED_PARAMETER(pVTab)(void)(pVTab);
10380 return SQLITE_OK0;
10381}
10382static int vec0Rollback(sqlite3_vtab *pVTab) {
10383 UNUSED_PARAMETER(pVTab)(void)(pVTab);
10384 return SQLITE_OK0;
10385}
10386
10387/**
10388 * xRename implementation for vec0.
10389 * Renames all shadow tables to match the new virtual table name,
10390 * then updates cached table names and finalizes stale prepared statements.
10391 */
10392static int vec0Rename(sqlite3_vtab *pVtab, const char *zNew) {
10393 vec0_vtab *p = (vec0_vtab *)pVtab;
10394 int rc = SQLITE_OK0;
10395
10396 // Build a single SQL string with ALTER TABLE RENAME for every shadow table.
10397 sqlite3_str *s = sqlite3_str_newsqlite3_api->str_new(p->db);
10398
10399 // Core shadow tables (always present)
10400 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10401 "ALTER TABLE \"%w\".\"%w_info\" RENAME TO \"%w_info\";",
10402 p->schemaName, p->tableName, zNew);
10403 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10404 "ALTER TABLE \"%w\".\"%w_rowids\" RENAME TO \"%w_rowids\";",
10405 p->schemaName, p->tableName, zNew);
10406 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10407 "ALTER TABLE \"%w\".\"%w_chunks\" RENAME TO \"%w_chunks\";",
10408 p->schemaName, p->tableName, zNew);
10409
10410 // Auxiliary shadow table (only if auxiliary columns exist)
10411 if (p->numAuxiliaryColumns > 0) {
10412 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10413 "ALTER TABLE \"%w\".\"%w_auxiliary\" RENAME TO \"%w_auxiliary\";",
10414 p->schemaName, p->tableName, zNew);
10415 }
10416
10417 // Per-vector-column shadow tables
10418 for (int i = 0; i < p->numVectorColumns; i++) {
10419 // Non-FLAT columns (rescore, IVF, DiskANN) don't create _vector_chunks
10420 // (mirror the guard in vec0_init around VEC0_SHADOW_VECTOR_N_CREATE).
10421 if (p->vector_columns[i].index_type == VEC0_INDEX_TYPE_FLAT) {
10422 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10423 "ALTER TABLE \"%w\".\"%w_vector_chunks%02d\" RENAME TO \"%w_vector_chunks%02d\";",
10424 p->schemaName, p->tableName, i, zNew, i);
10425 }
10426
10427#if SQLITE_VEC_ENABLE_RESCORE1
10428 if (p->shadowRescoreChunksNames[i]) {
10429 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10430 "ALTER TABLE \"%w\".\"%w_rescore_chunks%02d\" RENAME TO \"%w_rescore_chunks%02d\";",
10431 p->schemaName, p->tableName, i, zNew, i);
10432 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10433 "ALTER TABLE \"%w\".\"%w_rescore_vectors%02d\" RENAME TO \"%w_rescore_vectors%02d\";",
10434 p->schemaName, p->tableName, i, zNew, i);
10435 }
10436#endif
10437
10438#if SQLITE_VEC_ENABLE_DISKANN0
10439 if (p->shadowVectorsNames[i]) {
10440 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10441 "ALTER TABLE \"%w\".\"%w_vectors%02d\" RENAME TO \"%w_vectors%02d\";",
10442 p->schemaName, p->tableName, i, zNew, i);
10443 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10444 "ALTER TABLE \"%w\".\"%w_diskann_nodes%02d\" RENAME TO \"%w_diskann_nodes%02d\";",
10445 p->schemaName, p->tableName, i, zNew, i);
10446 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10447 "ALTER TABLE \"%w\".\"%w_diskann_buffer%02d\" RENAME TO \"%w_diskann_buffer%02d\";",
10448 p->schemaName, p->tableName, i, zNew, i);
10449 }
10450#endif
10451 }
10452
10453#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
10454 for (int i = 0; i < p->numVectorColumns; i++) {
10455 if (p->shadowIvfCellsNames[i]) {
10456 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10457 "ALTER TABLE \"%w\".\"%w_ivf_centroids%02d\" RENAME TO \"%w_ivf_centroids%02d\";",
10458 p->schemaName, p->tableName, i, zNew, i);
10459 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10460 "ALTER TABLE \"%w\".\"%w_ivf_cells%02d\" RENAME TO \"%w_ivf_cells%02d\";",
10461 p->schemaName, p->tableName, i, zNew, i);
10462 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10463 "ALTER TABLE \"%w\".\"%w_ivf_rowid_map%02d\" RENAME TO \"%w_ivf_rowid_map%02d\";",
10464 p->schemaName, p->tableName, i, zNew, i);
10465 // _ivf_vectors is only created when quantizer != none
10466 // (mirror ivf_create_shadow_tables in sqlite-vec-ivf.c).
10467 if (p->vector_columns[i].ivf.quantizer != VEC0_IVF_QUANTIZER_NONE) {
10468 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10469 "ALTER TABLE \"%w\".\"%w_ivf_vectors%02d\" RENAME TO \"%w_ivf_vectors%02d\";",
10470 p->schemaName, p->tableName, i, zNew, i);
10471 }
10472 }
10473 }
10474#endif
10475
10476 // Per-metadata-column shadow tables
10477 for (int i = 0; i < p->numMetadataColumns; i++) {
10478 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10479 "ALTER TABLE \"%w\".\"%w_metadatachunks%02d\" RENAME TO \"%w_metadatachunks%02d\";",
10480 p->schemaName, p->tableName, i, zNew, i);
10481 if (p->metadata_columns[i].kind == VEC0_METADATA_COLUMN_KIND_TEXT) {
10482 sqlite3_str_appendfsqlite3_api->str_appendf(s,
10483 "ALTER TABLE \"%w\".\"%w_metadatatext%02d\" RENAME TO \"%w_metadatatext%02d\";",
10484 p->schemaName, p->tableName, i, zNew, i);
10485 }
10486 }
10487
10488 char *zSql = sqlite3_str_finishsqlite3_api->str_finish(s);
10489 if (!zSql) {
10490 return SQLITE_NOMEM7;
10491 }
10492
10493 rc = sqlite3_execsqlite3_api->exec(p->db, zSql, 0, 0, 0);
10494 sqlite3_freesqlite3_api->free(zSql);
10495 if (rc != SQLITE_OK0) {
10496 return rc;
10497 }
10498
10499 // Finalize all prepared statements — they reference old table names.
10500 vec0_free_resources(p);
10501
10502 // Update cached table name
10503 sqlite3_freesqlite3_api->free(p->tableName);
10504 p->tableName = sqlite3_mprintfsqlite3_api->mprintf("%s", zNew);
10505 if (!p->tableName) return SQLITE_NOMEM7;
10506
10507 // Update cached shadow table names
10508 sqlite3_freesqlite3_api->free(p->shadowRowidsName);
10509 p->shadowRowidsName = sqlite3_mprintfsqlite3_api->mprintf("%s_rowids", zNew);
10510
10511 sqlite3_freesqlite3_api->free(p->shadowChunksName);
10512 p->shadowChunksName = sqlite3_mprintfsqlite3_api->mprintf("%s_chunks", zNew);
10513
10514 for (int i = 0; i < p->numVectorColumns; i++) {
10515 sqlite3_freesqlite3_api->free(p->shadowVectorChunksNames[i]);
10516 p->shadowVectorChunksNames[i] =
10517 sqlite3_mprintfsqlite3_api->mprintf("%s_vector_chunks%02d", zNew, i);
10518
10519#if SQLITE_VEC_ENABLE_RESCORE1
10520 if (p->shadowRescoreChunksNames[i]) {
10521 sqlite3_freesqlite3_api->free(p->shadowRescoreChunksNames[i]);
10522 p->shadowRescoreChunksNames[i] =
10523 sqlite3_mprintfsqlite3_api->mprintf("%s_rescore_chunks%02d", zNew, i);
10524 sqlite3_freesqlite3_api->free(p->shadowRescoreVectorsNames[i]);
10525 p->shadowRescoreVectorsNames[i] =
10526 sqlite3_mprintfsqlite3_api->mprintf("%s_rescore_vectors%02d", zNew, i);
10527 }
10528#endif
10529
10530#if SQLITE_VEC_ENABLE_DISKANN0
10531 if (p->shadowVectorsNames[i]) {
10532 sqlite3_freesqlite3_api->free(p->shadowVectorsNames[i]);
10533 p->shadowVectorsNames[i] =
10534 sqlite3_mprintfsqlite3_api->mprintf("%s_vectors%02d", zNew, i);
10535 sqlite3_freesqlite3_api->free(p->shadowDiskannNodesNames[i]);
10536 p->shadowDiskannNodesNames[i] =
10537 sqlite3_mprintfsqlite3_api->mprintf("%s_diskann_nodes%02d", zNew, i);
10538 }
10539#endif
10540 }
10541
10542#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
10543 for (int i = 0; i < p->numVectorColumns; i++) {
10544 if (p->shadowIvfCellsNames[i]) {
10545 sqlite3_freesqlite3_api->free(p->shadowIvfCellsNames[i]);
10546 p->shadowIvfCellsNames[i] =
10547 sqlite3_mprintfsqlite3_api->mprintf("%s_ivf_cells%02d", zNew, i);
10548 }
10549 }
10550#endif
10551
10552 for (int i = 0; i < p->numMetadataColumns; i++) {
10553 sqlite3_freesqlite3_api->free(p->shadowMetadataChunksNames[i]);
10554 p->shadowMetadataChunksNames[i] =
10555 sqlite3_mprintfsqlite3_api->mprintf("%s_metadatachunks%02d", zNew, i);
10556 }
10557
10558 return SQLITE_OK0;
10559}
10560
10561static sqlite3_module vec0Module = {
10562 /* iVersion */ 3,
10563 /* xCreate */ vec0Create,
10564 /* xConnect */ vec0Connect,
10565 /* xBestIndex */ vec0BestIndex,
10566 /* xDisconnect */ vec0Disconnect,
10567 /* xDestroy */ vec0Destroy,
10568 /* xOpen */ vec0Open,
10569 /* xClose */ vec0Close,
10570 /* xFilter */ vec0Filter,
10571 /* xNext */ vec0Next,
10572 /* xEof */ vec0Eof,
10573 /* xColumn */ vec0Column,
10574 /* xRowid */ vec0Rowid,
10575 /* xUpdate */ vec0Update,
10576 /* xBegin */ vec0Begin,
10577 /* xSync */ vec0Sync,
10578 /* xCommit */ vec0Commit,
10579 /* xRollback */ vec0Rollback,
10580 /* xFindFunction */ 0,
10581 /* xRename */ vec0Rename,
10582 /* xSavepoint */ 0,
10583 /* xRelease */ 0,
10584 /* xRollbackTo */ 0,
10585 /* xShadowName */ vec0ShadowName,
10586#if SQLITE_VERSION_NUMBER3053002 >= 3044000
10587 /* xIntegrity */ 0, // https://github.com/asg017/sqlite-vec/issues/44
10588#endif
10589};
10590#pragma endregion
10591
10592
10593#ifdef SQLITE_VEC_ENABLE_AVX
10594#define SQLITE_VEC_DEBUG_BUILD_AVX"" "avx"
10595#else
10596#define SQLITE_VEC_DEBUG_BUILD_AVX"" ""
10597#endif
10598#ifdef SQLITE_VEC_ENABLE_NEON
10599#define SQLITE_VEC_DEBUG_BUILD_NEON"" "neon"
10600#else
10601#define SQLITE_VEC_DEBUG_BUILD_NEON"" ""
10602#endif
10603#if SQLITE_VEC_ENABLE_RESCORE1
10604#define SQLITE_VEC_DEBUG_BUILD_RESCORE"rescore" "rescore"
10605#else
10606#define SQLITE_VEC_DEBUG_BUILD_RESCORE"rescore" ""
10607#endif
10608
10609#if SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE0
10610#define SQLITE_VEC_DEBUG_BUILD_IVF"" "ivf"
10611#else
10612#define SQLITE_VEC_DEBUG_BUILD_IVF"" ""
10613#endif
10614
10615#if SQLITE_VEC_ENABLE_DISKANN0
10616#define SQLITE_VEC_DEBUG_BUILD_DISKANN"" "diskann"
10617#else
10618#define SQLITE_VEC_DEBUG_BUILD_DISKANN"" ""
10619#endif
10620
10621#define SQLITE_VEC_DEBUG_BUILD"" " " "" " " "rescore" " " "" " " "" \
10622 SQLITE_VEC_DEBUG_BUILD_AVX"" " " SQLITE_VEC_DEBUG_BUILD_NEON"" " " \
10623 SQLITE_VEC_DEBUG_BUILD_RESCORE"rescore" " " SQLITE_VEC_DEBUG_BUILD_IVF"" " " \
10624 SQLITE_VEC_DEBUG_BUILD_DISKANN""
10625
10626#define SQLITE_VEC_DEBUG_STRING"Version: " "v0.1.10-alpha.4" "\n" "Date: " "2026-05-18T06:53:35Z+0000"
"\n" "Commit: " "04d28bd21773981e2d266bbf6aa4efbd011eb4f6" "\n"
"Build flags: " "" " " "" " " "rescore" " " "" " " ""
\
10627 "Version: " SQLITE_VEC_VERSION"v0.1.10-alpha.4" "\n" \
10628 "Date: " SQLITE_VEC_DATE"2026-05-18T06:53:35Z+0000" "\n" \
10629 "Commit: " SQLITE_VEC_SOURCE"04d28bd21773981e2d266bbf6aa4efbd011eb4f6" "\n" \
10630 "Build flags: " SQLITE_VEC_DEBUG_BUILD"" " " "" " " "rescore" " " "" " " ""
10631
10632SQLITE_VEC_API int sqlite3_vec_init(sqlite3 *db, char **pzErrMsg,
10633 const sqlite3_api_routines *pApi) {
10634#ifndef SQLITE_CORE
10635 SQLITE_EXTENSION_INIT2(pApi)sqlite3_api=pApi;;
10636#endif
10637 int rc = SQLITE_OK0;
10638
10639#define DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) (SQLITE_UTF81 | SQLITE_INNOCUOUS0x000200000 | SQLITE_DETERMINISTIC0x000000800)
10640
10641 rc = sqlite3_create_function_v2sqlite3_api->create_function_v2(db, "vec_version", 0, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800),
10642 SQLITE_VEC_VERSION"v0.1.10-alpha.4", _static_text_func, NULL((void*)0),
10643 NULL((void*)0), NULL((void*)0));
10644 if (rc != SQLITE_OK0) {
10645 return rc;
10646 }
10647 rc = sqlite3_create_function_v2sqlite3_api->create_function_v2(db, "vec_debug", 0, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800),
10648 SQLITE_VEC_DEBUG_STRING"Version: " "v0.1.10-alpha.4" "\n" "Date: " "2026-05-18T06:53:35Z+0000"
"\n" "Commit: " "04d28bd21773981e2d266bbf6aa4efbd011eb4f6" "\n"
"Build flags: " "" " " "" " " "rescore" " " "" " " ""
, _static_text_func,
10649 NULL((void*)0), NULL((void*)0), NULL((void*)0));
10650 if (rc != SQLITE_OK0) {
10651 return rc;
10652 }
10653 static struct {
10654 const char *zFName;
10655 void (*xFunc)(sqlite3_context *, int, sqlite3_value **);
10656 int nArg;
10657 int flags;
10658 } aFunc[] = {
10659 // clang-format off
10660 //{"vec_version", _static_text_func, 0, DEFAULT_FLAGS, (void *) SQLITE_VEC_VERSION },
10661 //{"vec_debug", _static_text_func, 0, DEFAULT_FLAGS, (void *) SQLITE_VEC_DEBUG_STRING },
10662 {"vec_distance_l2", vec_distance_l2, 2, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000, },
10663 {"vec_distance_l1", vec_distance_l1, 2, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000, },
10664 {"vec_distance_hamming",vec_distance_hamming, 2, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000, },
10665 {"vec_distance_cosine", vec_distance_cosine, 2, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000, },
10666 {"vec_length", vec_length, 1, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000, },
10667 {"vec_type", vec_type, 1, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800), },
10668 {"vec_to_json", vec_to_json, 1, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000 | SQLITE_RESULT_SUBTYPE0x001000000, },
10669 {"vec_add", vec_add, 2, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000 | SQLITE_RESULT_SUBTYPE0x001000000, },
10670 {"vec_sub", vec_sub, 2, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000 | SQLITE_RESULT_SUBTYPE0x001000000, },
10671 {"vec_slice", vec_slice, 3, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000 | SQLITE_RESULT_SUBTYPE0x001000000, },
10672 {"vec_normalize", vec_normalize, 1, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000 | SQLITE_RESULT_SUBTYPE0x001000000, },
10673 {"vec_f32", vec_f32, 1, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000 | SQLITE_RESULT_SUBTYPE0x001000000, },
10674 {"vec_bit", vec_bit, 1, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000 | SQLITE_RESULT_SUBTYPE0x001000000, },
10675 {"vec_int8", vec_int8, 1, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000 | SQLITE_RESULT_SUBTYPE0x001000000, },
10676 {"vec_quantize_int8", vec_quantize_int8, 2, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000 | SQLITE_RESULT_SUBTYPE0x001000000, },
10677 {"vec_quantize_binary", vec_quantize_binary, 1, DEFAULT_FLAGS(1 | 0x000200000 | 0x000000800) | SQLITE_SUBTYPE0x000100000 | SQLITE_RESULT_SUBTYPE0x001000000, },
10678 // clang-format on
10679 };
10680
10681 static struct {
10682 char *name;
10683 const sqlite3_module *module;
10684 void *p;
10685 void (*xDestroy)(void *);
10686 } aMod[] = {
10687 // clang-format off
10688 {"vec0", &vec0Module, NULL((void*)0), NULL((void*)0)},
10689 {"vec_each", &vec_eachModule, NULL((void*)0), NULL((void*)0)},
10690 // clang-format on
10691 };
10692
10693 for (unsigned long i = 0; i < countof(aFunc)(sizeof(aFunc) / sizeof((aFunc)[0])) && rc == SQLITE_OK0; i++) {
10694 rc = sqlite3_create_function_v2sqlite3_api->create_function_v2(db, aFunc[i].zFName, aFunc[i].nArg,
10695 aFunc[i].flags, NULL((void*)0), aFunc[i].xFunc, NULL((void*)0),
10696 NULL((void*)0), NULL((void*)0));
10697 if (rc != SQLITE_OK0) {
10698 *pzErrMsg = sqlite3_mprintfsqlite3_api->mprintf("Error creating function %s: %s",
10699 aFunc[i].zFName, sqlite3_errmsgsqlite3_api->errmsg(db));
10700 return rc;
10701 }
10702 }
10703
10704 for (unsigned long i = 0; i < countof(aMod)(sizeof(aMod) / sizeof((aMod)[0])) && rc == SQLITE_OK0; i++) {
10705 rc = sqlite3_create_module_v2sqlite3_api->create_module_v2(db, aMod[i].name, aMod[i].module, NULL((void*)0), NULL((void*)0));
10706 if (rc != SQLITE_OK0) {
10707 *pzErrMsg = sqlite3_mprintfsqlite3_api->mprintf("Error creating module %s: %s", aMod[i].name,
10708 sqlite3_errmsgsqlite3_api->errmsg(db));
10709 return rc;
10710 }
10711 }
10712
10713 return SQLITE_OK0;
10714}
10715
10716