Parse-time type inference for SELECT-item expressions.
Mirrors PostgreSQL's exprType (src/backend/nodes/nodeFuncs.c): each
node in the expression tree has a declared result OID, computed by
walking the AST during parse/analyze. PG looks up operator and
function signatures in pg_operator / pg_proc; we hardcode the
equivalent rules for the set of SQL we handle.
Consumed by translate-select to populate :select-item-oids on the
parsed map, which describeResult reads to emit correct
RowDescription OIDs via the Extended Query protocol — before Execute
runs, so value-based inference isn't available.
Return values:
nil when we can't determine it (unknown function, unresolvable
column, subquery, etc.) — callers fall back to TEXT (OID 25),
matching the pre-existing behavior.Parse-time type inference for SELECT-item expressions.
Mirrors PostgreSQL's `exprType` (src/backend/nodes/nodeFuncs.c): each
node in the expression tree has a declared result OID, computed by
walking the AST during parse/analyze. PG looks up operator and
function signatures in `pg_operator` / `pg_proc`; we hardcode the
equivalent rules for the set of SQL we handle.
Consumed by `translate-select` to populate `:select-item-oids` on the
parsed map, which `describeResult` reads to emit correct
RowDescription OIDs via the Extended Query protocol — before Execute
runs, so value-based inference isn't available.
Return values:
- A positive integer OID when the type is determined.
- `nil` when we can't determine it (unknown function, unresolvable
column, subquery, etc.) — callers fall back to TEXT (OID 25),
matching the pre-existing behavior.(expr-oid expr env)Return the inferred PG OID for a JSqlParser expression, or nil if we can't determine it.
env carries the live db and schema:
{:db <datahike db>
:schema <schema map>
:table-aliases {alias → real-table-name}
:default-table <string or nil>
:hints <schema-hint map or nil>}
Return the inferred PG OID for a JSqlParser expression, or nil if we
can't determine it.
`env` carries the live db and schema:
{:db <datahike db>
:schema <schema map>
:table-aliases {alias → real-table-name}
:default-table <string or nil>
:hints <schema-hint map or nil>}(resolve-aggregate-result-oid agg-name input-oid)Given an aggregate name and the OID of its first argument, return
the result OID per sql-aggregate->return-oid. Returns nil for
unknown aggregates or unresolvable rules (caller falls back).
Public so the translator can derive the runtime fn variant from the same rule the OID inference uses — avoids drift between describeResult's reported type and the actual runtime.
Given an aggregate name and the OID of its first argument, return the result OID per `sql-aggregate->return-oid`. Returns nil for unknown aggregates or unresolvable rules (caller falls back). Public so the translator can derive the runtime fn variant from the same rule the OID inference uses — avoids drift between describeResult's reported type and the actual runtime.
Aggregate function → return-OID rule. Three rule shapes:
integer (an OID): always returns this OID, regardless of input. Used for COUNT (always INT8) and the variance/correlation family (always FLOAT8).
:arg-type: returns the OID of the first argument. Used for
MIN/MAX where the result-type tracks the input.
map {<input-oid> <output-oid> … :default <fallback>}:
resolved by looking up the first argument's OID. Used for SUM/AVG
to match PG's pg_proc.dat per-input-type return rules:
AVG(int2|int4|int8|numeric) → numeric (PG) AVG(float4|float8) → float8 SUM(int2|int4) → int8 SUM(int8|numeric) → numeric (overflow-safe) SUM(float4) → float4 SUM(float8) → float8
PG promotes integer SUMs to int8/numeric to prevent overflow, and AVG(int) to numeric to preserve fractional precision. Without these per-input rules, AVG(total_cents) renders as a truncated INT8 in Metabase even though the runtime returns a Double, and SUM(int8) silently overflows when the sum exceeds Long/MAX_VALUE.
Aggregate function → return-OID rule. Three rule shapes:
- integer (an OID): always returns this OID, regardless of input.
Used for COUNT (always INT8) and the variance/correlation family
(always FLOAT8).
- `:arg-type`: returns the OID of the first argument. Used for
MIN/MAX where the result-type tracks the input.
- map `{<input-oid> <output-oid> … :default <fallback>}`:
resolved by looking up the first argument's OID. Used for SUM/AVG
to match PG's `pg_proc.dat` per-input-type return rules:
AVG(int2|int4|int8|numeric) → numeric (PG)
AVG(float4|float8) → float8
SUM(int2|int4) → int8
SUM(int8|numeric) → numeric (overflow-safe)
SUM(float4) → float4
SUM(float8) → float8
PG promotes integer SUMs to int8/numeric to prevent overflow,
and AVG(int) to numeric to preserve fractional precision. Without
these per-input rules, AVG(total_cents) renders as a truncated
INT8 in Metabase even though the runtime returns a Double, and
SUM(int8) silently overflows when the sum exceeds Long/MAX_VALUE.Scalar function → return OID. Entries either a fixed OID or a keyword
dispatched in function-oid for arg-dependent return types.
Scalar function → return OID. Entries either a fixed OID or a keyword dispatched in `function-oid` for arg-dependent return types.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |