-- test/sql/dnf_resolution.sql -- -- Regression test for the DNF (k>0) within-tile resolution semantics. -- -- The bug fixed in commit 34c5e52 caused the AM to intersect -- (AND) the within-tile trigram alternatives instead of unioning -- (OR) them. The full p5_read fixture has enough rows that the -- bug masked itself: with ~50 rows, the wrong-mode result still -- happened to match the right-mode result. The fixtures here -- are deliberately tiny so that a single misplaced operator -- changes the row count. -- -- Each subtest constructs a row whose body matches the canonical -- pattern under k=1 by exactly one edit, then asserts that the -- index returns it. If the within-tile semantics regress to -- AND, the row is dropped because the canonical trigrams aren't -- all present. CREATE EXTENSION IF NOT EXISTS pg_tre; psql:test/sql/dnf_resolution.sql:19: NOTICE: extension "pg_tre" already exists, skipping CREATE EXTENSION DROP TABLE IF EXISTS dnf_t; psql:test/sql/dnf_resolution.sql:21: NOTICE: table "dnf_t" does not exist, skipping DROP TABLE CREATE TABLE dnf_t (id int PRIMARY KEY, body text); CREATE TABLE -- Each row is at edit distance 1 from 'foobar' via a different -- single-edit class: INSERT INTO dnf_t VALUES (1, 'foobar'), -- exact (k=0) (2, 'fooar'), -- delete 'b' (3, 'foovbar'), -- insert 'v' at position 3 (4, 'foopar'), -- substitute 'b' -> 'p' (5, 'unrelated'); -- must NOT match INSERT 0 5 CREATE INDEX dnf_idx ON dnf_t USING tre (body); psql:test/sql/dnf_resolution.sql:33: NOTICE: pg_tre: collected 23 trigram entries from 5 heap tuples psql:test/sql/dnf_resolution.sql:33: NOTICE: pg_tre: built 19 posting trees psql:test/sql/dnf_resolution.sql:33: NOTICE: pg_tre: build complete, indexed 5 heap tuples into 19 trigrams CREATE INDEX SET enable_seqscan = off; SET -- Sanity: k=0 returns only the exact row. SELECT id FROM dnf_t WHERE body %~~ tre_pattern('foobar', 0) ORDER BY id; id ---- 1 (1 row) -- The real test: k=1 must return rows 1, 2, 3, 4 (every kind of -- single edit) but not row 5. If the AM regresses to AND-within- -- tile, row 1 is the only one that has every spine trigram of -- 'foobar' and the test fails. SELECT id FROM dnf_t WHERE body %~~ tre_pattern('foobar', 1) ORDER BY id; id ---- 1 2 3 4 (4 rows) -- k=2 should additionally tolerate a 2-edit miss. INSERT INTO dnf_t VALUES (6, 'fopar'); -- 2 edits from 'foobar' INSERT 0 1 SELECT id FROM dnf_t WHERE body %~~ tre_pattern('foobar', 2) ORDER BY id; id ---- 1 2 3 4 6 (5 rows) -- Cross-check with seq-scan: index and seq must agree exactly. DO $$ DECLARE ix int[]; sq int[]; BEGIN EXECUTE 'SET LOCAL enable_seqscan = off'; EXECUTE 'SELECT array_agg(id ORDER BY id) FROM dnf_t ' 'WHERE body %~~ tre_pattern($1, $2)' USING 'foobar', 1 INTO ix; EXECUTE 'SET LOCAL enable_seqscan = on'; EXECUTE 'SET LOCAL enable_indexscan = off'; EXECUTE 'SET LOCAL enable_bitmapscan = off'; EXECUTE 'SELECT array_agg(id ORDER BY id) FROM dnf_t ' 'WHERE tre_amatch(body, $1, $2)' USING 'foobar', 1 INTO sq; IF ix IS NOT DISTINCT FROM sq THEN RAISE NOTICE 'OK: idx=% seq=%', ix, sq; ELSE RAISE EXCEPTION 'DNF resolution mismatch: idx=% seq=%', ix, sq; END IF; END$$; psql:test/sql/dnf_resolution.sql:72: NOTICE: OK: idx={1,2,3,4} seq={1,2,3,4} DO -- Multi-tile case: k=2 with a longer pattern produces multiple -- tiles; verify the inter-tile OR also works correctly. DROP TABLE IF EXISTS dnf_long; psql:test/sql/dnf_resolution.sql:76: NOTICE: table "dnf_long" does not exist, skipping DROP TABLE CREATE TABLE dnf_long (id int PRIMARY KEY, body text); CREATE TABLE INSERT INTO dnf_long VALUES (1, 'approximate'), -- exact (2, 'aproximate'), -- 1 edit (3, 'aproxmate'), -- 2 edits (4, 'totally other'); -- no match INSERT 0 4 CREATE INDEX dnf_long_idx ON dnf_long USING tre (body); psql:test/sql/dnf_resolution.sql:83: NOTICE: pg_tre: collected 35 trigram entries from 4 heap tuples psql:test/sql/dnf_resolution.sql:83: NOTICE: pg_tre: built 23 posting trees psql:test/sql/dnf_resolution.sql:83: NOTICE: pg_tre: build complete, indexed 4 heap tuples into 23 trigrams CREATE INDEX SELECT id FROM dnf_long WHERE body %~~ tre_pattern('approximate', 2) ORDER BY id; id ---- 1 2 3 (3 rows) DROP TABLE dnf_t; DROP TABLE DROP TABLE dnf_long; DROP TABLE