Table-in-out functions
On this page
Streaming a relation through, batch by batch.
function defineRowTransformFunction
Section titled âfunction defineRowTransformFunctionâexport function defineRowTransformFunction<TArgs = Record<string, any>,>(config: RowTransformConfig<TArgs>): VgiFunctionDescription
Define a blended (âUNNEST-styleâ) table-in-out function: its positional args
ARE its per-row input columns, so ONE registration serves every call shape â
f(52, 13) (literal -> one input row), FROM t, f(t.x, t.y) (columns ->
streaming), and LATERAL f(t.x, t.y). Mirrors vgi-pythonâs
RowTransformFunction (Phase B).
Registers as a TABLE function with FunctionInfo.input_from_args = true;
the workerâs overload resolution matches blended overloads by INPUT-COLUMN
count (the positional args are not on the wire). Map-shaped, no finalize.
function defineTableInOutFunction
Section titled âfunction defineTableInOutFunctionâexport function defineTableInOutFunction<TArgs = Record<string, any>,TState = null,>(config: TableInOutConfig<TArgs, TState>): VgiFunctionconst PARENT_ROW_METADATA_KEY
Section titled âconst PARENT_ROW_METADATA_KEYâconst PARENT_ROW_METADATA_KEY = âvgi_rpc.parent_row#b64âDescription
Metadata key carrying per-output-row provenance: base64 of a raw little-endian int32[] mapping each output row to the input row that produced it. Shared by string with the C++ extension and vgi-python.
function parentRowsMetadata
Section titled âfunction parentRowsMetadataâexport function parentRowsMetadata(parentRows: number[],outputRows: number,extra?: Map<string, string>,): Map<string, string>Description
Fold per-output-row provenance into an emit metadata map.
Used by the batched correlated LATERAL operator (blended
RowTransformFunction under FROM t, f(t.x) / LATERAL): the C++ extension
ships a whole input chunk to the worker in ONE exchange and reads ONE
output batch, then maps each output row back to the input row that produced
it via this array â so a 1->N fan-out or 1->0 filter can be batched instead
of driven row-by-row.
parentRows[i] is the 0-based index (into the input batch) of the row that
produced output row i. Encoded as a raw little-endian int32 array (NOT
Arrow IPC), base64-encoded, under vgi_rpc.parent_row#b64. Absent metadata
means an identity 1->1 map (the common case: the extension assumes it, and
requires output rows == input rows).
Contract: parentRows.length MUST equal the emitted batchâs row count (a
mismatch is a worker bug that would corrupt the stamping). Values are
range-checked against the input width on the C++ side. Mirrors vgi-pythonâs
_merge_parent_rows / out.emit(..., parent_rows=[...]).
interface RowTransformConfig
Section titled âinterface RowTransformConfigâexport interface RowTransformConfig<TArgs = Record<string, any>>Fields
namestringonBind(params: TableInOutBindParams<TArgs>) => | { outputSchema: VgiSchema; opaqueData?: Uint8Array } | Promise<{ outputSchema: VgiSchema; opaqueData?: Uint8Array }>Bind: return the output schema. The input schema (the declared per-row columns, typed by the C++ bind) is on
params.bindCall.input_schema.process( params: RowTransformProcessParams<TArgs>, batch: VgiBatch, out: OutputCollector, ) => void | Promise<void>Per-row map: transform one input batch, emit exactly one output batch via
out. 1->1, 1->N (with {@link parentRowsMetadata} provenance), and 1->0 (a 0-row emit) all work. There is NO finalize â a blended function is a per-row map (DuckDB forbids FinalExecute under correlated LATERAL, one of the call shapes blended must serve). Accumulating functions use a classic TableInput table-in-out or a TableBufferingFunction.descriptionstringoptionalargsRecord<string, VgiDataType>optionalPositional args = the per-row INPUT COLUMNS (real typed args on the wire, no synthetic TABLE placeholder). Read from
batchby declared name in process(); NOT surfaced onparams.args.varargs{ name: string; type: VgiDataType; doc?: string }optionalTrailing VARARGS input columns: the per-row input is N columns of the declared type. A varargs blended function has no per-column declared names (the C++ bind names them col0..colN-1), so process() reads the columns POSITIONALLY off
batch.namedArgsRecord<string, VgiDataType>optionalNamed (string-position) args stay bind-time scalars on
params.args.argDefaultsRecord<string, any>optionalargDocsRecord<string, string>optionalPer-argument descriptions keyed by arg name (surfaced as
vgi_doc).projectionPushdownbooleanoptionalfilterPushdownbooleanoptionalautoApplyFiltersbooleanoptionalstabilityFunctionStabilityoptionalexamplesFunctionExample[]optionalcategoriesstring[]optionaltagsRecord<string, string>optionalmaxWorkersnumberoptionalrequiredSettingsstring[]optionalrequiredSecretsstring[]optional
type RowTransformProcessParams
Section titled âtype RowTransformProcessParamsâexport type RowTransformProcessParams<TArgs = Record<string, any>> =TableInOutProcessParams<TArgs>;Description
Process params for a blended row-transform function. args carries only the
NAMED (bind-time scalar) options â the positional args are the per-row input
columns, read from batch in process() (by declared name for fixed args,
positionally for varargs).
interface TableInOutBindParams
Section titled âinterface TableInOutBindParamsâexport interface TableInOutBindParams<TArgs = Record<string, any>>Fields
argsTArgsbindCallBindRequestsettingsRecord<string, any>secretsRecord<string, Record<string, any>>
interface TableInOutConfig
Section titled âinterface TableInOutConfigâexport interface TableInOutConfig<TArgs = Record<string, any>,TState = null,>Fields
namestringdescriptionstringoptionalargsRecord<string, VgiDataType>optionalnamedArgsRecord<string, VgiDataType>optionalNamed arguments (optional, DuckDB passes by name)
argDefaultsRecord<string, any>optionalArgument defaults
onBind(params: TableInOutBindParams<TArgs>) => | { outputSchema: VgiSchema; opaqueData?: Uint8Array } | Promise<{ outputSchema: VgiSchema; opaqueData?: Uint8Array }>optionalBind: default passes through input schema. May be async.
onInit(params: { args: TArgs; initCall: InitRequest; outputSchema: VgiSchema; executionId: Uint8Array; }) => GlobalInitResponse | Promise<GlobalInitResponse>optionalinitialState(params: TableInOutProcessParams<TArgs>) => TStateoptionalprocess( params: TableInOutProcessParams<TArgs>, state: TState, batch: VgiBatch, out: OutputCollector ) => void | Promise<void>optionalProcess: transform input batch, emit output via out
finalize( params: TableInOutProcessParams<TArgs>, states: TState[] ) => VgiBatch[] | Promise<VgiBatch[]>optionalFinalize: emit final batches after all input processed. Receives all worker states collected from storage (matches Pythonâs finish(params, states)).
projectionPushdownbooleanoptionalfilterPushdownbooleanoptionalautoApplyFiltersbooleanoptionalstabilityFunctionStabilityoptionalexamplesFunctionExample[]optionalcategoriesstring[]optionaltagsRecord<string, string>optionalmaxWorkersnumberoptionalrequiredSettingsstring[]optionalrequiredSecretsstring[]optional
interface TableInOutProcessParams
Section titled âinterface TableInOutProcessParamsâexport interface TableInOutProcessParams<TArgs = Record<string, any>>Fields
argsTArgsinitCallInitRequestinitResponseGlobalInitResponseoutputSchemaVgiSchemasettingsRecord<string, any>secretsRecord<string, Record<string, any>>storageBoundStorageShared storage for cross-phase and cross-worker data (SQLite-backed).
pushdownFiltersPushdownFiltersoptionalsubstreamIdUint8Array | nulloptionalStable client-minted id for this streaming table-in-out substream. Present (identical across init / every process() / finalize) when the client fanned this function out across per-substream workers; use it to key per-substream accumulated state in shared storage so a finalize() that lands on a different HTTP backend than the process() calls still finds it.
null/undefinedfor the serial path or an old client. Mirrors vgi-pythonâsProcessParams.substream_id.ifNoneMatchstringoptionalConditional-revalidation validator (exchange-mode result cache): the client holds a stale cached result for THIS input unit and asks the worker to confirm freshness cheaply. When set, process() may answer with a 0-row
cacheControlMetadata({ notModified: true, ... })batch instead of recomputing. Rides the input batchâs custom metadata (attached by the C++ WriteInputBatch). Undefined on a normal call.ifModifiedSincestringoptionalRFC 3339 Last-Modified validator for conditional revalidation. Companion to {@link ifNoneMatch}. Undefined on a normal call.