spanalyzer

package module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 12, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

README

spanalyzer

Go Reference

spanalyzer is a Spanner analyzer framework: an experimental Go library and CLI toolkit for deriving Cloud Spanner GoogleSQL query result row types from Spanner DDL, and for building query analysis and code generation workflows on top of that.

The current implementation parses Spanner DDL with github.com/cloudspannerecosystem/memefish and analyzes queries with github.com/goccy/go-googlesql. These are implementation details of the framework, not part of its contract.

This repository was previously named go-googlesql-spanner-poc.

The repository hosts four Go modules, split along dependency weight:

  • github.com/apstndb/spanalyzer — the analyzer framework: DDL catalog, GoogleSQL analysis, type conversion, code generation planning, and the lightweight CLIs (spanner-analyzer, spanner-function-catalog). Depends on memefish and the GoogleSQL frontend, but not on container tooling.
  • github.com/apstndb/spanalyzer/plancontract — a lightweight nested module that normalizes raw spannerpb.QueryPlan values (operator family classification, operator topology, plan digests) and evaluates plan contracts against them. It works with plans obtained from Cloud Spanner, the emulator, Spanner Omni, or saved artifacts, and depends only on the Spanner protos, CEL, and YAML — not on the GoogleSQL frontend or containers.
  • github.com/apstndb/spanalyzer/cmd/spanner-query-gen — the query code generation CLI, including the Omni-backed plan-report workflow and integration tests. This is where spanemuboost, testcontainers, and the Docker client enter the dependency graph.
  • github.com/apstndb/spanalyzer/tools — developer-only Spanner Omni probes (spanner-query-plan-shape, optparam-plan-probe), with the same container-tooling dependencies.

Development across modules uses the committed go.work workspace.

In this document, "GoogleSQL frontend" refers to the analyzer and catalog library formerly named ZetaSQL. "Spanner GoogleSQL" refers to Cloud Spanner's SQL dialect. Historical ZetaSQL names appear only when referring to upstream API names or repositories that still use them.

Usage

go run ./cmd/spanner-analyzer \
  --ddl testdata/order-proto-schema.sql \
  --proto-descriptors-file testdata/protos/order_descriptors.pb \
  --sql 'SELECT OrderInfo.order_number FROM Orders'

Output excerpt:

fields:
- name: order_number
  type:
    code: STRING

--proto-descriptors-file accepts a Protocol Buffers FileDescriptorSet used to resolve types named by CREATE PROTO BUNDLE or ALTER PROTO BUNDLE. The flag is repeatable.

--ddl is optional. Queries that only use built-in functions, parameters, INFORMATION_SCHEMA, or SPANNER_SYS can be analyzed without a schema file:

go run ./cmd/spanner-analyzer \
  --sql 'SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES'

Registered GoogleSQL frontend and Spanner function signatures can be dumped with the dedicated function catalog command:

go run ./cmd/spanner-function-catalog

Use --verbose=false to print only function names. --ddl and --proto-descriptors-file are also accepted when the catalog depends on schema objects or proto descriptors.

Developer-only probes live under tools/. For example, tools/spanner-query-plan-shape starts Spanner Omni through spanemuboost and prints raw query plan node shapes for plan normalization work. Long-form investigation notes and review archives live under research/; they are non-normative supporting material rather than the public CLI contract.

The repository includes the Protocol Buffers example from the Cloud Spanner protocol buffers reference under testdata/protos/, including order_protos.proto and its compiled order_descriptors.pb descriptor set.

Named query parameters can be declared with --param name=TYPE. Positional parameters can be declared with repeatable --positional-param TYPE.

go run ./cmd/spanner-analyzer \
  --sql 'SELECT @id AS id' \
  --param id=INT64

More complex queries can mix aggregate functions, conditional expressions, and proto field access. The output is still the Cloud Spanner result row type, not query data.

go run ./cmd/spanner-analyzer \
  --ddl testdata/order-proto-schema.sql \
  --proto-descriptors-file testdata/protos/order_descriptors.pb \
  --sql '
    SELECT
      COUNT(*) AS order_count,
      SUM(Id) AS id_sum,
      AVG(Id) AS avg_id,
      IF(COUNT(*) > 0, "nonempty", "empty") AS status,
      CASE WHEN MAX(Id) >= 100 THEN "large" ELSE "small" END AS id_bucket,
      COALESCE(MIN(OrderInfo.order_number), "none") AS first_order_number
    FROM Orders'

Output:

fields:
- name: order_count
  type:
    code: INT64
- name: id_sum
  type:
    code: INT64
- name: avg_id
  type:
    code: FLOAT64
- name: status
  type:
    code: STRING
- name: id_bucket
  type:
    code: STRING
- name: first_order_number
  type:
    code: STRING

--sql-mode expression analyzes a single GoogleSQL expression and returns a single Spanner Type instead of a query result row type.

go run ./cmd/spanner-analyzer \
  --sql-mode expression \
  --sql 'AI.SCORE(@prompt)' \
  --param 'prompt=STRING(MAX)'

Output:

code: FLOAT64

Polymorphic functions resolve their return type from the argument type.

go run ./cmd/spanner-analyzer \
  --sql-mode expression \
  --sql 'ARRAY_FIRST([1, 2, 3])'

Output:

code: INT64
go run ./cmd/spanner-analyzer \
  --sql-mode expression \
  --sql 'ARRAY_FIRST(["a", "b"])'

Output:

code: STRING

Cloud Spanner INFORMATION_SCHEMA tables are registered as built-in catalog tables for analysis. They provide names and column types only; no row data is materialized.

go run ./cmd/spanner-analyzer \
  --sql 'SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, SPANNER_TYPE
         FROM INFORMATION_SCHEMA.COLUMNS'

Cloud Spanner SPANNER_SYS introspection tables are also registered as built-in catalog tables. They are useful for type-checking monitoring queries and statistics helpers such as SPANNER_SYS.DISTRIBUTION_PERCENTILE.

go run ./cmd/spanner-analyzer \
  --sql 'SELECT
           INTERVAL_END,
           TABLE_NAME,
           READ_QUERY_COUNT
         FROM SPANNER_SYS.TABLE_OPERATIONS_STATS_MINUTE'
go run ./cmd/spanner-analyzer \
  --sql 'SELECT
           SPANNER_SYS.DISTRIBUTION_PERCENTILE(LATENCY_DISTRIBUTION[OFFSET(0)], 99.0) AS p99
         FROM SPANNER_SYS.QUERY_STATS_TOTAL_10MINUTE'

The Spanner lock statistics documentation uses a join between transaction and lock statistics tables. The same shape can be analyzed without DDL:

go run ./cmd/spanner-analyzer \
  --sql 'SELECT
           t.INTERVAL_END,
           t.AVG_COMMIT_LATENCY_SECONDS,
           l.TOTAL_LOCK_WAIT_SECONDS
         FROM SPANNER_SYS.TXN_STATS_TOTAL_10MINUTE AS t
         LEFT JOIN SPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE AS l
           ON t.INTERVAL_END = l.INTERVAL_END
         ORDER BY t.INTERVAL_END'

The CLI also exposes selected GoogleSQL analyzer options from execute_query_tool, including --product-mode, --strict-name-resolution, --fold-literal-cast, --prune-unused-columns, and --parse-location-record-type. The default --product-mode is external, matching Cloud Spanner's public GoogleSQL dialect. --mode=spanner_type emits the Cloud Spanner type protobuf as YAML by default. YAML output is produced by converting the protojson result with github.com/goccy/go-yaml. Use --output json or --output textproto to emit another protobuf format.

go run ./cmd/spanner-analyzer \
  --sql-mode expression \
  --sql '1'

Output:

code: INT64

JSON output is still available:

go run ./cmd/spanner-analyzer \
  --sql-mode expression \
  --sql '1' \
  --output json

Output:

{
  "code": "INT64"
}

--mode=go_struct emits Go code for a struct that can receive query result rows. Use --go-client=bigquery, --go-client=spanner, or --go-client=both to choose struct tags and field types. The default is both, which emits both bigquery and spanner tags. In both mode the generator keeps one field per result column and emits a small NullValue[T] helper so the same DTO can be loaded from BigQuery with bigquery.ValueLoader and from Spanner with spanner.Decoder.

go run ./cmd/spanner-analyzer \
  --mode go_struct \
  --sql 'SELECT 1 AS n'

Output excerpt:

package main

import (
	"cloud.google.com/go/bigquery"
	"fmt"
)

type QueryRow struct {
	N NullValue[int64] `bigquery:"n" spanner:"n"`
}

func (r *QueryRow) Load(values []bigquery.Value, schema bigquery.Schema) error {
	if len(values) != len(schema) {
		return fmt.Errorf("bigquery row has %d values for %d schema fields", len(values), len(schema))
	}
	for i, field := range schema {
		switch field.Name {
		case "n":
			if err := r.N.LoadBigQuery(values[i]); err != nil {
				return fmt.Errorf("n: %w", err)
			}
		}
	}
	return nil
}

type NullValue[T any] struct {
	Value T
	Valid bool
}

func (n NullValue[T]) IsNull() bool {
	return !n.Valid
}

func (n *NullValue[T]) LoadBigQuery(value bigquery.Value) error {
	return n.set(value)
}

func (n *NullValue[T]) DecodeSpanner(input interface{}) error {
	return n.set(input)
}

func (n *NullValue[T]) set(value interface{}) error {
	if value == nil {
		var zero T
		n.Value = zero
		n.Valid = false
		return nil
	}
	typed, ok := value.(T)
	if !ok {
		return fmt.Errorf("cannot decode %T", value)
	}
	n.Value = typed
	n.Valid = true
	return nil
}

BigQuery mode is also available. It analyzes BigQuery GoogleSQL queries against BigQuery DDL and emits a BigQuery REST TableSchema shaped result. The default mode for --dialect=bigquery is --mode=bigquery_type.

go run ./cmd/spanner-analyzer \
  --dialect bigquery \
  --sql 'SELECT 1 AS n, ["a", "b"] AS tags'

Output:

fields:
- name: "n"
  type: INTEGER
  mode: NULLABLE
- name: tags
  type: STRING
  mode: REPEATED

BigQuery and Spanner use different GoogleSQL feature sets. For example, BigQuery mode accepts pipe query syntax, while the default Spanner mode rejects it.

go run ./cmd/spanner-analyzer \
  --dialect bigquery \
  --sql 'FROM UNNEST([STRUCT("apples" AS item, 2 AS sales, "fruit" AS category),
                      STRUCT("carrots", 8, "vegetable"),
                      STRUCT("apples", 7, "fruit")]) AS produce
         |> WHERE category = "fruit"
         |> AGGREGATE COUNT(*) AS num_items, SUM(sales) AS total_sales
            GROUP BY item
         |> ORDER BY item'

Output:

fields:
- name: item
  type: STRING
  mode: NULLABLE
- name: num_items
  type: INTEGER
  mode: NULLABLE
- name: total_sales
  type: INTEGER
  mode: NULLABLE

BigQuery DDL is analyzed by the GoogleSQL frontend, so BigQuery table schemas can use nested STRUCT, repeated ARRAY, JSON, BIGNUMERIC, and RANGE<DATE|DATETIME|TIMESTAMP> types.

go run ./cmd/spanner-analyzer \
  --dialect bigquery \
  --ddl bigquery-schema.sql \
  --sql 'SELECT customer_id, profile, events FROM mydataset.customers'

For BigQuery-to-Spanner federated queries that use EXTERNAL_QUERY, pass BigQuery DDL and Spanner DDL for each BigQuery connection ID. The analyzer provides a EXTERNAL_QUERY table-valued function that returns the row type inferred from the inner Spanner query using the connection-specific Spanner catalog.

go run ./cmd/spanner-analyzer \
  --dialect bigquery \
  --ddl bigquery-schema.sql \
  --external-ddl my-project.us.example-db=spanner-schema.sql \
  --sql "SELECT c.customer_id, rq.first_order_date
         FROM mydataset.customers AS c
         LEFT JOIN EXTERNAL_QUERY(
           'my-project.us.example-db',
           '''SELECT CustomerId AS customer_id, MIN(OrderDate) AS first_order_date
              FROM Orders
              GROUP BY CustomerId''') AS rq
           ON rq.customer_id = c.customer_id"

If the Spanner schema uses PROTO BUNDLE, provide descriptor sets for the same connection. Proto fields are available while analyzing that connection's inner Spanner SQL, but top-level PROTO values still cannot be returned through BigQuery EXTERNAL_QUERY.

go run ./cmd/spanner-analyzer \
  --dialect bigquery \
  --external-ddl example-project.asia-northeast1.example-connection=testdata/order-proto-schema.sql \
  --external-proto-descriptors-file example-project.asia-northeast1.example-connection=testdata/protos/order_descriptors.pb \
  --sql "SELECT * FROM EXTERNAL_QUERY(
           'example-project.asia-northeast1.example-connection',
           '''SELECT OrderInfo.order_number, OrderInfo.shipping_address.city FROM Orders''')"

Output:

fields:
- name: order_number
  type: STRING
  mode: NULLABLE
- name: city
  type: STRING
  mode: NULLABLE

--mode is inspired by GoogleSQL execute_query modes. The default --mode=spanner_type returns the Cloud Spanner row type for query mode, or a single Cloud Spanner type for expression mode. With --dialect=bigquery, the default --mode=bigquery_type returns a BigQuery TableSchema shaped schema. --mode=parse prints the parser AST, --mode=analyze prints the resolved AST debug string like GoogleSQL execute_query analyze mode, --mode=unparse prints parser AST converted back to SQL, and --mode=go_struct prints Go result struct code. Modes can be comma-separated, for example --mode=parse,analyze,spanner_type.

GoogleSQL is initialized once per process through go-googlesql.

Dialect feature presets start from GoogleSQL EnableMaximumLanguageFeaturesForDevelopment() and then disable features that are not available in the selected dialect. Use --enable-maximum-development-language-features to skip that blacklist and try raw development features, for example when validating a newly released Spanner feature before this project has updated its preset.

Library components

The public API is intentionally split into composable steps:

  • BuildSchemaCatalog parses Spanner DDL into this project's Spanner schema catalog.
  • BuildGoogleSQLCatalogFromSpannerCatalog and BuildGoogleSQLCatalogFromDDL convert that schema into a GoogleSQL frontend catalog, analyzer options, and type factory.
  • BuildBigQueryGoogleSQLCatalogFromDDL converts BigQuery DDL into a GoogleSQL frontend catalog.
  • GoogleSQLHelper wraps parse, analyze, unparse, and resolved AST debug operations against that catalog.
  • RowTypeFromAnalyzerOutput, RowTypeFromResolvedQuery, and TypeFromAnalyzerOutput convert GoogleSQL analyzer results into Cloud Spanner protobuf metadata.
  • BigQueryTableSchemaFromAnalyzerOutput, BigQueryTableSchemaFromResolvedQuery, and BigQueryTableFieldSchemaFromGoogleSQLType convert GoogleSQL analyzer types into BigQuery REST TableSchema shaped metadata.
  • Analyzer remains a convenience wrapper that wires these components together for the CLI-style row type use case.
  • BigQueryAnalyzer does the same for BigQuery TableSchema output. Connection-specific Spanner analyzers can be attached with SetExternalQueryAnalyzers to infer EXTERNAL_QUERY result schemas.

License

This project is licensed under the Apache License 2.0.

The source distribution does not vendor github.com/goccy/go-googlesql or its embedded googlesql.wasm artifact. Binary distributions built from this project do include that dependency transitively, so distributors should include the relevant third-party license notices for at least:

If future releases vendor dependencies or attach compiled binaries, add the corresponding third-party license and NOTICE material to those release artifacts.

Limitations

  • PROTO BUNDLE support requires descriptor set files. DDL alone is not enough to analyze proto fields.
  • Cloud Spanner and the Cloud Spanner emulator use the GoogleSQL frontend's native MakeProtoType and MakeEnumType APIs with descriptors from the active proto bundle. This project now loads the supplied descriptor set into the GoogleSQL frontend descriptor pool and uses those native proto and enum types when building the analyzer catalog.
  • Proto and enum query outputs are converted back to Spanner row metadata when possible, including nested proto fields selected as values.
  • Property graph DDL registers node and edge tables, labels, and direct column property definitions through the go-googlesql v0.2.0 SimpleGraph* constructors. More advanced Spanner graph metadata, including arbitrary property expressions and dynamic labels/properties, is still limited.
  • Some Spanner-specific functions are registered locally because they are not included in the default go-googlesql builtin function set. This includes commit timestamp, sequence, search, TOKENLIST, and AI helper functions needed for query analysis.
  • ML.PREDICT is registered as an analyzer-only table-valued function. It models schema only, returns model output columns followed by non-duplicated input relation columns, and does not execute prediction logic. It supports ML.PREDICT, PREDICT, and SAFE.ML.PREDICT names.
  • TOKENLIST is supported as an internal analysis type for search expressions, but Cloud Spanner result sets cannot return TOKENLIST, so the Cloud Spanner protobuf API has no TypeCode for it.
  • Named arguments for locally registered Spanner functions are normalized before analysis because the current Go binding does not expose the GoogleSQL frontend's argument name setters.
  • BigQuery mode currently registers ordinary BigQuery tables and views from DDL but does not model every DDL side effect. Dataset DDL, indexes, and drops are ignored because they do not change query result types in the current catalog model.
  • BigQuery bigquery_type output is derived from resolved GoogleSQL types. It can represent repeated and nested fields, but query result nullability is not tracked, so non-repeated query output fields are emitted as NULLABLE.
  • BigQuery-to-Spanner federated queries use the EXTERNAL_QUERY table-valued function. The current implementation identifies EXTERNAL_QUERY calls by literal connection and SQL arguments and delegates row type inference to the matching Spanner analyzer. It does not evaluate connection options, permissions, PostgreSQL-dialect Spanner SQL, or non-literal dynamic SQL expressions.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrStatementHasNoRowType = errors.New("statement has no row type")

Functions

func InitGoogleSQL

func InitGoogleSQL() error

func RowTypeFromAnalyzerOutput

func RowTypeFromAnalyzerOutput(out *googlesql.AnalyzerOutput, schema *Catalog) (*spannerpb.StructType, error)

func RowTypeFromResolvedQuery

func RowTypeFromResolvedQuery(query *googlesql.ResolvedQueryStmt, schema *Catalog) (*spannerpb.StructType, error)

func SpannerTypeFromGoogleSQLType

func SpannerTypeFromGoogleSQLType(t googlesql.Googlesql_TypeNode) (*spannerpb.Type, error)

func TypeFromAnalyzerOutput

func TypeFromAnalyzerOutput(out *googlesql.AnalyzerOutput) (*spannerpb.Type, error)

Types

type Analyzer

type Analyzer struct {
	// contains filtered or unexported fields
}

func NewAnalyzer

func NewAnalyzer(schema *Catalog) (*Analyzer, error)

func NewAnalyzerFromDDL

func NewAnalyzerFromDDL(path, ddlSQL string) (*Analyzer, error)

func NewAnalyzerFromDDLWithOptions

func NewAnalyzerFromDDLWithOptions(path, ddlSQL string, options ...AnalyzerOption) (*Analyzer, error)

func NewAnalyzerFromDDLWithProtoDescriptorFiles

func NewAnalyzerFromDDLWithProtoDescriptorFiles(path, ddlSQL string, protoDescriptorPaths []string) (*Analyzer, error)

func NewAnalyzerFromDDLWithProtoDescriptorFilesAndOptions

func NewAnalyzerFromDDLWithProtoDescriptorFilesAndOptions(path, ddlSQL string, protoDescriptorPaths []string, options ...AnalyzerOption) (*Analyzer, error)

func NewAnalyzerFromGoogleSQLCatalog

func NewAnalyzerFromGoogleSQLCatalog(googleSQLCatalog *GoogleSQLCatalog) (*Analyzer, error)

func NewAnalyzerWithOptions

func NewAnalyzerWithOptions(schema *Catalog, options ...AnalyzerOption) (*Analyzer, error)

func (*Analyzer) AddPositionalQueryParameter

func (a *Analyzer) AddPositionalQueryParameter(spec *TypeSpec) error

func (*Analyzer) AddQueryParameter

func (a *Analyzer) AddQueryParameter(name string, spec *TypeSpec) error

func (*Analyzer) FunctionCatalogDebugString

func (a *Analyzer) FunctionCatalogDebugString(verbose bool) (string, error)

func (*Analyzer) ParseDebugString

func (a *Analyzer) ParseDebugString(sqlMode, sql string) (string, error)

func (*Analyzer) ResolvedASTDebugString

func (a *Analyzer) ResolvedASTDebugString(sqlMode, sql string) (string, error)

func (*Analyzer) RowTypeForExpression

func (a *Analyzer) RowTypeForExpression(sql string) (*spannerpb.StructType, error)

func (*Analyzer) RowTypeForStatement

func (a *Analyzer) RowTypeForStatement(sql string) (*spannerpb.StructType, error)

func (*Analyzer) TypeForExpression

func (a *Analyzer) TypeForExpression(sql string) (*spannerpb.Type, error)

func (*Analyzer) Unparse

func (a *Analyzer) Unparse(sqlMode, sql string) (string, error)

type AnalyzerOption

type AnalyzerOption func(*analyzerConfig)

func WithFoldLiteralCast

func WithFoldLiteralCast(enabled bool) AnalyzerOption

func WithMaximumDevelopmentLanguageFeatures

func WithMaximumDevelopmentLanguageFeatures(enabled bool) AnalyzerOption

func WithParseLocationRecordType

func WithParseLocationRecordType(recordType googlesql.ParseLocationRecordType) AnalyzerOption

func WithProductMode

func WithProductMode(mode googlesql.ProductMode) AnalyzerOption

func WithPruneUnusedColumns

func WithPruneUnusedColumns(enabled bool) AnalyzerOption

func WithStrictNameResolution

func WithStrictNameResolution(enabled bool) AnalyzerOption

type BigQueryAnalyzer

type BigQueryAnalyzer struct {
	// contains filtered or unexported fields
}

BigQueryAnalyzer analyzes BigQuery GoogleSQL statements and returns BigQuery REST TableSchema-shaped metadata.

func NewBigQueryAnalyzerFromDDL

func NewBigQueryAnalyzerFromDDL(path, ddlSQL string, options ...AnalyzerOption) (*BigQueryAnalyzer, error)

NewBigQueryAnalyzerFromDDL builds a BigQuery analyzer from BigQuery DDL.

func NewBigQueryAnalyzerFromGoogleSQLCatalog

func NewBigQueryAnalyzerFromGoogleSQLCatalog(catalog *BigQueryGoogleSQLCatalog) (*BigQueryAnalyzer, error)

NewBigQueryAnalyzerFromGoogleSQLCatalog wraps an existing BigQuery GoogleSQL catalog.

func (*BigQueryAnalyzer) AddQueryParameter

func (a *BigQueryAnalyzer) AddQueryParameter(name string, spec *TypeSpec) error

func (*BigQueryAnalyzer) AddSpannerExternalDataset

func (a *BigQueryAnalyzer) AddSpannerExternalDataset(dataset, spannerSource string, catalog *Catalog) (*BigQuerySpannerExternalDatasetBinding, error)

AddSpannerExternalDataset registers a BigQuery-visible projection of Spanner tables under dataset. It models BigQuery Spanner external datasets for static analysis only; it does not create BigQuery datasets or Spanner connections.

func (*BigQueryAnalyzer) AddSpannerExternalDatasetWithOptions

func (a *BigQueryAnalyzer) AddSpannerExternalDatasetWithOptions(dataset, spannerSource string, catalog *Catalog, options BigQuerySpannerExternalDatasetOptions) (*BigQuerySpannerExternalDatasetBinding, error)

AddSpannerExternalDatasetWithOptions registers a BigQuery-visible projection of Spanner tables under dataset with explicit static-analysis metadata.

func (*BigQueryAnalyzer) ParseDebugString

func (a *BigQueryAnalyzer) ParseDebugString(sqlMode, sql string) (string, error)

ParseDebugString returns the parser AST debug string.

func (*BigQueryAnalyzer) ResolvedASTDebugString

func (a *BigQueryAnalyzer) ResolvedASTDebugString(sqlMode, sql string) (string, error)

ResolvedASTDebugString returns the resolved AST debug string.

func (*BigQueryAnalyzer) SetExternalQueryAnalyzers

func (a *BigQueryAnalyzer) SetExternalQueryAnalyzers(analyzers map[string]*Analyzer)

SetExternalQueryAnalyzers sets Spanner analyzers keyed by BigQuery connection ID for EXTERNAL_QUERY result schema inference.

func (*BigQueryAnalyzer) TableSchemaForExpression

func (a *BigQueryAnalyzer) TableSchemaForExpression(sql string) (*BigQueryTableSchema, error)

TableSchemaForExpression analyzes a single expression and returns a one-field BigQuery TableSchema-shaped result schema.

func (*BigQueryAnalyzer) TableSchemaForStatement

func (a *BigQueryAnalyzer) TableSchemaForStatement(sql string) (*BigQueryTableSchema, error)

TableSchemaForStatement analyzes a query statement and returns a BigQuery REST TableSchema-shaped result schema.

func (*BigQueryAnalyzer) Unparse

func (a *BigQueryAnalyzer) Unparse(sqlMode, sql string) (string, error)

Unparse returns SQL generated from the parser AST.

type BigQueryDataPolicyOption

type BigQueryDataPolicyOption struct {
	Name string `json:"name,omitempty"`
}

BigQueryDataPolicyOption mirrors the REST dataPolicies entry shape.

type BigQueryDatasetReference

type BigQueryDatasetReference struct {
	Project string `json:"project,omitempty" yaml:"project,omitempty"`
	Dataset string `json:"dataset" yaml:"dataset"`
	Path    string `json:"path" yaml:"path"`
}

type BigQueryFieldElementType

type BigQueryFieldElementType struct {
	Type string `json:"type,omitempty"`
}

BigQueryFieldElementType mirrors the REST fieldElementType object used by RANGE fields.

type BigQueryGoogleSQLCatalog

type BigQueryGoogleSQLCatalog struct {
	SimpleCatalog *googlesql.SimpleCatalog

	AnalyzerOptions *googlesql.AnalyzerOptions
	TypeFactory     *googlesql.TypeFactory
	// contains filtered or unexported fields
}

BigQueryGoogleSQLCatalog contains a GoogleSQL frontend catalog built from BigQuery DDL.

func BuildBigQueryGoogleSQLCatalogFromDDL

func BuildBigQueryGoogleSQLCatalogFromDDL(path, ddlSQL string, options ...AnalyzerOption) (*BigQueryGoogleSQLCatalog, error)

BuildBigQueryGoogleSQLCatalogFromDDL analyzes BigQuery DDL and registers its tables and views in a GoogleSQL frontend catalog.

func (*BigQueryGoogleSQLCatalog) Helper

Helper returns a reusable GoogleSQL helper for this catalog.

type BigQueryPolicyTags

type BigQueryPolicyTags struct {
	Names []string `json:"names,omitempty"`
}

BigQueryPolicyTags mirrors the REST policyTags object.

type BigQuerySpannerExternalDatasetBinding

type BigQuerySpannerExternalDatasetBinding struct {
	Kind                            string                                                         `json:"kind" yaml:"kind"`
	Name                            string                                                         `json:"name,omitempty" yaml:"name,omitempty"`
	BigQueryDataset                 string                                                         `json:"bigquery_dataset" yaml:"bigquery_dataset"`
	BigQueryDatasetRef              BigQueryDatasetReference                                       `json:"bigquery_dataset_ref" yaml:"bigquery_dataset_ref"`
	SpannerSource                   string                                                         `json:"spanner_source" yaml:"spanner_source"`
	SourceSchema                    string                                                         `json:"source_schema" yaml:"source_schema"`
	ExternalSource                  string                                                         `json:"external_source,omitempty" yaml:"external_source,omitempty"`
	Location                        string                                                         `json:"location,omitempty" yaml:"location,omitempty"`
	LocationMetadata                *BigQuerySpannerExternalDatasetLocationMetadata                `json:"location_metadata,omitempty" yaml:"location_metadata,omitempty"`
	Connection                      string                                                         `json:"connection,omitempty" yaml:"connection,omitempty"`
	CloudResourceConnection         string                                                         `json:"cloud_resource_connection,omitempty" yaml:"cloud_resource_connection,omitempty"`
	CloudResourceConnectionMetadata *BigQuerySpannerExternalDatasetCloudResourceConnectionMetadata `json:"cloud_resource_connection_metadata,omitempty" yaml:"cloud_resource_connection_metadata,omitempty"`
	Access                          string                                                         `json:"access_mode,omitempty" yaml:"access_mode,omitempty"`
	DatabaseRole                    string                                                         `json:"database_role,omitempty" yaml:"database_role,omitempty"`
	DatabaseRoleSource              string                                                         `json:"database_role_source,omitempty" yaml:"database_role_source,omitempty"`
	AccessVerification              BigQuerySpannerExternalDatasetVerification                     `json:"access_verification" yaml:"access_verification"`
	RequiresDataBoostAccess         bool                                                           `json:"requires_databoost_access" yaml:"requires_databoost_access"`
	ProjectionPolicy                BigQuerySpannerExternalDatasetProjectionPolicy                 `json:"projection_policy" yaml:"projection_policy"`
	ProjectionMatrix                BigQuerySpannerExternalDatasetProjectionMatrix                 `json:"projection_matrix" yaml:"projection_matrix"`
	Execution                       BigQuerySpannerExternalDatasetExecution                        `json:"execution" yaml:"execution"`
	Limitations                     []string                                                       `json:"limitations,omitempty" yaml:"limitations,omitempty"`
	Warnings                        []QueryCodegenPlanWarning                                      `json:"warnings,omitempty" yaml:"warnings,omitempty"`
	VetSuppressions                 []QueryCodegenPlanVetSuppression                               `json:"vet_suppressions,omitempty" yaml:"vet_suppressions,omitempty"`
	ProjectedTables                 []BigQuerySpannerExternalDatasetTable                          `json:"projected_tables,omitempty" yaml:"projected_tables,omitempty"`
}

type BigQuerySpannerExternalDatasetCloudResourceConnectionMetadata

type BigQuerySpannerExternalDatasetCloudResourceConnectionMetadata struct {
	ID                      string `json:"id,omitempty" yaml:"id,omitempty"`
	ParsedLocation          string `json:"parsed_location,omitempty" yaml:"parsed_location,omitempty"`
	ParsedLocationCanonical string `json:"parsed_location_canonical,omitempty" yaml:"parsed_location_canonical,omitempty"`
	LocationMatch           bool   `json:"location_match,omitempty" yaml:"location_match,omitempty"`
}

type BigQuerySpannerExternalDatasetColumn

type BigQuerySpannerExternalDatasetColumn struct {
	Name                        string `json:"name" yaml:"name"`
	SpannerType                 string `json:"spanner_type,omitempty" yaml:"spanner_type,omitempty"`
	BigQueryType                string `json:"bigquery_type,omitempty" yaml:"bigquery_type,omitempty"`
	Visible                     bool   `json:"visible" yaml:"visible"`
	VisibleInBigQueryMetadata   bool   `json:"visible_in_bigquery_metadata" yaml:"visible_in_bigquery_metadata"`
	UnderlyingSpannerPrimaryKey bool   `json:"underlying_spanner_primary_key,omitempty" yaml:"underlying_spanner_primary_key,omitempty"`
	BigQueryKeyMetadataVisible  bool   `json:"bigquery_key_metadata_visible" yaml:"bigquery_key_metadata_visible"`
	Reason                      string `json:"reason,omitempty" yaml:"reason,omitempty"`
}

type BigQuerySpannerExternalDatasetExecution

type BigQuerySpannerExternalDatasetExecution struct {
	DataBoost     string `json:"data_boost" yaml:"data_boost"`
	QueryPriority string `json:"query_priority" yaml:"query_priority"`
	Writable      bool   `json:"writable" yaml:"writable"`
}

type BigQuerySpannerExternalDatasetLocationMetadata

type BigQuerySpannerExternalDatasetLocationMetadata struct {
	Configured string `json:"configured,omitempty" yaml:"configured,omitempty"`
	Canonical  string `json:"canonical,omitempty" yaml:"canonical,omitempty"`
}

type BigQuerySpannerExternalDatasetOptions

type BigQuerySpannerExternalDatasetOptions struct {
	Project                  string
	DefaultProject           string
	ExternalSource           string
	Location                 string
	Connection               string
	CloudResourceConnection  string
	Access                   string
	DatabaseRole             string
	DatabaseRoleSource       string
	AccessVerificationStatus string
	AccessVerificationSource string
	AccessVerificationHint   string
	AccessVerification       BigQuerySpannerExternalDatasetVerification
	UnsupportedColumns       string
	NamedSchemaPolicy        string
}

type BigQuerySpannerExternalDatasetProjectionMatrix

type BigQuerySpannerExternalDatasetProjectionMatrix struct {
	Source                 string                                              `json:"source" yaml:"source"`
	SourceURL              string                                              `json:"source_url,omitempty" yaml:"source_url,omitempty"`
	DocsLastUpdated        string                                              `json:"docs_last_updated,omitempty" yaml:"docs_last_updated,omitempty"`
	DocsLastChecked        string                                              `json:"docs_last_checked,omitempty" yaml:"docs_last_checked,omitempty"`
	GeneratorMatrixVersion int                                                 `json:"generator_matrix_version" yaml:"generator_matrix_version"`
	Rows                   []BigQuerySpannerExternalDatasetProjectionMatrixRow `json:"rows,omitempty" yaml:"rows,omitempty"`
}

type BigQuerySpannerExternalDatasetProjectionMatrixRow

type BigQuerySpannerExternalDatasetProjectionMatrixRow struct {
	Object          string `json:"object" yaml:"object"`
	Behavior        string `json:"behavior" yaml:"behavior"`
	DefaultSeverity string `json:"default_severity" yaml:"default_severity"`
	EvidenceKind    string `json:"evidence_kind" yaml:"evidence_kind"`
	SourceURL       string `json:"source_url,omitempty" yaml:"source_url,omitempty"`
}

type BigQuerySpannerExternalDatasetProjectionPolicy

type BigQuerySpannerExternalDatasetProjectionPolicy struct {
	UnsupportedColumns string `json:"unsupported_columns" yaml:"unsupported_columns"`
	NamedSchemas       string `json:"named_schemas" yaml:"named_schemas"`
}

type BigQuerySpannerExternalDatasetTable

type BigQuerySpannerExternalDatasetTable struct {
	Name                       string                                 `json:"name" yaml:"name"`
	BigQueryTable              string                                 `json:"bigquery_table" yaml:"bigquery_table"`
	SourceTable                string                                 `json:"source_table" yaml:"source_table"`
	SpannerTable               string                                 `json:"spanner_table" yaml:"spanner_table"`
	Visible                    bool                                   `json:"visible" yaml:"visible"`
	VisibleInBigQueryMetadata  bool                                   `json:"visible_in_bigquery_metadata" yaml:"visible_in_bigquery_metadata"`
	BigQueryKeyMetadataVisible bool                                   `json:"bigquery_key_metadata_visible" yaml:"bigquery_key_metadata_visible"`
	Reason                     string                                 `json:"reason,omitempty" yaml:"reason,omitempty"`
	NameMatching               string                                 `json:"name_matching,omitempty" yaml:"name_matching,omitempty"`
	Columns                    []BigQuerySpannerExternalDatasetColumn `json:"columns,omitempty" yaml:"columns,omitempty"`
}

type BigQuerySpannerExternalDatasetVerification

type BigQuerySpannerExternalDatasetVerification struct {
	Status                           string `json:"status" yaml:"status"`
	Source                           string `json:"source" yaml:"source"`
	ConfiguredHint                   string `json:"configured_hint,omitempty" yaml:"configured_hint,omitempty"`
	CheckedAt                        string `json:"checked_at,omitempty" yaml:"checked_at,omitempty"`
	Verifier                         string `json:"verifier,omitempty" yaml:"verifier,omitempty"`
	EvidenceDigest                   string `json:"evidence_digest,omitempty" yaml:"evidence_digest,omitempty"`
	IndependentlyVerifiedByGenerator bool   `json:"independently_verified_by_generator" yaml:"independently_verified_by_generator"`
	Volatile                         bool   `json:"volatile,omitempty" yaml:"volatile,omitempty"`
}

type BigQueryTableFieldSchema

type BigQueryTableFieldSchema struct {
	Name             string                      `json:"name,omitempty"`
	Type             string                      `json:"type,omitempty"`
	Mode             string                      `json:"mode,omitempty"`
	Fields           []*BigQueryTableFieldSchema `json:"fields,omitempty"`
	RangeElementType *BigQueryFieldElementType   `json:"rangeElementType,omitempty"`
	Description      string                      `json:"description,omitempty"`
	MaxLength        string                      `json:"maxLength,omitempty"`
	Precision        string                      `json:"precision,omitempty"`
	Scale            string                      `json:"scale,omitempty"`
	Collation        string                      `json:"collation,omitempty"`
	DefaultValueExpr string                      `json:"defaultValueExpression,omitempty"`
	PolicyTags       *BigQueryPolicyTags         `json:"policyTags,omitempty"`
	DataPolicies     []*BigQueryDataPolicyOption `json:"dataPolicies,omitempty"`
	RoundingMode     string                      `json:"roundingMode,omitempty"`
}

BigQueryTableFieldSchema mirrors the BigQuery REST TableFieldSchema JSON shape for fields this project can infer from GoogleSQL analyzer types.

func BigQueryTableFieldSchemaFromExpressionAnalyzerOutput

func BigQueryTableFieldSchemaFromExpressionAnalyzerOutput(name string, out *googlesql.AnalyzerOutput) (*BigQueryTableFieldSchema, error)

BigQueryTableFieldSchemaFromExpressionAnalyzerOutput converts a resolved expression to a BigQuery REST TableFieldSchema-shaped field.

func BigQueryTableFieldSchemaFromGoogleSQLType

func BigQueryTableFieldSchemaFromGoogleSQLType(name string, typ googlesql.Googlesql_TypeNode) (*BigQueryTableFieldSchema, error)

BigQueryTableFieldSchemaFromGoogleSQLType converts a GoogleSQL frontend type to a BigQuery REST TableFieldSchema-shaped field.

type BigQueryTableSchema

type BigQueryTableSchema struct {
	Fields []*BigQueryTableFieldSchema `json:"fields,omitempty"`
}

BigQueryTableSchema mirrors the BigQuery REST TableSchema JSON shape.

func BigQueryTableSchemaFromAnalyzerOutput

func BigQueryTableSchemaFromAnalyzerOutput(out *googlesql.AnalyzerOutput) (*BigQueryTableSchema, error)

BigQueryTableSchemaFromAnalyzerOutput converts a resolved query statement to a BigQuery REST TableSchema-shaped schema.

func BigQueryTableSchemaFromResolvedQuery

func BigQueryTableSchemaFromResolvedQuery(query *googlesql.ResolvedQueryStmt) (*BigQueryTableSchema, error)

BigQueryTableSchemaFromResolvedQuery converts a resolved query to a BigQuery REST TableSchema-shaped schema.

type Catalog

type Catalog struct {
	Tables           map[string]*Table
	Indexes          map[string]*Index
	Views            map[string]*View
	ViewOrder        []string
	PropertyGraphs   map[string]*PropertyGraph
	Sequences        map[string]*Sequence
	Models           map[string]*Model
	ProtoTypes       map[string]bool
	ProtoDescriptors *ProtoDescriptorSet
}

func BuildSchemaCatalog

func BuildSchemaCatalog(path, ddlSQL string) (*Catalog, error)

func (*Catalog) ApplyDDL

func (c *Catalog) ApplyDDL(ddl ast.DDL) error

func (*Catalog) LoadProtoDescriptorSetFiles

func (c *Catalog) LoadProtoDescriptorSetFiles(paths []string) error

type Column

type Column struct {
	Name                 string
	Type                 *TypeSpec
	NotNull              bool
	Hidden               bool
	PrimaryKey           bool
	DefaultSQL           string
	GeneratedSQL         string
	OnUpdateSQL          string
	AllowCommitTimestamp bool
}

type GoogleSQLCatalog

type GoogleSQLCatalog struct {
	SpannerCatalog *Catalog
	SimpleCatalog  *googlesql.SimpleCatalog

	AnalyzerOptions *googlesql.AnalyzerOptions
	TypeFactory     *googlesql.TypeFactory
	DescriptorPool  *googlesql.DescriptorPool
	// contains filtered or unexported fields
}

func BuildGoogleSQLCatalogFromDDL

func BuildGoogleSQLCatalogFromDDL(path, ddlSQL string, protoDescriptorPaths []string, options ...AnalyzerOption) (*GoogleSQLCatalog, error)

func BuildGoogleSQLCatalogFromSpannerCatalog

func BuildGoogleSQLCatalogFromSpannerCatalog(schema *Catalog, options ...AnalyzerOption) (*GoogleSQLCatalog, error)

func (*GoogleSQLCatalog) FunctionCatalogDebugString

func (c *GoogleSQLCatalog) FunctionCatalogDebugString(verbose bool) (string, error)

func (*GoogleSQLCatalog) Helper

func (c *GoogleSQLCatalog) Helper() *GoogleSQLHelper

func (*GoogleSQLCatalog) TypeSpecToGoogleSQLType

func (c *GoogleSQLCatalog) TypeSpecToGoogleSQLType(spec *TypeSpec) (googlesql.Googlesql_TypeNode, error)

type GoogleSQLHelper

type GoogleSQLHelper struct {
	Catalog     *googlesql.SimpleCatalog
	Options     *googlesql.AnalyzerOptions
	TypeFactory *googlesql.TypeFactory
}

func (*GoogleSQLHelper) AnalyzeExpression

func (h *GoogleSQLHelper) AnalyzeExpression(sql string) (*googlesql.AnalyzerOutput, error)

func (*GoogleSQLHelper) AnalyzeStatement

func (h *GoogleSQLHelper) AnalyzeStatement(sql string) (*googlesql.AnalyzerOutput, error)

func (*GoogleSQLHelper) Parse

func (h *GoogleSQLHelper) Parse(sqlMode, sql string) (*googlesql.ParserOutput, error)

func (*GoogleSQLHelper) ParseDebugString

func (h *GoogleSQLHelper) ParseDebugString(sqlMode, sql string) (string, error)

func (*GoogleSQLHelper) ResolvedASTDebugString

func (h *GoogleSQLHelper) ResolvedASTDebugString(sqlMode, sql string) (string, error)

func (*GoogleSQLHelper) Unparse

func (h *GoogleSQLHelper) Unparse(sqlMode, sql string) (string, error)

type GraphDerivedProperty

type GraphDerivedProperty struct {
	Name string
	SQL  string
}

type GraphElement

type GraphElement struct {
	Name              string
	Alias             string
	KeyColumns        []string
	Source            *GraphEndpoint
	Destination       *GraphEndpoint
	Labels            []*GraphLabelProperties
	Properties        *GraphProperties
	PropertiesSQL     string
	DynamicLabel      string
	DynamicProperties string
}

type GraphEndpoint

type GraphEndpoint struct {
	KeyColumns       []string
	ElementReference string
	ReferenceColumns []string
}

type GraphLabelProperties

type GraphLabelProperties struct {
	Name          string
	Default       bool
	Properties    *GraphProperties
	PropertiesSQL string
}

type GraphProperties

type GraphProperties struct {
	NoProperties      bool
	AllColumns        bool
	ExceptColumns     []string
	DerivedProperties []*GraphDerivedProperty
}

type Index

type Index struct {
	Name          ObjectName
	TableName     ObjectName
	Keys          []*KeyPart
	StoredColumns []string
	NullFiltered  bool
}

type KeyPart

type KeyPart struct {
	Name string
	Desc bool
}

type Model

type Model struct {
	Name    string
	Inputs  []*ModelColumn
	Outputs []*ModelColumn
}

type ModelColumn

type ModelColumn struct {
	Name string
	Type *TypeSpec
}

type ObjectName

type ObjectName struct {
	Parts []string
}

func (ObjectName) String

func (n ObjectName) String() string

type PropertyGraph

type PropertyGraph struct {
	Name       string
	RawSQL     string
	NodeTables []*GraphElement
	EdgeTables []*GraphElement
}

type ProtoDescriptorSet

type ProtoDescriptorSet struct {
	// contains filtered or unexported fields
}

func LoadProtoDescriptorSetFiles

func LoadProtoDescriptorSetFiles(paths []string) (*ProtoDescriptorSet, error)

type QueryCodegenDiagnosticError

type QueryCodegenDiagnosticError struct {
	ID      string
	Stage   string
	Subject string
	Message string
	Err     error
}

func (QueryCodegenDiagnosticError) Error

func (QueryCodegenDiagnosticError) Unwrap

type QueryCodegenPlanVetSuppression

type QueryCodegenPlanVetSuppression struct {
	Rule    string `json:"rule" yaml:"rule"`
	Reason  string `json:"reason" yaml:"reason"`
	Owner   string `json:"owner,omitempty" yaml:"owner,omitempty"`
	Expires string `json:"expires,omitempty" yaml:"expires,omitempty"`
}

type QueryCodegenPlanWarning

type QueryCodegenPlanWarning struct {
	Rule        string `json:"rule" yaml:"rule"`
	Severity    string `json:"severity" yaml:"severity"`
	Message     string `json:"message" yaml:"message"`
	Remediation string `json:"remediation,omitempty" yaml:"remediation,omitempty"`
}

type Sequence

type Sequence struct {
	Name ObjectName
}

type StructField

type StructField struct {
	Name string
	Type *TypeSpec
}

type Table

type Table struct {
	Name       ObjectName
	Columns    []*Column
	PrimaryKey []*KeyPart
	Synonyms   []string
}

func (*Table) Column

func (t *Table) Column(name string) (*Column, int)

type TypeSpec

type TypeSpec struct {
	Code         spannerpb.TypeCode
	Tokenlist    bool
	ArrayElement *TypeSpec
	StructFields []StructField
	ProtoTypeFQN string
	Length       *int64
	Max          bool
}

TypeSpec is this package's internal schema type representation.

It intentionally sits between Spanner DDL, the GoogleSQL frontend type system, and spannerpb.Type. Spanner DDL contains details that either are not representable in ResultSet Type metadata or are needed before descriptor resolution, such as TOKENLIST columns, STRING/BYTES length modifiers, STRING(MAX), and named proto or enum references from PROTO BUNDLE. Keeping those details here lets the catalog build GoogleSQL analyzer types first and convert only final analyzer results to spannerpb.Type.

func ParseTypeSpec

func ParseTypeSpec(path, typeSQL string) (*TypeSpec, error)

func TypeSpecFromSpannerPB

func TypeSpecFromSpannerPB(t *spannerpb.Type) (*TypeSpec, error)

func (*TypeSpec) SpannerPB

func (t *TypeSpec) SpannerPB() (*spannerpb.Type, error)

type View

type View struct {
	Name  ObjectName
	Query string
}

Directories

Path Synopsis
cmd
internal
optparam
Package optparam models optional query parameters that drive dynamic SQL generation at codegen time.
Package optparam models optional query parameters that drive dynamic SQL generation at codegen time.
plancontract module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL