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 ¶
- Variables
- func Fingerprint(datasource, dialectName string, c codegen.Compiled) string
- func Hints(p Plan, th Threshold) []string
- func ValidateTemplateScopes(datasources, allowTemplates, rejectTemplates []string) error
- type AggregateGuard
- type AnalyzeConfig
- type AnalyzePolicy
- type AnalyzeSampler
- type CallGuard
- type ChainGate
- type Decision
- type EnforceCap
- type Estimate
- type EstimateOption
- type ExceededError
- type Explainer
- type FakeAnalyzeSampler
- type FakeExplainer
- type Feedback
- type FeedbackStore
- type Gate
- type Layer
- type MemoryStore
- func NewAdaptiveMemoryStore(size int, factor float64, minSamples int, invalidator PlanInvalidator) *MemoryStore
- func NewAdaptiveMemoryStoreWithBounds(size, maxKeys int, factor float64, minSamples int, invalidator PlanInvalidator) *MemoryStore
- func NewMemoryStore() *MemoryStore
- func NewMemoryStoreWithBounds(windowSize, maxKeys int) *MemoryStore
- func NewMemoryStoreWithWindow(size int) *MemoryStore
- type NoopFeedbackStore
- type Phase
- type PhasedLayer
- type Plan
- type PlanInvalidator
- type ScanType
- type Score
- type StaticRule
- type Statistics
- type Threshold
- type WriteGuard
Constants ¶
This section is empty.
Variables ¶
var ErrCostExceeded = errors.New("query cost exceeded threshold")
ErrCostExceeded is the sentinel for any cost-gate rejection (soft or hard).
Functions ¶
func Fingerprint ¶
Fingerprint returns a stable baseline key derived from datasource, dialect, normalized generated SQL, and bound parameter types. Values are deliberately excluded.
func ValidateTemplateScopes ¶
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.
type AnalyzeConfig ¶
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.
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.
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 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.
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.
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.
type EstimateOption ¶
type EstimateOption func(*Estimate)
EstimateOption configures NewEstimate.
func WithFailClosed ¶
func WithFailClosed() EstimateOption
WithFailClosed rejects EXPLAIN errors and unknown plans.
type ExceededError ¶
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) Unwrap ¶
func (e *ExceededError) Unwrap() error
Unwrap returns ErrCostExceeded so errors.Is works.
type Explainer ¶
Explainer estimates a plan for one query. Implementations live in x/providers and parse dialect-specific EXPLAIN output.
type FakeAnalyzeSampler ¶
FakeAnalyzeSampler is a test implementation.
func (FakeAnalyzeSampler) ExplainAnalyze ¶
ExplainAnalyze implements AnalyzeSampler.
type FakeExplainer ¶
FakeExplainer is a hand-written Explainer for tests.
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 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 ¶
func (NoopFeedbackStore) Stats(string) (Statistics, bool)
Stats implements FeedbackStore.
type PhasedLayer ¶
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 Score ¶
Score is the 0-100 normalized plan quality (higher is safer), with the risk factors that were hit.
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.
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.