redshiftdata

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 3, 2026 License: MIT Imports: 18 Imported by: 0

README

Redshift Data

Parity grade: A · SDK aws-sdk-go-v2/service/redshiftdata@v1.43.0 · last audited 2026-07-25 (2b2a22e6d)

Coverage

Metric Value
Operations audited 12 (7 ok, 1 partial, 4 gap)
Feature families 2 (2 ok)
Known gaps 8
Deferred items 1
Resource leaks clean
Known gaps
  • CancelStatement can never succeed against this backend: ExecuteStatement/BatchExecuteStatement set Status=FINISHED synchronously, so by the time a client calls CancelStatement the statement is always already terminal and CancelStatement always returns ErrTerminalState (ValidationException). This matches real AWS semantics ("To be canceled, a query must be running") given the backend's synchronous-completion design. Not fixed this pass -- would require modeling async statement execution (a state machine with a delay before reaching FINISHED), which is a larger behavioral change beyond a wire-shape/bug-fix pass.
  • ValidateConnectionTarget (models.go) enforces "exactly one of ClusterIdentifier/WorkgroupName" per real AWS constraints but is never called from any handler. ExecuteStatement/BatchExecuteStatement handlers are intentionally permissive (see TestHandler_ExecuteStatement_AllowsBothClusterAndWorkgroup / AllowsNeitherClusterNorWorkgroup in handler_statements_validation_test.go) -- this looks like a deliberate relaxation for ease of testing rather than an oversight, so left as-is. Re-review if strict AWS-parity validation becomes a priority.
  • DescribeStatement does not return RedshiftPid (optional field, always absent instead of 0); DbGroups not returned by ExecuteStatement/BatchExecuteStatement. Both are optional wire fields the real client zero-values when absent, so not a functional gap, just lower fidelity -- no group/pid registry exists in this mock to source real values from.
  • ClientToken and SessionKeepAliveSeconds are accepted on ExecuteStatement/BatchExecuteStatement's wire (unmarshalled into the request struct) but are not behaviorally significant. ClientToken idempotency (returning the same statement for a retried request with the same token) and session keep-alive/expiry both require modeling request-retry dedup and time-bounded session lifetimes this in-memory backend does not have; inventing either risks fabricating undocumented AWS behavior not verifiable without a live cluster (same reasoning as rdsdata's typeHint gap). Relatedly, this mock does NOT mint a fresh SessionId when SessionKeepAliveSeconds>0 and no SessionId is supplied (real AWS would start a new session and return its id) -- SessionId here is pure passthrough of whatever the caller already provided, since there's no session-scoped state (temp tables, transaction visibility, etc.) that a minted id would actually gate.
  • RoleLevel is parsed on ListStatements' request body but never applied as a filter: real semantics are "true (default) = all statements this IAM role has run, false = only this IAM session's statements," but this mock has no per-caller-identity or per-session model of statement ownership, so there is no signal to filter on. All statements are visible regardless of RoleLevel, matching the "true" default in effect at all times.
  • ActiveStatementsExceededException, ActiveSessionsExceededException, DatabaseConnectionException, ExecuteStatementException, BatchExecuteStatementException, and QueryTimeoutException are all real modeled exception types in aws-sdk-go-v2/service/redshiftdata/types/errors.go but are unreachable by design in this backend: ExecuteStatement/BatchExecuteStatement always complete synchronously and successfully against in-memory demo data (no real cluster connection to fail, no concurrent-statement or concurrent-session limit tracked). Deliberately NOT implemented this pass: inventing trigger conditions (e.g. an arbitrary "N active statements" cap, or making some ClusterIdentifier/SecretArn values fail with DatabaseConnectionException) would fabricate gopherstack-only behavior with no real-AWS trigger to field-diff against -- consistent with rdsdata's precedent of leaving unreachable-by-design SDK exceptions undone rather than guessing.
  • ListStatements items include several fields (ClusterIdentifier, WorkgroupName, Database, DbUser, HasResultSet, Duration) that don't exist on the real StatementData shape at all. The AWS SDK's JSON deserializer silently discards unknown keys, so this is harmless today, but flagged in case a future SDK version repurposes one of those key names.
  • ListSessions (new this pass) never returns Status=BUSY or Status=CLOSED, and never returns SessionAliveSeconds/SessionTtl/CurrentStatementId at all: this backend executes every statement synchronously to a terminal state (no mid-flight window to observe BUSY/CurrentStatementId) and does not track SessionKeepAliveSeconds expiry (no SessionTtl to compare "now" against, so CLOSED can never be derived). Modeling any of these would require the same async-execution and keep-alive state machine already flagged as out-of-scope for CancelStatement/ClientToken/SessionKeepAliveSeconds above -- not invented here for the same reason. ListSessions also can't see sessions that were only ever referenced via SessionKeepAliveSeconds without an explicit SessionId (this mock doesn't mint one, see ExecuteStatement's note).
Deferred
  • none

More

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound is returned when a statement does not exist.
	ErrNotFound = awserr.New("ResourceNotFoundException", awserr.ErrNotFound)
	// ErrTerminalState is returned when cancelling a statement that is already in a terminal state.
	ErrTerminalState = awserr.New("ValidationException", awserr.ErrConflict)
	// ErrValidation is returned when input validation fails.
	ErrValidation = awserr.New("ValidationException", awserr.ErrInvalidParameter)
	// ErrNoResultSet is returned when fetching results for a statement with no result set.
	ErrNoResultSet = awserr.New("ValidationException", awserr.ErrInvalidParameter)
)
View Source
var ErrNilAppContext = errors.New("nil AppContext passed to RedshiftData Provider.Init")

ErrNilAppContext is returned by Init when a nil AppContext is passed.

Functions

func ValidateConnectionTarget

func ValidateConnectionTarget(clusterIdentifier, workgroupName string) error

ValidateConnectionTarget verifies that exactly one of clusterIdentifier or workgroupName is provided, matching the AWS constraint.

func ValidateListSessionsRequest added in v1.2.0

func ValidateListSessionsRequest(sessionID, status, clusterIdentifier, workgroupName, database string) error

ValidateListSessionsRequest enforces the mutual-exclusivity constraints documented on ListSessionsInput (aws-sdk-go-v2/service/redshiftdata's api_op_ListSessions.go): SessionId can't be combined with Status/ClusterIdentifier/WorkgroupName/Database, and ClusterIdentifier/WorkgroupName can't both be set.

func ValidateListStatementsStatus

func ValidateListStatementsStatus(status string) error

ValidateListStatementsStatus returns ErrValidation if status is not a known value. An empty string is also accepted (matches FINISHED per AWS default).

Types

type ConfigProvider

type ConfigProvider interface {
	GetRedshiftDataSettings() Settings
}

ConfigProvider is a private interface to extract Redshift Data configuration from the abstract AppContext Config.

type Handler

type Handler struct {
	Backend StorageBackend

	AccountID string
	Region    string
	// contains filtered or unexported fields
}

Handler is the HTTP handler for the AWS Redshift Data API.

func NewHandler

func NewHandler(backend StorageBackend) *Handler

NewHandler creates a new Redshift Data handler.

func (*Handler) ChaosOperations

func (h *Handler) ChaosOperations() []string

ChaosOperations returns all operations that can be fault-injected.

func (*Handler) ChaosRegions

func (h *Handler) ChaosRegions() []string

ChaosRegions returns all regions this handler handles.

func (*Handler) ChaosServiceName

func (h *Handler) ChaosServiceName() string

ChaosServiceName returns the lowercase AWS service name for fault rule matching.

func (*Handler) ExtractOperation

func (h *Handler) ExtractOperation(c *echo.Context) string

ExtractOperation extracts the operation name from the X-Amz-Target header.

func (*Handler) ExtractResource

func (h *Handler) ExtractResource(c *echo.Context) string

ExtractResource extracts the statement ID from the request body.

func (*Handler) GetSupportedOperations

func (h *Handler) GetSupportedOperations() []string

GetSupportedOperations returns the list of supported Redshift Data operations.

func (*Handler) Handler

func (h *Handler) Handler() echo.HandlerFunc

Handler returns the Echo handler function for Redshift Data requests.

func (*Handler) MatchPriority

func (h *Handler) MatchPriority() int

MatchPriority returns the routing priority.

func (*Handler) Name

func (h *Handler) Name() string

Name returns the service name.

func (*Handler) Reset

func (h *Handler) Reset()

Reset clears all backend state. Useful for test isolation.

func (*Handler) Restore

func (h *Handler) Restore(ctx context.Context, data []byte) error

Restore implements persistence.Persistable by delegating to the backend.

func (*Handler) RouteMatcher

func (h *Handler) RouteMatcher() service.Matcher

RouteMatcher returns a function that matches Redshift Data API requests. Requests are identified by the X-Amz-Target header prefix "RedshiftData.".

func (*Handler) Snapshot

func (h *Handler) Snapshot(ctx context.Context) []byte

Snapshot implements persistence.Persistable by delegating to the backend. Before this, Handler had no Snapshot/Restore of its own, so redshiftdata was silently excluded from Gopherstack's persistence.Manager (it type- asserts each service's Registerable to persistence.Persistable) even though InMemoryBackend fully implemented both methods -- a dead-wiring bug fixed as part of the Phase 3.3 rollout.

func (*Handler) StartWorker

func (h *Handler) StartWorker(ctx context.Context) error

StartWorker starts the background janitor if configured.

func (*Handler) WithJanitor

func (h *Handler) WithJanitor(interval, statementTTL time.Duration, taskTimeout ...time.Duration) *Handler

WithJanitor attaches a background janitor to the handler. If the backend is not an *InMemoryBackend, this is a no-op.

type InMemoryBackend

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

InMemoryBackend is an in-memory store for Redshift Data API statements. All regional resource maps are nested by region (outer key = region) so that the same-named statement in two regions are fully isolated.

func NewInMemoryBackend

func NewInMemoryBackend(accountID, region string) *InMemoryBackend

NewInMemoryBackend creates a new in-memory Redshift Data backend.

func (*InMemoryBackend) AccountID

func (b *InMemoryBackend) AccountID() string

AccountID returns the AWS account ID this backend is configured for.

func (*InMemoryBackend) BatchExecuteStatement

func (b *InMemoryBackend) BatchExecuteStatement(
	ctx context.Context,
	sqls []string, clusterIdentifier, workgroupName, database, dbUser, secretARN, statementName string,
	withEvent bool, resultFormat string,
	parameters []SQLParameter,
	sessionID string,
) (*Statement, error)

BatchExecuteStatement creates and immediately completes a batch SQL statement.

func (*InMemoryBackend) CancelStatement

func (b *InMemoryBackend) CancelStatement(ctx context.Context, id string) error

CancelStatement marks a statement as aborted.

func (*InMemoryBackend) DescribeStatement

func (b *InMemoryBackend) DescribeStatement(ctx context.Context, id string) (*Statement, error)

DescribeStatement returns the details of a statement by ID.

func (*InMemoryBackend) EvictExpiredStatements

func (b *InMemoryBackend) EvictExpiredStatements(cutoff time.Time) int

EvictExpiredStatements removes terminal statements whose UpdatedAt is older than the given cutoff across all regions. Returns the number of evicted statements. Only terminal states (FINISHED, FAILED, ABORTED) are eligible for eviction.

func (*InMemoryBackend) ExecuteStatement

func (b *InMemoryBackend) ExecuteStatement(
	ctx context.Context,
	sql, clusterIdentifier, workgroupName, database, dbUser, secretARN, statementName string,
	withEvent bool, resultFormat string,
	parameters []SQLParameter,
	sessionID string,
) (*Statement, error)

ExecuteStatement creates and immediately completes a SQL statement.

func (*InMemoryBackend) ListSessions added in v1.2.0

func (b *InMemoryBackend) ListSessions(
	ctx context.Context,
	filter ListSessionsFilter,
) ([]*SessionData, string, error)

ListSessions returns a page of sessions derived from stored statements that share a non-empty SessionID (see groupSessions), sorted newest-first by CreatedAt to match ListStatements' ordering convention.

func (*InMemoryBackend) ListStatements

func (b *InMemoryBackend) ListStatements(
	ctx context.Context,
	filter ListStatementsFilter,
) ([]*Statement, string, error)

ListStatements returns statements sorted by creation time (newest first). An omitted Status matches AWS by returning only finished statements. Returns the page slice and a next-token string (non-empty when more pages exist).

func (*InMemoryBackend) Region

func (b *InMemoryBackend) Region() string

Region returns the AWS region this backend is configured for.

func (*InMemoryBackend) Reset

func (b *InMemoryBackend) Reset()

Reset clears all stored statements across all regions.

func (*InMemoryBackend) Restore

func (b *InMemoryBackend) Restore(ctx context.Context, data []byte) error

Restore loads backend state from a JSON snapshot. It implements persistence.Persistable.

func (*InMemoryBackend) Snapshot

func (b *InMemoryBackend) Snapshot(ctx context.Context) []byte

Snapshot serializes the backend state to JSON. It implements persistence.Persistable.

type Janitor

type Janitor struct {
	Backend      *InMemoryBackend
	Interval     time.Duration
	StatementTTL time.Duration
	// TaskTimeout bounds each individual sweep task. When zero, each task runs
	// without a deadline. When non-zero, a child context with this timeout is
	// created for each sweep pass, preventing a stalled operation from blocking
	// the janitor loop indefinitely.
	TaskTimeout time.Duration
}

Janitor is the Redshift Data background worker that evicts completed statements after a configurable TTL to prevent unbounded growth of in-memory state. It complements the ring-buffer cap: the ring buffer evicts by count, the janitor evicts by age.

func NewJanitor

func NewJanitor(backend *InMemoryBackend, interval, statementTTL time.Duration) *Janitor

NewJanitor creates a new Janitor for the given backend. Zero values for interval or statementTTL fall back to package defaults.

func (*Janitor) Run

func (j *Janitor) Run(ctx context.Context)

Run runs the janitor loop until ctx is cancelled. It should be started in a goroutine: go janitor.Run(ctx).

func (*Janitor) SweepOnce

func (j *Janitor) SweepOnce(ctx context.Context)

SweepOnce runs a single sweep pass. Exposed for testing.

type ListSessionsFilter added in v1.2.0

type ListSessionsFilter struct {
	ClusterIdentifier string
	WorkgroupName     string
	Database          string
	SessionID         string
	Status            string
	NextToken         string
	MaxResults        int
}

ListSessionsFilter controls session filtering and pagination.

type ListStatementsFilter

type ListStatementsFilter struct {
	ClusterIdentifier string
	WorkgroupName     string
	Database          string
	StatementName     string
	Status            string
	NextToken         string
	MaxResults        int
}

ListStatementsFilter controls statement filtering and pagination.

type Provider

type Provider struct{}

Provider implements service.Provider for AWS Redshift Data.

func (*Provider) Init

Init initializes the Redshift Data service backend and handler.

func (*Provider) Name

func (p *Provider) Name() string

Name returns the provider name.

type SQLParameter

type SQLParameter struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

SQLParameter is a named SQL parameter for use in parameterized queries, matching the SQLParameter type in the AWS Redshift Data API.

type SessionData added in v1.2.0

type SessionData struct {
	CreatedAt         time.Time `json:"createdAt"`
	UpdatedAt         time.Time `json:"updatedAt"`
	SessionID         string    `json:"sessionId"`
	ClusterIdentifier string    `json:"clusterIdentifier,omitempty"`
	WorkgroupName     string    `json:"workgroupName,omitempty"`
	Database          string    `json:"database,omitempty"`
	DBUser            string    `json:"dbUser,omitempty"`
	Status            string    `json:"status"`
}

SessionData represents an AWS Redshift Data API session, matching the SessionData shape returned by ListSessions. This backend does not model sessions as a first-class stored resource -- there is no explicit CreateSession/CloseSession API to persist against. Instead, a session is derived by grouping stored Statement records that share a non-empty SessionID (see groupSessions in sessions.go): the session's connection target and timestamps come from the statements that ran within it.

SessionAliveSeconds and SessionTTL are intentionally omitted (both optional wire members): tracking them behaviorally would require the same SessionKeepAliveSeconds plumbing that ExecuteStatement/BatchExecuteStatement already accept-but-ignore (see handleExecuteStatement's doc comment) -- adding real semantics for one op without the other would be inconsistent, and this pass only implements ListSessions.

type Settings

type Settings struct {
	JanitorInterval time.Duration `json:"janitor_interval" env:"REDSHIFTDATA_JANITOR_INTERVAL" default:"1m"  help:"Janitor tick interval."` //nolint:lll // Kong struct tag makes this line long
	StatementTTL    time.Duration ``                                                                                                        //nolint:lll // Kong struct tag makes this line long
	/* 134-byte string literal not displayed */
}

Settings holds service-level configuration for the Redshift Data backend. Fields are picked up by the Kong CLI parser when this struct is embedded in the root CLI command.

type Statement

type Statement struct {
	CreatedAt         time.Time `json:"createdAt"`
	UpdatedAt         time.Time `json:"updatedAt"`
	Database          string    `json:"database"`
	ID                string    `json:"id"`
	ClusterIdentifier string    `json:"clusterIdentifier"`
	WorkgroupName     string    `json:"workgroupName"`
	QueryString       string    `json:"queryString"`
	DBUser            string    `json:"dbUser"`
	SecretARN         string    `json:"secretARN"`
	StatementName     string    `json:"statementName"`
	ResultFormat      string    `json:"resultFormat"`
	// SessionID is the session identifier echoed back from the ExecuteStatement/
	// BatchExecuteStatement request that created this statement (StatementData.SessionId
	// / DescribeStatementOutput.SessionId in the real API). Empty when the caller did
	// not supply one -- this mock does not mint new session ids on the caller's behalf,
	// it only threads through what was provided (see handleExecuteStatement).
	SessionID     string             `json:"sessionID,omitempty"`
	Status        string             `json:"status"`
	Error         string             `json:"error"`
	QueryStrings  []string           `json:"queryStrings"`
	Parameters    []SQLParameter     `json:"parameters,omitempty"`
	SubStatements []SubStatementData `json:"subStatements,omitempty"`
	// DurationMs is the total wall-clock execution time in milliseconds. Populated
	// when the statement reaches a terminal state (FINISHED / FAILED / ABORTED).
	DurationMs       int64 `json:"durationMs"`
	ResultRows       int64 `json:"resultRows"`
	ResultSize       int64 `json:"resultSize"`
	HasResultSet     bool  `json:"hasResultSet"`
	IsBatchStatement bool  `json:"isBatchStatement"`
	// WithEvent indicates whether an EventBridge event is generated on completion.
	WithEvent bool `json:"withEvent"`
}

Statement represents an AWS Redshift Data API SQL statement.

type StorageBackend

type StorageBackend interface {
	// Statement execution
	ExecuteStatement(
		ctx context.Context,
		sql, clusterIdentifier, workgroupName, database, dbUser, secretARN, statementName string,
		withEvent bool, resultFormat string,
		parameters []SQLParameter,
		sessionID string,
	) (*Statement, error)
	BatchExecuteStatement(
		ctx context.Context,
		sqls []string, clusterIdentifier, workgroupName, database, dbUser, secretARN, statementName string,
		withEvent bool, resultFormat string,
		parameters []SQLParameter,
		sessionID string,
	) (*Statement, error)

	// Statement inspection
	DescribeStatement(ctx context.Context, id string) (*Statement, error)
	CancelStatement(ctx context.Context, id string) error
	// ListStatements returns a page of statements and a next-token for pagination.
	ListStatements(ctx context.Context, filter ListStatementsFilter) (
		[]*Statement, string, error,
	)

	// Sessions
	// ListSessions returns a page of sessions -- derived from stored statements
	// that share a SessionID, not a separately stored resource -- and a
	// next-token for pagination.
	ListSessions(ctx context.Context, filter ListSessionsFilter) (
		[]*SessionData, string, error,
	)

	// Maintenance
	// EvictExpiredStatements removes terminal statements older than cutoff.
	// Returns the number of evicted statements.
	EvictExpiredStatements(cutoff time.Time) int

	// Lifecycle
	Reset()
	Region() string
	AccountID() string
	Snapshot(ctx context.Context) []byte
	Restore(ctx context.Context, data []byte) error
}

StorageBackend defines the interface for Redshift Data backend implementations. All methods must be safe for concurrent use.

type SubStatementData

type SubStatementData struct {
	ID           string    `json:"id"`
	CreatedAt    time.Time `json:"createdAt"`
	UpdatedAt    time.Time `json:"updatedAt"`
	QueryString  string    `json:"queryString"`
	Status       string    `json:"status"`
	Error        string    `json:"error"`
	HasResultSet bool      `json:"hasResultSet"`
	ResultRows   int64     `json:"resultRows"`
	ResultSize   int64     `json:"resultSize"`
	DurationMs   int64     `json:"durationMs"`
}

SubStatementData represents a single sub-statement within a batch, matching the SubStatementData shape returned by AWS DescribeStatement for batch runs.

Jump to

Keyboard shortcuts

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