Skip to content

Evaluate intersects_extent@1 with DuckDB core && semantics - #14

Merged
rustyconover merged 2 commits into
mainfrom
fix/intersects-extent-conformance
Nov 11, 2026
Merged

rustyconover merged 2 commits into
mainfrom
fix/intersects-extent-conformance

Conversation

@rustyconover

Copy link
Copy Markdown
Contributor

Why

The VGI DuckDB extension (v2.0, 67c7710) now derives column && <constant> from exact spatial predicates (ST_Intersects, ST_Within, and others) and pushes it to every worker that declares duckdb.spatial/intersects_extent@1. This SDK's && evaluator is therefore in the correctness path for ordinary spatial queries. The semantics are now specified in Query-farm/vgi-python#105 (spec section 5.11.1), with a shared conformance corpus of 46 geometries and 2,116 ordered pairs taken from DuckDB 2.0 core &&. This branch copies that corpus and runs every case in all four byte-order combinations.

What was wrong

  • SDK library: PushdownFilters returned TRUE for every row. A query's own geom && <constant>, which DuckDB removes from its plan as an exact filter, therefore never filtered anything. Under NOT, every row was dropped.
  • Example worker: it evaluated the filter with the spatial extension's st_intersects_extent. 297 cases per encoding returned false where DuckDB returns true.

Fix

  • New WkbExtent reads ISO WKB and EWKB in either byte order, nested collections included, and follows DuckDB core semantics. PushdownFilters uses it.
  • The example worker now relies on FilterApplier.
  • Advisory evaluation errors keep the rows; required ones throw.

Tests

  • New: IntersectsExtentConformanceTest covers the corpus, an EWKB re-encoding of it, hand-written EWKB cases and failure cases.
  • New: SpatialFilterConformanceTest in the example worker.
  • ./gradlew :vgi:test :vgi-example-worker:test: all new tests pass. Two existing tests fail only because their Python conformance peer cannot start in a local environment where a sibling checkout is missing.

🤖 Generated with Claude Code

rustyconover and others added 2 commits November 10, 2026 13:13
…tics

FilterApplier treated the extension call as a constant TRUE: rows were
never filtered by a pushed `geom && const` (an EXACT filter DuckDB removes
from its plan), and under NOT the predicate dropped every row. The example
worker then re-applied it through the embedded engine's spatial
st_intersects_extent, which treats NaN coordinates as never intersecting
and so dropped rows DuckDB core keeps (297 of 1849 corpus pairs).

Add WkbExtent, an ISO WKB (LE/BE, Z/M/ZM, nested collections) extent
reader matching core: empty geometries and all-NaN POINTs contribute no
vertex, a NaN axis on any other vertex is unbounded, bounds inclusive,
exact doubles. Malformed/unsupported values (including EWKB flags) raise
FilterV2Exception: an ADVISORY predicate then keeps the batch's rows, a
REQUIRED one fails the scan. SpatialFilterExampleFunction now relies on
FilterApplier alone.

Tests run the DuckDB 2.0 conformance corpus (43 geometries, 1849 pairs)
through FilterApplier and through the example worker's filter step for
all four LE/BE combinations, plus advisory-failure and NULL cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DuckDB 2.0 core reads EWKB, as do the TypeScript and C# SDK evaluators,
so rejecting it failed EXACT-mode scans DuckDB would answer. WkbExtent now
accepts the Z (0x80000000), M (0x40000000) and SRID (0x20000000) high-bit
flags per (sub-)geometry in either byte order: Z/M select the vertex width
like the ISO 1000/2000/3000 offsets, and the 4-byte SRID is skipped. A type
carrying both conventions, or a truncated SRID, is still rejected.

Tests: the whole corpus re-encoded as EWKB (SRID on the outer geometry
only, and on every part) must match DuckDB core for all LE/BE combos, plus
hand-written EWKB POINT+SRID and POLYGON Z+SRID in both byte orders must
match their ISO equivalents. The corpus is regenerated to 46 geometries /
2116 cases (adds POINT Z (nan nan 5), POINT Z (nan nan nan),
MULTIPOINT Z ((nan nan 5), (9 9 9))).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rustyconover
rustyconover merged commit 650cff8 into main Nov 11, 2026
12 checks passed
@rustyconover
rustyconover deleted the fix/intersects-extent-conformance branch November 11, 2026 13:18
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