minisql

package
v0.16.0 Latest Latest
Warning

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

Go to latest
Published: Apr 19, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DatabaseHeaderMagic identifies a MiniSQL database file.
	DatabaseHeaderMagic = "minisql\x00"
	// DatabaseFileFormatVersion identifies the current on-disk file header format.
	DatabaseFileFormatVersion = uint32(1)
)
View Source
const (
	// SchemaTableName is the internal table used to store schema metadata.
	SchemaTableName = "minisql_schema"
	// StatsTableName ...
	StatsTableName = "minisql_stats"
	// MaxColumns ...
	MaxColumns = 64
	// RootPageConfigSize is the number of bytes reserved for the root page config header.
	RootPageConfigSize = 100
)
View Source
const (
	// MaxInlineRowIDs ...
	MaxInlineRowIDs = 4
	// MaxOverflowRowIDsPerPage ...
	MaxOverflowRowIDsPerPage = 510 // (4096 - 1 - 8 ) / 8

)
View Source
const (
	// InternalNodeMaxCells is (4096 - 6 - 8) / 12.
	InternalNodeMaxCells = 340
	// RootInternalNodeMaxCells is (4096 - 6 - 8 - 100) / 12.
	RootInternalNodeMaxCells = 331
)

InternalNode capacity constants derived from page and header sizes. Page size: 4096, Header size: 6 (base) + 8 (internal), ICell size: 12.

View Source
const (
	// MaxInlineVarchar ...
	MaxInlineVarchar = 255 // Store up to 255 bytes inline
	// MaxOverflowPageData ...
	MaxOverflowPageData = 4096 - 1 - 8 // Page size - page type byte - OverflowPageHeader size
	// MaxOverflowTextSize limits the maximum size of a text value to 16 overflow pages.
	MaxOverflowTextSize = MaxOverflowPageData * 16
)
View Source
const (
	// PageSize ...
	PageSize = 4096 // 4 kilobytes

	// UsablePageSize returns the usable size of a page after accounting for headers
	// Page size minus base + internal/leaf header, minus key and null bitmask
	UsablePageSize = PageSize - 7 - 8 - 8 - 8
)
View Source
const (
	// PageTypeLeaf ...
	PageTypeLeaf byte = iota
	// PageTypeInternal identifies an internal (non-leaf) B+ tree node page.
	PageTypeInternal
	// PageTypeOverflow identifies a text overflow page.
	PageTypeOverflow
	// PageTypeIndex identifies an index B+ tree node page.
	PageTypeIndex
	// PageTypeFree identifies a free (unused) page available for reuse.
	PageTypeFree
	// PageTypeIndexOverflow identifies an index overflow page for large row ID lists.
	PageTypeIndexOverflow
)

PageType constants identify the type of data stored in a database page.

View Source
const (
	// WALMagic is the 8-byte magic string at the start of every WAL file.
	WALMagic = "miniwal\n"
	// WALVersion is the current on-disk WAL format version.
	WALVersion = uint32(1)
	// WALFileHeaderSize is the fixed byte size of the WAL file header.
	WALFileHeaderSize = 32
	// WALFrameHeaderSize is the fixed byte size of each WAL frame header.
	WALFrameHeaderSize = 24
)

WAL file-format constants.

View Source
const ICellSize = 12 // (8+4)

ICellSize is the serialised byte size of an ICell (8-byte key + 4-byte child pointer).

View Source
const MaxIndexKeySize = 255

MaxIndexKeySize is the maximum number of bytes allowed for a single index key.

View Source
const MinimumIndexCells = 4

MinimumIndexCells is the minimum number of cells required in an index node. TODO - this is not used currently

View Source
const PageCacheSize = 2000

PageCacheSize is the default maximum number of pages to keep in memory.

View Source
const RightChildNotSet = math.MaxUint32

RightChildNotSet is the sentinel value indicating an internal node has no right child yet.

Variables

View Source
var ErrDuplicateKey = errors.New("duplicate key")

ErrDuplicateKey ...

View Source
var ErrNoMoreRows = errors.New("no more rows")

ErrNoMoreRows ...

View Source
var ErrNotFound = errors.New("not found")

ErrNotFound ...

View Source
var ErrNotWALMode = errors.New("WAL mode is not enabled")

ErrNotWALMode is returned when a WAL-specific operation is called on a transaction manager that is not in WAL mode.

View Source
var ErrTxConflict = errors.New("transaction conflict detected")

ErrTxConflict is returned when an optimistic concurrency check fails at commit time.

View Source
var FunctionNow = Function{Name: nowFunctionName}

FunctionNow ...

View Source
var (

	// MainTableSQL is the DDL used to create the internal schema metadata table.
	MainTableSQL = fmt.Sprintf(`create table "%s" (
	type int4 not null,
	name varchar(255) not null,
	tbl_name varchar(255),
	root_page int4 not null,
	sql text
);`, SchemaTableName)
)
View Source
var (

	// StatsTableSQL is the DDL used to create the internal statistics table.
	StatsTableSQL = fmt.Sprintf(`create table "%s" (
	tbl varchar(255),
	idx varchar(255),
	stat text
);`, StatsTableName)
)

Functions

func IsValidCondition

func IsValidCondition(c Condition) bool

IsValidCondition checks that all fields of the condition are set

func NewPager

func NewPager(file DBFile, pageSize, maxCachedPages int) (*pagerImpl, error)

NewPager opens the database file and initialises the pager. maxCachedPages sets the maximum number of pages to keep in cache (0 = use default).

func PrimaryKeyName

func PrimaryKeyName(tableName string) string

PrimaryKeyName ...

func RecoverFromWAL added in v0.12.0

func RecoverFromWAL(dbPath string, dbFile DBFile, pageSize uint32) (bool, error)

RecoverFromWAL checks for a WAL file at dbPath+"-wal" and, if found, replays all committed frames into dbFile. The WAL is truncated on success. Returns true when recovery was performed.

func UniqueIndexName

func UniqueIndexName(tableName string, columns ...string) string

UniqueIndexName ...

func UnmarshalDatabaseHeader

func UnmarshalDatabaseHeader(buf []byte, dbHeader *DatabaseHeader) error

UnmarshalDatabaseHeader deserialises a database header from the given byte slice.

func WithTransaction

func WithTransaction(ctx context.Context, tx *Transaction) context.Context

WithTransaction stores a transaction in the context and returns the new context.

Types

type AggregateExpr

type AggregateExpr struct {
	Kind   AggregateKind
	Column string // source column name; empty for COUNT(*)
}

AggregateExpr describes a single aggregate function call in a SELECT list. Parallel to Fields: Fields[i] holds the synthetic output column name (e.g. "SUM(price)"), Aggregates[i] holds the kind and source column. A zero-value AggregateExpr (Kind == 0) means the corresponding field is not an aggregate. Aggregates is only populated when the query contains at least one aggregate function.

type AggregateKind

type AggregateKind int

AggregateKind identifies the type of aggregate function.

const (
	// AggregateCount ...
	AggregateCount AggregateKind = iota + 1 // COUNT(*)
	// AggregateSum ...
	AggregateSum // SUM(col)
	// AggregateAvg is the AVG aggregate function.
	AggregateAvg // AVG(col)
	// AggregateMin is the MIN aggregate function.
	AggregateMin // MIN(col)
	// AggregateMax is the MAX aggregate function.
	AggregateMax // MAX(col)
)

AggregateKind constants enumerate the supported aggregate functions.

func (AggregateKind) String

func (k AggregateKind) String() string

type ArithOp added in v0.4.0

type ArithOp int

ArithOp identifies the arithmetic operator in a binary Expr node.

const (
	ArithAdd ArithOp = iota + 1 // +
	ArithSub                    // -
	ArithMul                    // *
	ArithDiv                    // /
)

ArithOp constants.

func (ArithOp) String added in v0.4.0

func (op ArithOp) String() string

type BTreeIndex

type BTreeIndex interface {
	GetRootPageIdx() PageIndex
	FindRowIDs(ctx context.Context, key any) ([]RowID, error)
	SeekLastKey(ctx context.Context, pageIdx PageIndex) (any, error)
	Insert(ctx context.Context, key any, rowID RowID) error
	Delete(ctx context.Context, key any, rowID RowID) error
	ScanAll(ctx context.Context, reverse bool, callback indexScanner) error
	ScanRange(ctx context.Context, rangeCondition RangeCondition, reverse bool, callback indexScanner) error
	BFS(ctx context.Context, f indexCallback) error
}

BTreeIndex ...

type CaseWhen added in v0.8.0

type CaseWhen struct {
	Cond *ConditionNode // searched CASE: WHEN <condition>
	When *Expr          // simple CASE: WHEN <value> (compared to parent CaseInput)
	Then *Expr          // THEN <result>
}

CaseWhen holds one WHEN/THEN branch of a CASE expression. Exactly one of Cond (searched CASE) or When (simple CASE) is set.

type Cell

type Cell struct {
	NullBitmask uint64
	Key         RowID
	Value       []byte
	// contains filtered or unexported fields
}

Cell ...

func (*Cell) Marshal

func (c *Cell) Marshal(buf []byte)

Marshal ...

func (*Cell) Size

func (c *Cell) Size() uint64

Size ...

func (*Cell) Unmarshal

func (c *Cell) Unmarshal(columns []Column, buf []byte) (uint64, error)

Unmarshal ...

type Column

type Column struct {
	Kind ColumnKind
	Size uint32
	// PrimaryKey      bool
	// Autoincrement   bool
	// Unique          bool
	Nullable        bool
	DefaultValue    OptionalValue
	DefaultValueNow bool
	Name            string
}

Column ...

type ColumnKind

type ColumnKind int

ColumnKind ...

const (
	// Boolean ...
	Boolean ColumnKind = iota + 1
	Int4
	Int8
	Real
	Double
	Varchar
	Text
	Timestamp
)

ColumnKind constants enumerate the supported column data types.

func (ColumnKind) IsInt

func (k ColumnKind) IsInt() bool

IsInt ...

func (ColumnKind) IsText

func (k ColumnKind) IsText() bool

IsText ...

func (ColumnKind) String

func (k ColumnKind) String() string

type CompositeKey

type CompositeKey struct {
	Columns []Column
	Values  []any
	// Store the binary representation for comparison (excludes length prefixes for varchars)
	Comparison []byte
}

CompositeKey holds the column definitions and values for a multi-column index key.

func NewCompositeKey

func NewCompositeKey(columns []Column, values ...any) CompositeKey

NewCompositeKey constructs a CompositeKey from the given columns and values.

func (*CompositeKey) Marshal

func (ck *CompositeKey) Marshal(buf []byte, i uint64) error

Marshal serialises the composite key into buf starting at offset i.

func (CompositeKey) Prefix

func (ck CompositeKey) Prefix(columns int) CompositeKey

Prefix returns a CompositeKey containing only the first n columns' comparison bytes.

func (CompositeKey) Size

func (ck CompositeKey) Size() uint64

Size returns the serialised byte size of the composite key.

func (*CompositeKey) Unmarshal

func (ck *CompositeKey) Unmarshal(buf []byte, i uint64) (uint64, error)

Unmarshal deserialises a composite key from buf starting at offset i, returning bytes consumed.

type Condition

type Condition struct {
	// Operand1 is the left hand side operand
	Operand1 Operand
	// Operator is e.g. "=", ">"
	Operator Operator
	// Operand2 is the right hand side operand
	Operand2 Operand
}

Condition represents a single predicate: operand1 operator operand2.

func FieldIsBetween

func FieldIsBetween(field Field, low, high any) Condition

FieldIsBetween creates a field BETWEEN low AND high condition.

func FieldIsEqual

func FieldIsEqual(field Field, operandType OperandType, value any) Condition

FieldIsEqual creates a field = value condition.

func FieldIsGreater

func FieldIsGreater(field Field, operandType OperandType, value any) Condition

FieldIsGreater creates a field > value condition.

func FieldIsGreaterOrEqual

func FieldIsGreaterOrEqual(field Field, operandType OperandType, value any) Condition

FieldIsGreaterOrEqual creates a field >= value condition.

func FieldIsInAny

func FieldIsInAny(field Field, values ...any) Condition

FieldIsInAny creates a field IN (values...) condition.

func FieldIsLess

func FieldIsLess(field Field, operandType OperandType, value any) Condition

FieldIsLess creates a field < value condition.

func FieldIsLessOrEqual

func FieldIsLessOrEqual(field Field, operandType OperandType, value any) Condition

FieldIsLessOrEqual creates a field <= value condition.

func FieldIsLike

func FieldIsLike(field Field, operandType OperandType, value any) Condition

FieldIsLike creates a field LIKE value condition.

func FieldIsNotBetween

func FieldIsNotBetween(field Field, low, high any) Condition

FieldIsNotBetween creates a field NOT BETWEEN low AND high condition.

func FieldIsNotEqual

func FieldIsNotEqual(field Field, operandType OperandType, value any) Condition

FieldIsNotEqual creates a field != value condition.

func FieldIsNotInAny

func FieldIsNotInAny(field Field, values ...any) Condition

FieldIsNotInAny creates a field NOT IN (values...) condition.

func FieldIsNotLike

func FieldIsNotLike(field Field, operandType OperandType, value any) Condition

FieldIsNotLike creates a field NOT LIKE value condition.

func FieldIsNotNull

func FieldIsNotNull(field Field) Condition

FieldIsNotNull creates a field IS NOT NULL condition.

func FieldIsNull

func FieldIsNull(field Field) Condition

FieldIsNull creates a field IS NULL condition.

func (Condition) Operands

func (c Condition) Operands() []Operand

Operands returns both operands of the condition as a slice.

type ConditionNode

type ConditionNode struct {
	Leaf  *Condition     // non-nil for leaf nodes
	Left  *ConditionNode // non-nil for branch nodes
	Op    LogicOp        // logical operator for branch nodes
	Right *ConditionNode // non-nil for branch nodes
}

ConditionNode is a node in a boolean expression tree for WHERE clauses. Leaf nodes (Leaf != nil) hold a single Condition. Branch nodes (Left != nil) join two sub-expressions with a logical operator.

func (*ConditionNode) Columns added in v0.8.0

func (n *ConditionNode) Columns() []string

Columns returns all column names referenced in the condition tree.

func (*ConditionNode) IsLeaf

func (n *ConditionNode) IsLeaf() bool

IsLeaf returns true if this is a leaf node.

func (*ConditionNode) String added in v0.8.0

func (n *ConditionNode) String() string

String returns a human-readable representation of the condition tree, used as a fallback column name for CASE expressions without AS aliases.

func (*ConditionNode) ToDNF

func (n *ConditionNode) ToDNF() OneOrMore

ToDNF converts the condition tree to Disjunctive Normal Form. The result is a OneOrMore where each Conditions group is a conjunction (conditions ANDed together) and the outer slice is a disjunction (groups ORed). This allows arbitrary WHERE nesting to be evaluated by existing row filtering code.

type Conditions

type Conditions []Condition

Conditions is a slice of Condition values joined by AND within a single OR group.

type ConflictAction

type ConflictAction int

ConflictAction describes what to do when an INSERT violates a uniqueness constraint.

const (
	// ConflictActionNone is the default: propagate the error.
	ConflictActionNone ConflictAction = iota
	// ConflictActionDoNothing silently skips the offending row.
	ConflictActionDoNothing
	// ConflictActionDoUpdate applies the SET assignments to the conflicting row.
	ConflictActionDoUpdate
)

type Cursor

type Cursor struct {
	Table      *Table
	PageIdx    PageIndex
	CellIdx    uint32
	EndOfTable bool
}

Cursor is a position within a table's B+ tree used to traverse or modify rows.

func (*Cursor) LeafNodeInsert

func (c *Cursor) LeafNodeInsert(ctx context.Context, key RowID, row Row) error

LeafNodeInsert inserts a row at the cursor's current position, splitting the leaf node if necessary.

func (*Cursor) LeafNodeSplitInsert

func (c *Cursor) LeafNodeSplitInsert(ctx context.Context, key RowID, row Row) error

LeafNodeSplitInsert creates a new leaf node, moves half the cells over, inserts the new value, and updates or creates a parent internal node.

type DBFile

type DBFile interface {
	io.ReadSeeker
	io.ReaderAt
	io.WriterAt
	io.Closer
	Sync() error
}

DBFile ...

type DDLChanges

type DDLChanges struct {
	CreateTables  []*Table
	DropTables    []string
	CreateIndexes map[string]SecondaryIndex // table name -> index
	DropIndexes   map[string]SecondaryIndex // table name -> index
}

DDLChanges accumulates schema modifications made within a single transaction.

func (DDLChanges) CreatedIndex

func (d DDLChanges) CreatedIndex(tableName string, index SecondaryIndex) DDLChanges

CreatedIndex records an index creation in the DDL change set.

func (DDLChanges) CreatedTable

func (d DDLChanges) CreatedTable(t *Table) DDLChanges

CreatedTable records a table creation in the DDL change set.

func (DDLChanges) DroppedIndex

func (d DDLChanges) DroppedIndex(tableName string, index SecondaryIndex) DDLChanges

DroppedIndex records an index drop in the DDL change set.

func (DDLChanges) DroppedTable

func (d DDLChanges) DroppedTable(tableName string) DDLChanges

DroppedTable records a table drop in the DDL change set.

func (DDLChanges) HasChanges

func (d DDLChanges) HasChanges() bool

HasChanges reports whether there are any uncommitted DDL changes.

type DDLSaver

type DDLSaver interface {
	SaveDDLChanges(ctx context.Context, changes DDLChanges)
}

DDLSaver ...

type Database

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

Database is the top-level embedded SQL database instance.

func NewDatabase

func NewDatabase(ctx context.Context, logger *zap.Logger, dbFilePath string, parser Parser, factory PagerFactory, saver PageSaver, walCfg *WALConfig, opts ...DatabaseOption) (*Database, error)

NewDatabase creates a new database. walCfg wires in the Write-Ahead Log; pass nil for in-memory/test databases that do not require WAL (commits fall back to writing directly to the pager).

func (*Database) Analyze

func (d *Database) Analyze(ctx context.Context, target string) error

Analyze gathers statistics for all tables (or a specific target) and stores them in the stats table.

func (*Database) Checkpoint added in v0.12.0

func (d *Database) Checkpoint(_ context.Context) error

Checkpoint checkpoints the WAL into the database file and truncates the WAL. It is a no-op when no WAL is configured.

Checkpoint blocks new WAL writers until it completes. Readers are not blocked: they continue to use the (now being reset) WAL index, which is fine because the pager cache still holds the correct pages and the DB file is being written with the same data.

func (*Database) Close

func (d *Database) Close() error

Close flushes and closes the underlying page storage.

func (*Database) ExecuteStatement

func (d *Database) ExecuteStatement(ctx context.Context, stmt Statement) (StatementResult, error)

ExecuteStatement executes a single statement and returns the result

func (*Database) GetDDLSaver

func (d *Database) GetDDLSaver() DDLSaver

GetDDLSaver returns the DDLSaver interface backed by this database.

func (*Database) GetFileName

func (d *Database) GetFileName() string

GetFileName returns the database file name

func (*Database) GetSaver

func (d *Database) GetSaver() PageSaver

GetSaver returns the page saver for this database

func (*Database) GetTable

func (d *Database) GetTable(ctx context.Context, name string) (*Table, bool)

GetTable retrieves a table by name in a thread-safe manner.

func (*Database) GetTransactionManager

func (d *Database) GetTransactionManager() *TransactionManager

GetTransactionManager returns the transaction manager for this database

func (*Database) IntegrityCheck added in v0.5.0

func (d *Database) IntegrityCheck(ctx context.Context) (IntegrityReport, error)

IntegrityCheck performs a deeper structural walk of the database file.

In addition to QuickCheck, it traverses reachable table, index, and overflow pages from schema roots, reports orphan pages, and flags pages that appear in both live structures and the free list.

func (*Database) ListTableNames

func (d *Database) ListTableNames(ctx context.Context) []string

ListTableNames lists names of all tables in the database

func (*Database) PrepareStatement

func (d *Database) PrepareStatement(ctx context.Context, query string) (Statement, error)

PrepareStatement parses and caches a SQL statement, returning the parsed Statement.

func (*Database) PrepareStatements

func (d *Database) PrepareStatements(ctx context.Context, sql string) ([]Statement, error)

PrepareStatements parses SQL into a slice of Statement struct

func (*Database) QuickCheck added in v0.4.0

func (d *Database) QuickCheck(ctx context.Context) (IntegrityReport, error)

QuickCheck performs a cheap structural health check of the open database.

It validates header-linked free-list metadata and the decodability/shape of table and index root pages, but it does not walk full B-tree contents or cross-check tables against indexes.

func (*Database) Reopen

func (d *Database) Reopen(ctx context.Context, factory PagerFactory, saver PageSaver) error

Reopen replaces the pager and transaction manager with fresh instances backed by the given factory and saver.

func (*Database) SaveDDLChanges

func (d *Database) SaveDDLChanges(ctx context.Context, changes DDLChanges)

SaveDDLChanges applies committed DDL changes (table/index creates and drops) to the in-memory schema.

func (*Database) Vacuum

func (d *Database) Vacuum(ctx context.Context) error

Vacuum compacts the database file by copying all live data into a fresh file, then atomically replacing the original. The algorithm is:

  1. Create a temporary database file with its own pager.
  2. Acquire the exclusive database write lock, blocking all concurrent reads and writes for the duration.
  3. Recreate every table schema (tables first, indexes second) in the temp DB.
  4. Copy every row from the live DB into the temp DB.
  5. Flush and close both the temp DB and the live DB.
  6. Safe atomic file swap: a. Rename live → live.bak b. Rename temp → live (on failure, restore live from live.bak) c. Remove live.bak
  7. Reopen the database with a fresh pager and transaction manager.

Crash-safety: if the process crashes between steps 6a and 6b the original data is intact in live.bak. On restart the caller should check for a live.bak file and rename it back if the expected database file is missing.

VACUUM must not be called from inside an explicit user transaction; doing so returns an error.

type DatabaseHeader

type DatabaseHeader struct {
	FirstFreePage PageIndex // Points to first free page, 0 if none
	FreePageCount uint32    // Number of free pages available
}

DatabaseHeader stores the global database state persisted at the start of the first page.

func (*DatabaseHeader) Marshal

func (h *DatabaseHeader) Marshal() ([]byte, error)

Marshal serialises the database header to a byte slice.

func (*DatabaseHeader) Size

func (h *DatabaseHeader) Size() uint64

Size returns the fixed serialised byte size of the database header.

type DatabaseOption

type DatabaseOption func(*Database)

DatabaseOption is a functional option for configuring a Database.

func WithMaxCachedStatements

func WithMaxCachedStatements(maxStatements int) DatabaseOption

WithMaxCachedStatements configures the maximum number of prepared statements to keep in the LRU cache.

type Direction

type Direction int

Direction ...

const (
	// Asc ...
	Asc Direction = iota + 1
	// Desc is the descending sort direction.
	Desc
)

Direction constants define the sort order for ORDER BY clauses.

func (Direction) String

func (d Direction) String() string

type ExcludedRef added in v0.2.0

type ExcludedRef struct {
	Column string
}

ExcludedRef represents a reference to EXCLUDED.column_name inside an ON CONFLICT DO UPDATE SET clause. At upsert time it resolves to the value that was proposed for insertion but rejected due to the conflict.

type Expr added in v0.4.0

type Expr struct {
	// CASE expression fields (CaseClauses != nil means this is a CASE expression)
	CaseInput   *Expr      // simple CASE operand; nil for searched CASE
	CaseClauses []CaseWhen // WHEN/THEN pairs; non-nil marks this as a CASE expr
	CaseElse    *Expr      // ELSE branch; nil means ELSE NULL

	FuncName string  // built-in function name, e.g. "COALESCE", "NULLIF"
	Args     []*Expr // function arguments (used when FuncName != "")

	// CAST expression (CastExpr != nil means this is a CAST expression)
	CastExpr       *Expr      // the expression to cast
	CastTargetType ColumnKind // the target type (never 0 when CastExpr is set)

	IsNull  bool   // true when this node represents an explicit SQL NULL literal
	Column  string // column reference, may include alias prefix ("u.price")
	Literal any    // int64, float64, bool, or TextPointer
	Left    *Expr
	Right   *Expr
	Op      ArithOp
}

Expr is an arithmetic expression tree node. Exactly one interpretation is active (checked in priority order):

  • CaseClauses != nil: a CASE WHEN expression
  • FuncName != "": a built-in function call (Args holds the arguments)
  • CastExpr != nil: a CAST(expr AS type) expression
  • IsNull: an explicit NULL literal
  • Column != "": a column reference (read value from the row)
  • Literal != nil: a scalar literal (int64, float64, bool, TextPointer)
  • Left != nil && Op != 0: a binary arithmetic operation

func (*Expr) Columns added in v0.4.0

func (e *Expr) Columns() []string

Columns returns all column names referenced by this expression.

func (*Expr) Eval added in v0.4.0

func (e *Expr) Eval(row Row) (any, error)

Eval evaluates the expression against a row, returning a numeric result. NULL propagates: any NULL operand produces a nil result. Returns int64 when both operands are int64 (except division, which always returns float64). Returns float64 when either operand is float64.

func (*Expr) String added in v0.4.0

func (e *Expr) String() string

String returns a human-readable representation suitable for use as a default column name.

type Field

type Field struct {
	AliasPrefix string
	Name        string
	// Alias is the output column name when an AS clause is used on a computed
	// expression (e.g. SELECT price * 1.1 AS discounted).
	Alias string
	// Expr is non-nil when the field is a computed arithmetic expression rather
	// than a plain column reference.
	Expr *Expr
}

Field ...

func (Field) OutputName added in v0.4.0

func (f Field) OutputName() string

OutputName returns the name to use for this field in result column metadata. For computed expressions it returns the Alias (if set) or the expression string.

func (Field) String

func (f Field) String() string

type Flusher

type Flusher interface {
	TotalPages() uint32
	Flush(context.Context, PageIndex) error
	FlushBatch(context.Context, []PageIndex) error
	Close() error
}

Flusher ...

type FreePage

type FreePage struct {
	NextFreePage PageIndex // Points to next free page, 0 if last

}

FreePage reuses the existing page structure for tracking free (unused) pages.

func (*FreePage) Marshal

func (n *FreePage) Marshal(buf []byte) error

Marshal ...

func (*FreePage) Unmarshal

func (n *FreePage) Unmarshal(buf []byte) error

Unmarshal ...

type Function

type Function struct {
	Name string
}

Function ...

type Header struct {
	IsInternal bool
	IsRoot     bool
	Parent     PageIndex
}

Header ...

func (*Header) Marshal

func (h *Header) Marshal(buf []byte)

Marshal ...

func (*Header) Size

func (h *Header) Size() uint64

Size ...

func (*Header) Unmarshal

func (h *Header) Unmarshal(buf []byte) (uint64, error)

Unmarshal ...

type ICell

type ICell struct {
	Key   RowID
	Child PageIndex
}

ICell ...

func (*ICell) Marshal

func (c *ICell) Marshal(buf []byte)

Marshal ...

func (*ICell) Size

func (c *ICell) Size() uint64

Size ...

func (*ICell) Unmarshal

func (c *ICell) Unmarshal(buf []byte) (uint64, error)

Unmarshal ...

type Index

type Index[T IndexKey] struct {
	Name    string
	Columns []Column
	// contains filtered or unexported fields
}

Index ...

func NewNonUniqueIndex

func NewNonUniqueIndex[T IndexKey](logger *zap.Logger, txManager *TransactionManager, name string, columns []Column, pager TxPager, rootPageIdx PageIndex) (*Index[T], error)

NewNonUniqueIndex ...

func NewUniqueIndex

func NewUniqueIndex[T IndexKey](logger *zap.Logger, txManager *TransactionManager, name string, columns []Column, pager TxPager, rootPageIdx PageIndex) (*Index[T], error)

NewUniqueIndex ...

func (*Index[T]) BFS

func (ui *Index[T]) BFS(ctx context.Context, f indexCallback) error

BFS ...

func (*Index[T]) Delete

func (ui *Index[T]) Delete(ctx context.Context, keyAny any, rowID RowID) error

Delete ...

func (*Index[T]) FindRowIDs

func (ui *Index[T]) FindRowIDs(ctx context.Context, keyAny any) ([]RowID, error)

FindRowIDs ...

func (*Index[T]) GetRootPageIdx

func (ui *Index[T]) GetRootPageIdx() PageIndex

GetRootPageIdx ...

func (*Index[T]) Insert

func (ui *Index[T]) Insert(ctx context.Context, keyAny any, rowID RowID) error

Insert ...

func (*Index[T]) ScanAll

func (ui *Index[T]) ScanAll(ctx context.Context, reverse bool, callback indexScanner) error

ScanAll iterates over all keys in the index in order using in-order traversal

func (*Index[T]) ScanRange

func (ui *Index[T]) ScanRange(ctx context.Context, rangeCondition RangeCondition, reverse bool, callback indexScanner) error

ScanRange scans keys within the specified range using in-order traversal with range checks.

func (*Index[T]) Seek

func (ui *Index[T]) Seek(ctx context.Context, page *Page, keyAny any) (IndexCursor[T], bool, error)

Seek ...

func (*Index[T]) SeekLastKey

func (ui *Index[T]) SeekLastKey(ctx context.Context, pageIdx PageIndex) (any, error)

SeekLastKey returns the largest key in the index, used for autoincrement primary keys.

func (*Index[T]) SeekWithPrefix

func (ui *Index[T]) SeekWithPrefix(ctx context.Context, page *Page, prefixAny any, prefixColumns int) (IndexCursor[T], bool, error)

SeekWithPrefix ...

type IndexCell

type IndexCell[T IndexKey] struct {
	Key          T
	InlineRowIDs uint32 // only for non-unique indexes
	RowIDs       []RowID
	Overflow     PageIndex // 0 if not used (only for non-unique indexes)
	Child        PageIndex
	// contains filtered or unexported fields
}

IndexCell holds a single key entry within an index node, along with its associated row IDs and child pointer.

func NewIndexCell

func NewIndexCell[T IndexKey](unique bool) IndexCell[T]

NewIndexCell ...

func (*IndexCell[T]) Clone

func (c *IndexCell[T]) Clone() IndexCell[T]

Clone ...

func (*IndexCell[T]) Marshal

func (c *IndexCell[T]) Marshal(buf []byte) error

Marshal ...

func (*IndexCell[T]) RemoveRowID

func (c *IndexCell[T]) RemoveRowID(id RowID) int

RemoveRowID ...

func (*IndexCell[T]) ReplaceRowID

func (c *IndexCell[T]) ReplaceRowID(id, newID RowID) int

ReplaceRowID ...

func (*IndexCell[T]) Size

func (c *IndexCell[T]) Size() uint64

Size ...

func (*IndexCell[T]) Unmarshal

func (c *IndexCell[T]) Unmarshal(columns []Column, buf []byte) (uint64, error)

Unmarshal ...

type IndexCursor

type IndexCursor[T IndexKey] struct {
	Index   *Index[T]
	PageIdx PageIndex
	CellIdx uint32
}

IndexCursor holds a position within an index, grouping page and cell index. TODO - currently this struct has no methods; consider merging into Index or adding useful methods.

type IndexInfo

type IndexInfo struct {
	Name    string
	Columns []Column
}

IndexInfo ...

type IndexKey

type IndexKey interface {
	int8 | int32 | int64 | float32 | float64 | string | CompositeKey
}

IndexKey ...

type IndexNode

type IndexNode[T IndexKey] struct {
	Header IndexNodeHeader
	Cells  []IndexCell[T] // (PageSize - (5)) / (CellSize + 4 + 8)
}

IndexNode is a B+ tree node used by the index, containing a header and a slice of index cells.

func NewIndexNode

func NewIndexNode[T IndexKey](unique bool, cells ...IndexCell[T]) *IndexNode[T]

NewIndexNode creates a new IndexNode with the given uniqueness flag and optional initial cells.

func NewRootIndexNode

func NewRootIndexNode[T IndexKey](unique bool, cells ...IndexCell[T]) *IndexNode[T]

NewRootIndexNode ...

func (*IndexNode[T]) AppendCells

func (n *IndexNode[T]) AppendCells(cells ...IndexCell[T])

AppendCells ...

func (*IndexNode[T]) AtLeastHalfFull

func (n *IndexNode[T]) AtLeastHalfFull() bool

AtLeastHalfFull ...

func (*IndexNode[T]) AvailableSpace

func (n *IndexNode[T]) AvailableSpace() uint64

AvailableSpace ...

func (*IndexNode[T]) Child

func (n *IndexNode[T]) Child(childIdx uint32) (PageIndex, error)

Child returns a node index of nth child of the node marked by its index (0 for the leftmost child, index equal to number of keys means the rightmost child).

func (*IndexNode[T]) Children

func (n *IndexNode[T]) Children() []PageIndex

Children ...

func (*IndexNode[T]) Clone

func (n *IndexNode[T]) Clone() *IndexNode[T]

Clone ...

func (*IndexNode[T]) DeleteKeyAndRightChild

func (n *IndexNode[T]) DeleteKeyAndRightChild(idx uint32) error

DeleteKeyAndRightChild removes the key at idx plus the right child pointer from the index node.

func (*IndexNode[T]) FirstCell

func (n *IndexNode[T]) FirstCell() IndexCell[T]

FirstCell ...

func (*IndexNode[T]) GetRightChildByIndex

func (n *IndexNode[T]) GetRightChildByIndex(idx uint32) PageIndex

GetRightChildByIndex ...

func (*IndexNode[T]) HasSpaceForKey

func (n *IndexNode[T]) HasSpaceForKey(key T) bool

HasSpaceForKey ...

func (*IndexNode[T]) Keys

func (n *IndexNode[T]) Keys() []T

Keys ...

func (*IndexNode[T]) LastCell

func (n *IndexNode[T]) LastCell() IndexCell[T]

LastCell ...

func (*IndexNode[T]) Marshal

func (n *IndexNode[T]) Marshal(buf []byte) error

Marshal ...

func (*IndexNode[T]) MaxSpace

func (n *IndexNode[T]) MaxSpace() uint64

MaxSpace ...

func (*IndexNode[T]) PrependCell

func (n *IndexNode[T]) PrependCell(cell IndexCell[T])

PrependCell ...

func (*IndexNode[T]) RemoveFirstCell

func (n *IndexNode[T]) RemoveFirstCell()

RemoveFirstCell ...

func (*IndexNode[T]) RemoveLastCell

func (n *IndexNode[T]) RemoveLastCell() IndexCell[T]

RemoveLastCell ...

func (*IndexNode[T]) RowIDs

func (n *IndexNode[T]) RowIDs() []RowID

RowIDs returns inlined row IDs; there could be more row IDs in overflow pages, so keep that in mind when working with non-unique indexes.

func (*IndexNode[T]) SetChild

func (n *IndexNode[T]) SetChild(idx uint32, childPage PageIndex) error

SetChild ...

func (*IndexNode[T]) Size

func (n *IndexNode[T]) Size() uint64

Size ...

func (*IndexNode[T]) SplitInHalves

func (n *IndexNode[T]) SplitInHalves(unique bool) (uint32, uint32)

SplitInHalves ...

func (*IndexNode[T]) TakenSpace

func (n *IndexNode[T]) TakenSpace() uint64

TakenSpace ...

func (*IndexNode[T]) Unmarshal

func (n *IndexNode[T]) Unmarshal(columns []Column, buf []byte) (uint64, error)

Unmarshal ...

type IndexNodeHeader

type IndexNodeHeader struct {
	IsRoot     bool
	IsLeaf     bool
	Parent     PageIndex
	Keys       uint32
	RightChild PageIndex
}

IndexNodeHeader ...

func (*IndexNodeHeader) Marshal

func (h *IndexNodeHeader) Marshal(buf []byte)

Marshal ...

func (*IndexNodeHeader) Size

func (h *IndexNodeHeader) Size() (s uint64)

Size ...

func (*IndexNodeHeader) Unmarshal

func (h *IndexNodeHeader) Unmarshal(buf []byte) (uint64, error)

Unmarshal ...

type IndexOverflowPage

type IndexOverflowPage struct {
	Header IndexOverflowPageHeader
	RowIDs []RowID
}

IndexOverflowPage ...

func (*IndexOverflowPage) LastRowID

func (h *IndexOverflowPage) LastRowID() RowID

LastRowID ...

func (*IndexOverflowPage) Marshal

func (h *IndexOverflowPage) Marshal(buf []byte) error

Marshal ...

func (*IndexOverflowPage) RemoveLastRowID

func (h *IndexOverflowPage) RemoveLastRowID() RowID

RemoveLastRowID ...

func (*IndexOverflowPage) Size

func (h *IndexOverflowPage) Size() uint64

Size ...

func (*IndexOverflowPage) Unmarshal

func (h *IndexOverflowPage) Unmarshal(buf []byte) error

Unmarshal ...

type IndexOverflowPageHeader

type IndexOverflowPageHeader struct {
	NextPage  PageIndex // 0 if last page
	ItemCount uint32    // how many row IDs are stored in this page
}

IndexOverflowPageHeader ...

func (*IndexOverflowPageHeader) Size

func (h *IndexOverflowPageHeader) Size() uint64

Size ...

type IndexStats

type IndexStats struct {
	NEntry    int64   // Total number of entries in the index
	NDistinct []int64 // Distinct values for each column prefix
}

IndexStats holds parsed statistics for an index

func (IndexStats) EstimateRangeRows

func (s IndexStats) EstimateRangeRows(rangeCondition RangeCondition, columnIndex int) int64

EstimateRangeRows estimates the number of rows that will match a range condition. Returns the estimated row count, or -1 if estimation isn't possible. Uses uniform distribution assumption for simplicity.

func (IndexStats) Selectivity

func (s IndexStats) Selectivity() float64

Selectivity returns the selectivity of the index (0.0 to 1.0) Higher selectivity means more distinct values relative to total entries For composite indexes, uses the final column prefix

type IntegrityIssue added in v0.4.0

type IntegrityIssue struct {
	Code    string
	Message string
	Page    *PageIndex
	Object  string
}

IntegrityIssue represents a single integrity problem discovered by a check.

type IntegrityReport added in v0.4.0

type IntegrityReport struct {
	TotalPages        uint32
	CheckedRootPages  int
	CheckedFreePages  int
	CheckedLivePages  int
	FreeListPageCount uint32
	Issues            []IntegrityIssue
}

IntegrityReport summarises the result of an integrity check.

func (IntegrityReport) Ok added in v0.4.0

func (r IntegrityReport) Ok() bool

Ok returns true when the integrity check found no issues.

type InternalNode

type InternalNode struct {
	Header InternalNodeHeader
	ICells [InternalNodeMaxCells]ICell
}

InternalNode ...

func NewInternalNode

func NewInternalNode() *InternalNode

NewInternalNode ...

func (*InternalNode) AppendCells

func (n *InternalNode) AppendCells(cells ...ICell)

AppendCells ...

func (*InternalNode) AtLeastHalfFull

func (n *InternalNode) AtLeastHalfFull(maxIcells int) bool

AtLeastHalfFull ...

func (*InternalNode) Child

func (n *InternalNode) Child(childIdx uint32) (PageIndex, error)

Child returns a node index of nth child of the node marked by its index (0 for the leftmost child, index equal to number of keys means the rightmost child).

func (*InternalNode) Children

func (n *InternalNode) Children() []PageIndex

Children ...

func (*InternalNode) Clone

func (n *InternalNode) Clone() *InternalNode

Clone ...

func (*InternalNode) DeleteKeyAndRightChild

func (n *InternalNode) DeleteKeyAndRightChild(idx uint32) error

DeleteKeyAndRightChild removes the key at idx plus the right child pointer from the internal node.

func (*InternalNode) FirstCell

func (n *InternalNode) FirstCell() ICell

FirstCell ...

func (*InternalNode) GetRightChildByIndex

func (n *InternalNode) GetRightChildByIndex(idx uint32) PageIndex

GetRightChildByIndex ...

func (*InternalNode) IndexOfChild

func (n *InternalNode) IndexOfChild(key RowID) uint32

IndexOfChild returns the index of the child which should contain the given key. For example, if node has 2 keys, this could return 0 for the leftmost child, 1 for the middle child or 2 for the rightmost child. The returned value is not a node index!

func (*InternalNode) IndexOfPage

func (n *InternalNode) IndexOfPage(pageIdx PageIndex) (uint32, error)

IndexOfPage returns index of child which contains page number

func (*InternalNode) Keys

func (n *InternalNode) Keys() []RowID

Keys ...

func (*InternalNode) LastCell

func (n *InternalNode) LastCell() ICell

LastCell ...

func (*InternalNode) Marshal

func (n *InternalNode) Marshal(buf []byte) error

Marshal ...

func (*InternalNode) MoreThanHalfFull

func (n *InternalNode) MoreThanHalfFull(maxIcells int) bool

MoreThanHalfFull ...

func (*InternalNode) PrependCell

func (n *InternalNode) PrependCell(cell ICell)

PrependCell ...

func (*InternalNode) RemoveFirstCell

func (n *InternalNode) RemoveFirstCell()

RemoveFirstCell ...

func (*InternalNode) RemoveLastCell

func (n *InternalNode) RemoveLastCell()

RemoveLastCell ...

func (*InternalNode) SetChild

func (n *InternalNode) SetChild(idx uint32, childPage PageIndex) error

SetChild ...

func (*InternalNode) Size

func (n *InternalNode) Size() uint64

Size ...

func (*InternalNode) Unmarshal

func (n *InternalNode) Unmarshal(buf []byte) (uint64, error)

Unmarshal ...

type InternalNodeHeader

type InternalNodeHeader struct {
	Header
	KeysNum    uint32
	RightChild PageIndex
}

InternalNodeHeader ...

func (*InternalNodeHeader) Marshal

func (h *InternalNodeHeader) Marshal(buf []byte)

Marshal ...

func (*InternalNodeHeader) Size

func (h *InternalNodeHeader) Size() (s uint64)

Size ...

func (*InternalNodeHeader) Unmarshal

func (h *InternalNodeHeader) Unmarshal(buf []byte) (uint64, error)

Unmarshal ...

type Interval added in v0.11.0

type Interval struct {
	Months int32 // total months component (years×12 + months)
	Micros int64 // fixed-duration component in microseconds
}

Interval represents a SQL interval with two components:

  • Months: calendar months (years×12 + months); variable-length because a month contains a different number of days depending on which month it is.
  • Micros: fixed-duration part in microseconds (weeks×7×86400×1e6 + days×86400×1e6 + …).

Separating months from the fixed-duration component mirrors PostgreSQL's internal representation: INTERVAL '1 month' cannot be expressed as a fixed number of microseconds, so it must be handled via calendar arithmetic.

func ParseIntervalString added in v0.11.0

func ParseIntervalString(s string) (Interval, error)

ParseIntervalString parses an interval specification string such as "3 days", "1 year 2 months", "-4 hours 30 minutes".

Supported units (case-insensitive, singular or plural):

year, month, week, day, hour, minute, second, microsecond

Weeks are converted to days (1 week = 7 days) and stored in Micros. Negative values are supported per-component: "-1 day 2 hours".

func (Interval) String added in v0.11.0

func (iv Interval) String() string

String returns a human-readable SQL representation, e.g. "INTERVAL '3 days 4 hours'".

type Iterator

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

Iterator ...

func NewIterator

func NewIterator(rowFunc func(ctx context.Context) (Row, error)) Iterator

NewIterator ...

func NewSingleRowIterator

func NewSingleRowIterator(row Row) Iterator

NewSingleRowIterator ...

func (*Iterator) Close

func (i *Iterator) Close() error

Close ...

func (*Iterator) Err

func (i *Iterator) Err() error

Err ...

func (*Iterator) Next

func (i *Iterator) Next(ctx context.Context) bool

Next ...

func (*Iterator) Row

func (i *Iterator) Row() Row

Row ...

type Join

type Join struct {
	Type       JoinType
	TableName  string
	TableAlias string
	Conditions Conditions
	Joins      []Join
}

Join ...

func (Join) FromTableAlias

func (j Join) FromTableAlias() string

FromTableAlias ...

type JoinColumnPair

type JoinColumnPair struct {
	BaseTableColumn Field
	JoinTableColumn Field
}

JoinColumnPair represents a pair of columns used in a JOIN ON condition

type JoinPlan

type JoinPlan struct {
	Type            JoinType
	LeftScanIndex   int              // Index into Scans array (outer table)
	RightScanIndex  int              // Index into Scans array (inner table)
	Conditions      Conditions       // ON clause conditions
	OuterJoinColumn string           // Column name in outer table for index lookup optimization (first column for backward compat)
	InnerJoinColumn string           // Column name in inner table for index lookup optimization (first column for backward compat)
	JoinColumnPairs []JoinColumnPair // All join column pairs for composite index support
}

JoinPlan represents a join operation between two scans

type JoinType

type JoinType int

JoinType ...

const (
	// Inner ...
	Inner JoinType = iota + 1
	// Left is a LEFT JOIN.
	Left
	// Right is a RIGHT JOIN.
	Right
)

JoinType constants enumerate the supported JOIN varieties.

type LRUCache

type LRUCache[T any] interface {
	Get(T) (any, bool)
	GetAndPromote(T) (any, bool)
	Put(T, any, bool)
	EvictIfNeeded() (T, bool)
}

LRUCache ...

type LeafNode

type LeafNode struct {
	Header LeafNodeHeader
	Cells  []Cell
}

LeafNode ...

func NewLeafNode

func NewLeafNode(cells ...Cell) *LeafNode

NewLeafNode ...

func (*LeafNode) AppendCells

func (n *LeafNode) AppendCells(cells ...Cell)

AppendCells ...

func (*LeafNode) AtLeastHalfFull

func (n *LeafNode) AtLeastHalfFull() bool

AtLeastHalfFull ...

func (*LeafNode) AvailableSpace

func (n *LeafNode) AvailableSpace() uint64

AvailableSpace ...

func (*LeafNode) CanBorrowFirst

func (n *LeafNode) CanBorrowFirst() bool

CanBorrowFirst ...

func (*LeafNode) CanBorrowLast

func (n *LeafNode) CanBorrowLast() bool

CanBorrowLast ...

func (*LeafNode) CanMergeWith

func (n *LeafNode) CanMergeWith(n2 *LeafNode) bool

CanMergeWith ...

func (*LeafNode) Clone

func (n *LeafNode) Clone() *LeafNode

Clone cretes a shallow copy of the leaf node, sharing value slices until they are about to be modified at which point PrepareModifyCell should be called to clone the value slice for that cell.

func (*LeafNode) DeepClone

func (n *LeafNode) DeepClone() *LeafNode

DeepClone ...

func (*LeafNode) Delete

func (n *LeafNode) Delete(key RowID) (Cell, bool)

Delete ...

func (*LeafNode) FirstCell

func (n *LeafNode) FirstCell() Cell

FirstCell ...

func (*LeafNode) HasSpaceForRow

func (n *LeafNode) HasSpaceForRow(row Row) bool

HasSpaceForRow ...

func (*LeafNode) Keys

func (n *LeafNode) Keys() []RowID

Keys ...

func (*LeafNode) LastCell

func (n *LeafNode) LastCell() Cell

LastCell ...

func (*LeafNode) Marshal

func (n *LeafNode) Marshal(buf []byte) error

Marshal ...

func (*LeafNode) MaxSpace

func (n *LeafNode) MaxSpace() uint64

MaxSpace ...

func (*LeafNode) PrepareModifyCell

func (n *LeafNode) PrepareModifyCell(idx uint32)

PrepareModifyCell ensures the cell at idx is copy-on-write safe before modification.

func (*LeafNode) PrependCell

func (n *LeafNode) PrependCell(cell Cell)

PrependCell ...

func (*LeafNode) RemoveFirstCell

func (n *LeafNode) RemoveFirstCell()

RemoveFirstCell ...

func (*LeafNode) RemoveLastCell

func (n *LeafNode) RemoveLastCell()

RemoveLastCell ...

func (*LeafNode) Size

func (n *LeafNode) Size() uint64

Size ...

func (*LeafNode) TakenSpace

func (n *LeafNode) TakenSpace() uint64

TakenSpace ...

func (*LeafNode) Unmarshal

func (n *LeafNode) Unmarshal(columns []Column, buf []byte) (uint64, error)

Unmarshal ...

type LeafNodeHeader

type LeafNodeHeader struct {
	Header
	Cells    uint32
	NextLeaf PageIndex
}

LeafNodeHeader ...

func (*LeafNodeHeader) Marshal

func (h *LeafNodeHeader) Marshal(buf []byte)

Marshal ...

func (*LeafNodeHeader) Size

func (h *LeafNodeHeader) Size() uint64

Size ...

func (*LeafNodeHeader) Unmarshal

func (h *LeafNodeHeader) Unmarshal(buf []byte) (uint64, error)

Unmarshal ...

type LogicOp

type LogicOp int

LogicOp represents a boolean logic operator (AND or OR) used in a ConditionNode.

const (
	// LogicOpAnd represents the SQL AND logical operator.
	LogicOpAnd LogicOp = iota + 1
	// LogicOpOr represents the SQL OR logical operator.
	LogicOpOr
)

type OneOrMore

type OneOrMore []Conditions

OneOrMore contains a slice of multiple groups of singular condition, each group joined by OR boolean operator. Every singular condition in each group is joined by AND with other conditions in the same slice.

func NewOneOrMore

func NewOneOrMore(conditionGroups ...Conditions) OneOrMore

NewOneOrMore creates a new OneOrMore from the given condition groups.

func (OneOrMore) Append

func (o OneOrMore) Append(cond Condition) OneOrMore

Append adds a condition to the last group, creating a new group if empty.

func (OneOrMore) LastCondition

func (o OneOrMore) LastCondition() (Condition, bool)

LastCondition returns the last condition in the last group, if any.

func (OneOrMore) UpdateLast

func (o OneOrMore) UpdateLast(cond Condition)

UpdateLast replaces the last condition in the last group.

type Operand

type Operand struct {
	Type  OperandType
	Value any
}

Operand holds a typed value on one side of a condition expression.

func (Operand) IsField

func (o Operand) IsField() bool

IsField determines whether the operand is a literal or a field name

type OperandType

type OperandType int

OperandType classifies the value on either side of a condition operator.

const (
	// OperandField means the operand is a table column name.
	OperandField OperandType = iota + 1
	OperandPlaceholder
	OperandNull
	OperandQuotedString
	OperandBoolean
	OperandInteger
	OperandFloat
	OperandList
)

OperandType constants define the kinds of operand values.

type Operator

type Operator int

Operator represents a SQL comparison operator used in WHERE conditions.

const (
	// Eq -> "="
	Eq Operator = iota + 1
	// Ne -> "!="
	Ne
	// Gt -> ">"
	Gt
	// Lt -> "<"
	Lt
	// Gte -> ">="
	Gte
	// Lte -> "<="
	Lte
	// In -> "IN (...)"
	In
	// NotIn -> "NOT IN (...)"
	NotIn
	// Like -> "LIKE"
	Like
	// NotLike -> "NOT LIKE"
	NotLike
	// Between -> "BETWEEN ... AND ..."
	Between
	// NotBetween -> "NOT BETWEEN ... AND ..."
	NotBetween
)

func (Operator) String

func (o Operator) String() string

type OptionalValue

type OptionalValue struct {
	Value any
	Valid bool
}

OptionalValue ...

type OrderBy

type OrderBy struct {
	Field     Field
	Direction Direction
}

OrderBy ...

type OverflowPage

type OverflowPage struct {
	Header OverflowPageHeader
	Data   []byte
}

OverflowPage ...

func (*OverflowPage) Marshal

func (h *OverflowPage) Marshal(buf []byte) error

Marshal ...

func (*OverflowPage) Size

func (h *OverflowPage) Size() uint64

Size ...

func (*OverflowPage) Unmarshal

func (h *OverflowPage) Unmarshal(buf []byte) error

Unmarshal ...

type OverflowPageHeader

type OverflowPageHeader struct {
	NextPage PageIndex // 0 if last page
	DataSize uint32    // Actual data size in this page
}

OverflowPageHeader ...

func (*OverflowPageHeader) Size

func (h *OverflowPageHeader) Size() uint64

Size ...

type Page

type Page struct {
	Index             PageIndex
	OverflowPage      *OverflowPage
	FreePage          *FreePage
	InternalNode      *InternalNode
	LeafNode          *LeafNode
	IndexNode         any
	IndexOverflowNode *IndexOverflowPage
}

Page ...

func (*Page) Clear

func (p *Page) Clear()

Clear resets all node pointers on the page, preparing it for reuse.

func (*Page) Clone

func (p *Page) Clone() *Page

Clone creates a deep copy of the page.

type PageIndex

type PageIndex uint32

PageIndex ...

type PageSaver

type PageSaver interface {
	SavePage(context.Context, PageIndex, *Page)
	SaveHeader(context.Context, DatabaseHeader)
	SetWALIndex(*WALIndex)
	Flusher
}

PageSaver ...

type PageUnmarshaler

type PageUnmarshaler func(totalPages uint32, pageIdx PageIndex, buf []byte) (*Page, error)

PageUnmarshaler ...

type Pager

type Pager interface {
	GetPage(context.Context, PageIndex) (*Page, error)
	GetHeader(context.Context) DatabaseHeader
	TotalPages() uint32
}

Pager ...

type PagerFactory

type PagerFactory interface {
	ForTable([]Column) Pager
	ForIndex(columns []Column, unique bool) Pager
}

PagerFactory ...

type Parser

type Parser interface {
	Parse(context.Context, string) ([]Statement, error)
}

Parser ...

type Placeholder

type Placeholder struct{}

Placeholder ...

type PrimaryKey

type PrimaryKey struct {
	IndexInfo
	Autoincrement bool
	Index         BTreeIndex
}

PrimaryKey ...

func NewPrimaryKey

func NewPrimaryKey(indexName string, columns []Column, autoincrement bool) PrimaryKey

NewPrimaryKey ...

type QueryPlan

type QueryPlan struct {
	Scans []Scan
	Joins []JoinPlan // JOIN operations to perform

	// Ordering
	OrderBy      []OrderBy
	SortInMemory bool
	SortReverse  bool
}

QueryPlan determines how to execute a query

func (QueryPlan) Execute

func (p QueryPlan) Execute(ctx context.Context, provider TableProvider, selectedFields []Field, filteredPipe chan<- Row) error

Execute ...

type RangeBound

type RangeBound struct {
	Value     any
	Inclusive bool // true for >= or <=, false for > or <
}

RangeBound ...

type RangeCondition

type RangeCondition struct {
	Lower *RangeBound // nil = unbounded
	Upper *RangeBound // nil = unbounded
}

RangeCondition ...

type Row

type Row struct {
	Key     RowID
	Columns []Column
	Values  []OptionalValue
	// contains filtered or unexported fields
}

Row ...

func NewRow

func NewRow(columns []Column) Row

NewRow ...

func NewRowWithValues

func NewRowWithValues(columns []Column, values []OptionalValue) Row

NewRowWithValues ...

func (Row) AppendValues

func (r Row) AppendValues(fields []Field, values []OptionalValue) Row

AppendValues ...

func (Row) CheckConditions

func (r Row) CheckConditions(condGroup Conditions) (bool, error)

CheckConditions ...

func (Row) CheckOneOrMore

func (r Row) CheckOneOrMore(conditions OneOrMore) (bool, error)

CheckOneOrMore checks whether row satisfies one or more sets of conditions (cond1 AND cond2) OR (cond3 and cond4) ... etc

func (Row) Clone

func (r Row) Clone() Row

Clone ...

func (Row) GetColumn

func (r Row) GetColumn(name string) (Column, int)

GetColumn ...

func (Row) GetValue

func (r Row) GetValue(name string) (OptionalValue, bool)

GetValue ...

func (Row) GetValuesForColumns

func (r Row) GetValuesForColumns(columns []Column) ([]OptionalValue, bool)

GetValuesForColumns ...

func (Row) Marshal

func (r Row) Marshal() ([]byte, error)

Marshal ...

func (Row) NullBitmask

func (r Row) NullBitmask() uint64

NullBitmask returns a bitmask representing which columns are NULL

func (Row) OnlyFields

func (r Row) OnlyFields(fields ...Field) Row

OnlyFields ...

func (Row) SetValue

func (r Row) SetValue(name string, value OptionalValue) (Row, bool)

SetValue returns true if value has changed

func (Row) Size

func (r Row) Size() uint64

Size calculates a size of a row record excluding null bitmask and row ID

func (Row) Unmarshal

func (r Row) Unmarshal(cell Cell, selectedFields ...Field) (Row, error)

Unmarshal decodes cell into a Row. For columns not in selectedFields, an empty OptionalValue is inserted to maintain index alignment.

type RowID

type RowID uint64

RowID ...

type Scan

type Scan struct {
	TableName      string // Name of the table to scan
	TableAlias     string // Alias of the table (for JOINs)
	Type           ScanType
	IndexName      string
	IndexColumns   []Column
	IndexKeys      []any          // Keys to lookup in index
	RangeCondition RangeCondition // upper/lower bounds for range scan
	Filters        OneOrMore      // Additional filters to apply
	CoveringIndex  bool           // true = all needed columns are in the index; skip table row fetch
}

Scan ...

func (Scan) FilterRow

func (s Scan) FilterRow(row Row) (bool, error)

FilterRow applies filtering on scanned rows according to filters

type ScanType

type ScanType int

ScanType ...

const (
	// ScanTypeSequential is a full table scan.
	ScanTypeSequential ScanType = iota + 1
	// ScanTypeIndexAll is a full index scan.
	ScanTypeIndexAll
	// ScanTypeIndexPoint is an index lookup for specific key(s).
	ScanTypeIndexPoint
	// ScanTypeIndexRange is an index range scan.
	ScanTypeIndexRange
	// ScanTypeIndexFirst seeks to the first (smallest) key in the index — used for MIN optimisation.
	ScanTypeIndexFirst
	// ScanTypeIndexLast seeks to the last (largest) key in the index — used for MAX optimisation.
	ScanTypeIndexLast
)

ScanType constants define the available index and table scan strategies.

func (ScanType) String

func (st ScanType) String() string

type Schema

type Schema struct {
	Type      SchemaType
	Name      string
	TableName string
	RootPage  PageIndex
	DDL       string
}

Schema represents a single row in the internal schema metadata table.

type SchemaType

type SchemaType int

SchemaType identifies the kind of object recorded in the schema table.

const (
	// SchemaTable identifies a user table entry in the schema.
	SchemaTable SchemaType = iota + 1
	SchemaPrimaryKey
	SchemaUniqueIndex
	SchemaSecondaryIndex
)

SchemaType constants identify the kind of object recorded in the schema table.

type SecondaryIndex

type SecondaryIndex struct {
	IndexInfo
	Index BTreeIndex
}

SecondaryIndex ...

type Statement

type Statement struct {
	Kind          StatementKind
	IfNotExists   bool
	TableName     string // for SELECT, INSERT, UPDATE, DELETE, CREATE/DROP TABLE etc
	TableAlias    string
	Joins         []Join
	IndexName     string        // for CREATE/DROP INDEX
	Target        string        // for ANALYZE
	PragmaName    string        // for PRAGMA
	Columns       []Column      // use for CREATE TABLE
	PrimaryKey    PrimaryKey    // use for CREATE TABLE
	UniqueIndexes []UniqueIndex // use for CREATE TABLE
	// Used for SELECT (i.e. SELECTed field names) and INSERT (INSERTEDed field names)
	// and UPDATE (UPDATEDed field names as Updates map is not ordered)
	Distinct       bool
	Fields         []Field
	Aggregates     []AggregateExpr // parallel to Fields; only populated when query uses aggregate functions
	GroupBy        []Field         // columns in GROUP BY clause; only populated for grouped queries
	Having         OneOrMore       // HAVING conditions; only populated for grouped queries
	Aliases        map[string]string
	ConflictAction ConflictAction // INSERT ON CONFLICT action
	Inserts        [][]OptionalValue
	Updates        map[string]OptionalValue
	Functions      map[string]Function // NOW(), etc.
	Conditions     OneOrMore           // used for WHERE
	OrderBy        []OrderBy
	Limit          OptionalValue
	Offset         OptionalValue
	// Unions holds the UNION / UNION ALL branches chained to this SELECT.
	// Only populated on SELECT statements.
	Unions []UnionClause
}

Statement ...

func (Statement) AddJoin

func (s Statement) AddJoin(joinType JoinType, fromTableAlias, toTable, toTableAlias string, conditions Conditions) (Statement, error)

AddJoin ...

func (Statement) BindArguments

func (s Statement) BindArguments(args ...any) (Statement, error)

BindArguments ...

func (Statement) Clone

func (s Statement) Clone() Statement

Clone ...

func (Statement) ColumnByName

func (s Statement) ColumnByName(name string) (Column, bool)

ColumnByName ...

func (Statement) ColumnIdx

func (s Statement) ColumnIdx(name string) int

ColumnIdx ...

func (Statement) DDL

func (s Statement) DDL() string

DDL ...

func (Statement) HasField

func (s Statement) HasField(name string) bool

HasField ...

func (Statement) InsertValuesForColumns

func (s Statement) InsertValuesForColumns(insertIdx int, columns ...Column) []OptionalValue

InsertValuesForColumns ...

func (Statement) IsDDL

func (s Statement) IsDDL() bool

IsDDL ...

func (Statement) IsSelectAggregate

func (s Statement) IsSelectAggregate() bool

IsSelectAggregate returns true when the SELECT list contains at least one aggregate function (SUM, AVG, MIN, MAX). COUNT(*) alone uses the legacy IsSelectCountAll path and does NOT set this flag.

func (Statement) IsSelectAll

func (s Statement) IsSelectAll() bool

IsSelectAll ...

func (Statement) IsSelectCountAll

func (s Statement) IsSelectCountAll() bool

IsSelectCountAll ...

func (Statement) IsSelectGroupBy

func (s Statement) IsSelectGroupBy() bool

IsSelectGroupBy returns true when the SELECT has a GROUP BY clause.

func (Statement) NumPlaceholders

func (s Statement) NumPlaceholders() int

NumPlaceholders returns the number of placeholder parameters (?) in the statement.

func (Statement) Prepare

func (s Statement) Prepare(now Time) (Statement, error)

Prepare performs any necessary preparation on the statement before validation/execution.

func (Statement) ReadOnly

func (s Statement) ReadOnly() bool

ReadOnly ...

func (Statement) Validate

func (s Statement) Validate(table *Table) error

Validate ...

type StatementKind

type StatementKind int

StatementKind ...

const (
	// CreateTable ...
	CreateTable StatementKind = iota + 1
	DropTable
	CreateIndex
	DropIndex
	Insert
	Select
	Update
	Delete
	BeginTransaction
	CommitTransaction
	RollbackTransaction
	Analyze
	Vacuum
	Pragma
)

StatementKind constants enumerate the supported SQL statement types.

func (StatementKind) String

func (s StatementKind) String() string

type StatementResult

type StatementResult struct {
	Columns      []Column
	Rows         Iterator
	RowsAffected int
	LastInsertId int64
}

StatementResult ...

type Stats

type Stats struct {
	TableName string
	IndexName string
	StatValue string
}

Stats holds a single row from the internal statistics table.

type Table

type Table struct {
	Name    string
	Columns []Column

	PrimaryKey       PrimaryKey
	UniqueIndexes    map[string]UniqueIndex
	SecondaryIndexes map[string]SecondaryIndex
	// contains filtered or unexported fields
}

Table ...

func NewTable

func NewTable(logger *zap.Logger, pager TxPager, txManager *TransactionManager, name string, columns []Column, rootPageIdx PageIndex, provider TableProvider, opts ...TableOption) *Table

NewTable ...

func (*Table) BFS

func (t *Table) BFS(ctx context.Context, f callback) error

BFS ...

func (*Table) ColumnByName

func (t *Table) ColumnByName(name string) (Column, bool)

ColumnByName ...

func (*Table) Delete

func (t *Table) Delete(ctx context.Context, stmt Statement) (StatementResult, error)

Delete ...

func (*Table) DeleteKey

func (t *Table) DeleteKey(ctx context.Context, pageIdx PageIndex, key RowID) error

DeleteKey deletes a key from the table, when this is called, you should already have located the leaf that contains the key and pass its page and cell index here. The deletion process starts at the leaf and then recursively bubbles up the tree.

func (*Table) GetMaxKey

func (t *Table) GetMaxKey(ctx context.Context, page *Page) (RowID, error)

GetMaxKey ...

func (*Table) GetRootPageIdx

func (t *Table) GetRootPageIdx() PageIndex

GetRootPageIdx ...

func (*Table) HasIndexOnColumn

func (t *Table) HasIndexOnColumn(name string) bool

HasIndexOnColumn ...

func (*Table) HasIndexOnColumns

func (t *Table) HasIndexOnColumns(columns []Column) bool

HasIndexOnColumns ...

func (*Table) HasNoIndex

func (t *Table) HasNoIndex() bool

HasNoIndex ...

func (*Table) HasPrimaryKey

func (t *Table) HasPrimaryKey() bool

HasPrimaryKey ...

func (*Table) IndexByName

func (t *Table) IndexByName(name string) (BTreeIndex, bool)

IndexByName ...

func (*Table) IndexColumnsByIndexName

func (t *Table) IndexColumnsByIndexName(name string) ([]Column, bool)

IndexColumnsByIndexName ...

func (*Table) IndexInfoByColumnName

func (t *Table) IndexInfoByColumnName(name string) (IndexInfo, bool)

IndexInfoByColumnName ...

func (*Table) IndexInfoByColumns

func (t *Table) IndexInfoByColumns(columns []Column) (IndexInfo, bool)

IndexInfoByColumns looks up an index whose columns (in order) exactly match the given slice.

func (*Table) Insert

func (t *Table) Insert(ctx context.Context, stmt Statement) (StatementResult, error)

Insert ...

func (*Table) InternalNodeInsert

func (t *Table) InternalNodeInsert(ctx context.Context, parentPageIdx, childPageIdx PageIndex) error

InternalNodeInsert adds a new child/key pair to the parent internal node corresponding to the given child page.

func (*Table) InternalNodeSplitInsert

func (t *Table) InternalNodeSplitInsert(ctx context.Context, pageIdx, childPageIdx PageIndex) error

InternalNodeSplitInsert splits an internal node and inserts the child. It creates a sibling to hold (n-1)/2 keys, updates the parent's max key, inserts the sibling into the parent (possibly triggering further splits), and creates a new root if the original node was the root.

func (*Table) PlanQuery

func (t *Table) PlanQuery(ctx context.Context, stmt Statement) (QueryPlan, error)

PlanQuery creates a query plan based on the statement and table schema. This is in no way a sophisticated query planner, but a simple heuristic-based approach to determine whether an index scan can be used based on the WHERE conditions.

Consider a table with the following schema: CREATE TABLE users (

id INTEGER PRIMARY KEY,
email TEXT UNIQUE,
non_indexed_col TEXT,
created TIMESTAMP DEFAULT NOW()

); CREATE INDEX "idx_created" ON "users" (created);

If we select without a WHERE clause, we default to a sequential scan: SELECT * from users;

If a WHERE clause cannot be fully satisfied by an index or combination of indexes, we fall back to a sequential scan.

Remember that if you have multiple conditions separated by OR, if a single one does not use an index, we have to do a sequential scan anyway. Also remember that non equality conditions using != or NOT IN or conditions comparing to NULL cannot use indexes.

SEQUENTIAL SCANS: ----------------- SELECT * from users WHERE non_indexed_col = 'baz'; SELECT * from users WHERE id = 1 OR non_indexed_col = 'baz'; SELECT * FROM users WHERE id = 1 OR id IS NULL; SELECT * FROM users WHERE pk NOT IN (1,2,3);

INDEX POINT SCANS: ------------------ When there are only equality conditions on indexed columns (primary key or unique indexes), we can do index point scans:

SELECT * from users WHERE id = 1; - single point scan on PK index SELECT * from users WHERE id IN (1, 2, 3); - single point scan on PK index SELECT * from users WHERE email = 'foo@example.com'; - single point scan on unique index SELECT * FROM users WHERE id = 1 OR id id = 2 OR email = 'foo@example.com'; - multiple point scans

RANGE SCANS: ------------ For >, >=, <, <= conditions on indexed columns, we can do range scans:

SELECT * FROM users WHERE id > 10 AND id < 20 AND non_indexed_col = 'baz'; - range scan on PK index

For OR conditions, we can do multiple range scans if each condition group has a range condition. For example, following query can be executed as two range scans, one on PK column and one on secondary index:

SELECT * FROM users WHERE (id >= 10 AND id <= 20) OR created >= '2024-01-01';

When combining range scans with ordering, we currently fall back to in-memory sort:

SELECT * FROM users WHERE id >= 10 AND id <= 20 ORDER BY created DESC;

ORDER BY: --------- SELECT * from users ORDER BY id DESC; - use PK index for ordering SELECT * from users ORDER BY created DESC; - use index on created for ordering SELECT * from users ORDER BY non_indexed_col; - order in memory

func (*Table) RemoveSecondaryIndex

func (t *Table) RemoveSecondaryIndex(name string)

RemoveSecondaryIndex ...

func (*Table) Seek

func (t *Table) Seek(ctx context.Context, key RowID) (*Cursor, error)

Seek the cursor for a key, if it does not exist then return the cursor for the page and cell where it should be inserted

func (*Table) SeekFirst

func (t *Table) SeekFirst(ctx context.Context) (*Cursor, error)

SeekFirst returns a cursor pointing at the first row in the table.

func (*Table) SeekLast

func (t *Table) SeekLast(ctx context.Context, pageIdx PageIndex) (*Cursor, error)

SeekLast returns cursor pointing at the last row in the table

func (*Table) SeekNextRowID

func (t *Table) SeekNextRowID(ctx context.Context, pageIdx PageIndex) (*Cursor, RowID, error)

SeekNextRowID returns cursor pointing at the position after the last row ID plus a new row ID to insert

func (*Table) Select

func (t *Table) Select(ctx context.Context, stmt Statement) (StatementResult, error)

Select ...

func (*Table) SetSecondaryIndex

func (t *Table) SetSecondaryIndex(name string, columns []Column, index BTreeIndex)

SetSecondaryIndex ...

func (*Table) Update

func (t *Table) Update(ctx context.Context, stmt Statement) (StatementResult, error)

Update executes an UPDATE statement on the table and returns the result.

type TableOption

type TableOption func(*Table)

TableOption ...

func WithPrimaryKey

func WithPrimaryKey(pk PrimaryKey) TableOption

WithPrimaryKey ...

func WithSecondaryIndex

func WithSecondaryIndex(index SecondaryIndex) TableOption

WithSecondaryIndex ...

func WithUniqueIndex

func WithUniqueIndex(index UniqueIndex) TableOption

WithUniqueIndex ...

type TableProvider

type TableProvider interface {
	GetTable(ctx context.Context, name string) (*Table, bool)
}

TableProvider provides thread-safe access to tables

type TextPointer

type TextPointer struct {
	Length    uint32    // Total size of text
	FirstPage PageIndex // First overflow page (if not inline)
	Data      []byte
}

TextPointer is stored in the main row; text of length <= MaxInlineVarchar is stored inline, otherwise it points to an overflow page.

func NewTextPointer

func NewTextPointer(data []byte) TextPointer

NewTextPointer ...

func (TextPointer) IsEqual

func (tp TextPointer) IsEqual(tp2 TextPointer) bool

IsEqual ...

func (TextPointer) IsInline

func (tp TextPointer) IsInline() bool

IsInline ...

func (*TextPointer) Marshal

func (tp *TextPointer) Marshal(buf []byte, i uint64) error

Marshal ...

func (TextPointer) NumberOfPages

func (tp TextPointer) NumberOfPages() uint32

NumberOfPages ...

func (TextPointer) Size

func (tp TextPointer) Size() uint64

Size ...

func (TextPointer) String

func (tp TextPointer) String() string

func (*TextPointer) Unmarshal

func (tp *TextPointer) Unmarshal(buf []byte, i uint64) error

Unmarshal ...

type Time

type Time struct {
	Year         int32 // astonomical year numbering, e.g. 1 BC = year 0, 2 BC = -1, etc.
	Month        int8
	Day          int8
	Hour         int8
	Minutes      int8
	Seconds      int8
	Microseconds int32
}

Time is a custom type implementing a PostgreSQL-like TIMESTAMP type without timezone. low value 4713 BC high value 294276 AD

func FromMicroseconds

func FromMicroseconds(microseconds int64) Time

FromMicroseconds constructs a Time from microseconds since 2000-01-01 00:00:00 UTC.

func MustParseTimestamp

func MustParseTimestamp(timestampStr string) Time

MustParseTimestamp parses a timestamp string and panics on error.

func ParseTimestamp

func ParseTimestamp(timestampStr string) (Time, error)

ParseTimestamp parses a PostgreSQL-style timestamp string into a Time value.

func (Time) AddInterval added in v0.11.0

func (t Time) AddInterval(iv Interval, sign int32) Time

AddInterval adds (sign=+1) or subtracts (sign=-1) iv from t.

Month arithmetic is calendar-aware: adding 1 month to Jan 31 yields the last day of February (28 or 29 depending on the year). The day component of the interval uses fixed 86 400-second days, consistent with PostgreSQL.

func (Time) GoTime

func (t Time) GoTime() time.Time

GoTime converts the custom Time value to a standard library time.Time.

func (Time) String

func (t Time) String() string

func (Time) TotalMicroseconds

func (t Time) TotalMicroseconds() int64

TotalMicroseconds returns the microsecond count since 2000-01-01 00:00:00 UTC. Negative values represent dates before 2000-01-01 00:00:00 UTC.

type Transaction

type Transaction struct {
	ID            TransactionID
	StartTime     time.Time
	ReadSet       map[PageIndex]uint64    // pageIdx -> version when read
	WriteSet      map[PageIndex]WriteInfo // pageIdx -> modified page copy (+ table name, index name)
	DBHeaderRead  *uint64                 // version of DB header when read
	DBHeaderWrite *DatabaseHeader         // modified DB header
	DDLChanges    DDLChanges
	Status        TransactionStatus
	// contains filtered or unexported fields
}

Transaction tracks the read and write sets for optimistic concurrency control.

func MustTxFromContext

func MustTxFromContext(ctx context.Context) *Transaction

MustTxFromContext retrieves the current transaction from the context and panics if none is present.

func TxFromContext

func TxFromContext(ctx context.Context) *Transaction

TxFromContext retrieves the current transaction from the context, or nil if none.

func (*Transaction) Abort

func (tx *Transaction) Abort()

Abort sets status to TxAborted and discards all in-memory changes.

func (*Transaction) Commit

func (tx *Transaction) Commit()

Commit marks the transaction as committed.

func (*Transaction) GetDBHeaderReadVersion

func (tx *Transaction) GetDBHeaderReadVersion() (uint64, bool)

GetDBHeaderReadVersion returns the version of the database header as it was read, if any.

func (*Transaction) GetModifiedDBHeader

func (tx *Transaction) GetModifiedDBHeader() (*DatabaseHeader, bool)

GetModifiedDBHeader returns the in-memory modified database header, if any.

func (*Transaction) GetModifiedPage

func (tx *Transaction) GetModifiedPage(pageIdx PageIndex) (*Page, bool)

GetModifiedPage returns the in-memory modified copy of the page at pageIdx, if any.

func (*Transaction) GetReadVersions

func (tx *Transaction) GetReadVersions() map[PageIndex]uint64

GetReadVersions returns a copy of the page read-version map.

func (*Transaction) GetWriteVersions

func (tx *Transaction) GetWriteVersions() map[PageIndex]WriteInfo

GetWriteVersions returns the transaction's write set.

func (*Transaction) TrackDBHeaderRead

func (tx *Transaction) TrackDBHeaderRead(version uint64)

TrackDBHeaderRead records the version of the database header when it was read.

func (*Transaction) TrackDBHeaderWrite

func (tx *Transaction) TrackDBHeaderWrite(header DatabaseHeader)

TrackDBHeaderWrite records a modified database header in the transaction write set.

func (*Transaction) TrackRead

func (tx *Transaction) TrackRead(pageIdx PageIndex, version uint64)

TrackRead records that the given page was read at the given version.

func (*Transaction) TrackWrite

func (tx *Transaction) TrackWrite(pageIdx PageIndex, page *Page, table, index string)

TrackWrite records a modified page in the transaction write set.

type TransactionID

type TransactionID uint64

TransactionID is the unique identifier for a transaction.

type TransactionManager

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

TransactionManager coordinates optimistic concurrency control for the database.

func NewTransactionManager

func NewTransactionManager(logger *zap.Logger, dbFilePath string, factory TxPagerFactory, saver PageSaver, ddlSaver DDLSaver) *TransactionManager

NewTransactionManager creates and returns a new TransactionManager.

func (*TransactionManager) BeginTransaction

func (tm *TransactionManager) BeginTransaction(ctx context.Context) *Transaction

BeginTransaction starts a new transaction and registers it with the manager.

func (*TransactionManager) CheckpointWAL added in v0.12.0

func (tm *TransactionManager) CheckpointWAL(dbFile DBFile) error

CheckpointWAL checkpoints the WAL into dbFile, then truncates it.

Checkpoint sequence (all under walWriteMu so no concurrent writers can interleave):

  1. Write every unique page in the WAL to its correct offset in dbFile.
  2. fsync dbFile.
  3. Truncate the WAL file and write fresh salts (invalidates stale frames).
  4. Reset the in-memory WAL index (under tm.mu).

Returns ErrNotWALMode if no WAL is configured.

func (*TransactionManager) CommitTransaction

func (tm *TransactionManager) CommitTransaction(ctx context.Context, tx *Transaction) error

CommitTransaction validates the write set for conflicts and, if clean, persists all changes. When a WAL is configured it uses the WAL commit path; otherwise it writes directly to the pager (used by unit tests that do not set up a WAL file).

func (*TransactionManager) ExecuteInTransaction

func (tm *TransactionManager) ExecuteInTransaction(ctx context.Context, fn func(ctx context.Context) error) error

ExecuteInTransaction runs fn within a transaction, committing on success or rolling back on failure.

func (*TransactionManager) GlobalDBHeaderVersion

func (tm *TransactionManager) GlobalDBHeaderVersion(ctx context.Context) uint64

GlobalDBHeaderVersion returns the current committed version of the database header.

func (*TransactionManager) GlobalPageVersion

func (tm *TransactionManager) GlobalPageVersion(ctx context.Context, pageIdx PageIndex) uint64

GlobalPageVersion returns the current committed version of the given page.

func (*TransactionManager) RollbackTransaction

func (tm *TransactionManager) RollbackTransaction(ctx context.Context, tx *Transaction)

RollbackTransaction aborts the transaction and discards all in-memory changes.

func (*TransactionManager) SetCheckpointFunc added in v0.12.0

func (tm *TransactionManager) SetCheckpointFunc(fn func() error)

SetCheckpointFunc registers a callback that is invoked by runAutoCheckpoint when the WAL frame count exceeds checkpointThreshold. Typically set to Database.Checkpoint so the auto-checkpoint path mirrors the manual one.

type TransactionStatus

type TransactionStatus int

TransactionStatus represents the lifecycle state of a transaction.

const (
	// TxActive means the transaction is in progress and has not yet been committed or aborted.
	TxActive TransactionStatus = iota + 1
	// TxCommitted means the transaction has been successfully committed.
	TxCommitted
	// TxAborted means the transaction has been rolled back or aborted.
	TxAborted
)

TransactionStatus constants describe the lifecycle state of a transaction.

type TransactionalPager

type TransactionalPager struct {
	Pager
	// contains filtered or unexported fields
}

TransactionalPager wraps a base Pager and routes reads and writes through the current transaction.

func NewTransactionalPager

func NewTransactionalPager(basePager Pager, txManager *TransactionManager, table, index string) *TransactionalPager

NewTransactionalPager creates a TransactionalPager for the given table and index names.

func (*TransactionalPager) AddFreePage

func (tp *TransactionalPager) AddFreePage(ctx context.Context, pageIdx PageIndex) error

AddFreePage marks pageIdx as a free page and prepends it to the free list.

func (*TransactionalPager) GetFreePage

func (tp *TransactionalPager) GetFreePage(ctx context.Context) (*Page, error)

GetFreePage returns a free page from the free list, or allocates a new one.

func (*TransactionalPager) GetOverflowPage

func (tp *TransactionalPager) GetOverflowPage(ctx context.Context, pageIdx PageIndex) (*Page, error)

GetOverflowPage returns a writable copy of the overflow page at pageIdx.

func (*TransactionalPager) ModifyPage

func (tp *TransactionalPager) ModifyPage(ctx context.Context, pageIdx PageIndex) (*Page, error)

ModifyPage returns a writable copy of the page at pageIdx, creating one if it doesn't exist in the write set.

func (*TransactionalPager) ReadPage

func (tp *TransactionalPager) ReadPage(ctx context.Context, pageIdx PageIndex) (*Page, error)

ReadPage returns the page at pageIdx, returning the in-progress write copy if it exists.

type TxPager

type TxPager interface {
	ReadPage(context.Context, PageIndex) (*Page, error)
	ModifyPage(context.Context, PageIndex) (*Page, error)
	GetFreePage(context.Context) (*Page, error)
	AddFreePage(context.Context, PageIndex) error
	GetOverflowPage(context.Context, PageIndex) (*Page, error)
}

TxPager ...

type TxPagerFactory

type TxPagerFactory func(ctx context.Context, tableName, indexName string) (Pager, error)

TxPagerFactory ...

type UnionClause added in v0.9.0

type UnionClause struct {
	All  bool      // true = UNION ALL (keep duplicates); false = UNION (deduplicate)
	Stmt Statement // the chained SELECT
}

UnionClause represents a UNION or UNION ALL branch appended to a SELECT statement.

type UniqueIndex

type UniqueIndex struct {
	IndexInfo
	Index BTreeIndex
}

UniqueIndex ...

type WAL added in v0.12.0

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

WAL is a write-ahead log providing crash-safe durability for the database.

On each commit the transaction manager serialises all modified pages as WAL frames and calls AppendTransaction. A final "commit frame" (CommitSize > 0) marks the transaction as durable. Readers check the WAL index (see WALIndex) before reading the main DB file so they always see the latest committed version of any page.

Periodically, or on clean open, committed frames are copied back to the main DB file via Checkpoint and the WAL is truncated.

func CreateWAL added in v0.12.0

func CreateWAL(dbPath string, pageSize uint32) (*WAL, error)

CreateWAL creates a new WAL file (truncating any existing file at that path).

func OpenWAL added in v0.12.0

func OpenWAL(dbPath string, pageSize uint32) (*WAL, error)

OpenWAL opens an existing WAL file for reading and appending. Returns (nil, nil) when the WAL file does not exist (clean state).

func OpenWALAndRebuildIndex added in v0.12.0

func OpenWALAndRebuildIndex(dbPath string, pageSize uint32, walIndex *WALIndex) (wal *WAL, recovered bool, err error)

OpenWALAndRebuildIndex is the startup routine for WAL mode.

It checks for an existing WAL file at dbPath+"-wal":

  • If the file exists, it opens it for appending, reads all committed frames, and rebuilds walIndex from those frames. This is the crash- recovery path: committed writes that had not yet been checkpointed to the main DB file are reinstated in the in-memory index so reads see the correct data immediately.

  • If no WAL file exists, a fresh WAL file is created.

The caller owns the returned *WAL and must call WAL.Close() when done. walIndex is populated in-place; it must be non-nil. recovered is true when an existing WAL file with committed frames was found.

func (*WAL) AppendTransaction added in v0.12.0

func (w *WAL) AppendTransaction(pages []WALPage) error

AppendTransaction writes all modified pages as WAL frames and syncs the file. The last frame is marked as a commit frame (CommitSize = len(pages)). pages must be non-empty; each Data slice must be exactly pageSize bytes.

func (*WAL) Checkpoint added in v0.12.0

func (w *WAL) Checkpoint(dbFile DBFile) error

Checkpoint copies all committed WAL pages to the database file. It writes the latest version of each page (last write wins when a page appears in multiple transactions) and then fsyncs the database file. Callers should call Truncate after a successful checkpoint.

func (*WAL) Close added in v0.12.0

func (w *WAL) Close() error

Close closes the underlying WAL file handle without removing it.

func (*WAL) Delete added in v0.12.0

func (w *WAL) Delete() error

Delete closes and removes the WAL file. Used when transitioning back to a clean (no-WAL) state, e.g. after a full checkpoint on clean shutdown.

func (*WAL) FrameCount added in v0.12.0

func (w *WAL) FrameCount() int64

FrameCount returns the total number of frame slots written since the last Truncate (including both committed and uncommitted frames).

func (*WAL) ReadAllFrames added in v0.12.0

func (w *WAL) ReadAllFrames() ([]WALReadFrame, error)

ReadAllFrames scans the WAL file from the beginning and returns every frame that belongs to a committed transaction. Frames whose salts or CRCs do not match are treated as the end of the valid region; any pending (uncommitted) frames before the scan stops are silently discarded.

func (*WAL) Truncate added in v0.12.0

func (w *WAL) Truncate() error

Truncate resets the WAL to an empty state after a successful checkpoint. The file header is rewritten with fresh salts so that any unreachable frames left behind by a partial truncation are automatically invalidated.

type WALConfig added in v0.12.0

type WALConfig struct {
	WAL                 *WAL
	Index               *WALIndex
	DBFile              DBFile
	CheckpointThreshold int
}

WALConfig bundles the Write-Ahead Log objects that NewDatabase needs. Pass nil when creating in-memory/test databases that do not require WAL.

type WALIndex added in v0.12.0

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

WALIndex is an in-memory map from page index to the latest raw page bytes that have been committed to the WAL but not yet checkpointed to the main DB file. It is the authoritative source for the current page content during the window between a WAL commit and the next checkpoint.

All methods are safe for concurrent use.

Lifecycle:

  1. Created empty at database open via NewWALIndex.
  2. Populated from the WAL file via Rebuild when a non-empty WAL is found.
  3. Updated after each successful AppendTransaction via Update.
  4. Reset after a successful Checkpoint + Truncate via Reset.

The pager (Phase 4) calls Lookup before reading the DB file so readers always see the latest committed version of every page.

func NewWALIndex added in v0.12.0

func NewWALIndex() *WALIndex

NewWALIndex creates an empty WALIndex.

func (*WALIndex) Has added in v0.12.0

func (wi *WALIndex) Has(pageIdx PageIndex) bool

Has reports whether pageIdx has a committed WAL entry in the index.

func (*WALIndex) Lookup added in v0.12.0

func (wi *WALIndex) Lookup(pageIdx PageIndex) ([]byte, bool)

Lookup returns the raw page bytes for pageIdx if the page has a committed WAL entry that has not yet been checkpointed. The returned slice is a defensive copy; callers may modify it freely.

func (*WALIndex) MaxPageIndex added in v0.12.0

func (wi *WALIndex) MaxPageIndex() PageIndex

MaxPageIndex returns the largest page index stored in the WAL index, or 0 if the index is empty. Used by the pager to initialise totalPages when the DB file is empty (WAL-only mode) so that new-page allocation never clobbers existing WAL pages.

func (*WALIndex) Rebuild added in v0.12.0

func (wi *WALIndex) Rebuild(frames []WALReadFrame)

Rebuild replaces the index contents with the latest committed frame for each page found in frames. frames is expected to be the result of WAL.ReadAllFrames: all entries are already validated and belong to committed transactions. When the same page appears multiple times, the last occurrence wins (matching WAL semantics — later frames are more recent).

func (*WALIndex) Reset added in v0.12.0

func (wi *WALIndex) Reset()

Reset discards all entries. Called after a successful checkpoint + WAL truncation to reflect that the WAL no longer contains any data that is not already in the main DB file.

func (*WALIndex) Size added in v0.12.0

func (wi *WALIndex) Size() int

Size returns the number of unique page indices currently in the index.

func (*WALIndex) Update added in v0.12.0

func (wi *WALIndex) Update(pageIdx PageIndex, data []byte)

Update records the latest raw page bytes for pageIdx. A defensive copy of data is stored so the caller may reuse or free its slice. If a prior entry exists for pageIdx it is overwritten (later write wins).

type WALPage added in v0.12.0

type WALPage struct {
	Index PageIndex
	Data  []byte // must be exactly pageSize bytes
}

WALPage holds the page index and raw serialised content for one page to be appended to the WAL.

type WALReadFrame added in v0.12.0

type WALReadFrame struct {
	PageIndex PageIndex
	Data      []byte // raw page bytes (pageSize bytes)
}

WALReadFrame is a single validated, committed frame returned by ReadAllFrames.

type WriteInfo

type WriteInfo struct {
	*Page
	Table string
	Index string
}

WriteInfo holds a modified page together with the table and index names it belongs to.

type WritePage

type WritePage struct {
	Page  *Page
	Table string
}

WritePage associates a page with the table it belongs to.

Jump to

Keyboard shortcuts

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