engine

package
v0.5.3 Latest Latest
Warning

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

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

Documentation

Overview

Package engine runs statements against a database handle and encodes results into the transport-agnostic Value/Result shape shared by every protocol. It is deliberately conn-source-neutral: Query/Exec take a Queryer satisfied by a pooled *sql.Conn, a session-pinned conn, or the *sql.DB pool itself, so the same code serves autocommit and interactive-transaction paths.

Index

Constants

View Source
const (
	DefaultMaxRows        = 100_000
	DefaultMaxResultBytes = 64 << 20
)

DefaultMaxRows and DefaultMaxResultBytes bound a single result so a large SELECT can't OOM the process. A zero/negative configured limit falls back to these — a network-exposed result set is never unbounded.

Variables

View Source
var ErrDenied = errors.New("statement not permitted by server policy")

ErrDenied marks a statement rejected by server policy (not a SQL error).

Functions

func CodeName

func CodeName(primary int) string

CodeName maps a primary SQLite result code to its symbolic name, for the Hrana error `code` field (clients match on e.g. SQLITE_CONSTRAINT). Unknown codes fall back to SQLITE_ERROR.

func ExtendedCodeName

func ExtendedCodeName(extended int) string

ExtendedCodeName maps an extended SQLite result code to its symbolic name for the Hrana error `code` field, preserving the constraint subtype (UNIQUE vs FOREIGNKEY vs NOTNULL vs CHECK) that the primary code alone collapses to a bare SQLITE_CONSTRAINT. A client (e.g. an ORM error-mapper) needs the subtype to classify a violation, so the tx path must carry it. Codes outside the semantically-meaningful set fall back to the primary code's name.

func IsExplain

func IsExplain(sql string) bool

IsExplain reports whether the statement is an EXPLAIN / EXPLAIN QUERY PLAN, for Hrana describe's is_explain. The driver does not expose sqlite3_stmt_isexplain; the leading keyword is exact here because EXPLAIN is only valid as the first token of a statement.

func IsNotAuthorized

func IsNotAuthorized(err error) bool

IsNotAuthorized reports whether err is a statement rejected by the connection authorizer (SQLITE_AUTH) — a read-only principal attempting a write, or an ATTACH/DETACH buried in a script. Callers map it to a policy denial (403) rather than a plain SQL error envelope.

func IsReadOnly

func IsReadOnly(sql string) bool

IsReadOnly reports whether a statement only reads (SELECT and friends, and not a writing RETURNING). Phase-1-grade heuristic.

Types

type BatchError

type BatchError struct {
	Index int
	Err   error
}

BatchError wraps the error from a failing batch statement with its index, so the caller can tell the client which statement rolled the batch back.

func (*BatchError) Error

func (e *BatchError) Error() string

func (*BatchError) Unwrap

func (e *BatchError) Unwrap() error

type Column

type Column struct {
	Name string
}

Column describes one result column.

type Engine

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

Engine holds the result caps. Phase 7 adds the slow-log (driver TraceProfile) and the richer limits/cancellation wiring around these calls.

func New

func New(maxRows int, maxResultBytes int64) *Engine

New builds an Engine. A non-positive limit falls back to the safe default, so a result is always bounded.

func (*Engine) Batch

func (e *Engine) Batch(ctx context.Context, db TxBeginner, stmts []Statement) ([]*Result, error)

Batch runs a set of statements in ONE explicit transaction (BeginTx/Commit), all-or-nothing. Each statement dispatches via Run, so reads return rows and writes return affected/last-insert. A failure rolls the whole batch back and returns a *BatchError carrying the failing index. Hrana batch step-conditions and the interactive (pinned-conn) transactions arrive in Phase 2.

func (*Engine) Exec

func (e *Engine) Exec(ctx context.Context, q Queryer, s Statement) (*Result, error)

Exec runs a mutation/DDL statement and reports affected rows + last insert id.

func (*Engine) Query

func (e *Engine) Query(ctx context.Context, q Queryer, s Statement) (*Result, error)

Query runs a row-returning statement and scans the rows into a Result, honoring the max-rows cap (setting Truncated when hit).

func (*Engine) Run

func (e *Engine) Run(ctx context.Context, q Queryer, s Statement) (*Result, error)

Run picks Query for a row-returning statement and Exec otherwise, so a caller with a single statement of unknown shape gets rows for reads (and for `... RETURNING ...`) and affected/last-insert for plain writes. It first denies ATTACH/DETACH — those reach the host filesystem and bypass the registry / single-owner vault invariant. This is the interim default-deny ahead of the full per-principal authorizer (Phase 4).

The read/write split is a heuristic — the leading keyword plus a RETURNING probe — used on BOTH the native and Hrana execution paths. (Hrana `describe` no longer relies on it: it prepares the statement and reports the driver's exact sqlite3_stmt_readonly.) Wiring the same exact classification into Run is a follow-up. A misclassified writing-CTE without RETURNING still EXECUTES correctly (QueryContext runs it); only its rows_affected metadata goes unreported.

type Error

type Error struct {
	Code     int // primary SQLite result code
	Extended int // extended result code
	Msg      string
}

Error is the typed server error, carrying SQLite's primary and extended result codes so each protocol layer can map them (Hrana error, native JSON error) without re-parsing message strings.

func (*Error) Error

func (e *Error) Error() string

type Kind

type Kind uint8

Kind enumerates SQLite's five dynamic storage classes. The wire codecs (Hrana, protobuf, native JSON) all encode from this single internal union.

const (
	KindNull Kind = iota
	KindInt
	KindFloat
	KindText
	KindBlob
)

type NamedArg

type NamedArg struct {
	Name  string
	Value Value
}

NamedArg binds a value to a named SQLite parameter (:name / @name / $name).

type Queryer

type Queryer interface {
	ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
	QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
}

Queryer is the database/sql surface the engine needs; *sql.DB, *sql.Conn, and *sql.Tx all satisfy it.

type Result

type Result struct {
	Columns      []Column
	Rows         [][]Value
	RowsAffected int64
	LastInsertID int64
	Truncated    bool
	Cursor       string
}

Result is the transport-agnostic outcome of a statement: rows for a query, affected/last-insert for a mutation. Truncated + Cursor support the streaming / keyset-pagination story (Phase 1/2).

type Statement

type Statement struct {
	SQL   string
	Args  []Value
	Named []NamedArg
}

Statement is one SQL statement with its bind arguments — positional (Args) or named (Named), not both.

type TxBeginner

type TxBeginner interface {
	BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
}

TxBeginner is the subset of database/sql that starts a transaction; both *sql.DB and *sql.Conn satisfy it, so a batch can run on the shared pool or on a single guarded (read-only) connection.

type Value

type Value struct {
	Kind  Kind
	Int   int64
	Float float64
	Text  string
	Blob  []byte
}

Value is one cell: exactly one field is meaningful, selected by Kind.

func Blob

func Blob(b []byte) Value

func Float

func Float(f float64) Value

func Int

func Int(n int64) Value

func Null

func Null() Value

func Text

func Text(s string) Value

Jump to

Keyboard shortcuts

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