-- Copyright (C) 2026 Intel Corporation -- SPDX-License-Identifier: PostgreSQL -- Enable this database and wait for its worker before any index work, so this -- file runs standalone. Enrollment reserves the slot synchronously (the gate -- then passes), but the worker spawns asynchronously; the first INSERT would -- otherwise race its cold start and time out. Idempotent and a no-op in the -- full suite, where vamana_databases.sql (ordered first) has already warmed it. INSERT INTO vamana_databases (datname, enabled) VALUES (current_database(), true) ON CONFLICT (datname) DO NOTHING; DO $$ BEGIN FOR i IN 1 .. 300 LOOP PERFORM 1 FROM pg_stat_vamana_worker WHERE db_oid = (SELECT oid FROM pg_database WHERE datname = current_database()) AND worker_state = 'running'; EXIT WHEN FOUND; PERFORM pg_sleep(0.1); END LOOP; END $$; SET enable_seqscan = off; -- L2 CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL); SET client_min_messages = error; CREATE INDEX ON t USING vamana (val halfvec_l2_ops); RESET client_min_messages; INSERT INTO t (val) VALUES ('[1,2,4]'); SELECT * FROM t ORDER BY val <-> '[3,3,3]', id; id | val ----+--------- 2 | [1,2,3] 5 | [1,2,4] 3 | [1,1,1] 1 | [0,0,0] (4 rows) SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <-> (SELECT NULL::halfvec)) t2; count ------- 0 (1 row) SELECT COUNT(*) FROM t; count ------- 5 (1 row) TRUNCATE t; NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build SELECT * FROM t ORDER BY val <-> '[3,3,3]', id; id | val ----+----- (0 rows) DROP TABLE t; -- inner product CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL); CREATE INDEX ON t USING vamana (val halfvec_ip_ops); NOTICE: buffered 3 vectors for SVS index build NOTICE: building SVS index with 3 vectors of dimension 3 NOTICE: SVS index built successfully INSERT INTO t (val) VALUES ('[1,2,4]'); SELECT * FROM t ORDER BY val <#> '[3,3,3]', id; id | val ----+--------- 5 | [1,2,4] 2 | [1,2,3] 3 | [1,1,1] 1 | [0,0,0] (4 rows) SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <#> (SELECT NULL::halfvec)) t2; count ------- 0 (1 row) DROP TABLE t; -- cosine CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL); CREATE INDEX ON t USING vamana (val halfvec_cosine_ops); NOTICE: buffered 3 vectors for SVS index build NOTICE: building SVS index with 3 vectors of dimension 3 NOTICE: SVS index built successfully INSERT INTO t (val) VALUES ('[1,2,4]'); SELECT * FROM t ORDER BY val <=> '[3,3,3]', id; id | val ----+--------- 3 | [1,1,1] 2 | [1,2,3] 5 | [1,2,4] 1 | [0,0,0] (4 rows) SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <=> '[0,0,0]') t2; count ------- 4 (1 row) SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <=> (SELECT NULL::halfvec)) t2; count ------- 0 (1 row) DROP TABLE t; -- element width -- -- A halfvec element is half as wide as a vector element, so the datum has to -- be read at its own element width and widened on the way to the index. Read -- at the wrong width, every distance is computed from the wrong numbers and -- the rows come back in the wrong order, with no error. -- -- The data below is deliberately asymmetric. Symmetric data such as -- '[1,0,0]', '[0,1,0]', '[0,0,1]' cannot detect this: every candidate is -- mismeasured the same way and the ordering survives. Each case prints the -- index order and then the exact order over the same rows, so a difference -- between them is the failure, not a value anyone has to read. -- -- Note the missing ", id" tie-break that the rest of this file uses. It is -- left off on purpose: it puts an Incremental Sort above the index scan, and -- below DEFAULT_MIN_GROUP_SIZE (32) tuples that node buffers the whole input -- and sorts it outright, which repairs a wrong index order before it is ever -- printed. Every distance in these cases is distinct, so no tie-break is -- needed to make the output deterministic. CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[100,1,0]'), ('[0,2,0]'), ('[0,8,0]'), ('[0,32,0]'); SET client_min_messages = error; CREATE INDEX ON t USING vamana (val halfvec_l2_ops); RESET client_min_messages; -- The index is what answers this, and nothing re-sorts what it returns -- -- otherwise the comparison below would hold no matter what the index held. EXPLAIN (COSTS OFF) SELECT id FROM t ORDER BY val <-> '[0,1,0]'; QUERY PLAN ------------------------------------------ Index Scan using t_val_idx on t Order By: (val <-> '[0,1,0]'::halfvec) (2 rows) SELECT id FROM t ORDER BY val <-> '[0,1,0]'; id ---- 2 3 4 1 (4 rows) SET enable_indexscan = off; SET enable_seqscan = on; SELECT id FROM t ORDER BY val <-> '[0,1,0]'; id ---- 2 3 4 1 (4 rows) RESET enable_indexscan; SET enable_seqscan = off; DROP TABLE t; -- Same, for inner product and cosine: the element width is read the same way -- whatever the metric, so each metric has to be shown reaching its own -- correct order. -- -- The inner-product rows put the weight the query asks about in the first -- dimension and an opposing value in the second, because a wrong-width read -- pairs the two: with the L2 rows above, the pairing happens to preserve the -- correct order for this metric, and the case would pass either way. CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[1,32,0]'), ('[2,8,0]'), ('[8,2,0]'), ('[32,1,0]'); CREATE INDEX ON t USING vamana (val halfvec_ip_ops); NOTICE: buffered 4 vectors for SVS index build NOTICE: building SVS index with 4 vectors of dimension 3 NOTICE: SVS index built successfully SELECT id FROM t ORDER BY val <#> '[1,0,0]'; id ---- 4 3 2 1 (4 rows) SET enable_indexscan = off; SET enable_seqscan = on; SELECT id FROM t ORDER BY val <#> '[1,0,0]'; id ---- 4 3 2 1 (4 rows) RESET enable_indexscan; SET enable_seqscan = off; DROP TABLE t; CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[1,4,0]'), ('[1,1,0]'), ('[4,1,0]'), ('[0,1,0]'); CREATE INDEX ON t USING vamana (val halfvec_cosine_ops); NOTICE: buffered 4 vectors for SVS index build NOTICE: building SVS index with 4 vectors of dimension 3 NOTICE: SVS index built successfully SELECT id FROM t ORDER BY val <=> '[1,0,0]'; id ---- 3 2 1 4 (4 rows) SET enable_indexscan = off; SET enable_seqscan = on; SELECT id FROM t ORDER BY val <=> '[1,0,0]'; id ---- 3 2 1 4 (4 rows) RESET enable_indexscan; SET enable_seqscan = off; DROP TABLE t; -- A wider, denser case: 300 rows at 64 dimensions, every row distinct, with -- each dimension carrying its own value so that neither the correct ordering -- nor a mismeasured one is simply the row order. -- -- This one prints the top-5 distances rather than the top-5 ids: two rows can -- sit at the same distance from the query, and which of those the index puts -- first is arbitrary, while the sequence of distances is not. A wrong element -- width shows up as a sequence that does not ascend, or does not match the -- exact one below it. CREATE TABLE t (id int PRIMARY KEY, val halfvec(64)); INSERT INTO t SELECT i, (SELECT array_agg(CASE WHEN j = 1 THEN i ELSE ((i * (j + 7)) % 89) + 1 END ORDER BY j) FROM generate_series(1, 64) AS j)::halfvec FROM generate_series(1, 300) AS i; SET client_min_messages = error; CREATE INDEX ON t USING vamana (val halfvec_l2_ops); RESET client_min_messages; SELECT round((val <-> (SELECT val FROM t WHERE id = 150))::numeric, 3) AS distance FROM t ORDER BY val <-> (SELECT val FROM t WHERE id = 150) LIMIT 5; distance ---------- 0.000 89.000 89.000 204.291 204.465 (5 rows) SET enable_indexscan = off; SET enable_seqscan = on; SELECT round((val <-> (SELECT val FROM t WHERE id = 150))::numeric, 3) AS distance FROM t ORDER BY val <-> (SELECT val FROM t WHERE id = 150) LIMIT 5; distance ---------- 0.000 89.000 89.000 204.291 204.465 (5 rows) RESET enable_indexscan; SET enable_seqscan = off; DROP TABLE t; -- unlogged CREATE UNLOGGED TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL); CREATE INDEX ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 3 vectors for SVS index build NOTICE: building SVS index with 3 vectors of dimension 3 NOTICE: SVS index built successfully SELECT * FROM t ORDER BY val <-> '[3,3,3]', id; id | val ----+--------- 2 | [1,2,3] 3 | [1,1,1] 1 | [0,0,0] (3 rows) DROP TABLE t; -- options CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (graph_degree = 15); ERROR: value 15 out of bounds for option "graph_degree" DETAIL: Valid values are between "16" and "256". CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (graph_degree = 257); ERROR: value 257 out of bounds for option "graph_degree" DETAIL: Valid values are between "16" and "256". CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (alpha = 50); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (alpha = 201); ERROR: value 201 out of bounds for option "alpha" DETAIL: Valid values are between "-1" and "200". CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (graph_degree = 64, alpha = 120); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build DROP TABLE t; -- compression detailed parameters -- Test compression_type enum (0=none, 1=leanvec) CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 0); NOTICE: buffered 3 vectors for SVS index build NOTICE: building SVS index with 3 vectors of dimension 3 NOTICE: SVS index built successfully SELECT * FROM t ORDER BY val <-> '[3,3,3]', id; id | val ----+--------- 2 | [1,2,3] 3 | [1,1,1] 1 | [0,0,0] (3 rows) DROP TABLE t; -- compression error cases -- Test invalid compression_type values CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 99); ERROR: value 99 out of bounds for option "compression_type" DETAIL: Valid values are between "0" and "2". CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = -1); ERROR: value -1 out of bounds for option "compression_type" DETAIL: Valid values are between "0" and "2". CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 2); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build DROP TABLE t; -- Test invalid compression_primary values CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, compression_primary = 5); ERROR: invalid compression_primary value: 5 HINT: Valid values are: 4 (UINT4), -4 (INT4), 8 (UINT8), -8 (INT8) CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, compression_primary = 10); ERROR: value 10 out of bounds for option "compression_primary" DETAIL: Valid values are between "-8" and "8". CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, compression_primary = 3); ERROR: invalid compression_primary value: 3 HINT: Valid values are: 4 (UINT4), -4 (INT4), 8 (UINT8), -8 (INT8) CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, compression_primary = 16); ERROR: value 16 out of bounds for option "compression_primary" DETAIL: Valid values are between "-8" and "8". CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, compression_primary = 0); ERROR: invalid compression_primary value: 0 HINT: Valid values are: 4 (UINT4), -4 (INT4), 8 (UINT8), -8 (INT8) DROP TABLE t; -- Test invalid compression_secondary values CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, compression_primary = 4, compression_secondary = 5); ERROR: invalid compression_secondary value: 5 HINT: Valid values are: 4 (UINT4), -4 (INT4), 8 (UINT8), -8 (INT8) CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, compression_primary = 4, compression_secondary = 10); ERROR: value 10 out of bounds for option "compression_secondary" DETAIL: Valid values are between "-8" and "8". CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, compression_primary = 4, compression_secondary = 3); ERROR: invalid compression_secondary value: 3 HINT: Valid values are: 4 (UINT4), -4 (INT4), 8 (UINT8), -8 (INT8) CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, compression_primary = 4, compression_secondary = 16); ERROR: value 16 out of bounds for option "compression_secondary" DETAIL: Valid values are between "-8" and "8". DROP TABLE t; -- Test invalid leanvec_dims values CREATE TABLE t (id serial PRIMARY KEY, val halfvec(128)); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, leanvec_dims = 0); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, leanvec_dims = -2); ERROR: value -2 out of bounds for option "leanvec_dims" DETAIL: Valid values are between "-1" and "2000". CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, leanvec_dims = 200); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build DROP TABLE t; -- Test compression parameters without compression_type = 1 CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_primary = 4); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 0, compression_primary = 4); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 0, compression_secondary = 8); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build DROP TABLE t; -- Test invalid build parameter values CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (build_window_size = 0); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (build_window_size = -1); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (search_window_size = 0); ERROR: value 0 out of bounds for option "search_window_size" DETAIL: Valid values are between "10" and "10000". CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (search_window_size = -1); ERROR: value -1 out of bounds for option "search_window_size" DETAIL: Valid values are between "10" and "10000". DROP TABLE t; -- advanced build parameters -- Note: With small datasets (5 vectors) and halfvec quantization, -- exact result ordering can be non-deterministic due to graph structure variations. -- These tests verify parameter acceptance and basic functionality without exact ordering. -- Test build_window_size variations CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (build_window_size = 100); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <-> '[3,3,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (build_window_size = 150); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <-> '[3,3,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (build_window_size = 200); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <-> '[3,3,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; -- Test search_window_size variations CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (search_window_size = 50); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <-> '[3,3,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (search_window_size = 150); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <-> '[3,3,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (search_window_size = 200); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <-> '[3,3,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; -- Test use_search_history boolean CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (use_search_history = true); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <-> '[3,3,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (use_search_history = false); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <-> '[3,3,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; -- Test combined parameters CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops) WITH (build_window_size = 150, search_window_size = 100, use_search_history = true); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <-> '[3,3,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; -- Test with different distance metrics CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_ip_ops) WITH (build_window_size = 150); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <#> '[3,3,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[1,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_cosine_ops) WITH (search_window_size = 100); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <=> '[3,3,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; -- DML operations -- Test UPDATE of vector values CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 4 vectors for SVS index build NOTICE: building SVS index with 4 vectors of dimension 3 NOTICE: SVS index built successfully -- Update a vector and verify searchability UPDATE t SET val = '[5,5,5]' WHERE id = 2; SELECT * FROM t ORDER BY val <-> '[4,4,4]', id; id | val ----+--------- 2 | [5,5,5] 4 | [2,2,2] 3 | [1,1,1] 1 | [0,0,0] (4 rows) DROP TABLE t; -- Test DELETE of rows CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully -- Delete a row and verify it's not in results DELETE FROM t WHERE id = 3; SELECT * FROM t ORDER BY val <-> '[1,1,1]', id; id | val ----+--------- 1 | [0,0,0] 4 | [2,2,2] 2 | [1,2,3] 5 | [3,3,3] (4 rows) DROP TABLE t; -- Test INSERT after index creation CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 2 vectors for SVS index build NOTICE: building SVS index with 2 vectors of dimension 3 NOTICE: SVS index built successfully -- Insert new rows after index exists INSERT INTO t (val) VALUES ('[2,2,2]'), ('[3,3,3]'); SELECT * FROM t ORDER BY val <-> '[3,3,3]', id; id | val ----+--------- 4 | [3,3,3] 3 | [2,2,2] 2 | [1,2,3] 1 | [0,0,0] (4 rows) DROP TABLE t; -- Test mixed DML operations CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,1,1]'), ('[2,2,2]'), ('[3,3,3]'), ('[4,4,4]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully -- Mix of UPDATE, DELETE, INSERT UPDATE t SET val = '[1.5,1.5,1.5]' WHERE id = 2; DELETE FROM t WHERE id = 4; INSERT INTO t (val) VALUES ('[5,5,5]'); SELECT * FROM t ORDER BY val <-> '[2,2,2]', id; id | val ----+--------------- 3 | [2,2,2] 2 | [1.5,1.5,1.5] 1 | [0,0,0] 5 | [4,4,4] 6 | [5,5,5] (5 rows) DROP TABLE t; -- Test DML with different distance metrics CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[2,2,2]'); CREATE INDEX ON t USING vamana (val halfvec_ip_ops); NOTICE: buffered 4 vectors for SVS index build NOTICE: building SVS index with 4 vectors of dimension 3 NOTICE: SVS index built successfully UPDATE t SET val = '[5,5,5]' WHERE id = 2; DELETE FROM t WHERE id = 1; INSERT INTO t (val) VALUES ('[3,3,3]'); SELECT * FROM t ORDER BY val <#> '[3,3,3]', id; id | val ----+--------- 2 | [5,5,5] 5 | [3,3,3] 4 | [2,2,2] 3 | [1,1,1] (4 rows) DROP TABLE t; -- index introspection -- Verify basic index metadata CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'); CREATE INDEX vamana_meta_idx ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 3 vectors for SVS index build NOTICE: building SVS index with 3 vectors of dimension 3 NOTICE: SVS index built successfully SELECT indexname, tablename FROM pg_indexes WHERE indexname = 'vamana_meta_idx'; indexname | tablename -----------------+----------- vamana_meta_idx | t (1 row) DROP TABLE t; -- Verify index parameters appear in definition CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); CREATE INDEX vamana_params_idx ON t USING vamana (val halfvec_l2_ops) WITH (graph_degree = 64, alpha = 120); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build SELECT indexname, indexdef FROM pg_indexes WHERE indexname = 'vamana_params_idx'; indexname | indexdef -------------------+-------------------------------------------------------------------------------------------------------------------- vamana_params_idx | CREATE INDEX vamana_params_idx ON public.t USING vamana (val halfvec_l2_ops) WITH (graph_degree='64', alpha='120') (1 row) DROP TABLE t; -- Verify compression parameters in definition CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); CREATE INDEX vamana_compress_idx ON t USING vamana (val halfvec_l2_ops) WITH (compression_type = 1, compression_primary = 8); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build SELECT indexname FROM pg_indexes WHERE indexname = 'vamana_compress_idx'; indexname --------------------- vamana_compress_idx (1 row) DROP TABLE t; -- Verify operator class mappings (L2, inner product, cosine) CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); CREATE INDEX vamana_l2_idx ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build CREATE INDEX vamana_ip_idx ON t USING vamana (val halfvec_ip_ops); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build CREATE INDEX vamana_cosine_idx ON t USING vamana (val halfvec_cosine_ops); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build SELECT indexname FROM pg_indexes WHERE tablename = 't' AND indexname LIKE 'vamana_%_idx' ORDER BY indexname; indexname ------------------- vamana_cosine_idx vamana_ip_idx vamana_l2_idx (3 rows) DROP TABLE t; -- runtime parameter tuning CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL); CREATE INDEX ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 3 vectors for SVS index build NOTICE: building SVS index with 3 vectors of dimension 3 NOTICE: SVS index built successfully SET svs.search_window_size = 50; SELECT * FROM t ORDER BY val <-> '[3,3,3]', id; id | val ----+--------- 2 | [1,2,3] 3 | [1,1,1] 1 | [0,0,0] (3 rows) SET svs.search_window_size = 200; SELECT * FROM t ORDER BY val <-> '[3,3,3]', id; id | val ----+--------- 2 | [1,2,3] 3 | [1,1,1] 1 | [0,0,0] (3 rows) RESET svs.search_window_size; SELECT * FROM t ORDER BY val <-> '[3,3,3]', id; id | val ----+--------- 2 | [1,2,3] 3 | [1,1,1] 1 | [0,0,0] (3 rows) DROP TABLE t; -- test with reversed insertion order (tests index robustness) CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[1,2,4]'), ('[1,1,1]'), ('[1,2,3]'), ('[0,0,0]'), (NULL); CREATE INDEX ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 4 vectors for SVS index build NOTICE: building SVS index with 4 vectors of dimension 3 NOTICE: SVS index built successfully SELECT * FROM t ORDER BY val <-> '[3,3,3]', id; id | val ----+--------- 3 | [1,2,3] 1 | [1,2,4] 2 | [1,1,1] 4 | [0,0,0] (4 rows) DROP TABLE t; -- test top-K recall (verify index returns reasonable results) -- Note: Exact recall varies due to approximate nature of Vamana -- halfvec may have lower quality than vector due to quantization -- Use Perl TAP tests (test/t/*_recall.pl) for statistical recall verification CREATE TABLE t (id int, val halfvec(3)); INSERT INTO t VALUES (1, '[10,10,10]'), (2, '[20,20,20]'), (3, '[30,30,30]'), (4, '[1,2,3]'), (5, '[5,5,5]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 5 vectors for SVS index build NOTICE: building SVS index with 5 vectors of dimension 3 NOTICE: SVS index built successfully -- Verify index returns k results (exact ordering may vary with small datasets) SELECT COUNT(*) FROM (SELECT * FROM t ORDER BY val <-> '[1,2,3]' LIMIT 3) sub; count ------- 3 (1 row) DROP TABLE t; -- serialization -- CREATE INDEX persists to disk (no "not yet implemented" notice); -- INSERT invalidates the saved copy; next SELECT rebuilds from table and re-saves. CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), ('[3,3,3]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 4 vectors for SVS index build NOTICE: building SVS index with 4 vectors of dimension 3 NOTICE: SVS index built successfully INSERT INTO t (val) VALUES ('[2,2,2]'); SELECT * FROM t ORDER BY val <-> '[2,2,2]', id; id | val ----+--------- 5 | [2,2,2] 2 | [1,2,3] 3 | [1,1,1] 4 | [3,3,3] 1 | [0,0,0] (5 rows) DROP TABLE t; -- pgvector rejects NaN/Inf at parse time on tables carrying a vamana index (halfvec type) CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); CREATE INDEX ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 0 vectors for SVS index build NOTICE: no vectors to index, skipping SVS build INSERT INTO t (val) VALUES ('[1,NaN,3]'); ERROR: NaN not allowed in halfvec LINE 1: INSERT INTO t (val) VALUES ('[1,NaN,3]'); ^ INSERT INTO t (val) VALUES ('[1,Infinity,3]'); ERROR: infinite value not allowed in halfvec LINE 1: INSERT INTO t (val) VALUES ('[1,Infinity,3]'); ^ DROP TABLE t; CREATE TABLE t (id serial PRIMARY KEY, val halfvec(3)); INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,1,1]'); CREATE INDEX ON t USING vamana (val halfvec_l2_ops); NOTICE: buffered 2 vectors for SVS index build NOTICE: building SVS index with 2 vectors of dimension 3 NOTICE: SVS index built successfully SELECT * FROM t ORDER BY val <-> '[1,NaN,3]' LIMIT 1; ERROR: NaN not allowed in halfvec LINE 1: SELECT * FROM t ORDER BY val <-> '[1,NaN,3]' LIMIT 1; ^ SELECT * FROM t ORDER BY val <-> '[1,Infinity,3]' LIMIT 1; ERROR: infinite value not allowed in halfvec LINE 1: SELECT * FROM t ORDER BY val <-> '[1,Infinity,3]' LIMIT 1; ^ DROP TABLE t;