Documentation
¶
Overview ¶
Package spanpg provides experimental PostgreSQL-dialect helpers around Cloud Spanner: FormatPostgreSQLType for type strings, placeholder/param-key pairing for PostgreSQL SQL text, PostgreSQL literal formatting presets built on github.com/apstndb/spanvalue, thin bridges to existing spanvalue formatting, EncodeOptions adapting github.com/apstndb/spancodec encoding to the PG_NUMERIC / PG_JSONB type annotations the dialect requires on parameters, and PositionalParams / InsertStatement for binding ordered values to $1..$n placeholders.
Behavioral notes (query parameters use cloud.google.com/go/spanner.PGNumeric / cloud.google.com/go/spanner.PGJsonB; row metadata exposes TypeAnnotation on column types) are covered by the nested module `integration/pgtypeannotation` in this repository (see that directory’s README).
Stable cloud.google.com/go/spanner.GenericColumnValue construction remains in github.com/apstndb/spanvalue/gcvctor; [google.spanner.v1.Type] string rendering remains in github.com/apstndb/spantype. PostgreSQL-dialect spellings for cloud.google.com/go/spanner/apiv1/spannerpb.Type are available via FormatPostgreSQLType (see https://docs.cloud.google.com/spanner/docs/reference/postgresql/data-types and https://docs.cloud.google.com/spanner/docs/reference/dialect-differences).
Index ¶
- Variables
- func EncodeOptions() []spancodec.EncodeOption
- func FormatColumnPostgreSQLLiteral(value spanner.GenericColumnValue) (string, error)
- func FormatColumnSimple(gcv spanner.GenericColumnValue) (string, error)
- func FormatPostgreSQLType(typ *sppb.Type) stringdeprecated
- func FormatRowPostgreSQLLiteral(value *spanner.Row) ([]string, error)
- func InsertStatement(table string, columns []string, values []any) (spanner.Statement, error)
- func PositionalParams(values []any) (map[string]any, error)
- func PostgreSQLLiteralFormatConfig() *spanvalue.FormatConfig
- func PostgreSQLPlaceholder(n int) (sql string, ok bool)
- func StatementParamKey(n int) (key string, ok bool)
Constants ¶
This section is empty.
Variables ¶
var ErrUnsupportedPostgreSQLType = errors.New("unsupported PostgreSQL type")
ErrUnsupportedPostgreSQLType reports a Spanner type that cannot be rendered as executable PostgreSQL-dialect SQL because the interface does not support it.
Functions ¶
func EncodeOptions ¶ added in v0.2.0
func EncodeOptions() []spancodec.EncodeOption
EncodeOptions returns github.com/apstndb/spancodec options that adapt encoding to the PostgreSQL dialect: NUMERIC-family and JSON-family Go values produce PG_NUMERIC / PG_JSONB annotated GCVs instead of the GoogleSQL forms. Pass them to github.com/apstndb/spancodec.ValueOf, github.com/apstndb/spancodec.RowTypeFor, github.com/apstndb/spancodec.NewRowEncoder, and friends.
The adaptation is required, not cosmetic: the POSTGRESQL dialect rejects query parameters whose type lacks the annotation. Probe (integration/pgtypeannotation, emulator 1.5.54): binding a GenericColumnValue param with plain code:NUMERIC fails with codes.Unimplemented "Unsupported GoogleSQL Type: NUMERIC", and plain code:JSON fails with "Unsupported GoogleSQL Type: JSON"; the same values with the PG_NUMERIC / PG_JSONB annotation are accepted and the result column metadata echoes the annotation.
Registered mappings (each github.com/apstndb/spancodec.WithValueEncoder is paired with github.com/apstndb/spancodec.WithGoType so static inference — TypeFor, RowTypeFor, RowEncoder.RowType / ResultSetMetadata — carries the annotations too):
- math/big.Rat and *math/big.Rat (nil pointer → typed NULL PG_NUMERIC) → github.com/apstndb/spanvalue/gcvctor.PGNumericValue
- cloud.google.com/go/spanner.NullNumeric → PGNumericValue when Valid, typed NULL PG_NUMERIC otherwise
PGNumericValue formats the wire string with the client's canonical cloud.google.com/go/spanner.NumericString (9 fractional digits, silently rounding) even though PG numeric accepts a wider value space — matching the client mirror's NUMERIC scale. Because these registrations override the client mirror, github.com/apstndb/spancodec.WithLossOfPrecisionHandling does not apply to them. For exact wider-scale values use github.com/apstndb/spanvalue/gcvctor.PGNumericValueExact (spanvalue v0.8.1+) or pass cloud.google.com/go/spanner.PGNumeric wire strings (also the NaN path) directly.
- cloud.google.com/go/spanner.NullJSON → github.com/apstndb/spanvalue/gcvctor.PGJSONBValue of Value when Valid, typed NULL PG_JSONB otherwise. Like the client, Value is always marshaled: a Go string Value becomes a quoted JSON string on the wire; pass wire-format JSON text as encoding/json.RawMessage.
cloud.google.com/go/spanner.PGNumeric and cloud.google.com/go/spanner.PGJsonB already encode with the annotations via the client mirror and are deliberately NOT registered; they pass through unchanged with or without these options.
Hazard model (same as spancodec's): a registration overrides ALL built-in handling for its exact dynamic type only. Named types (e.g. type MyRat big.Rat) and other NUMERIC-capable inputs such as string-based wire values are untouched. Per spancodec's contract a registration for T also applies per element of []T, and the registered Spanner type supplies the ARRAY element type for nil and empty slices, so []big.Rat, []*big.Rat, []spanner.NullNumeric, and []spanner.NullJSON encode as arrays of PG-annotated elements. Since spancodec v0.1.2 static inference also resolves []T from the element registration (apstndb/spancodec#1), so no separate slice-type registrations are needed.
Decoding needs no counterpart: the client (and therefore github.com/apstndb/spancodec.Decode / github.com/apstndb/spancodec.ToStruct) checks only the TypeCode for big.Rat, NullNumeric, and NullJSON destinations, so PG_NUMERIC / PG_JSONB columns decode into them natively (pinned in integration/pgtypeannotation). The one PG-specific decode hazard is the value space, not the type: PG_NUMERIC columns can hold "NaN", which no big.Rat-based destination can represent (the client fails with "unexpected string value"); use cloud.google.com/go/spanner.PGNumeric when NaN is possible.
func FormatColumnPostgreSQLLiteral ¶ added in v0.2.0
func FormatColumnPostgreSQLLiteral(value spanner.GenericColumnValue) (string, error)
FormatColumnPostgreSQLLiteral formats a top-level column using PostgreSQLLiteralFormatConfig.
func FormatColumnSimple ¶
func FormatColumnSimple(gcv spanner.GenericColumnValue) (string, error)
FormatColumnSimple formats a spanner.GenericColumnValue using github.com/apstndb/spanvalue.SimpleFormatConfig (human-readable scalar and container output).
func FormatPostgreSQLType
deprecated
FormatPostgreSQLType renders a sppb.Type using PostgreSQL-dialect spellings.
Deprecated: the spelling table moved to github.com/apstndb/spantype.FormatTypePostgreSQL (spantype v0.3.12+) so type rendering is available without depending on spanpg; this alias delegates there and will be removed in the next breaking release. The spellings remain pinned against PostgreSQL-dialect Spanner databases by this repository's integration/pgtypeannotation probes.
func FormatRowPostgreSQLLiteral ¶ added in v0.2.0
FormatRowPostgreSQLLiteral formats a row using PostgreSQLLiteralFormatConfig.
func InsertStatement ¶ added in v0.2.0
InsertStatement builds INSERT INTO <table> (<cols>) VALUES ($1..$n) with PositionalParams, quoting the table and column identifiers with github.com/apstndb/spanvalue.QuoteIdentifier PostgreSQL rules. It returns an error when len(columns) != len(values) or when columns is empty.
values follow the PositionalParams contract: plain Go values or GenericColumnValue. Generic INSERT fragment helpers belong to spanvalue (apstndb/spanvalue#79); this binds the PostgreSQL-specific $n / p-n pairing.
func PositionalParams ¶ added in v0.2.0
PositionalParams maps ordered values to the p1..pn keys the PostgreSQL interface pairs with $1..$n placeholders (see StatementParamKey). values may be plain Go values (the client encodes them) or cloud.google.com/go/spanner.GenericColumnValue (binding an exact wire Type, e.g. from github.com/apstndb/spancodec.ValueOf with EncodeOptions).
func PostgreSQLLiteralFormatConfig ¶ added in v0.2.0
func PostgreSQLLiteralFormatConfig() *spanvalue.FormatConfig
PostgreSQLLiteralFormatConfig returns a new spanvalue.FormatConfig that produces parseable PostgreSQL-dialect literal expressions for scalar values plus ARRAY constructors. It rejects Spanner-specific types that the PostgreSQL interface does not support (for example PROTO, ENUM, and STRUCT) instead of emitting invalid SQL.
NULL values—scalar NULL and NULL arrays alike—render as the bare keyword NULL, not CAST(NULL AS <type>). Bare NULL is valid wherever the surrounding context fixes the type (INSERT column lists, comparisons against typed columns), which is the intended use of this config (for example SQL INSERT export through github.com/apstndb/spanvalue/writer). In context-free positions such as a bare SELECT NULL the backend has no type to infer, so callers needing a typed NULL expression must wrap it themselves (CAST(NULL AS bigint), ...). Both behaviors are pinned by the literal round-trip harness in integration/pgtypeannotation (pgliteral_roundtrip_test.go), which executes every literal form this config emits against a POSTGRESQL-dialect Spanner database.
Known backend canonicalizations (probed by the same harness): timestamptz literals are parsed with microsecond precision—sub-microsecond digits are rounded, and a nanosecond-precision value at the maximum timestamp (9999-12-31T23:59:59.999999999Z) rounds out of range and fails—and jsonb text is normalized (key order, whitespace, unicode escapes).
func PostgreSQLPlaceholder ¶
PostgreSQLPlaceholder returns the SQL text for the n-th bind placeholder in PostgreSQL dialect ($n, 1-based), e.g. 1 → "$1".
func StatementParamKey ¶
StatementParamKey returns the map key used in cloud.google.com/go/spanner.Statement.Params for the PostgreSQL-style placeholder $n where n is 1-based. For example, placeholder $1 uses Params key "p1", $2 uses "p2".
This matches the cloud.google.com/go/spanner client convention used with PostgreSQL dialect SQL (placeholders $1, $2, …). See integration coverage in https://github.com/apstndb/spanvalue/pull/45.
Types ¶
This section is empty.