Documentation
¶
Overview ¶
Package hazedb is a memory-resident SQL store for embedded Go applications with single-process deployment and latency-sensitive reads.
Index ¶
- Variables
- type ColumnDef
- type ColumnType
- type DB
- func (db *DB) Close() error
- func (db *DB) Exec(sql string, args ...any) (int, error)
- func (db *DB) FlushWAL() error
- func (db *DB) Query(sql string, args ...any) ([]string, []Row, error)
- func (db *DB) QueryRow(sql string, args ...any) ([]string, Row, error)
- func (db *DB) Transaction(fn func(*Tx) error) error
- type Options
- type Row
- type Schema
- type TableDef
- 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("fastsql: duplicate primary key") ErrUnknownTable = errors.New("fastsql: unknown table") ErrUnknownColumn = errors.New("fastsql: unknown column") ErrTypeMismatch = errors.New("fastsql: type mismatch") ErrParamMismatch = errors.New("fastsql: parameter count mismatch") ErrPKUpdate = errors.New("fastsql: UPDATE on PK column not supported") ErrParse = errors.New("fastsql: parse error") ErrWALCorrupt = errors.New("fastsql: WAL corrupted") ErrTableExists = errors.New("hazedb: table already exists") ErrTxUnsupported = errors.New("hazedb: operation not supported in a transaction") )
Functions ¶
This section is empty.
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).
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.
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 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) Exec ¶
Exec runs an INSERT, UPDATE, DELETE, CREATE TABLE, or DROP TABLE. 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) 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) 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.
type Options ¶
type Options struct {
// WALPath is the on-disk write-ahead log. Empty = memory-only
// (no durability). The file is created if it doesn't exist.
WALPath string
// Schema declares the tables. Required; at least one table.
Schema Schema
// SizeHint is a per-table row-count estimate for shard arena
// pre-allocation. Zero = use a small default.
SizeHint int
// WALFlushInterval is how often the background goroutine flushes the WAL
// buffer to the OS (and fsyncs when WALSync is set). Zero selects the
// safe default of 1s; a negative value disables the ticker entirely
// (manual FlushWAL() only). Ignored when WALPath is empty.
WALFlushInterval time.Duration
// WALSync makes the ticker fsync after flushing when anything is dirty,
// bounding power-loss to <= WALFlushInterval. Default false (flush only;
// survives process crash, not power loss).
WALSync bool
// WALSyncPerWrite flushes and fsyncs after every individual WAL record,
// under the WAL lock. Strongest durability (no acknowledged-loss window),
// highest per-write cost. Overrides the ticker's sync cadence.
WALSyncPerWrite bool
}
Options control Open behaviour.
type Schema ¶
type Schema struct {
Tables []TableDef
}
Schema is the database schema. Tables are addressed by name.
type TableDef ¶
TableDef defines a table. Exactly one column must have PK=true. Multi-column PK is v1.1+.
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 map key with no allocation — the primary key index is map[UUID]uint64.
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"). Beyond 4096 IDs in a single ms the timestamp is nudged forward to keep the ordering total. Client-supplied UUIDs get no such guarantee.
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.
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
¶
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. |