engine

package
v0.5.2 Latest Latest
Warning

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

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

Documentation

Overview

Package engine defines the database engine interface the console drives, and the engine-independent types it returns: catalog descriptions, result sets and normalised query plans.

A Session is owned by the console. It never receives SQL from an agent without the classifier having seen it first, and its catalog methods only run SQL built by the engine itself.

Index

Constants

View Source
const (
	AccessFull    = "full"    // full table scan
	AccessIndex   = "index"   // full scan of an index
	AccessRange   = "range"   // index or key range
	AccessLookup  = "lookup"  // equality lookup on a key or index
	AccessUnknown = "unknown" // the engine did not say
)

Access methods of a PlanNode.

View Source
const CutMark = "…"

CutMark ends a text value that was cut.

View Source
const MaxCellBytes = 64 << 10

MaxCellBytes is the most an engine keeps of one cell value. The engines apply it while reading, before a value is copied or converted (PostgreSQL on the wire, see the postgres capReader), so that a value of hundreds of megabytes built by the server (a numeric power, jsonb_pretty) never costs the console more. It equals the scan limit of the PII detectors: what is kept is what they read, and the renderer shows far less (max_cell_chars).

Variables

View Source
var ErrConnLost = errors.New("connection lost")

ErrConnLost reports that the database connection is gone. The console reconnects (asking for the secret again if needed) instead of retrying.

View Source
var ErrNoServerTLS = errors.New("the server does not offer TLS")

ErrNoServerTLS reports a server that does not offer TLS.

Functions

func CapBytes added in v0.5.0

func CapBytes(b []byte) (out []byte, cut bool)

CapBytes is a copy of a binary value, cut to MaxCellBytes bytes.

func CapText added in v0.5.0

func CapText(b []byte) (s string, cut bool)

CapText is the text of a value: b as is when it fits MaxCellBytes, else cut to at most MaxCellBytes bytes, CutMark included, and cut true. It copies no more of b than it keeps.

func ClientCertificate added in v0.5.0

func ClientCertificate(certFile, keyFile string) (tls.Certificate, error)

ClientCertificate loads the client certificate of tls_cert and its key from tls_key. The key must be readable by its owner only, as an ssh key. Errors name the files, never their content.

func CutAt added in v0.5.0

func CutAt(s string, n int) string

CutAt cuts s, which must be longer than n bytes, to at most n bytes followed by CutMark: at a rune boundary, then back over up to cutTail value-like characters, so that a value the cut splits (a partial e-mail address or number, which no detector would recognise) is dropped rather than shown in part.

func Names

func Names() []string

Names lists the registered engine names, sorted.

func ProbeDial added in v0.5.0

func ProbeDial(ctx context.Context, p config.Profile, def int) (net.Conn, error)

ProbeDial opens the TCP connection of a probe to the profile's host and port (def when the profile has none), bounded by ctx.

func ProbeHandshake added in v0.5.0

func ProbeHandshake(nc net.Conn, p config.Profile) ([]*x509.Certificate, error)

ProbeHandshake makes the TLS client handshake of a probe on nc and returns the server's certificates. A server that then refuses the handshake for want of a client certificate has already shown its own: they are returned with the error.

func Register

func Register(name string, e Engine)

Register makes an engine available under a config engine name. Engine packages call it from init; it panics on a duplicate or empty name.

func TLSConfig added in v0.5.0

func TLSConfig(p config.Profile) (*tls.Config, error)

TLSConfig builds the client TLS configuration of a network profile's tls mode, as libpq's sslmode: nil for disable and for a Unix socket; prefer and require encrypt without verifying, except require with tls_ca, which is verify-ca as in libpq; verify-ca checks the chain against tls_ca (or the system roots); verify-full checks the chain and that the certificate names host (or tls_server_name). "" is prefer, the mode of policies approved before the setting existed. tls_cert and tls_key, when set, are the client certificate presented to a server that asks for one.

func TLSVerifyHint added in v0.5.0

func TLSVerifyHint(err error, mode string) string

TLSVerifyHint is the way out of a connection refused because the server's certificate did not verify, as a private or self-signed one does since verify-full became the default of a remote host; "" for any other error.

Types

type ColumnDesc

type ColumnDesc struct {
	Name       string `json:"name"`
	Type       string `json:"type"`
	Nullable   bool   `json:"nullable"`
	PrimaryKey bool   `json:"primary_key,omitempty"`
	// Default is the column default as the catalog spells it, nil when none.
	Default *string `json:"default,omitempty"`
}

ColumnDesc describes one column for catalog.describe.

type ColumnInfo

type ColumnInfo struct {
	DB     string `json:"db"`
	Table  string `json:"table"`
	Column string `json:"column"`
	Type   string `json:"type"`
	// View is set for a column of a view (or a materialized view or a
	// foreign table): its base columns are unknown.
	View bool `json:"view,omitempty"`
}

ColumnInfo is one column of a table, as used for PII detection.

type DialFunc added in v0.5.0

type DialFunc func(ctx context.Context, network, addr string) (net.Conn, error)

DialFunc opens the network connection to the database server. nil is a direct TCP or Unix socket connection.

type Engine

type Engine interface {
	Connect(ctx context.Context, p config.Profile, secret []byte, dial DialFunc) (Session, error)
}

Engine opens sessions for one engine name. secret is the password, or nil when the engine needs none; it is never stored past Connect. dial, when not nil, opens every network connection of the session (main, control and cancel connections).

func Get

func Get(engine string) (Engine, error)

Get returns the engine registered under name.

type Flavor

type Flavor string

Flavor is the concrete server family behind a session.

const (
	FlavorMariaDB  Flavor = "mariadb"
	FlavorMySQL    Flavor = "mysql"
	FlavorPostgres Flavor = "postgres"
	FlavorSQLite   Flavor = "sqlite"
)

Flavors, matching the config engine names.

type IndexDesc

type IndexDesc struct {
	Name    string   `json:"name"`
	Columns []string `json:"columns"`
	Unique  bool     `json:"unique,omitempty"`
	Primary bool     `json:"primary,omitempty"`
}

IndexDesc describes one index for catalog.describe.

type Noticer

type Noticer interface {
	Notices() []string
}

Noticer is implemented by sessions with something the human must know about the connection itself, such as a fallback to no encryption. The console prints and audits each notice after connecting.

type Plan

type Plan struct {
	Root PlanNode `json:"root"`
	// Cost is the engine's total cost estimate for the statement, in its
	// own units (PostgreSQL Total Cost, MySQL query_cost, MariaDB cost), or
	// -1 when the engine gives none.
	Cost float64         `json:"cost"`
	Raw  json.RawMessage `json:"raw"`
}

Plan is a normalised plan plus the engine's raw plan, kept for the audit log and for debugging.

type PlanNode

type PlanNode struct {
	Table string `json:"table,omitempty"`
	// Access is one of the Access* constants for a table node, "" for a group.
	Access string `json:"access,omitempty"`
	// EstRows is the engine's estimate of rows examined per execution of the
	// node, or -1 when the engine has none.
	EstRows int64 `json:"est_rows"`
	// Sort and Temp report a sort or a temporary table. On a group they apply
	// to the output of the group's pipeline.
	Sort bool `json:"sort,omitempty"`
	Temp bool `json:"temp,omitempty"`
	// Correlated marks a subquery evaluated once per outer row.
	Correlated bool `json:"correlated,omitempty"`
	// NoJoinCond marks a table joined without a usable join condition, so
	// that every outer row reads all of it.
	NoJoinCond bool `json:"no_join_cond,omitempty"`
	// Recursive marks the group of a recursive CTE: how many times it
	// iterates is unknown to the planner, so its row estimate is a guess.
	Recursive bool `json:"recursive,omitempty"`
	// Detail is the engine's own label for the node, for display only.
	Detail   string     `json:"detail,omitempty"`
	Children []PlanNode `json:"children,omitempty"`
}

PlanNode is one node of a normalised plan.

A node with a Table is a table access. A node without one is a group: the plan root, a subquery, a derived table, a compound arm and so on, with Detail naming it. The table children of a group form, in order, one nested-loop pipeline: the rows examined are the product of their EstRows. The group children are subqueries and materialisations: their cost adds to the group, multiplied by the outer rows when Correlated.

type Result

type Result struct {
	Columns []ResultColumn `json:"columns"`
	Rows    [][]any        `json:"rows"`
	// Truncated is set when the statement produced more than maxRows rows.
	Truncated bool `json:"truncated"`
	// Affected is the number of rows changed by a write-class statement.
	Affected int64 `json:"affected"`
	// CutCells lists the cells, as [row, column] indexes of Rows, whose
	// value was longer than MaxCellBytes and was cut while it was read.
	CutCells [][2]int `json:"cut_cells,omitempty"`
}

Result is the outcome of Run. Rows hold driver values (nil, int64, float64, string, []byte, time.Time, ...); rendering and masking happen later, in the console.

func (*Result) CutSet added in v0.5.0

func (r *Result) CutSet() map[[2]int]bool

CutSet is CutCells as a set, for lookups over a whole result.

func (*Result) IsCut added in v0.5.0

func (r *Result) IsCut(row, col int) bool

IsCut reports whether the engine cut cell (row, col).

func (*Result) MarkCut added in v0.5.0

func (r *Result) MarkCut(row, col int)

MarkCut records that the engine cut cell (row, col) at MaxCellBytes.

type ResultColumn

type ResultColumn struct {
	Label        string `json:"label"`
	OriginDB     string `json:"origin_db,omitempty"`
	OriginTable  string `json:"origin_table,omitempty"`
	OriginColumn string `json:"origin_column,omitempty"`
}

ResultColumn is one result column: its label, and the base column it comes from when the engine reports it. The origin fields are all empty when the origin is unknown or not trustworthy.

func (ResultColumn) HasOrigin

func (c ResultColumn) HasOrigin() bool

HasOrigin reports whether the column carries an origin.

type Session

type Session interface {
	ServerVersion() string
	Flavor() Flavor
	// OriginColumns reports whether Run fills in result column origins.
	OriginColumns() bool
	// ExtraPrivileges lists the warnings about what the connection could do
	// beyond the profile tier.
	ExtraPrivileges(ctx context.Context, tier config.Tier) ([]string, error)
	Databases(ctx context.Context) ([]string, error)
	Tables(ctx context.Context, db string) ([]string, error)
	Describe(ctx context.Context, db, table string) (TableInfo, error)
	Columns(ctx context.Context, db string) ([]ColumnInfo, error)
	Explain(ctx context.Context, db, sql string) (Plan, error)
	// Run executes one classified statement. Write classes run in a
	// transaction and report Affected. Rows are capped at maxRows (no cap
	// when maxRows <= 0) and Truncated says whether more were available.
	Run(ctx context.Context, db string, st sqlclass.Statement, maxRows int) (Result, error)
	Ping(ctx context.Context) error
	Close() error
}

Session is one open connection with its policy-relevant settings applied (read-only mode for tier read, timeouts).

type TLSProber added in v0.5.0

type TLSProber interface {
	ProbeTLS(ctx context.Context, p config.Profile) ([]*x509.Certificate, error)
}

TLSProber is implemented by the engines whose protocol starts TLS before authentication. ProbeTLS connects to the profile's server directly (not through an ssh tunnel), starts TLS as the engine does and returns the certificates the server presents, leaf first, verifying nothing. It sends no user name and no secret, and presents no client certificate: locksql doctor uses it from an account that holds none.

type TableInfo

type TableInfo struct {
	DB      string       `json:"db"`
	Table   string       `json:"table"`
	Columns []ColumnDesc `json:"columns"`
	Indexes []IndexDesc  `json:"indexes,omitempty"`
	// EstRows is the engine's row estimate, or -1 when it has none.
	EstRows int64 `json:"est_rows"`
}

TableInfo is the catalog description of one table or view.

type Transport added in v0.5.0

type Transport struct {
	Mode, CA, Host string
	Plain          bool
	Tunneled       bool
}

Transport is how a session reached its server, for the notices: the profile's tls mode, tls_ca and host, whether the TCP connection runs without TLS, and whether it was dialled through an SSH tunnel.

func (Transport) Notices added in v0.5.0

func (t Transport) Notices() []string

Notices reports a connection an attacker on the path could read or stand in for: plain TCP, or TLS whose certificate chain is not verified. A tunnelled session is not advised to use an ssh tunnel.

Directories

Path Synopsis
Package mysql is the MariaDB and MySQL engine, on the go-mysql-org client (chosen because it reports each result column's origin schema, table and column).
Package mysql is the MariaDB and MySQL engine, on the go-mysql-org client (chosen because it reports each result column's origin schema, table and column).
Package postgres is the PostgreSQL engine, on pgx v5.
Package postgres is the PostgreSQL engine, on pgx v5.
Package sqlite is the SQLite engine, on the pure-Go modernc.org/sqlite driver.
Package sqlite is the SQLite engine, on the pure-Go modernc.org/sqlite driver.

Jump to

Keyboard shortcuts

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