Protocol & metadata
On this page
Enums, protocol shapes, secrets, and the function metadata DuckDB reads.
const arrowStateSerializer
Section titled âconst arrowStateSerializerâconst arrowStateSerializer: StateSerializerDescription
Arrow IPC state serializer â stores all data as native binary columns.
function arrowToMetadatas
Section titled âfunction arrowToMetadatasâexport function arrowToMetadatas(batch: VgiBatch): ResolvedMetadata[]Description
Deserialize Arrow RecordBatch to ResolvedMetadata array.
interface BindRequest
Section titled âinterface BindRequestâexport interface BindRequestFields
function_namestringargumentsArgumentsfunction_typeFunctionTypeinput_schemaVgiSchema | nullsettingsVgiBatch | nullsecretsVgiBatch | nullattach_opaque_dataUint8Array | nulltransaction_opaque_dataUint8Array | nullresolved_secrets_providedbooleancopy_fromCopyFromContext | nulloptionalCOPY ⌠FROM context â
null/absent unless this bind/init opens a COPY-FROM scan. Additive + name-keyed, so ordinary scans (which omit it on the wire) deserialize tonull. Mirrors vgi-pythonâsBindRequest.copy_from.copy_toCopyToContext | nulloptionalCOPY ⌠TO context â
null/absent unless this bind/init opens a COPY-TO sink. Additive + name-keyed, same wire-safe rationale ascopy_from. Mirrors vgi-pythonâsBindRequest.copy_to.at_unitstring | nulloptionalTime travel: the AT (TIMESTAMP|VERSION âŚ) clause for this scan, threaded from DuckDBâs per-reference bind. Both
nullwhen the scan has no AT clause. For inline-bound (function-backed) tables the actual on_bind RPC runs once at attach with no AT, so the per-scan AT is carried on the bind request embedded in each InitRequest â read it at init viainit_call.bind_call.at_unit(orTableProcessParams.atUnit). Mirrors vgi-pythonâsBindRequest.at_unit.at_valuestring | nulloptionalschema_namestring | nulloptionalCatalog schema that declares the function being bound. A worker may register the same name in more than one schema, so the bare name does not identify an implementation â resolution is by
(schema_name, function_name). Null for callers with no catalog context (COPY handler binds). Mirrors vgi-pythonâsBindRequest.schema_name.
interface BindResponse
Section titled âinterface BindResponseâexport interface BindResponseFields
output_schemaVgiSchemaopaque_dataUint8Array | nulllookup_secret_typesstring[]optionallookup_scopesstring[]optionallookup_namesstring[]optional
enum CatalogFunctionType
Section titled âenum CatalogFunctionTypeâexport enum CatalogFunctionType {SCALAR = "SCALAR",TABLE = "TABLE",TABLE_BUFFERING = "TABLE_BUFFERING",AGGREGATE = "AGGREGATE",}interface CopyFromContext
Section titled âinterface CopyFromContextâexport interface CopyFromContextDescription
Context for a COPY ... FROM read, threaded onto {@link BindRequest}.
Present only when the bind/init opens a COPY-FROM scan (null/absent
otherwise â set by the VGI extensionâs copy_from_bind). InitRequest
embeds the same BindRequest as bind_call, so process()/init also reach it
via initCall.bind_call.copy_from. The handlerâs options arrive through the
normal BindRequest.arguments (built from the COPY options), so they are not
duplicated here. Mirrors vgi-pythonâs protocol.CopyFromContext.
Fields
formatstringThe
FORMATname resolved at COPY bind time.file_pathstringThe source path from the
COPY ... FROM 'path'statement.expected_schemaVgiSchemaThe COPY targetâs column schema (name + type, in target order). The worker must bind its output to, and emit columns whose types match, this schema exactly â DuckDB inserts no cast between the scan and the INSERT. Holds the parsed Arrow Schema (the wire field is binary; deserialized here).
interface CopyToContext
Section titled âinterface CopyToContextâexport interface CopyToContextDescription
Context for a COPY ... TO write, threaded onto {@link BindRequest}.
Present only when the bind/init opens a COPY-TO sink (null/absent
otherwise â set by the VGI extensionâs copy_to_bind). InitRequest
embeds the same BindRequest as bind_call, so process()/combine() also
reach it via initCall.bind_call.copy_to. The handlerâs options arrive
through the normal BindRequest.arguments; the source columns ride the
existing BindRequest.input_schema (so they are not duplicated here).
Mirrors vgi-pythonâs protocol.CopyToContext.
Fields
formatstringThe
FORMATname resolved at COPY bind time.file_pathstringThe destination path from the
COPY ... TO 'path'statement.
const DEFAULT_MAX_WORKERS
Section titled âconst DEFAULT_MAX_WORKERSâconst DEFAULT_MAX_WORKERS = 99999function deserializeUserState
Section titled âfunction deserializeUserStateâexport function deserializeUserState(bytes: Uint8Array | null): anyDescription
Deserialize userState from Arrow IPC bytes. Reconstructs a plain JS object, preserving BigInt for Int64 columns.
enum DistinctDependence
Section titled âenum DistinctDependenceâexport enum DistinctDependence {DISTINCT_DEPENDENT = "DISTINCT_DEPENDENT",NOT_DISTINCT_DEPENDENT = "NOT_DISTINCT_DEPENDENT",}const EXCHANGE_STATE_SCHEMA
Section titled âconst EXCHANGE_STATE_SCHEMAâconst EXCHANGE_STATE_SCHEMADescription
Schema for the exchange state carried in HTTP state tokens.
interface FunctionExample
Section titled âinterface FunctionExampleâexport interface FunctionExampleFields
sqlstringdescriptionstringexpectedOutputstringoptional
interface FunctionMeta
Section titled âinterface FunctionMetaâexport interface FunctionMetaFields
namestringdescriptionstringoptionalstabilityFunctionStabilityoptionalnullHandlingNullHandlingoptionalexamplesFunctionExample[]optionalcategoriesstring[]optionaltagsRecord<string, string>optionalprojectionPushdownbooleanoptionalfilterPushdownbooleanoptionalsamplingPushdownbooleanoptionallateMaterializationbooleanoptionaltable (generator): opt in to DuckDBâs late-materialization rewrite. A TOP_N/LIMIT/SAMPLE over a rowid-bearing table is rewritten into a SEMI join â a narrow ordering scan selects survivors, then the wide scan re-fetches their columns with the surviving rowids pushed down. Surfaces as FunctionInfo
late_materialization. Only honoured by the C++ extension for tables whose worker also guarantees a UNIQUE, snapshot-stable rowid.supportedExpressionFiltersstring[]optionalautoApplyFiltersbooleanoptionalpreservesOrderOrderPreservationoptionalmaxWorkersnumberoptionalrequiredSettingsstring[]optionalrequiredSecretsstring[]optionalorderDependentOrderDependenceoptionaldistinctDependentDistinctDependenceoptionalhasFinalizebooleanoptionalFor table_in_out functions: whether the user defined a finalize callback. DuckDB issues a separate FINALIZE init() phase only when this is true; otherwise calling FinalExecute is unsupported and crashes the C++ side.
inputFromArgsbooleanoptionalBlended (âUNNEST-styleâ) table-in-out: the functionâs positional args ARE its per-row input columns (real typed args, no synthetic TABLE placeholder), so ONE registration serves f(52,13) (literal -> 1 input row), FROM t, f(t.x, t.y) (columns -> streaming), and LATERAL f(t.x,t.y). Set by {@link defineRowTransformFunction }; surfaces as FunctionInfo.input_from_args. The C++ extension reads it to enter the in-out registration branch with real-typed args and drive the literal single-row scan-mode. Mirrors vgi-pythonâs RowTransformFunction / ResolvedMetadata.input_from_args.
sinkOrderDependentbooleanoptionaltable_buffering: force ParallelSink=false in the C++ operator (single-thread, source-ordered ingest).
sourceOrderDependentbooleanoptionaltable_buffering: force serial Source drain in finalize_queue order (ParallelSource=false, SourceOrder=FIXED_ORDER).
requiresInputBatchIndexbooleanoptionaltable_buffering: thread DuckDBâs per-chunk batch_index into every process() call (RequiredPartitionInfo=BatchIndex).
supportsBatchIndexbooleanoptionaltable (generator): the function tags every emitted Arrow batch with a per-partition
vgi_batch_indexso DuckDBâs ordered sinks reassemble parallel output in partition order. Surfaces as FunctionInfosupports_batch_index.partitionKindâNOT_PARTITIONEDâ | âSINGLE_VALUE_PARTITIONSâ | âOVERLAPPING_PARTITIONSâ | âDISJOINT_PARTITIONSâoptionaltable (generator): Hive-style partition-columns mode. Functions declare a PartitionKind and annotate bind-schema fields; emitted batches carry
vgi_partition_values#b64metadata. Surfaces as FunctionInfopartition_kind.copyFromFormatstringoptionalCOPY ⌠FROM custom format reader: the SQL
FORMATidentifier this function backs (e.g.example_lines). Set by {@link defineCopyFromFunction }. When present, the catalog advertises this function viacopyFromFormats()/ thecatalog_copy_from_formatsRPC so the VGI extension registers a DuckDB CopyFunction for it. Mirrors vgi-pythonâsCopyFromFunction.COPY_FROM_FORMAT.copyFromDirectionstringoptionalCOPY direction; only
"from"is supported today. Default"from".copyFromCommentstring | nulloptionalOptional free-text comment surfaced by
vgi_copy_formats().copyToFormatstringoptionalCOPY ⌠TO custom format writer: the SQL
FORMATidentifier this function backs (e.g.example_lines_out). Set by {@link defineCopyToFunction }. When present, the catalog advertises this function viacopyFromFormats()(thecatalog_copy_from_formatsRPC returns all directions) so the VGI extension registers a DuckDB CopyFunction for it. The writer is atable_bufferingfunction under the hood, reusing thetable_buffering_process/table_buffering_combineRPCs. Mirrors vgi-pythonâsCopyToFunction.COPY_TO_FORMAT.copyToDirectionstringoptionalCOPY direction for a TO writer; always
"to". Default"to".copyToCommentstring | nulloptionalOptional free-text comment surfaced by
vgi_copy_formats().
class FunctionRegistry
Section titled âclass FunctionRegistryâexport class FunctionRegistryMethods
method registerInSchema
Section titled âmethod registerInSchemaâregisterInSchema(func: VgiFunction, schemaName: string, catalogName?: string): voidRecord that func is declared in schemaName, in addition to the flat
by-name index. Idempotent, and independent of register() so a function
reachable from several schemas (e.g. a scan function referenced by tables in
more than one schema) resolves from any of them.
method schemasFor
Section titled âmethod schemasForâschemasFor(functionName: string): string[]Schemas that declare functionName, sorted â for error messages.
method get
Section titled âmethod getâget(name: string, context?: OverloadContext): VgiFunctionenum FunctionStability
Section titled âenum FunctionStabilityâexport enum FunctionStability {CONSISTENT = "CONSISTENT",VOLATILE = "VOLATILE",CONSISTENT_WITHIN_QUERY = "CONSISTENT_WITHIN_QUERY",}enum FunctionType
Section titled âenum FunctionTypeâexport enum FunctionType {SCALAR = "scalar",TABLE = "table",// Sink+source function bound through defineTableBufferingFunction. Mirrors// vgi-python's FunctionType.TABLE_BUFFERING; without it a buffering bind fell// through deserializeBindRequest's normalization to a bare `as` cast.TABLE_BUFFERING = "table_buffering",AGGREGATE = "aggregate",}interface GlobalInitResponse
Section titled âinterface GlobalInitResponseâexport interface GlobalInitResponseFields
max_workersnumberexecution_idUint8Arrayopaque_dataUint8Array | null
interface HandlerState
Section titled âinterface HandlerStateâexport interface HandlerState<T = any>Description
Convention for handler state: mutable user state lives in .state.
Fields
stateTSerializable user state for HTTP exchange round-trips.
interface InitRequest
Section titled âinterface InitRequestâexport interface InitRequestFields
bind_callBindRequestoutput_schemaVgiSchemabind_opaque_dataUint8Array | nullprojection_idsnumber[] | nullpushdown_filtersVgiBatch | nulljoin_keysVgiBatch[]Join-key value batches, one per join-keys column. Keyed by the column name inside each batchâs schema. Populated when DuckDB promotes IN/OR lists or join predicates to batched join-keys pushdowns.
phaseTableInOutPhase | nullfinalize_state_idUint8Array | nullBuffered-table finalize stream: which finalize_state_id this stream serves. Set when phase=TABLE_BUFFERING_FINALIZE; null otherwise. Opaque bytes the workerâs combine() chose.
execution_idUint8Array | nullinit_opaque_dataUint8Array | nullsubstream_idUint8Array | nullPer-substream identity for parallel streaming table-in-out functions. A stable, CLIENT-minted id for one substream (one DuckDB PipelineExecutor), identical across this substreamâs init / every process tick / finalize. Unlike a worker-minted
execution_id, it survives an HTTP load balancer dispatching each request to an arbitrary backend: a finalize that lands on a different backend than the process() calls can still key the substreamâs accumulated state (in shared storage) bysubstream_id.nullwhen the client did not supply one (serial path, non-table-in-out functions, old clients). Mirrors vgi-pythonâsInitRequest.substream_id.order_by_column_namestring | nullorder_by_directionOrderByDirection | nullorder_by_null_orderOrderByNullOrder | nullorder_by_limitbigint | nulltablesample_percentagenumber | nulltablesample_seedbigint | null
function metadatasToArrow
Section titled âfunction metadatasToArrowâexport function metadatasToArrow(metadatas: ResolvedMetadata[]): VgiBatchDescription
Serialize multiple ResolvedMetadata to a single Arrow RecordBatch.
enum NullHandling
Section titled âenum NullHandlingâexport enum NullHandling {DEFAULT = "DEFAULT",SPECIAL = "SPECIAL",}enum OrderDependence
Section titled âenum OrderDependenceâexport enum OrderDependence {ORDER_DEPENDENT = "ORDER_DEPENDENT",NOT_ORDER_DEPENDENT = "NOT_ORDER_DEPENDENT",}enum OrderPreservation
Section titled âenum OrderPreservationâexport enum OrderPreservation {/** Output rows are in same order as input rows (DuckDB INSERTION_ORDER). */PRESERVES_ORDER = "PRESERVES_ORDER",/** Output order is undefined; may be reordered (DuckDB NO_ORDER). */NO_ORDER_GUARANTEE = "NO_ORDER_GUARANTEE",/** Output is in a fixed mandatory order; DuckDB serialises the pipeline * (single worker) to preserve it (DuckDB FIXED_ORDER). */FIXED_ORDER = "FIXED_ORDER",}interface ParameterInfo
Section titled âinterface ParameterInfoâexport interface ParameterInfoFields
namestringpositionnumber | nullpositionNamestring | nulltypeNamestring | nulldescriptionstringrequiredbooleandefaultstring | nullconstraintsstring | nullisTableInputbooleanisVarargsbooleanisConstboolean
interface ResolvedMetadata
Section titled âinterface ResolvedMetadataâexport interface ResolvedMetadataFields
namestringclassNamestringfunctionTypeCatalogFunctionTypedescriptionstringexamplesFunctionExample[]categoriesstring[]tagsRecord<string, string>parametersParameterInfo[]stabilityFunctionStabilitynullHandlingNullHandlingrequiredSettingsstring[]requiredSecretsstring[]projectionPushdownbooleanfilterPushdownbooleansamplingPushdownbooleansupportedExpressionFiltersstring[]preservesOrderOrderPreservationmaxWorkersnumber | nullorderDependentOrderDependencedistinctDependentDistinctDependence
function resolveMetadata
Section titled âfunction resolveMetadataâexport function resolveMetadata(func: VgiFunction): ResolvedMetadataconst ScanFunctionResultSchema
Section titled âconst ScanFunctionResultSchemaâconst ScanFunctionResultSchema = schema([field("function_name", utf8(), false),field("arguments", binary(), false),field("required_extensions", list(field("item", utf8(), true)), false),])type SecretFields
Section titled âtype SecretFieldsâexport type SecretFields = Record<string, any>;function secretForScope
Section titled âfunction secretForScopeâexport function secretForScope(secrets: SecretsDict, path: string): SecretFields | undefinedDescription
The secret whose scope is the longest prefix of path. The connector
serializes each secretâs scope as a newline-joined list of prefixes; a secret
with no (or empty) scope matches as a last-resort fallback. Returns undefined
only when there are no candidate secrets.
function secretForScopeOfType
Section titled âfunction secretForScopeOfTypeâexport function secretForScopeOfType(secrets: SecretsDict,path: string,type: string,): SecretFields | undefinedDescription
Like {@link secretForScope} but only over secrets of type.
type SecretsDict
Section titled âtype SecretsDictâexport type SecretsDict = Record<string, SecretFields>;function secretsOfType
Section titled âfunction secretsOfTypeâexport function secretsOfType(secrets: SecretsDict, type: string): SecretFields[]Description
Every resolved secret whose serialized type field matches type.
function secretType
Section titled âfunction secretTypeâexport function secretType(secrets: SecretsDict, name: string): string | undefinedDescription
The DuckDB secret type of the named secret (its serialized type field).
function serializeUserState
Section titled âfunction serializeUserStateâexport function serializeUserState(userState: any): Uint8Array | nullDescription
Serialize userState to Arrow IPC bytes. Infers schema from the JS object at runtime. Arrow IPC is self-describing, so deserialization doesnât need the schema ahead of time.
For an empty object {}, we emit a 0-row batch with empty schema â
deserializeUserState recognizes that shape and returns {} rather than
null. (null is reserved for âno userState declared at allâ.)
interface StreamHandlers
Section titled âinterface StreamHandlersâexport interface StreamHandlersFields
outputSchemaVgiSchemaproducerInit() => anyoptionalproducerFn(state: any, out: OutputCollector) => void | Promise<void>optionalexchangeInit() => anyoptionalexchangeFn( state: any, input: VgiBatch, out: OutputCollector ) => void | Promise<void>optionalinputSchemaVgiSchemaoptionalonTick(state: any, tickMetadata: Map<string, string> | undefined) => void | Promise<void>optionalFires once per tick batch on the producer path, before
producerFn. Receives the tickâs Arrow custom metadata so the handler can pick up per-tick signals likevgi_pushdown_filters(dynamic filter updates from DuckDBâs Top-N optimizer).
interface TableCardinality
Section titled âinterface TableCardinalityâexport interface TableCardinalityFields
estimatenumber | nullmaxnumber | null
enum TableInOutPhase
Section titled âenum TableInOutPhaseâexport enum TableInOutPhase {INPUT = "INPUT",FINALIZE = "FINALIZE",// Sink+Source (TableBufferingFunction) init phases. TABLE_BUFFERING is the// sink-side init (persist init metadata so any pool worker can serve// process/combine); TABLE_BUFFERING_FINALIZE is the per-finalize_state_id// Source-stream init.TABLE_BUFFERING = "TABLE_BUFFERING",TABLE_BUFFERING_FINALIZE = "TABLE_BUFFERING_FINALIZE",}interface VgiFunction
Section titled âinterface VgiFunctionâexport interface VgiFunctionDescription
A resolved, registered VGI function definition.
Fields
kindâscalarâ | âtableâ | âtable_in_outâ | âtable_bufferingâmetaFunctionMetaargumentSpecsArgumentSpec[]bind(request: BindRequest): BindResponse | Promise<BindResponse>globalInit(request: InitRequest): GlobalInitResponse | Promise<GlobalInitResponse>createStreamHandlers( request: InitRequest, response: GlobalInitResponse, accumulatedState?: any, ): StreamHandlersdefaultOutputSchemaVgiSchemaoptionalDefault output schema (for catalog registration). May be overridden at bind time.
cardinality(request: TableFunctionCardinalityRequest): TableCardinality | Promise<TableCardinality>optionalstatistics(request: TableFunctionCardinalityRequest): import(â../util/statistics.jsâ).ColumnStatistics[] | nulloptionalPer-column statistics for this table functionâs output given the userâs bind-time arguments. Returns null/[] when stats are unknown. Wired to the
table_function_statisticsRPC; DuckDB uses the bounds for plan-time filter elimination.dynamicToString(request: DynamicToStringRequest): Record<string, string> | Promise<Record<string, string>>optionalPer-execution diagnostics for EXPLAIN ANALYZE. DuckDB calls this at pipeline FinishSource via the
table_function_dynamic_to_stringRPC. Returns ordered keyâvalue strings; the C++ extension merges these with the intrinsic keys (Function, Rows Read, Threads).