Documentation
¶
Overview ¶
Package hazedb is a memory-resident SQL store for embedded Go applications with single-process deployment and latency-sensitive reads.
Index ¶
- Variables
- func ArgsFromJSON(raw []byte) ([]any, error)
- func DeregisterDBIf(name string, db *DB)
- func ErrorJSON(msg string) []byte
- func ExecResultJSON(affected int) []byte
- func LookupDBSlot(name string) *atomic.Pointer[DB]
- func QueryArgs(s string) ([]any, error)
- func RegisterDB(name string, db *DB)
- func RowToJSONObject(cols []string, row Row) ([]byte, error)
- func RowsToJSON(cols []string, rows []Row) ([]byte, error)
- func RowsToJSONObjects(cols []string, rows []Row) ([]byte, error)
- type ColumnDef
- type ColumnType
- type DB
- func (db *DB) Close() error
- func (db *DB) Exec(sql string, args ...any) (int, error)
- func (db *DB) ExecValues(sql string, args ...Value) (int, error)
- func (db *DB) FlushWAL() error
- func (db *DB) MetaJSON() []byte
- func (db *DB) MetaSnapshot() StoreMeta
- func (db *DB) Prepare(sql string) (*Stmt, error)
- func (db *DB) Query(sql string, args ...any) ([]string, []Row, error)
- func (db *DB) QueryEach(sql string, args []Value, visit func(cols []string, row Row) bool) error
- func (db *DB) QueryJSON(sql string, args ...Value) ([]string, []byte, error)
- func (db *DB) QueryJSONInto(dst []byte, sql string, args ...Value) ([]string, []byte, error)
- func (db *DB) QueryRow(sql string, args ...any) ([]string, Row, error)
- func (db *DB) QueryRowJSONByIndex(dst []byte, sql string, key Value) (out []byte, found bool, err error)
- func (db *DB) QueryRowJSONByPK(dst []byte, sql string, id UUID) (out []byte, found bool, err error)
- func (db *DB) QueryRowValues(sql string, args ...Value) ([]string, Row, error)
- func (db *DB) QueryValues(sql string, args ...Value) ([]string, []Row, error)
- func (db *DB) Transaction(fn func(*Tx) error) error
- type IndexDef
- type Options
- type Row
- type Schema
- type Stmt
- func (s *Stmt) Columns() []string
- func (s *Stmt) Exec(args ...any) (int, error)
- func (s *Stmt) Query(args ...any) ([]string, []Row, error)
- func (s *Stmt) QueryRow(args ...any) ([]string, Row, error)
- func (s *Stmt) QueryRowByIndex(key Value, dst []Value) (out []Value, found bool, err error)
- func (s *Stmt) QueryRowByPK(pk UUID, dst []Value) (out []Value, found bool, err error)
- type StoreMeta
- type TableDef
- type TableStat
- type Tx
- type UUID
- type Value
- func (v Value) AsInt() (int64, error)
- func (v Value) AsString() string
- func (v Value) Bool() bool
- func (v Value) Bytes() []byte
- func (v Value) Compare(o Value) (int, bool)
- func (v Value) Equal(o Value) bool
- func (v Value) Int() int64
- func (v Value) IsNull() bool
- func (v Value) Str() string
- func (v Value) UUID() UUID
- type ValueKind
Constants ¶
This section is empty.
Variables ¶
var ( ErrDuplicatePK = errors.New("hazedb: duplicate primary key") ErrUnknownTable = errors.New("hazedb: unknown table") ErrUnknownColumn = errors.New("hazedb: unknown column") ErrTypeMismatch = errors.New("hazedb: type mismatch") ErrParamMismatch = errors.New("hazedb: parameter count mismatch") ErrPKUpdate = errors.New("hazedb: UPDATE on PK column not supported") ErrParse = errors.New("hazedb: parse error") ErrUnindexedJoin = errors.New("hazedb: JOIN requires an index on the join column") ErrWALCorrupt = errors.New("hazedb: WAL corrupted") ErrWALVersion = errors.New("hazedb: WAL version mismatch") ErrTableExists = errors.New("hazedb: table already exists") ErrTxUnsupported = errors.New("hazedb: operation not supported in a transaction") ErrBatchTooLarge = errors.New("hazedb: atomic batch too large") ErrCapacity = errors.New("hazedb: store byte capacity exceeded") ErrReservedName = errors.New("hazedb: table name uses the reserved _hz_ prefix") ErrCompanionInMemory = errors.New("hazedb: companion must be an on-disk file, not in-memory") ErrClosed = errors.New("hazedb: database is closed") )
Functions ¶
func ArgsFromJSON ¶ added in v0.1.4
ArgsFromJSON parses a JSON array of positional SQL args into the []any db.Query / db.Exec accept. Empty/nil input yields no args. See the file header for the type mapping (notably the canonical-UUID-string rule).
func DeregisterDBIf ¶ added in v0.1.4
DeregisterDBIf clears the slot only if it still holds db (CAS). Safe for caddymodule Cleanup during reload: preserves a newer Provision's registration.
func ExecResultJSON ¶ added in v0.1.4
ExecResultJSON renders a write result as {"affected":n}. Hand-appended — the shape is fixed, so the reflection-based json.Marshal it used was pure overhead on every HTTP write response.
func LookupDBSlot ¶ added in v0.1.4
LookupDBSlot returns the stable atomic slot for name (lazily created). Cache it once and Load() per use:
var defaultSlot = hazedb.LookupDBSlot("default")
db := defaultSlot.Load() // nil until a caddymodule Provision registers one
func QueryArgs ¶ added in v0.1.4
QueryArgs parses an adapter's args parameter in either form:
- "" → no args
- starts with '[' → a JSON array (ArgsFromJSON; multi-arg / typed / writes)
- anything else → ONE positional arg passed directly: a canonical UUID string → UUID, otherwise STRING
The direct form lets a caller pass a key it already has — e.g. the UUID from a clicked link — straight into `WHERE id = ?` with no json_encode wrapping, the common single-key read. For integer args or several args, use the JSON array form so types are unambiguous.
func RegisterDB ¶ added in v0.1.4
RegisterDB publishes db under name. Pass nil to clear unconditionally; from Cleanup-style paths use DeregisterDBIf to avoid clobbering a newer registration.
func RowToJSONObject ¶ added in v0.1.43
RowToJSONObject renders ONE row as a single JSON object {"col":val,...} — the shape a PK / single-row read returns (vs RowsToJSONObjects' array). Never errors (kept for API symmetry).
func RowsToJSON ¶ added in v0.1.4
RowsToJSON renders a result set as {"columns":[...],"rows":[[...],...]}.
Hand-rolled: it appends each Value straight into one capacity-hinted buffer, with no [][]any intermediate, no interface boxing, and no reflection. On a hot read path (one PHP call per request) that is ~1.5–3× faster than encoding/json and turns ~4 allocations per row into a single buffer allocation. The returned []byte is the caller's to keep or copy (the PHP adapter copies it into a zend_string immediately). Never errors — the signature keeps the error for API symmetry with the rest of wire.go.
func RowsToJSONObjects ¶ added in v0.1.4
RowsToJSONObjects renders a result set as a JSON array of objects keyed by column name — [{"col":val,...},...] — the shape a fetchall-style caller forwards straight to an HTTP/JSON response. Same hand-rolled, single-buffer approach as RowsToJSON; never errors (error kept for API symmetry).
Types ¶
type ColumnDef ¶
type ColumnDef struct {
Name string
Type ColumnType
// PK marks the single primary-key column. It must be TypeUUID and is
// implicitly immutable.
PK bool
// Immutable rejects UPDATE SET on this column at plan time. Used for an
// ordering column (e.g. seq) so a tail index can cache its order safely.
Immutable bool
// PartitionKey marks the column the table is sharded/ordered by (e.g.
// thread_id on a messages table). At most one per table; must be UUID in
// v1; implicitly immutable (a partition move is DELETE + INSERT). Storage
// routing + the ordered tail index build on it.
PartitionKey bool
Nullable bool
}
ColumnDef describes one column at table-create time.
type ColumnType ¶
type ColumnType uint8
ColumnType is the declared type of a column. Generic v1 supports a small set; codegen (M3) expands to richer types.
const ( TypeInt ColumnType = iota + 1 TypeString TypeBytes TypeBool TypeUUID )
func (ColumnType) String ¶
func (t ColumnType) String() string
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
--- Gateway contract -------------------------------------------------------
*DB is the single official entry point — the "gateway". Every consumer enters through it: Caddy calls these methods as native Go, and the FrankenPHP/PHP extension reaches them via cgo (C → exported Go → these same methods). There is no second transport — the PHP path is cgo calling the very same verbs, not a parallel API. The gateway verbs are Open/Close/FlushWAL/Exec/Query/QueryRow here, plus Transaction (txn.go). The *Values (pre-typed args) and *JSON* (encode-in-place) methods are in-process fast-path variants of the same verbs, upholding the same guarantees. The verbs live in db_exec.go (writes) and db_query.go (reads); WAL/recovery replay is in db_replay.go.
Every verb upholds these guarantees, so all consumers inherit them for free:
- Validation. SQL is parsed, planned, and bound to the live catalog in prepare(); args are type-coerced in toValue. Bad SQL or args fail here.
- Boundary clone. []byte/Value args are deep-copied on the way in (storage never aliases caller memory), and returned rows are deep-cloned on the way out (callers may retain them past later writes).
- No bypass. table/shard/catalog/wal are unexported, so no consumer can reach storage around the validated verbs.
Caller obligation — parameterize. Pass values as ? placeholders, never spliced into the SQL text. prepare caches one compiled plan per unique SQL string and keeps it for the process lifetime; a parameterized statement set is finite so the cache stays bounded, but interpolating values mints a new key per call and the cache grows without bound in a long-lived process.
Boundary rule: db semantics live behind the gateway (this package); cross-cutting concerns — auth, tenancy, logging, and the PHP↔Go marshalling the extension needs — live in the consumer/adapter, which then calls these same verbs. Never push consumer-specific concerns into the core.
DB is the embedded database handle. One DB per process per WAL path. Open is goroutine-safe; Exec and Query are goroutine-safe.
func LookupDB ¶ added in v0.1.4
LookupDB returns the *DB registered under name, or nil. Convenience wrapper; hot-path consumers should cache the slot via LookupDBSlot and Load() per use.
func Open ¶
Open prepares the database. If WALPath is non-empty, the file is opened and any existing records are replayed into memory before Open returns. Open is blocking until replay completes.
func (*DB) Close ¶
Close stops the SQLite drain loop (which seals the active segment and runs a final drain so the mirror is current), then the index merger and the compaction sweeper, then flushes and closes the WAL, then closes the mirror. Memory-only DBs still stop the background loops. The drain loop is stopped first, while the WAL is still open. Close marks the DB closed before tearing anything down, so every public verb then fails with ErrClosed; a second Close is a no-op.
func (*DB) Exec ¶
Exec runs an INSERT, UPDATE, DELETE, CREATE TABLE, or DROP TABLE. Returns the affected row count (0 for DDL).
func (*DB) ExecValues ¶ added in v0.1.4
ExecValues runs a write with pre-typed Value arguments, skipping the []any arg-conversion layer Exec uses (no JSON decode, no interface boxing, no per-arg type switch). It is the in-process fast path for callers that already hold typed Values — notably the PHP extension reading a native zend_array via cgo, which avoids the json_encode/json.Decode round-trip the string args form pays. Returns the affected row count (0 for DDL).
func (*DB) FlushWAL ¶
FlushWAL forces bufio to fsync. Use before reading a record back from disk in tests, or for an explicit durability boundary in callers. Memory-only DBs are a no-op.
func (*DB) MetaJSON ¶ added in v0.1.53
MetaJSON renders MetaSnapshot as a JSON object for the out-of-core adapters (Caddy GET /meta, PHP hazedb_meta) — one wire-shape definition both share, so the HTTP and cgo surfaces always emit identical bytes. Cold operator path, so it uses stdlib json.Marshal (like ExecResultJSON/ErrorJSON) rather than the hand-rolled row encoder. Never errors — the struct is plain data.
func (*DB) MetaSnapshot ¶ added in v0.1.34
MetaSnapshot returns the current StoreMeta. It loads the catalog atomically (lock-free) and reads each table with one brief per-shard RLock sweep. Stats are sorted by table name for a stable overview.
func (*DB) Prepare ¶ added in v0.1.4
Prepare compiles sql into a reusable statement bound to the current catalog.
func (*DB) Query ¶
Query runs a SELECT. Returns the column names (in projection order) and the rows. Rows are deep-cloned; callers may retain them past future Exec calls without worrying about aliasing into storage.
func (*DB) QueryEach ¶ added in v0.1.14
QueryEach runs a SELECT and calls visit(cols, row) once per result row, in order. It is the low-allocation counterpart to QueryValues for consumers that serialize each row immediately (e.g. building a PHP array). visit returns false to stop early. cols is the same slice on every call.
The row obeys the streaming memory-safety contract above: valid only during the call; copy out anything kept. Use QueryValues when you need owned rows.
func (*DB) QueryJSON ¶ added in v0.1.14
QueryJSON runs a SELECT and returns the result as a JSON array of objects ([{"col":val,...},...]) — the same shape as RowsToJSONObjects, but encoded straight from the live rows into one buffer, with no intermediate []Row and no per-row clone. The returned bytes are the caller's to keep or copy. For a read-and-forward path (an HTTP/JSON response) this avoids materializing rows only to re-encode and discard them.
func (*DB) QueryJSONInto ¶ added in v0.1.16
QueryJSONInto is QueryJSON that appends into the caller-supplied buffer dst, returning the columns and the grown slice. Pass dst[:0] to reuse a pooled scratch buffer: a hot read-and-forward caller (the PHP/HTTP fetchall_json path) that keeps one buffer per worker and copies the result out immediately pays no per-call allocation for the JSON envelope — only the amortised growth to the high-water mark. The returned slice may share dst's backing array.
func (*DB) QueryRow ¶ added in v0.1.2
QueryRow runs a SELECT expected to yield a single row and returns the first matching row, or a nil Row if there is none — without allocating the []Row result slice that Query needs. For a PK-pinned query (WHERE id = ?) it goes straight through the point-read path (the common case); for an unpinned query it returns the first row of the scan, so constrain such queries with LIMIT 1 to avoid scanning more rows than needed. The returned row is deep-cloned, as with Query.
func (*DB) QueryRowJSONByIndex ¶ added in v0.1.44
func (db *DB) QueryRowJSONByIndex(dst []byte, sql string, key Value) (out []byte, found bool, err error)
QueryRowJSONByIndex is QueryRowJSONByPK for a single-indexed-equality point lookup: WHERE <indexed> = ? LIMIT 1 (no ORDER BY / OFFSET). It resolves the candidates through the secondary index, re-checks the full WHERE on each live candidate, and appends the first match as a flat JSON object into dst UNDER the shard read lock (no Row clone). key is the typed lookup value (no arg boxing); dst is caller-owned and reused, so a steady-state hit allocates only the index-bucket copy. Returns the grown buffer and whether a row matched.
func (*DB) QueryRowJSONByPK ¶ added in v0.1.43
QueryRowJSONByPK looks up a PK-pinned SELECT and appends the single matching row as a flat JSON object {"col":val,...} into dst, encoding the cells UNDER the shard read lock straight from the live row (no Row clone) with a typed id (no string→any boxing). dst is caller-owned and reused across calls, so a steady-state call allocates nothing. Returns the grown buffer and whether a row matched. The allocation-free read lane for an in-process JSON consumer (the Caddy GET handler); requires WHERE id = ? — a non-PK-pinned SELECT is rejected, like QueryRowByPK.
func (*DB) QueryRowValues ¶ added in v0.1.4
QueryRowValues is QueryRow with pre-typed args (see QueryValues).
func (*DB) QueryValues ¶ added in v0.1.4
QueryValues is Query with pre-typed args — the read counterpart of ExecValues, for in-process callers (the PHP extension) that already hold typed Values and want to skip the []any/JSON conversion. Reads never store the args, so no per-arg clone is needed.
type IndexDef ¶ added in v0.1.5
type IndexDef struct {
Name string // optional; auto-derived as "idx_<col>[_<col>...]" when empty
Columns []string
// Ordered makes this a sorted index (serves equality + ranges + ORDER BY)
// instead of the default hash index (equality only). A column has one or the
// other, not both. Composite indexes are always Ordered.
Ordered bool
}
IndexDef declares a secondary index on one or more non-PK columns. Maintained asynchronously and read through a hybrid path; see docs/secondary-indexes.md. A composite (multi-column) index must be Ordered (see parseIndexClause).
type Options ¶
type Options struct {
// Schema declares the tables present at startup. May be empty — tables can
// also be created at runtime with CREATE TABLE.
Schema Schema
// WALPath is the directory holding the write-ahead log segments, created if
// absent. Setting it turns the WAL ON; leaving it empty is memory-only
// (nothing survives a restart). The WAL has one durability story: a write is
// sealed to disk within ~0.5s (or sooner once 1 MiB has accumulated), so a
// crash loses at most that window. Acknowledge-after-fsync is intentionally
// not offered — use a disk-first database if you need it.
WALPath string
// CompanionPath is where the SQLite companion file lives — always a real file on
// disk, present in EVERY mode (WAL on or off). It is hazedb's always-on store:
// the _hz_events operational log (logging, health, later perf samples) and,
// when WAL is on, the data mirror + recovery base. Set it to pin hazedb.db at
// one fixed path regardless of WAL. Empty defaults to "hazedb.db" inside WALPath
// when WAL is on, else "hazedb.db" in the working directory. Never in-memory.
CompanionPath string
// MaxBytes caps the store's approximate in-RAM size (the sum of every table's
// byte tally, the same figure MetaSnapshot reports). An INSERT that would push
// the total past it is rejected with ErrCapacity; the store never auto-evicts,
// so the caller frees space with DELETE / DROP TABLE. 0 (the default) is
// unlimited and adds no write-path cost.
MaxBytes int64
// contains filtered or unexported fields
}
Options configure Open. The EXPORTED fields are the entire operator surface; the unexported fields are internal tuning, settable only from package tests (the defaults are right for every deployment). Genuine implementation constants — buffer sizes, flush triggers, SQLite PRAGMAs, segment naming, shard counts — are not settings and live next to the code that uses them.
type Schema ¶
type Schema struct {
Tables []TableDef
}
Schema is the database schema. Tables are addressed by name.
type Stmt ¶ added in v0.1.4
type Stmt struct {
// contains filtered or unexported fields
}
Stmt is a SQL string compiled to a plan once and reused. Versus the bare DB.Query/Exec path it skips the per-call statement-cache lookup (no SQL-string hash), and it adds a typed, zero-allocation point-read fast path, QueryRowByPK. Safe for concurrent use: the held plan is rebound automatically if a CREATE/DROP changes the catalog after Prepare.
func (*Stmt) Columns ¶ added in v0.1.4
Columns returns the SELECT output column names (nil for a non-SELECT). The slice is shared and read-only — callers must not mutate it.
func (*Stmt) QueryRow ¶ added in v0.1.4
QueryRow runs a prepared single-row SELECT. See DB.QueryRow.
func (*Stmt) QueryRowByIndex ¶ added in v0.1.32
QueryRowByIndex is the point-lookup fast path for a single secondary-index equality: the statement must pin exactly one indexed column with an explicit single-row cap — WHERE <indexed> = ? LIMIT 1 — and no ORDER BY or OFFSET. It returns the first live row that passes the full WHERE and stops. The match is ordering-undefined by design: this serves unique-key lookups (fetch the account row for an email at login) and existence checks (does this email already exist?), where "any one match" is the answer.
It cannot return the newest/highest row — there is no ordering on this path. For that, write ORDER BY <ordered-indexed col> DESC LIMIT 1, which compiles to the ordered-index walk and is rejected here (orderOrdinal >= 0). The mandatory LIMIT 1 keeps that distinction explicit at the call site.
key is the typed value for the one parameter (no interface boxing); the matching row's projection is written into dst, grown only if too small — reuse it across calls. found reports whether a row matched. In steady state it allocates only the index-bucket copy (~one small slice); the projection scan and the empty dirty overlay add none. The full WHERE is re-checked on each live candidate (staleness + any residual), so a statement needing a second parameter returns an error rather than a wrong row.
func (*Stmt) QueryRowByPK ¶ added in v0.1.4
QueryRowByPK is the zero-allocation point-read fast path. The statement must be a PK-pinned SELECT (WHERE <pk> = ?); the key is taken as a typed UUID (no interface boxing) and the projected cells are written into dst, which is grown only if too small — reuse it across calls. found reports whether a row matched. Non-byte cells are copied directly; BYTES cells are cloned to honour storage's no-alias guarantee, so a projection without BYTES columns allocates nothing.
type StoreMeta ¶ added in v0.1.34
type StoreMeta struct {
Tables int `json:"tables"`
// MaxBytes is the configured byte cap (Options.MaxBytes); 0 means unlimited.
// TotalApproxBytes is what it is measured against — an insert is rejected once
// the total would exceed it.
MaxBytes int64 `json:"max_bytes"`
// TotalRows / TotalApproxBytes / TotalTombstones roll up every table's line, so
// a caller gets the store-wide figures without summing TableStats itself.
// TotalApproxBytes is the sum of the per-table estimates and inherits their
// slight over-bias.
TotalRows int `json:"total_rows"`
TotalApproxBytes int64 `json:"total_approx_bytes"`
TotalTombstones int `json:"total_tombstones"`
TableStats []TableStat `json:"table_stats"`
}
MetaSnapshot / StoreMeta give a lock-light overview of what the store holds: the table count plus, per table, row count, column count, secondary-index count, and an in-RAM size. For operator dashboards and health checks — a read path, never the write path.
The size walks every live row under a brief per-shard RLock and sums each cell's exact footprint, so the payload term — the part that varies — is exact, not sampled. It adds the fixed per-row overhead and a flat per-row charge for each secondary index, both modeled constants biased slightly high. Cost is O(live rows): right for an occasional dashboard hit, not for a per-write budget check — a future byte cap maintains its own O(1) counter on the write path rather than calling this.
type TableDef ¶
TableDef defines a table. Exactly one column must have PK=true. Multi-column PK is v1.1+.
type TableStat ¶ added in v0.1.34
type TableStat struct {
Name string `json:"name"`
Rows int `json:"rows"`
Columns int `json:"columns"`
Indexes int `json:"indexes"`
ApproxBytes int64 `json:"approx_bytes"`
Tombstones int `json:"tombstones"`
}
TableStat is one table's line in a StoreMeta. ApproxBytes sums exact cell payloads plus modeled overhead (see StoreMeta); a display layer formats it to MiB.
Tombstones is the count of dead arena slots — rows deleted but whose arena slot is not yet reclaimed. It is a gauge, not a leak: the background compaction sweeper (compact.go) reclaims dense shards, so it rises with deletes and falls as the sweeper runs. (Partitioned scan cost is independent — the delete path prunes a partition's scan list, so scanPartition stays O(live) regardless.) A momentarily high Tombstones/(Rows+Tombstones) fraction is normal between sweeps; a persistently high one means deletes outrun the sweeper's interval.
type Tx ¶
type Tx struct {
// contains filtered or unexported fields
}
Tx is the transaction handle passed to the db.Transaction closure.
type UUID ¶
type UUID [16]byte
UUID is a 128-bit identifier (RFC 9562). It is a fixed array so it is comparable and usable directly as a key with no allocation — the primary key index is the open-addressed pkMap (pkmap.go) keyed by UUID.
func NewUUIDv7 ¶
func NewUUIDv7() UUID
NewUUIDv7 returns a fresh UUIDv7 with within-millisecond monotonicity: IDs from this process sort by creation time, including inside one millisecond, via a 12-bit counter in rand_a (RFC 9562 "fixed-length dedicated counter"). The counter caps at 4096 IDs per ms (≈4.1M auto-PKs/sec); beyond that the timestamp is nudged forward to keep the ordering total, so under sustained bulk-load above that rate the stamp drifts ahead of the wall clock (it self-corrects once the rate drops; uniqueness and ordering always hold).
Auto-PK inserts (id omitted) are the only callers. The stamp advances by a single lock-free CAS, so parallel inserts never queue behind a generator mutex; rand_b is copied from one of uuidRandShards independently locked buffers. Client-supplied UUIDs skip this path entirely — no monotonicity guarantee, but also no shared state touched.
func ParseUUID ¶
ParseUUID parses the canonical 36-character hyphenated hex form. It accepts any well-formed UUID (version is not enforced here — callers that require v7 check IsV7). Used at the API boundary to turn a string PK into the internal [16]byte; storage never sees the string form.
Hand-decoded via a nibble lookup table in one pass — no per-segment hex.Decode call and no string→[]byte conversion (a hot read-path cost since every string PK arg lands here).
func ParseUUIDOk ¶ added in v0.1.59
ParseUUIDOk is ParseUUID without the error: it returns ok=false instead of formatting an error. The text adapters guess UUID-ness by trying to parse every string arg (the WHERE email=? case parses-and-fails on the hot path), so the discarded error string in ParseUUID was an allocation per non-UUID arg. Callers that only branch on success use this; callers that surface the error (DDL/coercion) use ParseUUID.
func (UUID) AppendString ¶ added in v0.1.44
AppendString appends u's canonical 8-4-4-4-12 lowercase hex form to b and returns the extended slice — the allocation-free counterpart of String for hot encoders that pack into a reused buffer (the PHP row builder, JSON output), where String's per-call result string is pure waste.
func (UUID) IsV7 ¶
IsV7 reports whether u has the v7 version nibble and the RFC 4122/9562 variant bits (10xx). Used to validate client-supplied IDs.
type Value ¶
type Value struct {
Kind ValueKind
// contains filtered or unexported fields
}
Value is the runtime cell type: a packed 32-byte tagged union (versus the 72 bytes a struct with separate int/string/bytes/uuid fields would take). Kind is the public tag; the payload is overlapped across two words and a pointer, since a cell is only ever one kind at a time:
- KindInt / KindBool : the value lives in w0
- KindUUID : the 16 bytes live inline in (w0, w1), big-endian so comparing the words equals byte-lexicographic order
- KindString/KindBytes: ptr is the backing-data pointer, w0 the length
- KindNull : all zero
ptr is ALWAYS nil or a real Go pointer (a string/[]byte backing) — never a reinterpreted non-pointer — so the garbage collector scans it correctly and keeps the backing alive. Read payloads through the typed accessors below; never touch the private fields.
func (Value) AsInt ¶
AsInt returns the value as int64, coercing strings via strconv. Used for ORDER BY / range comparisons.
func (Value) AsString ¶
AsString returns the value formatted as text. Used for PK keys in the map index and for display.
func (Value) Compare ¶
Compare returns -1/0/1 for v < o, v == o, v > o. Coerces along the most-precise route: int-int → numeric, otherwise string-string. Null comparisons return 0 with comparable=false to let callers decide.
Source Files
¶
- ast.go
- budget.go
- catalog.go
- compact.go
- composite_key.go
- db.go
- db_exec.go
- db_query.go
- db_registry.go
- db_replay.go
- drain.go
- errors.go
- eval.go
- events.go
- exec_select.go
- exec_write.go
- filter.go
- join.go
- lexer.go
- mutation_codec.go
- options.go
- parser.go
- partition_store.go
- pkmap.go
- plan.go
- query_stream.go
- recover_sqlite.go
- schema.go
- secindex.go
- stats.go
- stmt.go
- store.go
- store_compact.go
- store_read.go
- store_write.go
- txn.go
- uuid.go
- value.go
- wal.go
- wal_segment.go
- wire.go
Directories
¶
| Path | Synopsis |
|---|---|
|
addons
|
|
|
frankenphp-ext
module
|
|
|
caddymodule
module
|
|
|
Package GO-SQLDB is a deliberately minimal spike to validate the central thesis of the GO-SQLDB design: that an in-memory Go store with a canonical WAL can beat SQLite-in-memory on the hot OLTP path.
|
Package GO-SQLDB is a deliberately minimal spike to validate the central thesis of the GO-SQLDB design: that an in-memory Go store with a canonical WAL can beat SQLite-in-memory on the hot OLTP path. |