nullability

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package nullability decides, per result column, whether the generated Go field must be a pointer — under the spec's per-shape-sound discipline: narrowing uses only the skeleton; guarded fragments NEVER narrow. See docs/design/05-nullability.md.

Correctness invariant: if Analyze reports a column non-nullable, no reachable shape can return NULL there. False positives (nullable verdicts for always-present values) cost a pointer, never a panic.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Analyze

func Analyze(maxTree dialect.Tree, maxR ast.Rendering, desc dialect.Desc,
	cat *cache.Catalog, overrides map[string]bool) []bool

Analyze returns nullable-ness per result column of desc.Columns.

The discipline, mechanically:

  • Guarded joins are ignored entirely. They are INNER/LEFT and contribute no result columns (R2), so they can filter rows but never null-extend a skeleton column. Reasoning "guarded INNER join implies its FK is non-null" would be per-shape UNSOUND (review counterexample F1b) — do not add it.
  • No WHERE-based narrowing at all in v0.1, not even from skeleton predicates (kept conservative; guarded-predicate narrowing is never sound, F1a).
  • Skeleton outer joins null-extend their side (RelRef.NullableSide, computed by the frontend for LEFT/RIGHT/FULL).
  • SrcRel provenance is trusted only when the source relation is visibly PRESENT in the statement's own FROM list (schema-aware) and no construct can smuggle provenance past Relations(): engines attribute columns THROUGH derived tables, CTEs, and (on some engines) views to base tables, and grouping sets null out grouping columns outright. Every one of those was a proven NULL-into-value counterexample before this check — see TestNullabilitySoundnessAdversarial. An unrecognized or unresolvable source OID therefore fails SAFE to nullable.

func AnalyzeAll

func AnalyzeAll(fe dialect.Frontend, rs []ast.Rendering, descs []dialect.Desc,
	cat *cache.Catalog, overrides map[string]bool) ([]bool, error)

AnalyzeAll runs Analyze over every verified rendering and unions the results per column — the spec's nullable-most rule for @choose projection cases (a case may be nullable where another is not; review counterexample F1c). Renderings must already have passed the column-agreement check (equal lengths).

Types

type Verdict

type Verdict struct {
	Nullable bool
	Reason   string
}

Verdict couples the per-column decision with the reason it was reached — surfaced by `explain` so a conservative verdict is auditable (and a null_overrides entry can be written with confidence) instead of opaque.

func AnalyzeAllVerdicts

func AnalyzeAllVerdicts(fe dialect.Frontend, rs []ast.Rendering, descs []dialect.Desc,
	cat *cache.Catalog, overrides map[string]bool) ([]Verdict, error)

AnalyzeAllVerdicts is AnalyzeAll with reasons: the union keeps the first rendering's reason while a column stays non-nullable and adopts the flipping rendering's reason when one turns it nullable.

func AnalyzeVerdicts

func AnalyzeVerdicts(maxTree dialect.Tree, maxR ast.Rendering, desc dialect.Desc,
	cat *cache.Catalog, overrides map[string]bool) []Verdict

AnalyzeVerdicts is Analyze with reasons.

Jump to

Keyboard shortcuts

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