Documentation
¶
Overview ¶
Package metadata provides concrete bridge implementations of the api.* metadata interfaces backed by *recordlayer.RecordMetaData.
Mirrors Java's RecordLayerSchemaTemplate / RecordLayerTable / RecordLayerColumn / RecordLayerIndex types — the bridge between the SQL layer's declarative view of schema and the record-layer storage engine's proto-descriptor view.
Direction of dependency: the relational layer depends on the record layer, never the other way. Don't reach back from pkg/recordlayer into pkg/relational.
Java-compliance notes ¶
The proto-to-DataType mapping in proto_types.go mirrors Java's com.apple.foundationdb.record.query.plan.cascades.typing.Type (fromProtobufFieldDescriptor + Record.fromDescriptorPreservingName) exactly for the cases that matter today:
- scalar kinds → primitive types (IntegerType / LongType / etc)
- enum → EnumType with declared values
- message / group → recursive StructType, with two short-circuits: (a) com.apple.foundationdb.record.UUID → UUIDType, and (b) "message M { repeated R values = 1; }" nullable-array wrapper → ArrayType (see unwrapWrappedArray / Java's NullableArrayTypeUtils.describesWrappedArray)
- repeated → ArrayType(element)
- map → UnresolvedType
No known behavioural divergences from Java remain in this bridge for the Phase 3 primary path. Edge cases the Java side also has acknowledged TODOs about (table-level nullable=true, maps as UnresolvedType, auxiliary types from Union enums) mirror Java's behaviour rather than Java's intent.
Doesn't block the Phase 3 semantic analyzer on the primary path (CRUD over typed proto records + basic aggregations).
Version semantics ¶
SchemaTemplate.Version() is catalog-level and decoupled from RecordMetaData.Version(). The default constructor NewRecordLayerSchemaTemplate passes md.Version() for convenience, but NewRecordLayerSchemaTemplateWithVersion lets the catalog pin a different value — matches Java's fromRecordMetadata(md, name, version) signature exactly. Catalogs that want to increment the schema version without also rebuilding storage metadata need the explicit-version constructor.
Index ¶
- type Builder
- func (b *Builder) AddAggregateIndex(tableName, indexName string, groupColumns []string, aggType, aggColumn string) *Builder
- func (b *Builder) AddCardinalityIndex(tableName, indexName, cardColumn string) *Builder
- func (b *Builder) AddIndex(tableName, indexName string, columns []string, unique bool) *Builder
- func (b *Builder) AddTable(name string, columns []ColumnSpec, primaryKey []string) *Builder
- func (b *Builder) AddVectorIndex(tableName, indexName, vectorColumn string, partitionColumns []string, ...) *Builder
- func (b *Builder) AddVectorIndexUsing(method, tableName, indexName, vectorColumn string, partitionColumns []string, ...) *Builder
- func (b *Builder) Build() (*RecordLayerSchemaTemplate, error)
- func (b *Builder) SetEnableLongRows(v bool) *Builder
- func (b *Builder) SetIntermingleTables(v bool) *Builder
- func (b *Builder) SetName(name string) *Builder
- func (b *Builder) SetStoreRowVersions(v bool) *Builder
- func (b *Builder) SetVersion(v int) *Builder
- type ColumnSpec
- type RecordLayerColumn
- type RecordLayerIndex
- func (i *RecordLayerIndex) Accept(v api.Visitor)
- func (i *RecordLayerIndex) IndexColumnNames() []string
- func (i *RecordLayerIndex) IndexIsUnique() bool
- func (i *RecordLayerIndex) IndexName() string
- func (i *RecordLayerIndex) IndexPrimaryKeyColumns() []string
- func (i *RecordLayerIndex) IndexRecordTypes() []string
- func (i *RecordLayerIndex) IndexType() string
- func (i *RecordLayerIndex) IsSparse() bool
- func (i *RecordLayerIndex) IsUnique() bool
- func (i *RecordLayerIndex) MetadataName() string
- func (i *RecordLayerIndex) TableName() string
- func (i *RecordLayerIndex) Underlying() *recordlayer.Index
- type RecordLayerSchemaTemplate
- func (s *RecordLayerSchemaTemplate) Accept(v api.Visitor)
- func (s *RecordLayerSchemaTemplate) EnableLongRows() bool
- func (s *RecordLayerSchemaTemplate) FindInvokedRoutine(_ string) (api.InvokedRoutine, error)
- func (s *RecordLayerSchemaTemplate) FindTable(name string) (api.Table, error)
- func (s *RecordLayerSchemaTemplate) FindView(_ string) (api.View, error)
- func (s *RecordLayerSchemaTemplate) GenerateSchema(databaseID, schemaName string) api.Schema
- func (s *RecordLayerSchemaTemplate) Indexes() ([]string, error)
- func (s *RecordLayerSchemaTemplate) IntermingleTables() bool
- func (s *RecordLayerSchemaTemplate) InvokedRoutines() ([]api.InvokedRoutine, error)
- func (s *RecordLayerSchemaTemplate) MetadataName() string
- func (s *RecordLayerSchemaTemplate) StoreRowVersions() bool
- func (s *RecordLayerSchemaTemplate) TableIndexMapping() (map[string][]string, error)
- func (s *RecordLayerSchemaTemplate) Tables() ([]api.Table, error)
- func (s *RecordLayerSchemaTemplate) TemporaryInvokedRoutines() ([]api.InvokedRoutine, error)
- func (s *RecordLayerSchemaTemplate) TransactionBoundMetadataAsString() (string, error)
- func (s *RecordLayerSchemaTemplate) Underlying() *recordlayer.RecordMetaData
- func (s *RecordLayerSchemaTemplate) Version() int
- func (s *RecordLayerSchemaTemplate) Views() ([]api.View, error)
- type RecordLayerTable
- func (t *RecordLayerTable) Accept(v api.Visitor)
- func (t *RecordLayerTable) Columns() []api.Column
- func (t *RecordLayerTable) Indexes() []api.Index
- func (t *RecordLayerTable) MetadataName() string
- func (t *RecordLayerTable) RecordType() *recordlayer.RecordType
- func (t *RecordLayerTable) StructDataType() *api.StructType
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder constructs a RecordLayerSchemaTemplate from SQL-level table definitions without requiring a pre-compiled protobuf FileDescriptor.
Mirrors Java's RecordLayerSchemaTemplate.Builder at the level needed for CREATE SCHEMA TEMPLATE DDL: name, version, tables with typed columns and primary keys, and store-level flags.
func NewSchemaTemplateBuilder ¶
func NewSchemaTemplateBuilder() *Builder
NewSchemaTemplateBuilder returns a Builder with sensible defaults (enableLongRows=true, version=1). Matches Java's default.
func (*Builder) AddAggregateIndex ¶
func (b *Builder) AddAggregateIndex(tableName, indexName string, groupColumns []string, aggType, aggColumn string) *Builder
AddAggregateIndex registers an aggregate index (SUM, COUNT, MIN, MAX) on the named table. groupColumns are the GROUP BY columns; aggColumn is the aggregated column (empty for COUNT). aggType is one of "SUM", "COUNT", "MIN", "MAX".
func (*Builder) AddCardinalityIndex ¶
AddCardinalityIndex registers a CARDINALITY() value index on the named table. cardColumn is the array column whose element count forms the single key column (possibly dotted for an array nested in a struct, e.g. "struct.int_arr"). The index key is built as FunctionExpr("cardinality", field(col, Concatenate)) at materialise time. Must be called after the table is registered via AddTable.
func (*Builder) AddIndex ¶
AddIndex registers a VALUE index on the named table. columns is the ordered list of field names that form the index key. unique causes uniqueness enforcement to be wired into the recordlayer index. Must be called after the table is registered via AddTable. Returns the builder unchanged (and records a deferred error) if the table name is unknown or any column name is not present in the table definition.
func (*Builder) AddTable ¶
func (b *Builder) AddTable(name string, columns []ColumnSpec, primaryKey []string) *Builder
AddTable registers a table definition. columns must be listed in declared order; primaryKey is the ordered slice of column names.
func (*Builder) AddVectorIndex ¶
func (b *Builder) AddVectorIndex(tableName, indexName, vectorColumn string, partitionColumns []string, options map[string]string) *Builder
AddVectorIndex registers a VECTOR (HNSW) index on the named table. vectorColumn is the single indexed vector field; partitionColumns form the HNSW partition prefix (each distinct partition value gets its own independent graph). options carries the HNSW tuning keys (metric, ef_construction, m, ...). The vector column must be declared with a VECTOR(dims, ...) type; the dimension count is derived from it.
Mirrors Java's DdlVisitor.visitVectorIndexDefinition, which requires exactly one indexed column of VECTOR type and derives HNSW_NUM_DIMENSIONS from the column's VectorType. AddVectorIndex registers an HNSW vector index (the default method).
func (*Builder) AddVectorIndexUsing ¶
func (b *Builder) AddVectorIndexUsing(method, tableName, indexName, vectorColumn string, partitionColumns []string, options map[string]string) *Builder
AddVectorIndexUsing registers a vector index with an explicit method: "HNSW" (graph, Java-compatible wire format) or "SPFRESH" (RFC-094 centroid+posting-list, Go-native). SPFresh does not support PARTITION BY.
func (*Builder) Build ¶
func (b *Builder) Build() (*RecordLayerSchemaTemplate, error)
Build materialises the schema template. Returns an error when no tables are registered or types cannot be mapped to proto field types.
func (*Builder) SetEnableLongRows ¶
func (*Builder) SetIntermingleTables ¶
func (*Builder) SetStoreRowVersions ¶
func (*Builder) SetVersion ¶
type ColumnSpec ¶
type ColumnSpec struct {
// contains filtered or unexported fields
}
ColumnSpec describes a single column within a table.
func NewColumnSpec ¶
func NewColumnSpec(name string, dt api.DataType, fieldNum int32) ColumnSpec
NewColumnSpec constructs a ColumnSpec for use with Builder.AddTable.
type RecordLayerColumn ¶
type RecordLayerColumn struct {
// contains filtered or unexported fields
}
RecordLayerColumn adapts a single protobuf field descriptor to the api.Column interface. Zero value is not useful — build via newColumn().
func (*RecordLayerColumn) Accept ¶
func (c *RecordLayerColumn) Accept(v api.Visitor)
Accept dispatches into the Visitor.
func (*RecordLayerColumn) DataType ¶
func (c *RecordLayerColumn) DataType() api.DataType
DataType returns the column's SQL type.
func (*RecordLayerColumn) FieldDescriptor ¶
func (c *RecordLayerColumn) FieldDescriptor() protoreflect.FieldDescriptor
FieldDescriptor exposes the underlying proto field descriptor for callers that need the raw proto view (e.g. wire-format decoding). Not part of api.Column.
func (*RecordLayerColumn) MetadataName ¶
func (c *RecordLayerColumn) MetadataName() string
MetadataName returns the column name.
type RecordLayerIndex ¶
type RecordLayerIndex struct {
// contains filtered or unexported fields
}
RecordLayerIndex adapts a *recordlayer.Index (plus its owning record type name) to api.Index.
Java's RecordLayerIndex.isSparse() returns `predicate != null` — a predicate-filtered index is considered sparse. recordlayer.Index has an equivalent Predicate field, so we apply the same rule.
func (*RecordLayerIndex) Accept ¶
func (i *RecordLayerIndex) Accept(v api.Visitor)
Accept dispatches into the Visitor.
func (*RecordLayerIndex) IndexColumnNames ¶
func (i *RecordLayerIndex) IndexColumnNames() []string
IndexColumnNames returns the field names from the index's root key expression. Satisfies cascades.IndexDef.
func (*RecordLayerIndex) IndexIsUnique ¶
func (i *RecordLayerIndex) IndexIsUnique() bool
IndexIsUnique returns whether the index enforces uniqueness. Satisfies cascades.IndexDef.
func (*RecordLayerIndex) IndexName ¶
func (i *RecordLayerIndex) IndexName() string
IndexName returns the index name. Satisfies cascades.IndexDef.
func (*RecordLayerIndex) IndexPrimaryKeyColumns ¶
func (i *RecordLayerIndex) IndexPrimaryKeyColumns() []string
IndexPrimaryKeyColumns returns nil. This type is only used by the metadata visitor pattern (api.Visitor), never passed to NewPlanContextFromIndexDefs. The production Cascades path uses metadataIndexDef (cascades_generator.go) which returns real PK columns. Satisfies cascades.IndexDef.
func (*RecordLayerIndex) IndexRecordTypes ¶
func (i *RecordLayerIndex) IndexRecordTypes() []string
IndexRecordTypes returns the owning record type. Satisfies cascades.IndexDef.
func (*RecordLayerIndex) IndexType ¶
func (i *RecordLayerIndex) IndexType() string
IndexType returns the record-layer index-type constant ("VALUE", "COUNT", "SUM", "RANK", ...).
func (*RecordLayerIndex) IsSparse ¶
func (i *RecordLayerIndex) IsSparse() bool
IsSparse matches Java's RecordLayerIndex.isSparse() which is "predicate != null" — a predicate-filtered index is sparse because only records matching the predicate have entries.
func (*RecordLayerIndex) IsUnique ¶
func (i *RecordLayerIndex) IsUnique() bool
IsUnique delegates to the underlying recordlayer.Index, which reads IndexOptions.UNIQUE_OPTION — matches Java's Index.isUnique().
func (*RecordLayerIndex) MetadataName ¶
func (i *RecordLayerIndex) MetadataName() string
MetadataName returns the index name.
func (*RecordLayerIndex) TableName ¶
func (i *RecordLayerIndex) TableName() string
TableName returns the name of the record type (table) this index belongs to. For universal indexes the name is empty — callers that care must check HasUniversalOwner() or inspect the metadata.
func (*RecordLayerIndex) Underlying ¶
func (i *RecordLayerIndex) Underlying() *recordlayer.Index
Underlying exposes the record-layer Index for callers that need access to its root expression, options, version metadata, etc.
type RecordLayerSchemaTemplate ¶
type RecordLayerSchemaTemplate struct {
// contains filtered or unexported fields
}
RecordLayerSchemaTemplate is the concrete api.SchemaTemplate backed by a *recordlayer.RecordMetaData.
Construction materialises every table + index up front so lookups are O(1) and the template is safe for concurrent reads. The underlying RecordMetaData is assumed immutable (matching Java's RecordMetaData invariant).
Views / invoked routines / temporary routines are stub-empty — record-layer has no native equivalents, and the SQL-level stores for them land in a later phase (catalog storage layer). Same for the transaction-bound diagnostic string.
func NewRecordLayerSchemaTemplate ¶
func NewRecordLayerSchemaTemplate(name string, md *recordlayer.RecordMetaData) (*RecordLayerSchemaTemplate, error)
NewRecordLayerSchemaTemplate builds the bridge with the underlying RecordMetaData's version. Equivalent to Java's RecordLayerSchemaTemplate.fromRecordMetadata(md, name, md.getVersion()). Use NewRecordLayerSchemaTemplateWithVersion when the catalog-level version should differ from the storage-level version.
Returns an error when md is nil so callers at boundary layers (DSN parsing, RPC handlers) get a clean failure rather than a panic.
func NewRecordLayerSchemaTemplateWithVersion ¶
func NewRecordLayerSchemaTemplateWithVersion(name string, md *recordlayer.RecordMetaData, version int) (*RecordLayerSchemaTemplate, error)
NewRecordLayerSchemaTemplateWithVersion mirrors Java's RecordMetadataDeserializer.getSchemaTemplate(name, version): the schema-template version is independent of RecordMetaData.Version(), which the record-layer storage engine uses for its own bookkeeping. The catalog bumps the template version on every DDL change, and that number is what api.SchemaTemplate.Version() reports.
func (*RecordLayerSchemaTemplate) Accept ¶
func (s *RecordLayerSchemaTemplate) Accept(v api.Visitor)
Accept runs Java's visitor cascade:
startVisit → visit → <tables.accept> → <routines.accept> → <views.accept> → finishVisit
Matches RecordLayerSchemaTemplate.accept() in the Java tree. The package-level api.VisitSchemaTemplateTree only handles the start/visit/finish triple — it cannot iterate children because api.SchemaTemplate returns typed child collections (Tables/Views/ Routines) via methods that can error. We override here so the cascade matches Java behaviour.
func (*RecordLayerSchemaTemplate) EnableLongRows ¶
func (s *RecordLayerSchemaTemplate) EnableLongRows() bool
EnableLongRows delegates to the underlying metadata's splitLongRecords flag.
func (*RecordLayerSchemaTemplate) FindInvokedRoutine ¶
func (s *RecordLayerSchemaTemplate) FindInvokedRoutine(_ string) (api.InvokedRoutine, error)
FindInvokedRoutine returns (nil, nil).
func (*RecordLayerSchemaTemplate) FindTable ¶
func (s *RecordLayerSchemaTemplate) FindTable(name string) (api.Table, error)
FindTable looks up a table by exact name; returns (nil, nil) when not found.
func (*RecordLayerSchemaTemplate) FindView ¶
func (s *RecordLayerSchemaTemplate) FindView(_ string) (api.View, error)
FindView returns (nil, nil) — same rationale as Views.
func (*RecordLayerSchemaTemplate) GenerateSchema ¶
func (s *RecordLayerSchemaTemplate) GenerateSchema(databaseID, schemaName string) api.Schema
GenerateSchema materialises an api.Schema bound to databaseID + schemaName. Mirrors Java's factory method.
func (*RecordLayerSchemaTemplate) Indexes ¶
func (s *RecordLayerSchemaTemplate) Indexes() ([]string, error)
Indexes returns every index name declared in this template, in sorted order. Matches Java's flat-list semantics.
func (*RecordLayerSchemaTemplate) IntermingleTables ¶
func (s *RecordLayerSchemaTemplate) IntermingleTables() bool
IntermingleTables mirrors Java's RecordLayerSchemaTemplate.isIntermingleTables() which is !RecordMetaData.primaryKeyHasRecordTypePrefix(). When the underlying metadata has no RecordTypeKey prefix on primary keys, rows from different record types share the same keyspace prefix and the SQL layer treats them as intermingled.
func (*RecordLayerSchemaTemplate) InvokedRoutines ¶
func (s *RecordLayerSchemaTemplate) InvokedRoutines() ([]api.InvokedRoutine, error)
InvokedRoutines is always empty — stored routines (UDFs) are a SQL-layer concept not backed by record-layer.
func (*RecordLayerSchemaTemplate) MetadataName ¶
func (s *RecordLayerSchemaTemplate) MetadataName() string
MetadataName returns the template name provided at construction.
func (*RecordLayerSchemaTemplate) StoreRowVersions ¶
func (s *RecordLayerSchemaTemplate) StoreRowVersions() bool
StoreRowVersions delegates to the underlying metadata's storeRecordVersions flag.
func (*RecordLayerSchemaTemplate) TableIndexMapping ¶
func (s *RecordLayerSchemaTemplate) TableIndexMapping() (map[string][]string, error)
TableIndexMapping returns a map of tableName → index names. Deterministic: both outer keys and inner slices are sorted.
func (*RecordLayerSchemaTemplate) Tables ¶
func (s *RecordLayerSchemaTemplate) Tables() ([]api.Table, error)
Tables returns the tables in deterministic (sorted-by-name) order. Error slot is reserved for future catalog-backed implementations; this bridge never returns an error.
func (*RecordLayerSchemaTemplate) TemporaryInvokedRoutines ¶
func (s *RecordLayerSchemaTemplate) TemporaryInvokedRoutines() ([]api.InvokedRoutine, error)
TemporaryInvokedRoutines is always empty.
func (*RecordLayerSchemaTemplate) TransactionBoundMetadataAsString ¶
func (s *RecordLayerSchemaTemplate) TransactionBoundMetadataAsString() (string, error)
TransactionBoundMetadataAsString is a diagnostic string. The Java side tags each transaction-bound piece; we have none, so return an empty string.
func (*RecordLayerSchemaTemplate) Underlying ¶
func (s *RecordLayerSchemaTemplate) Underlying() *recordlayer.RecordMetaData
Underlying exposes the record-layer metadata for callers that need proto-descriptor-level access (e.g. the query executor).
func (*RecordLayerSchemaTemplate) Version ¶
func (s *RecordLayerSchemaTemplate) Version() int
Version returns the schema-template version. Matches Java's SchemaTemplate.getVersion() — independent from RecordMetaData.getVersion(); the caller passes the catalog-level version to NewRecordLayerSchemaTemplateWithVersion, or NewRecordLayerSchemaTemplate uses RecordMetaData.Version() as a sensible default.
type RecordLayerTable ¶
type RecordLayerTable struct {
// contains filtered or unexported fields
}
RecordLayerTable adapts a recordlayer.RecordType to api.Table.
The view is computed eagerly at construction so repeated Columns() / StructDataType() calls are cheap; if that becomes a problem we can switch to lazy caching. Current sizes (dozens of fields) make it not worth optimising.
func (*RecordLayerTable) Accept ¶
func (t *RecordLayerTable) Accept(v api.Visitor)
Accept dispatches into the Visitor. The default cascade visits the table itself, then its indexes and columns — mirroring Java's Table.accept().
func (*RecordLayerTable) Columns ¶
func (t *RecordLayerTable) Columns() []api.Column
Columns returns the columns in declared order.
func (*RecordLayerTable) Indexes ¶
func (t *RecordLayerTable) Indexes() []api.Index
Indexes returns the indexes on this table.
func (*RecordLayerTable) MetadataName ¶
func (t *RecordLayerTable) MetadataName() string
MetadataName returns the table (record-type) name.
func (*RecordLayerTable) RecordType ¶
func (t *RecordLayerTable) RecordType() *recordlayer.RecordType
RecordType exposes the underlying record-layer type for callers that need its proto descriptor, primary key, etc.
func (*RecordLayerTable) StructDataType ¶
func (t *RecordLayerTable) StructDataType() *api.StructType
StructDataType returns the table's composite struct type.