cost

package
v0.1.6 Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package cost implements the defense-in-depth cost & resource gate.

EXPLAIN is one optional layer, not a leash. Layers have Safety, Estimate, and Enforcement phases. A static PK/template bypass skips Estimate only; guards and deterministic caps still run. CALL is denied unless reviewed explicitly, and optional write/aggregate guards remain independent of EXPLAIN support.

Runtime/DB-native guards sit beneath this synchronous gate:

  • context.WithTimeout plus QueryContext/ExecContext is the portable cancellation contract. Drivers are responsible for propagating it.
  • native statement/scan timeouts are not SET per request: *sql.DB may run the SET and query on different pooled connections. Configure those at the database/user level. MySQL-compatible providers do set sql_safe_updates through the DSN, which applies when each connection is established.

Estimate failure defaults to Plan{ScanUnknown, !StatsFresh} for compatibility. FailClosed, RequireKnownScan, or RequireFreshStats can make it a hard reject.

Index

Constants

This section is empty.

Variables

View Source
var ErrCostExceeded = errors.New("query cost exceeded threshold")

ErrCostExceeded is the sentinel for any cost-gate rejection (soft or hard).

Functions

func Fingerprint

func Fingerprint(datasource, dialectName string, c codegen.Compiled) string

Fingerprint returns a stable baseline key derived from datasource, dialect, normalized generated SQL, and bound parameter types. Values are deliberately excluded.

func Hints

func Hints(p Plan, th Threshold) []string

Hints produces table-driven rewrite suggestions for a rejected plan.

func ValidateTemplateScopes

func ValidateTemplateScopes(datasources, allowTemplates, rejectTemplates []string) error

ValidateTemplateScopes rejects legacy exact-SQL baselines that would stop matching when more than one datasource is configured.

Types

type AggregateGuard

type AggregateGuard struct {
	RequirePredicate bool
}

AggregateGuard can require aggregate queries to carry a valid predicate.

func (AggregateGuard) Check

Check implements Layer.

func (AggregateGuard) Name

func (AggregateGuard) Name() string

Name implements Layer.

func (AggregateGuard) Phase

func (AggregateGuard) Phase() Phase

Phase implements PhasedLayer.

type AnalyzeConfig

type AnalyzeConfig struct {
	Enabled    bool
	SampleRate float64
	ReadOnly   bool
	Timeout    time.Duration
}

AnalyzeConfig controls optional runtime sampling. The zero value disables it.

type AnalyzePolicy

type AnalyzePolicy struct {
	Config  AnalyzeConfig
	Sampler AnalyzeSampler
	Random  func() float64
}

AnalyzePolicy safely gates optional EXPLAIN ANALYZE sampling. Providers are not required to implement AnalyzeSampler.

func (AnalyzePolicy) Sample

func (p AnalyzePolicy) Sample(ctx context.Context, c codegen.Compiled) (Plan, bool, error)

Sample runs only for compiled read-only statements when explicitly enabled. The bool reports whether sampling was attempted.

type AnalyzeSampler

type AnalyzeSampler interface {
	ExplainAnalyze(ctx context.Context, compiled codegen.Compiled) (Plan, error)
}

AnalyzeSampler is an optional, read-only EXPLAIN ANALYZE capability. It is never invoked unless explicitly enabled by configuration.

type CallGuard

type CallGuard struct {
	Datasource     string
	DialectName    string
	LegacyExactSQL bool
	AllowTemplates []string
}

CallGuard rejects CALL by default. A reviewed template must be explicitly listed to permit a procedure invocation.

func (CallGuard) Check

Check implements Layer.

func (CallGuard) Name

func (CallGuard) Name() string

Name implements Layer.

func (CallGuard) Phase

func (CallGuard) Phase() Phase

Phase implements PhasedLayer.

type ChainGate

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

ChainGate runs layers in order. Bypass only suppresses estimate layers; mandatory rejection always takes precedence over an earlier soft decision.

func NewGate

func NewGate(layers ...Layer) *ChainGate

NewGate chains layers into a Gate.

func NewGateFromCapabilities

func NewGateFromCapabilities(caps dialect.Capabilities, ex Explainer, th Threshold, feedback FeedbackStore) *ChainGate

NewGateFromCapabilities assembles the synchronous gate chain: StaticRule always; Estimate only when the dialect's estimates are trustworthy; EnforceCap when a row cap is configured. RuntimeGuard/DBNative run at execution time.

func (*ChainGate) Check

func (g *ChainGate) Check(ctx context.Context, c codegen.Compiled) (Decision, error)

Check runs the chain. A Rewritten decision updates the compiled query for later layers and the final return.

func (*ChainGate) Layers

func (g *ChainGate) Layers() []Layer

Layers returns the chain's layers (for introspection/testing).

type Decision

type Decision struct {
	Allow     bool
	Soft      bool
	Bypass    bool
	Plan      *Plan
	Score     *Score
	Hints     []string
	Rewritten *codegen.Compiled
}

Decision is a layer's verdict. Bypass skips optional estimate layers only; mandatory safety and enforcement layers continue to run.

type EnforceCap

type EnforceCap struct {
	HardRows int64
}

EnforceCap is the deterministic backstop: it wraps a read query in SELECT * FROM (<q>) sub LIMIT hard_rows so the worst case is bounded, independent of estimate correctness.

func (EnforceCap) Check

Check implements Layer.

func (EnforceCap) Name

func (e EnforceCap) Name() string

Name implements Layer.

func (EnforceCap) Phase

func (EnforceCap) Phase() Phase

Phase implements PhasedLayer.

type Estimate

type Estimate struct {
	Explainer  Explainer
	Threshold  Threshold
	Feedback   FeedbackStore
	FailClosed bool
}

Estimate is the optional EXPLAIN pre-filter layer. It runs only when the dialect's estimates are trustworthy (assembled by NewGateFromCapabilities).

func NewEstimate

func NewEstimate(ex Explainer, th Threshold, feedback FeedbackStore, opts ...EstimateOption) Estimate

NewEstimate constructs an Estimate. Existing struct literals remain valid; the default behavior continues to degrade EXPLAIN failures.

func (Estimate) Check

func (e Estimate) Check(ctx context.Context, c codegen.Compiled) (Decision, error)

Check implements Layer.

func (Estimate) Name

func (e Estimate) Name() string

Name implements Layer.

func (Estimate) Phase

func (Estimate) Phase() Phase

Phase implements PhasedLayer.

type EstimateOption

type EstimateOption func(*Estimate)

EstimateOption configures NewEstimate.

func WithFailClosed

func WithFailClosed() EstimateOption

WithFailClosed rejects EXPLAIN errors and unknown plans.

type ExceededError

type ExceededError struct {
	Plan      Plan
	Score     Score
	Threshold Threshold
	Hints     []string
	Soft      bool
}

ExceededError carries the estimate, score, threshold, and rewrite hints so the agent can rewrite and retry. Soft marks a soft reject (suggest LIMIT).

func (*ExceededError) Error

func (e *ExceededError) Error() string

Error implements error.

func (*ExceededError) Unwrap

func (e *ExceededError) Unwrap() error

Unwrap returns ErrCostExceeded so errors.Is works.

type Explainer

type Explainer interface {
	Explain(ctx context.Context, query string, args []any) (Plan, error)
}

Explainer estimates a plan for one query. Implementations live in x/providers and parse dialect-specific EXPLAIN output.

type FakeAnalyzeSampler

type FakeAnalyzeSampler struct {
	Plan Plan
	Err  error
}

FakeAnalyzeSampler is a test implementation.

func (FakeAnalyzeSampler) ExplainAnalyze

ExplainAnalyze implements AnalyzeSampler.

type FakeExplainer

type FakeExplainer struct {
	Plan Plan
	Err  error
}

FakeExplainer is a hand-written Explainer for tests.

func (FakeExplainer) Explain

func (f FakeExplainer) Explain(_ context.Context, _ string, _ []any) (Plan, error)

Explain returns the configured Plan/Err.

type Feedback

type Feedback struct {
	Template      string
	EstimatedRows int64
	ActualRows    int64
	Rows          int64 // deprecated alias for ActualRows
	Duration      time.Duration
}

Feedback records one observed execution for a query template, used to calibrate future estimates against reality.

type FeedbackStore

type FeedbackStore interface {
	Record(f Feedback)
	Stats(template string) (Statistics, bool)
}

FeedbackStore records observed executions and exposes bounded statistics.

type Gate

type Gate interface {
	Check(ctx context.Context, c codegen.Compiled) (Decision, error)
}

Gate is the synchronous gate consulted before execution (invariant I4).

type Layer

type Layer interface {
	Name() string
	Check(ctx context.Context, c codegen.Compiled) (Decision, error)
}

Layer is one stage of the gate.

type MemoryStore

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

MemoryStore keeps a bounded sliding window per fingerprint.

func NewAdaptiveMemoryStore

func NewAdaptiveMemoryStore(size int, factor float64, minSamples int, invalidator PlanInvalidator) *MemoryStore

NewAdaptiveMemoryStore additionally invalidates a plan when a new actual-row count exceeds the prior window average by factor.

func NewAdaptiveMemoryStoreWithBounds

func NewAdaptiveMemoryStoreWithBounds(
	size, maxKeys int,
	factor float64,
	minSamples int,
	invalidator PlanInvalidator,
) *MemoryStore

NewAdaptiveMemoryStoreWithBounds additionally bounds the number of distinct fingerprints retained by the adaptive store.

func NewMemoryStore

func NewMemoryStore() *MemoryStore

NewMemoryStore returns an in-memory FeedbackStore.

func NewMemoryStoreWithBounds

func NewMemoryStoreWithBounds(windowSize, maxKeys int) *MemoryStore

NewMemoryStoreWithBounds returns a store bounded both per fingerprint and across all fingerprints. When full, the oldest inserted fingerprint is evicted.

func NewMemoryStoreWithWindow

func NewMemoryStoreWithWindow(size int) *MemoryStore

NewMemoryStoreWithWindow returns a store retaining at most size samples per fingerprint.

func (*MemoryStore) Anomalous

func (s *MemoryStore) Anomalous(template string, factor float64, minSamples int) bool

Anomalous reports a sudden increase over the preceding bounded history. At least minSamples historical samples are required to avoid cold-start noise. factor values <= 1 use the conservative default of 3.

func (*MemoryStore) AverageRows

func (s *MemoryStore) AverageRows(template string) (int64, bool)

AverageRows is retained for source compatibility; new code should use Stats.

func (*MemoryStore) Record

func (s *MemoryStore) Record(f Feedback)

Record implements FeedbackStore.

func (*MemoryStore) Stats

func (s *MemoryStore) Stats(template string) (Statistics, bool)

Stats implements FeedbackStore.

type NoopFeedbackStore

type NoopFeedbackStore struct{}

NoopFeedbackStore discards feedback.

func (NoopFeedbackStore) AverageRows

func (NoopFeedbackStore) AverageRows(string) (int64, bool)

AverageRows is retained for source compatibility.

func (NoopFeedbackStore) Record

func (NoopFeedbackStore) Record(Feedback)

Record implements FeedbackStore.

func (NoopFeedbackStore) Stats

Stats implements FeedbackStore.

type Phase

type Phase uint8

Phase separates mandatory safety/enforcement from optional estimates.

const (
	PhaseSafety Phase = iota
	PhaseEstimate
	PhaseEnforcement
)

type PhasedLayer

type PhasedLayer interface {
	Layer
	Phase() Phase
}

PhasedLayer identifies where a layer belongs. Layers without Phase are treated as mandatory enforcement for backwards-compatible composition.

type Plan

type Plan struct {
	TotalCost       float64
	EstimatedRows   int64
	EstimatedBytes  int64
	ActualRows      int64
	ExecutionTime   time.Duration
	ScanType        ScanType
	PartitionPruned bool
	HasSort         bool
	HasTempTable    bool
	StatsFresh      bool
	Raw             json.RawMessage
}

Plan is the normalized physical plan from an EXPLAIN. TotalCost is the dialect-native cost (reference only); decisions rely on the normalized Score.

type PlanInvalidator

type PlanInvalidator interface {
	InvalidatePlan(fingerprint string)
}

PlanInvalidator invalidates cached plans after material feedback changes.

type ScanType

type ScanType uint8

ScanType classifies the access path of a plan.

const (
	// ScanUnknown means the access path could not be determined.
	ScanUnknown ScanType = iota
	// ScanSeq is a sequential scan.
	ScanSeq
	// ScanIndex is an index scan.
	ScanIndex
	// ScanPoint is a primary-key / unique-index point lookup.
	ScanPoint
	// ScanFull is a full table scan.
	ScanFull
)

type Score

type Score struct {
	Value   int
	Factors []string
}

Score is the 0-100 normalized plan quality (higher is safer), with the risk factors that were hit.

func ScorePlan

func ScorePlan(p Plan) Score

ScorePlan derives a normalized Score from a Plan. It is a pure function and the heart of cross-dialect comparability (PG cost vs MySQL cost vs SQLite no-cost all map to the same scale).

type StaticRule

type StaticRule struct {
	PKWhitelist     bool
	Datasource      string
	DialectName     string
	LegacyExactSQL  bool
	AllowTemplates  []string
	RejectTemplates []string
}

StaticRule applies whitelist/blacklist checks without EXPLAIN. PK and allow matches bypass only optional Estimate layers; mandatory guards still run.

func (StaticRule) Check

Check implements Layer.

func (StaticRule) Name

func (s StaticRule) Name() string

Name implements Layer.

func (StaticRule) Phase

func (StaticRule) Phase() Phase

Phase implements PhasedLayer.

type Statistics

type Statistics struct {
	Samples       int
	AverageRows   int64
	AverageTime   time.Duration
	LatestRows    int64
	LatestTime    time.Duration
	EstimatedRows int64
}

Statistics is a bounded-window summary for one fingerprint.

type Threshold

type Threshold struct {
	Enabled                   bool
	Datasource                string
	DialectName               string
	SoftScore                 int
	HardScore                 int
	MaxRows                   int64
	MaxBytes                  int64
	RejectFullScan            bool
	WhitelistPKPoint          bool
	RequirePKForWrite         bool // reject UPDATE/DELETE that is not a PK point write
	RequireAggregatePredicate bool
	ExplainFailClosed         bool
	DisableEstimate           bool
	RequireKnownScan          bool
	RequireFreshStats         bool
	LegacyExactSQL            bool
	AllowTemplates            []string
	RejectTemplates           []string
}

Threshold configures the gate. SoftScore/HardScore are 0-100 cutoffs.

type WriteGuard

type WriteGuard struct{}

WriteGuard is a deterministic write-safety layer, independent of EXPLAIN. A write (UPDATE/DELETE) whose predicate is not a full primary-key point lookup is hard-rejected. This backstops databases whose row estimates are unreliable (MySQL/OceanBase), where an unbounded WHERE could touch millions of rows. Point writes are already bypassed by StaticRule's PK whitelist; known-good bulk writes can be admitted via AllowTemplates after review.

func (WriteGuard) Check

Check implements Layer.

func (WriteGuard) Name

func (WriteGuard) Name() string

Name implements Layer.

func (WriteGuard) Phase

func (WriteGuard) Phase() Phase

Phase implements PhasedLayer.

Jump to

Keyboard shortcuts

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