Skip to content

Fix five divergences from TIN behavior - #13

Open
piki wants to merge 4 commits into
mainfrom
fix/parameter-and-subquery-scoring
Open

piki wants to merge 4 commits into
mainfrom
fix/parameter-and-subquery-scoring

Conversation

@piki

@piki piki commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

Fixes #11 and three related things.

Note, this changes the function signature on an internal UDF, score_bound, used in scoring. If you get an error that score_bound is missing, DROP EXTENSION tin CASCADE ; CREATE EXTENSION tin; and then recreate your indexes.

Behavior TIN Lead before Lead now
Parameterized quals, score both quals first qual only matches
Subquery aggregate works XX000 error matches
Score with another table's ==> qual 3.7907639 0 matches
max_score with NOT (... ==> ...) 3.3638825 4.7505517 matches
Highlight, parameters / subquery both terms / works first term / error matches

piki and others added 4 commits September 21, 2026 11:39
…ueries

score_support() combined multiple ==> expressions only when every query was
a text Const, so a parameterized query scored with the first expression
alone.  Pass the expressions to score_bound() as a text[] and combine them
at run time, which works for Param nodes too.

The qual walker also looked only at jointree->quals.  A subquery that the
planner pulls up leaves its quals in a nested FromExpr, so tin.score() found
no ==> qual and raised the scoring-context error.  Walk the whole jointree.

Fixes #11

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
find_matching_tin_index() rewrote the operand's varno to 1 so it could be
compared against a stored index expression, then accepted any Var with
varno 1.  A ==> qual on the first range table entry therefore passed as a
qual on the scored relation: scoring another table in the same query used
the wrong document column, the wrong search expression, and the other
table's corpus, silently.  Require every Var in the operand to belong to
the scored relation before normalizing.

A qual under NOT excludes rows rather than describing them, so its terms
must not reach the scorer.  They changed tin.max_score(), which takes the
maximum over the documents matching the combined query.  Stop the qual
walker at NOT.

Both behaviours now match TIN.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tin.highlight() carried the same two defects the scorer had.  combined_query()
needed text Const nodes and fell back to the first qual, so a parameterized
query marked only the first term; and the qual walker read jointree->quals
only, so a pulled-up subquery raised "requires an explicit query or a
matching tin index scan".

Concatenate non-constant search expressions in the plan, walk the whole
jointree, and reuse the scorer's varno and negation helpers.  Constant quals
still fold into a single Const, so their plans are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Changing score_bound()'s signature means a catalog created by an earlier
build no longer has the function the support function looks up.  Every
scored query, EXPLAIN included, then failed at plan time with "function
tin.score_bound(text, text[], ...) does not exist" -- a function the user
never called, and no hint about the cause.

Report it as an undefined-function error naming the real cause, with the
reinstall in DETAIL.  The recommendation needs CASCADE: a plain DROP
EXTENSION always fails here, because anyone reaching this error has a tin
index that depends on the extension.  CASCADE drops those indexes, so the
detail says to recreate them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parameterized scoring mismatch and subquery error

1 participant