Skip to content

fix(query): push down indexed equality + IN filters and surface DB errors#224

Open
jxom wants to merge 1 commit into
mainfrom
fix/pushdown-indexed-decoded-columns
Open

fix(query): push down indexed equality + IN filters and surface DB errors#224
jxom wants to merge 1 commit into
mainfrom
fix/pushdown-indexed-decoded-columns

Conversation

@jxom

@jxom jxom commented Jun 4, 2026

Copy link
Copy Markdown
Member

WHERE "orderId" = X (unquoted), WHERE "orderId" IN (X, Y), and similar multi-row joins against decoded indexed columns previously fell through to abi_uint(topic1) = N predicates with no pushdown, forcing Postgres to compute abi_uint over every selector-matching row in logs and routinely tripping the per-query statement_timeout.

The single-row = X LIMIT 1 shape worked only because the planner streamed enough rows before timing out. Cadent (and other downstream clients) had to fan multi-row joins out as N parallel single-row queries to work around the failure.

What this PR does

  • Splits rewrite_filters_for_pushdown into two passes — = and IN (...) — that each rewrite a decoded-indexed-column predicate into a raw topicN = '\\x...' (or topicN IN ('\\x...', ...)) form Postgres can resolve via the logs index.
  • Accepts both quoted ('17486013') and unquoted (17486013) numeric literals on the equality form.
  • Leaves IN (SELECT ...) subqueries untouched (the regex's inner paren-free restriction skips them).
  • Surfaces the actual Postgres DbError (severity + message) via a new format_error_chain helper instead of the opaque "db error" head string from tokio_postgres::Error::Display. Without this the underlying timeout was invisible to API clients.

Live verification (testnet)

Before:

SELECT "orderId" FROM OrderPlaced WHERE "orderId" = 17486015        -- db error
SELECT "orderId" FROM OrderPlaced WHERE "orderId" IN (17486015, …)  -- db error
SELECT "orderId" FROM OrderPlaced WHERE "orderId" BETWEEN x AND y   -- db error

After (same testnet, same data):

SELECT "orderId" FROM OrderPlaced WHERE "orderId" = 17486015        -- 1 row
SELECT "orderId" FROM OrderPlaced WHERE "orderId" IN (17486015, …)  -- N rows

Test impact

  • src/query/parser.rs: added rewrite_eq_for_pushdown / rewrite_in_for_pushdown helpers + snapshots covering quoted addresses, IN-list, and unquoted numeric equality.
  • src/service/mod.rs: format_error_chain + threading through sanitize_db_error.
  • Full suite: 286 passed.

Downstream

Unblocks cadent#53 (GET /exchanges/:tokenA/:tokenB/orders), which joins OrderCancelled and OrderFilled by orderId IN (...) against an OrderPlaced scan window. Also cleans up the per-orderId single-row workaround currently used by the swap-feed and OHLC routes.


Amp-Thread-ID: https://ampcode.com/threads/T-019e929b-cab4-745f-804a-8c5e03ae80dc

…rors

`WHERE "orderId" = X` (unquoted), `WHERE "orderId" IN (X, Y)`, and
similar multi-row joins against decoded indexed columns previously fell
through to `abi_uint(topic1) = N` predicates with no pushdown, forcing
Postgres to compute `abi_uint` over every selector-matching row in
`logs` and routinely tripping the per-query `statement_timeout`.

The single-row `= X LIMIT 1` shape worked only because the planner
streamed enough rows before timing out. Cadent (and other downstream
clients) had to fan multi-row joins out as N parallel single-row
queries to work around the failure.

This patch:

- Splits `rewrite_filters_for_pushdown` into two passes — `=` and
  `IN (...)` — that each rewrite a decoded-indexed-column predicate
  into a raw `topicN = '\\x...'` (or `topicN IN ('\\x...', ...)`) form
  Postgres can resolve via the logs index.
- Accepts both quoted (`'17486013'`) and unquoted (`17486013`)
  numeric literals on the equality form.
- Leaves `IN (SELECT ...)` subqueries untouched (the regex's inner
  paren-free restriction skips them).
- Surfaces the actual Postgres `DbError` (severity + message) via a
  new `format_error_chain` helper instead of the opaque "db error"
  head string from `tokio_postgres::Error::Display`. Without this the
  underlying timeout was invisible to API clients.

Amp-Thread-ID: https://ampcode.com/threads/T-019e929b-cab4-745f-804a-8c5e03ae80dc
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