Skip to content
Query.Farm
Talk with Us

Catalogs

On this page

Schemas, tables, views, macros, constraints, and scan metadata.

source
public sealed class CatalogForeignKey

Description

One CatalogTable.ForeignKeys entry — column-NAME form (resolved against CatalogTable.Columns at registration time, mirroring Protocol.ForeignKeyInfo which travels column names directly, not indices).

Public members

public required IReadOnlyList<string> Columns { get; init; }
public required IReadOnlyList<string> ReferencedColumns { get; init; }
public required string ReferencedTable { get; init; }
public string? ReferencedSchema { get; init; }
source
public sealed class CatalogMacro

Description

A declaratively-registered catalog macro (scalar or table) — see Protocol.MacroInfo for the wire shape this becomes.

Public members

public Dictionary<string, string> Tags { get; init; }
public IReadOnlyDictionary<string, string> ParameterDocs { get; init; }

Per-parameter descriptions, keyed by parameter NAME (a subset of Parameters) — surfaced via vgi_function_arguments() 's arg_description column ( vgi_doc field metadata on Protocol.MacroInfo.ArgumentsSchema). Empty (the default) means no parameter is documented.

public List<string> Parameters { get; init; }

Every parameter's name, in positional-binding order.

public RecordBatch? ParameterDefaults { get; init; }

A one-row RecordBatch whose field names are the (a subset of Parameters) defaulted parameters and whose single row holds each one's default value — null when no parameter has a default.

public required Protocol.MacroType MacroType { get; init; }
public required string Definition { get; init; }

The macro body: a scalar expression for Protocol.MacroType.Scalar, or a SELECT query for Protocol.MacroType.Table — references Parameters by name.

public required string Name { get; init; }
public string SchemaName { get; init; }
public string? Comment { get; init; }
source
public sealed class CatalogTable

Description

A declaratively-registered catalog table — the real, queryable-as-a-plain-table analog of an ITableFunction (which is only reachable as schema.function_name(…) ). Mirrors vgi-python's declarative vgi.catalog.Table (see docs/catalog-interface.md 's "Function-Backed Tables (Recommended)" section): the recommended shape backs a table entirely by an already-registered ScanFunction and lets Columns default to that function's own ITableFunction.OutputSchema, so the column list is declared exactly once. A writable table (see test/sql/integration/simple_writable/*.test ) additionally names an ITableInOutFunction per write operation — the C++ extension resolves INSERT/UPDATE/DELETE by looking up a VGI table-in-out function by name (see Protocol.ScanFunctionResult's doc comment) and feeding it the affected rows over the SAME exchange-stream protocol an ordinary table-in-out function like echo already uses — there is no separate "write function" kind on the wire.

Public members

public Dictionary<string, string> Tags { get; init; }
public Func<string, string, (IReadOnlyList<object?> Positional, IReadOnlyDictionary<string, object?> Named)>? ResolveScanArguments { get; init; }

Resolves this table's SCAN CALL ARGUMENTS (overriding ScanArguments/ ScanNamedArguments) for a given AT clause — consulted by Internal.VgiServiceImpl.CatalogTableScanBranchesGetAsync for a ScanFunction-backed (non-Branches) table with InlineScanFunction false, on EVERY bind (both AT and no-AT — atUnit / atValue are empty strings for "no AT clause", not null, so a default/current-version answer is still required). This is the native "columns-based" time-travel mechanism: the catalog resolves AT into a scan-function ARGUMENT (e.g. a resolved version ) rather than swapping the table's declared schema — see tt_pushdown_cols / cache_versioned . null (the default) means "use ScanArguments/ScanNamedArguments unchanged, ignore AT".

public Func<string, string, CatalogTable>? ResolveAtClause { get; init; }

Resolves this table's declared shape (typically Columns + ScanArguments/ScanNamedArguments) for a specific AT clause — called from catalog_table_get ONLY when SupportsTimeTravel is set and the query actually carries an AT clause. Takes the raw (atUnit, atValue) pair (never null/empty when called) and returns the CatalogTable variant to serve — e.g. a different Columns schema for a table with per-version schema evolution ( versioned_data / versioned_constraints ). Throw (with a message DuckDB should surface verbatim, e.g. "Unknown version: …" ) for an out-of-range/unsupported value. null (the default) means "serve this table unchanged for any AT clause" — the right choice for a table whose SCAN FUNCTION (not its catalog schema) resolves the version itself, either by reading Table.TableBindParams.AtUnit/ Table.TableBindParams.AtValue directly ( tt_pushdown_fn ) or via ResolveScanArguments ( tt_pushdown_cols , cache_versioned ).

public IReadOnlyDictionary<string, ColumnStatisticsInput> Statistics { get; init; }

Per-column statistics, keyed by column NAME — served via the catalog_table_column_statistics_get RPC (Internal.ColumnStatisticsCodec builds the wire batch) whenever non-empty, which also implies Protocol.TableInfo.SupportsColumnStatistics. Empty (the default) means the table declares no statistics — the optimizer gets no filter-elimination help.

public IReadOnlyDictionary<string, object?> ScanNamedArguments { get; init; }

Fixed NAMED call arguments, same purpose as ScanArguments.

public IReadOnlyDictionary<string, string> ColumnComments { get; init; }

Per-column comments, keyed by column NAME (resolved against Columns/ ScanFunction's output schema at registration time) — applied as "comment" Arrow field metadata (see vgi_catalog_api.cpp 's column-metadata reader), surfaced via duckdb_columns().comment . A column with no entry here reports a NULL comment.

public IReadOnlyDictionary<string, string> ColumnDefaults { get; init; }

Per-column DEFAULT value expressions (raw SQL, e.g. "9.99" / "'unknown'" ), keyed by column NAME — applied as "default" Arrow field metadata, surfaced via duckdb_columns().column_default . Mutually exclusive with a generated-expression column (not yet surfaced by this builder). A column with no entry here reports a NULL default.

public IReadOnlyDictionary<string, string> GeneratedColumns { get; init; }

Per-column GENERATED ALWAYS AS expressions (raw SQL, e.g. "n * 2" ), keyed by column NAME — applied as "generated_expression" Arrow field metadata ( VGI_GENERATED_EXPRESSION_METADATA_KEY ), surfaced via duckdb_columns().column_default as DuckDB's own CAST((<expr>) AS <column_type>) rendering. Mutually exclusive per-column with ColumnDefaults (a column is either stored-with-a-default or computed, never both). Empty (the default) means no generated columns.

public IReadOnlyList<CatalogForeignKey> ForeignKeys { get; init; }
public IReadOnlyList<IReadOnlyList<string>> RequiredFilters { get; init; }

Required WHERE-filter groups in conjunctive normal form (CNF): an AND (outer list) of OR-groups (inner lists) of dotted-path column references (e.g. "s.a" for a struct subfield). A group is satisfied when the query's WHERE clause carries a filter on ANY one of its member paths (or a filter on a PREFIX of that path — a filter on the whole struct 's' satisfies a required 's.a'); every group must be satisfied or the C++ optimizer refuses the query with a BinderException before it runs. A single-path group is a plain mandatory filter; a multi-path group like ["a", "b"] means "one of a, b". Empty (the default) means no enforcement. Surfaced on Protocol.TableInfo.RequiredFilters and, pre-error, via the extension-injected vgi_required_filters duckdb_tables().tags entry.

public IReadOnlyList<IReadOnlyList<string>> UniqueColumns { get; init; }
public IReadOnlyList<ScanBranchSpec>? Branches { get; init; }

Explicit multi-branch declaration ( catalog_table_scan_branches_get ) — when non-null (even an EMPTY list, to exercise the C++ loud-fail-on-zero-branches contract; see catalog/multi_branch_empty_branches.test ), this is the table's scan in full and ScanFunction should be left null: an inline ScanFunction always wins on the C++ side ( VgiTableEntry::GetScanFunctionImpl never even calls catalog_table_scan_branches_get for the actual scan when it's set), so a table declaring both would have this list consulted ONLY by the vgi_table_branches() diagnostic, never by a real query. A table with neither this NOR ScanFunction set (rare — only makes sense alongside an explicit Columns) is a worker bug, caught at catalog_table_scan_branches_get time.

public IReadOnlyList<object?> ScanArguments { get; init; }

Fixed positional call arguments baked into ScanFunction's inline Protocol.ScanFunctionResult — e.g. a table backed by a function whose FIRST argument is a required row count ( Table(function=SequenceFunction, arguments=Arguments(positional=(pa.scalar(1_000_000),))) in vgi-python's terms) declares that constant here so every scan of this table binds with it. Empty (the default) means the scan function takes no arguments from the table descriptor.

public IReadOnlyList<string> CheckConstraints { get; init; }

Raw SQL boolean expressions, e.g. "(budget >= 0)" — surfaced verbatim as duckdb_constraints().constraint_text 's CHECK(…) wrapper.

public IReadOnlyList<string> NotNullColumns { get; init; }

Column NAMES (resolved to Protocol.TableInfo.NotNullConstraints indices against Columns at registration time).

public IReadOnlyList<string> PrimaryKeyColumns { get; init; }
public IReadOnlyList<string> RequiredExtensions { get; init; }

DuckDB extensions required to scan any of Branches (e.g. ["iceberg"] ) — surfaced on Protocol.ScanBranchesResult.RequiredExtensions. Ignored (a plain ScanFunction-backed table has none) unless Branches is also set.

public ITableFunction? ScanFunction { get; init; }

The read path — a normal table function (also independently registered under this table's SchemaName/ITableFunction.Name so the C++ side can call it by name once it resolves this table's inline Protocol.TableInfo.ScanFunction).

public ITableInOutFunction? DeleteFunction { get; init; }
public ITableInOutFunction? InsertFunction { get; init; }
public ITableInOutFunction? UpdateFunction { get; init; }
public Schema ResolveColumns() ;

Resolves Columns, falling back to ScanFunction's output schema — throws if neither is available.

public Schema? Columns { get; init; }

The table's column schema. Defaults to ScanFunction's ITableFunction.OutputSchema when null (the recommended function-backed pattern) — set explicitly only for a table with no backing scan function.

public bool InlineScanFunction { get; init; }

Whether ScanFunction is inlined onto Protocol.TableInfo.ScanFunction (the default, and the only behavior before this flag existed) — the C++ extension then uses it directly and never calls catalog_table_scan_branches_get /logs vgi.scan_function.inlined (see table/inlined_scan_function.test ). Set false for a table that should exercise the legacy per-bind RPC lookup path instead — ScanFunction stays registered as an ordinary callable function and Protocol.IVgiService.CatalogTableScanBranchesGetAsync still answers for it (a single synthesized branch wrapping the same function), it's just no longer inlined onto this table's own Protocol.TableInfo.

public bool SupportsDelete { get; init; }
public bool SupportsInsert { get; init; }
public bool SupportsReturning { get; init; }

Whether INSERT/UPDATE/DELETE … RETURNING is allowed — independent per-operation support flags aren't part of the wire protocol, so this applies to whichever of insert/update/delete IS supported.

public bool SupportsTimeTravel { get; init; }

Whether this table honours AT (VERSION => …) / AT (TIMESTAMP => …) time-travel clauses. false (the default) makes Internal.VgiServiceImpl.CatalogTableGetAsync refuse any AT clause against this table with a clear error — see table/time_travel.test 's "AT clause on non-time-travel table" case. Multi-branch tables (Branches non-null) are exempt from this check (they're passed through to the C++ extension's OWN multi-branch-specific AT refusal instead — see catalog/multi_branch_scan.test ).

public bool SupportsUpdate { get; init; }
public long? CardinalityEstimate { get; init; }
public long? CardinalityMax { get; init; }
public long? StatisticsCacheMaxAgeSeconds { get; init; }

How long the C++ extension may cache a fetched statistics response before re-issuing catalog_table_column_statistics_get — null means no TTL cap is advertised (worker/C++-side default applies). 0 forces a re-fetch on every query.

public required string Name { get; init; }
public string SchemaName { get; init; }
public string? Comment { get; init; }
public string? RowIdColumn { get; init; }

The row-identity column for UPDATE/DELETE (Internal.VgiRowIdMetadata). Required when SupportsUpdate or SupportsDelete is set.

source
public sealed class CatalogView

Description

A declaratively-registered catalog view — see Protocol.ViewInfo for the wire shape this becomes.

Public members

public Dictionary<string, string> ColumnComments { get; init; }
public Dictionary<string, string> Tags { get; init; }
public required string Definition { get; init; }
public required string Name { get; init; }
public string SchemaName { get; init; }
public string? Comment { get; init; }
source
public sealed class ColumnStatisticsInput

Description

One column's declared statistics — the worker-side input to Internal.ColumnStatisticsCodec. Mirrors vgi-python's ColumnStatisticsInput : Min/Max accept a bare CLR scalar (long/double/string/bool/ byte[]) matching the column's own type — null means "unknown", not "the column has no rows". Used both by CatalogTable.Statistics (fixed, declared-at-registration stats) and any worker code building the table_function_statistics / catalog_table_column_statistics_get RPC response by hand.

Public members

public bool HasNotNull { get; init; }
public bool HasNull { get; init; }
public bool? ContainsUnicode { get; init; }

String-typed columns only — null for every other column type.

public long? DistinctCount { get; init; }
public long? MaxStringLength { get; init; }

String-typed columns only — null for every other column type.

public object? Max { get; init; }
public object? Min { get; init; }
source
public sealed class CopyFormat

Description

A declaratively-registered COPY TO/FROM custom format — see Protocol.CopyFromFormatInfo for the wire shape this becomes. Built by Worker.RegisterCopyFromFormat/Worker.RegisterCopyToFormat, not constructed directly by most fixtures.

Public members

public Dictionary<string, string> Tags { get; init; }
public bool Ordered { get; init; }
public required Schema Options { get; init; }
public required string Direction { get; init; }

"from" or "to" .

public required string FormatName { get; init; }
public required string Handler { get; init; }
public string Description { get; init; }
public string? Comment { get; init; }
source
public sealed record ScanBranchSpec

Description

A declarative, worker-side description of one arm of a CatalogTable.Branches multi-branch table — the catalog-registration-time analog of the wire Protocol.ScanBranch DTO (which Internal.VgiServiceImpl builds from this at catalog_table_scan_branches_get time). See Protocol.ScanBranch's doc comment for the three mutually exclusive branch kinds this maps onto. A record (not a plain class) so callers can derive a variant with with — e.g. Seq(100) with { BranchFilter = "n < 50" } — without repeating every other property.

Public members

public IReadOnlyDictionary<string, object?> NamedArguments { get; init; }
public IReadOnlyDictionary<string, object?>? FormatOptions { get; init; }
public IReadOnlyList<object?> PositionalArguments { get; init; }
public IReadOnlyList<string>? FormatLocations { get; init; }
public bool Writable { get; init; }

Declares this the INSERT target among a table's branches. At most one branch of a given CatalogTable.Branches list may set this.

public string? BranchFilter { get; init; }

Raw SQL boolean expression (e.g. "n < 50" ) the C++ optimizer can use to prune this whole branch when it provably can't match a query's WHERE clause. Null/empty means unconstrained.

public string? FormatName { get; init; }

Format-branch kind — names WHAT the data is ( csv / parquet /…) and WHERE (FormatLocations), letting the C++ client pick the matching reader function itself. FormatOptions become that reader's named arguments.

public string? FunctionName { get; init; }

Function-branch kind — a VGI table function this worker itself serves, OR a native DuckDB function ( read_parquet , read_csv_auto , iceberg_scan , …) resolved directly against DuckDB's own catalog without ever reaching this worker.

public string? SourceCatalog { get; init; }

Catalog-table-branch kind — scans SourceCatalog.SourceSchema.SourceTable in a companion catalog directly. No in-scope fixture exercises this kind yet.

public string? SourceSchema { get; init; }
public string? SourceTable { get; init; }