Skip to content

Generate the index search of every operator from the catalog - #425

Merged
estebanzimanyi merged 1 commit into
MobilityDB:mainfrom
estebanzimanyi:gen/index-routing-from-catalog
Oct 2, 2026
Merged

estebanzimanyi merged 1 commit into
MobilityDB:mainfrom
estebanzimanyi:gen/index-routing-from-catalog

Conversation

@estebanzimanyi

Copy link
Copy Markdown
Member

tools/codegen_duck_udfs.py writes src/include/generated/index_search_ops.hpp from the catalog's
per-signature indexSearch {columnLeft, columnRight}: one row per name a signature is reached
under, its SQL name and its operator's symbol, the symbol read from the doc comment of its
columnLeft value in the catalog's IndexSearchOp enum, carrying the search of column <name> query
and, when the operator's MobilityDB declaration has a COMMUTATOR, the search of
query <name> column. A name routed to two different searches fails generation. The hand-written
index_search_ops.hpp keeps only what the catalog does not state, the axis each search compares
along and the box types carrying it, and reads every name from the generated table. The R-tree and
SP-tree scan optimizers ask that table before taking the index, so a predicate whose operand order
has no search stays a filter answered by a scan.

Why: the hand-written table answered the overlapping orderings with the query on the left by the
opposite ordering, query &< column through INDEX_OVERRIGHT, which states a different predicate:
INDEX_OVERRIGHT accepts every stored box whose start is not before the query's start, while
query &< column holds of a box whose end is not before the query's end. No search states the
latter, which is why MobilityDB declares &< without a COMMUTATOR and its operator classes leave
it to a scan. The catalog states each operator's searches from that declaration, so reading them
from it makes the routing the MobilityDB one.

Witness: over 2999 points (i, i), with the query box X [500, 501], the index answered
query &< t with 2500 rows where a scan answers 2499, query &> t with 501 for 500 and
stboxOverbefore(query, t) with 2634 for 2633; now the plan of each holds no MOBILITY RTREE INDEX
and the three answer as the scan, while query << t still reaches the index through its commuted
INDEX_RIGHT and agrees with the scan.

Measured: the generated table holds 90 names from the catalog of the pinned commit, every
overlapping ordering without a commuted search and every strict one commuting to its opposite;
the generated UDF sources do not change. test/sql/parity/095_index_ordering_query_on_left.test
fails on the hand-written table at its first &< plan check and passes its 23 assertions now;
the full suite passes 3089 assertions in 109 test cases, with no compiler warning in the changed
files.

tools/codegen_duck_udfs.py writes src/include/generated/index_search_ops.hpp from the catalog's
per-signature indexSearch {columnLeft, columnRight}: one row per name a signature is reached
under, its SQL name and its operator's symbol, the symbol read from the doc comment of its
columnLeft value in the catalog's IndexSearchOp enum, carrying the search of `column <name> query`
and, when the operator's MobilityDB declaration has a COMMUTATOR, the search of
`query <name> column`. A name routed to two different searches fails generation. The hand-written
index_search_ops.hpp keeps only what the catalog does not state, the axis each search compares
along and the box types carrying it, and reads every name from the generated table. The R-tree and
SP-tree scan optimizers ask that table before taking the index, so a predicate whose operand order
has no search stays a filter answered by a scan.

Why: the hand-written table answered the overlapping orderings with the query on the left by the
opposite ordering, `query &< column` through INDEX_OVERRIGHT, which states a different predicate:
INDEX_OVERRIGHT accepts every stored box whose start is not before the query's start, while
`query &< column` holds of a box whose end is not before the query's end. No search states the
latter, which is why MobilityDB declares `&<` without a COMMUTATOR and its operator classes leave
it to a scan. The catalog states each operator's searches from that declaration, so reading them
from it makes the routing the MobilityDB one.

Witness: over 2999 points (i, i), with the query box X [500, 501], the index answered
`query &< t` with 2500 rows where a scan answers 2499, `query &> t` with 501 for 500 and
stboxOverbefore(query, t) with 2634 for 2633; now the plan of each holds no MOBILITY RTREE INDEX
and the three answer as the scan, while `query << t` still reaches the index through its commuted
INDEX_RIGHT and agrees with the scan.

Measured: the generated table holds 90 names from the catalog of the pinned commit, every
overlapping ordering without a commuted search and every strict one commuting to its opposite;
the generated UDF sources do not change. test/sql/parity/095_index_ordering_query_on_left.test
fails on the hand-written table at its first `&<` plan check and passes its 23 assertions now;
the full suite passes 3089 assertions in 109 test cases, with no compiler warning in the changed
files.
@estebanzimanyi
estebanzimanyi merged commit 9e1f60c into MobilityDB:main Oct 2, 2026
9 checks passed
@estebanzimanyi
estebanzimanyi deleted the gen/index-routing-from-catalog branch October 2, 2026 11:30
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.

1 participant