Documentation
¶
Index ¶
- Constants
- Variables
- func IsValidCondition(c Condition) bool
- func NewPager(file DBFile, pageSize, maxCachedPages int) (*pagerImpl, error)
- func PrimaryKeyName(tableName string) string
- func RecoverFromWAL(dbPath string, dbFile DBFile, pageSize uint32) (bool, error)
- func UniqueIndexName(tableName string, columns ...string) string
- func UnmarshalDatabaseHeader(buf []byte, dbHeader *DatabaseHeader) error
- func WithTransaction(ctx context.Context, tx *Transaction) context.Context
- type AggregateExpr
- type AggregateKind
- type ArithOp
- type BTreeIndex
- type CaseWhen
- type Cell
- type Column
- type ColumnKind
- type CompositeKey
- type Condition
- func FieldIsBetween(field Field, low, high any) Condition
- func FieldIsEqual(field Field, operandType OperandType, value any) Condition
- func FieldIsGreater(field Field, operandType OperandType, value any) Condition
- func FieldIsGreaterOrEqual(field Field, operandType OperandType, value any) Condition
- func FieldIsInAny(field Field, values ...any) Condition
- func FieldIsLess(field Field, operandType OperandType, value any) Condition
- func FieldIsLessOrEqual(field Field, operandType OperandType, value any) Condition
- func FieldIsLike(field Field, operandType OperandType, value any) Condition
- func FieldIsNotBetween(field Field, low, high any) Condition
- func FieldIsNotEqual(field Field, operandType OperandType, value any) Condition
- func FieldIsNotInAny(field Field, values ...any) Condition
- func FieldIsNotLike(field Field, operandType OperandType, value any) Condition
- func FieldIsNotNull(field Field) Condition
- func FieldIsNull(field Field) Condition
- type ConditionNode
- type Conditions
- type ConflictAction
- type Cursor
- type DBFile
- type DDLChanges
- func (d DDLChanges) CreatedIndex(tableName string, index SecondaryIndex) DDLChanges
- func (d DDLChanges) CreatedTable(t *Table) DDLChanges
- func (d DDLChanges) DroppedIndex(tableName string, index SecondaryIndex) DDLChanges
- func (d DDLChanges) DroppedTable(tableName string) DDLChanges
- func (d DDLChanges) HasChanges() bool
- type DDLSaver
- type Database
- func (d *Database) Analyze(ctx context.Context, target string) error
- func (d *Database) Checkpoint(_ context.Context) error
- func (d *Database) Close() error
- func (d *Database) ExecuteStatement(ctx context.Context, stmt Statement) (StatementResult, error)
- func (d *Database) GetDDLSaver() DDLSaver
- func (d *Database) GetFileName() string
- func (d *Database) GetSaver() PageSaver
- func (d *Database) GetTable(ctx context.Context, name string) (*Table, bool)
- func (d *Database) GetTransactionManager() *TransactionManager
- func (d *Database) IntegrityCheck(ctx context.Context) (IntegrityReport, error)
- func (d *Database) ListTableNames(ctx context.Context) []string
- func (d *Database) PrepareStatement(ctx context.Context, query string) (Statement, error)
- func (d *Database) PrepareStatements(ctx context.Context, sql string) ([]Statement, error)
- func (d *Database) QuickCheck(ctx context.Context) (IntegrityReport, error)
- func (d *Database) Reopen(ctx context.Context, factory PagerFactory, saver PageSaver) error
- func (d *Database) SaveDDLChanges(ctx context.Context, changes DDLChanges)
- func (d *Database) Vacuum(ctx context.Context) error
- type DatabaseHeader
- type DatabaseOption
- type Direction
- type ExcludedRef
- type Expr
- type Field
- type Flusher
- type FreePage
- type Function
- type Header
- type ICell
- type Index
- func (ui *Index[T]) BFS(ctx context.Context, f indexCallback) error
- func (ui *Index[T]) Delete(ctx context.Context, keyAny any, rowID RowID) error
- func (ui *Index[T]) FindRowIDs(ctx context.Context, keyAny any) ([]RowID, error)
- func (ui *Index[T]) GetRootPageIdx() PageIndex
- func (ui *Index[T]) Insert(ctx context.Context, keyAny any, rowID RowID) error
- func (ui *Index[T]) ScanAll(ctx context.Context, reverse bool, callback indexScanner) error
- func (ui *Index[T]) ScanRange(ctx context.Context, rangeCondition RangeCondition, reverse bool, ...) error
- func (ui *Index[T]) Seek(ctx context.Context, page *Page, keyAny any) (IndexCursor[T], bool, error)
- func (ui *Index[T]) SeekLastKey(ctx context.Context, pageIdx PageIndex) (any, error)
- func (ui *Index[T]) SeekWithPrefix(ctx context.Context, page *Page, prefixAny any, prefixColumns int) (IndexCursor[T], bool, error)
- type IndexCell
- func (c *IndexCell[T]) Clone() IndexCell[T]
- func (c *IndexCell[T]) Marshal(buf []byte) error
- func (c *IndexCell[T]) RemoveRowID(id RowID) int
- func (c *IndexCell[T]) ReplaceRowID(id, newID RowID) int
- func (c *IndexCell[T]) Size() uint64
- func (c *IndexCell[T]) Unmarshal(columns []Column, buf []byte) (uint64, error)
- type IndexCursor
- type IndexInfo
- type IndexKey
- type IndexNode
- func (n *IndexNode[T]) AppendCells(cells ...IndexCell[T])
- func (n *IndexNode[T]) AtLeastHalfFull() bool
- func (n *IndexNode[T]) AvailableSpace() uint64
- func (n *IndexNode[T]) Child(childIdx uint32) (PageIndex, error)
- func (n *IndexNode[T]) Children() []PageIndex
- func (n *IndexNode[T]) Clone() *IndexNode[T]
- func (n *IndexNode[T]) DeleteKeyAndRightChild(idx uint32) error
- func (n *IndexNode[T]) FirstCell() IndexCell[T]
- func (n *IndexNode[T]) GetRightChildByIndex(idx uint32) PageIndex
- func (n *IndexNode[T]) HasSpaceForKey(key T) bool
- func (n *IndexNode[T]) Keys() []T
- func (n *IndexNode[T]) LastCell() IndexCell[T]
- func (n *IndexNode[T]) Marshal(buf []byte) error
- func (n *IndexNode[T]) MaxSpace() uint64
- func (n *IndexNode[T]) PrependCell(cell IndexCell[T])
- func (n *IndexNode[T]) RemoveFirstCell()
- func (n *IndexNode[T]) RemoveLastCell() IndexCell[T]
- func (n *IndexNode[T]) RowIDs() []RowID
- func (n *IndexNode[T]) SetChild(idx uint32, childPage PageIndex) error
- func (n *IndexNode[T]) Size() uint64
- func (n *IndexNode[T]) SplitInHalves(unique bool) (uint32, uint32)
- func (n *IndexNode[T]) TakenSpace() uint64
- func (n *IndexNode[T]) Unmarshal(columns []Column, buf []byte) (uint64, error)
- type IndexNodeHeader
- type IndexOverflowPage
- type IndexOverflowPageHeader
- type IndexStats
- type IntegrityIssue
- type IntegrityReport
- type InternalNode
- func (n *InternalNode) AppendCells(cells ...ICell)
- func (n *InternalNode) AtLeastHalfFull(maxIcells int) bool
- func (n *InternalNode) Child(childIdx uint32) (PageIndex, error)
- func (n *InternalNode) Children() []PageIndex
- func (n *InternalNode) Clone() *InternalNode
- func (n *InternalNode) DeleteKeyAndRightChild(idx uint32) error
- func (n *InternalNode) FirstCell() ICell
- func (n *InternalNode) GetRightChildByIndex(idx uint32) PageIndex
- func (n *InternalNode) IndexOfChild(key RowID) uint32
- func (n *InternalNode) IndexOfPage(pageIdx PageIndex) (uint32, error)
- func (n *InternalNode) Keys() []RowID
- func (n *InternalNode) LastCell() ICell
- func (n *InternalNode) Marshal(buf []byte) error
- func (n *InternalNode) MoreThanHalfFull(maxIcells int) bool
- func (n *InternalNode) PrependCell(cell ICell)
- func (n *InternalNode) RemoveFirstCell()
- func (n *InternalNode) RemoveLastCell()
- func (n *InternalNode) SetChild(idx uint32, childPage PageIndex) error
- func (n *InternalNode) Size() uint64
- func (n *InternalNode) Unmarshal(buf []byte) (uint64, error)
- type InternalNodeHeader
- type Interval
- type Iterator
- type Join
- type JoinColumnPair
- type JoinPlan
- type JoinType
- type LRUCache
- type LeafNode
- func (n *LeafNode) AppendCells(cells ...Cell)
- func (n *LeafNode) AtLeastHalfFull() bool
- func (n *LeafNode) AvailableSpace() uint64
- func (n *LeafNode) CanBorrowFirst() bool
- func (n *LeafNode) CanBorrowLast() bool
- func (n *LeafNode) CanMergeWith(n2 *LeafNode) bool
- func (n *LeafNode) Clone() *LeafNode
- func (n *LeafNode) DeepClone() *LeafNode
- func (n *LeafNode) Delete(key RowID) (Cell, bool)
- func (n *LeafNode) FirstCell() Cell
- func (n *LeafNode) HasSpaceForRow(row Row) bool
- func (n *LeafNode) Keys() []RowID
- func (n *LeafNode) LastCell() Cell
- func (n *LeafNode) Marshal(buf []byte) error
- func (n *LeafNode) MaxSpace() uint64
- func (n *LeafNode) PrepareModifyCell(idx uint32)
- func (n *LeafNode) PrependCell(cell Cell)
- func (n *LeafNode) RemoveFirstCell()
- func (n *LeafNode) RemoveLastCell()
- func (n *LeafNode) Size() uint64
- func (n *LeafNode) TakenSpace() uint64
- func (n *LeafNode) Unmarshal(columns []Column, buf []byte) (uint64, error)
- type LeafNodeHeader
- type LogicOp
- type OneOrMore
- type Operand
- type OperandType
- type Operator
- type OptionalValue
- type OrderBy
- type OverflowPage
- type OverflowPageHeader
- type Page
- type PageIndex
- type PageSaver
- type PageUnmarshaler
- type Pager
- type PagerFactory
- type Parser
- type Placeholder
- type PrimaryKey
- type QueryPlan
- type RangeBound
- type RangeCondition
- type Row
- func (r Row) AppendValues(fields []Field, values []OptionalValue) Row
- func (r Row) CheckConditions(condGroup Conditions) (bool, error)
- func (r Row) CheckOneOrMore(conditions OneOrMore) (bool, error)
- func (r Row) Clone() Row
- func (r Row) GetColumn(name string) (Column, int)
- func (r Row) GetValue(name string) (OptionalValue, bool)
- func (r Row) GetValuesForColumns(columns []Column) ([]OptionalValue, bool)
- func (r Row) Marshal() ([]byte, error)
- func (r Row) NullBitmask() uint64
- func (r Row) OnlyFields(fields ...Field) Row
- func (r Row) SetValue(name string, value OptionalValue) (Row, bool)
- func (r Row) Size() uint64
- func (r Row) Unmarshal(cell Cell, selectedFields ...Field) (Row, error)
- type RowID
- type Scan
- type ScanType
- type Schema
- type SchemaType
- type SecondaryIndex
- type Statement
- func (s Statement) AddJoin(joinType JoinType, fromTableAlias, toTable, toTableAlias string, ...) (Statement, error)
- func (s Statement) BindArguments(args ...any) (Statement, error)
- func (s Statement) Clone() Statement
- func (s Statement) ColumnByName(name string) (Column, bool)
- func (s Statement) ColumnIdx(name string) int
- func (s Statement) DDL() string
- func (s Statement) HasField(name string) bool
- func (s Statement) InsertValuesForColumns(insertIdx int, columns ...Column) []OptionalValue
- func (s Statement) IsDDL() bool
- func (s Statement) IsSelectAggregate() bool
- func (s Statement) IsSelectAll() bool
- func (s Statement) IsSelectCountAll() bool
- func (s Statement) IsSelectGroupBy() bool
- func (s Statement) NumPlaceholders() int
- func (s Statement) Prepare(now Time) (Statement, error)
- func (s Statement) ReadOnly() bool
- func (s Statement) Validate(table *Table) error
- type StatementKind
- type StatementResult
- type Stats
- type Table
- func (t *Table) BFS(ctx context.Context, f callback) error
- func (t *Table) ColumnByName(name string) (Column, bool)
- func (t *Table) Delete(ctx context.Context, stmt Statement) (StatementResult, error)
- func (t *Table) DeleteKey(ctx context.Context, pageIdx PageIndex, key RowID) error
- func (t *Table) GetMaxKey(ctx context.Context, page *Page) (RowID, error)
- func (t *Table) GetRootPageIdx() PageIndex
- func (t *Table) HasIndexOnColumn(name string) bool
- func (t *Table) HasIndexOnColumns(columns []Column) bool
- func (t *Table) HasNoIndex() bool
- func (t *Table) HasPrimaryKey() bool
- func (t *Table) IndexByName(name string) (BTreeIndex, bool)
- func (t *Table) IndexColumnsByIndexName(name string) ([]Column, bool)
- func (t *Table) IndexInfoByColumnName(name string) (IndexInfo, bool)
- func (t *Table) IndexInfoByColumns(columns []Column) (IndexInfo, bool)
- func (t *Table) Insert(ctx context.Context, stmt Statement) (StatementResult, error)
- func (t *Table) InternalNodeInsert(ctx context.Context, parentPageIdx, childPageIdx PageIndex) error
- func (t *Table) InternalNodeSplitInsert(ctx context.Context, pageIdx, childPageIdx PageIndex) error
- func (t *Table) PlanQuery(ctx context.Context, stmt Statement) (QueryPlan, error)
- func (t *Table) RemoveSecondaryIndex(name string)
- func (t *Table) Seek(ctx context.Context, key RowID) (*Cursor, error)
- func (t *Table) SeekFirst(ctx context.Context) (*Cursor, error)
- func (t *Table) SeekLast(ctx context.Context, pageIdx PageIndex) (*Cursor, error)
- func (t *Table) SeekNextRowID(ctx context.Context, pageIdx PageIndex) (*Cursor, RowID, error)
- func (t *Table) Select(ctx context.Context, stmt Statement) (StatementResult, error)
- func (t *Table) SetSecondaryIndex(name string, columns []Column, index BTreeIndex)
- func (t *Table) Update(ctx context.Context, stmt Statement) (StatementResult, error)
- type TableOption
- type TableProvider
- type TextPointer
- func (tp TextPointer) IsEqual(tp2 TextPointer) bool
- func (tp TextPointer) IsInline() bool
- func (tp *TextPointer) Marshal(buf []byte, i uint64) error
- func (tp TextPointer) NumberOfPages() uint32
- func (tp TextPointer) Size() uint64
- func (tp TextPointer) String() string
- func (tp *TextPointer) Unmarshal(buf []byte, i uint64) error
- type Time
- type Transaction
- func (tx *Transaction) Abort()
- func (tx *Transaction) Commit()
- func (tx *Transaction) GetDBHeaderReadVersion() (uint64, bool)
- func (tx *Transaction) GetModifiedDBHeader() (*DatabaseHeader, bool)
- func (tx *Transaction) GetModifiedPage(pageIdx PageIndex) (*Page, bool)
- func (tx *Transaction) GetReadVersions() map[PageIndex]uint64
- func (tx *Transaction) GetWriteVersions() map[PageIndex]WriteInfo
- func (tx *Transaction) TrackDBHeaderRead(version uint64)
- func (tx *Transaction) TrackDBHeaderWrite(header DatabaseHeader)
- func (tx *Transaction) TrackRead(pageIdx PageIndex, version uint64)
- func (tx *Transaction) TrackWrite(pageIdx PageIndex, page *Page, table, index string)
- type TransactionID
- type TransactionManager
- func (tm *TransactionManager) BeginTransaction(ctx context.Context) *Transaction
- func (tm *TransactionManager) CheckpointWAL(dbFile DBFile) error
- func (tm *TransactionManager) CommitTransaction(ctx context.Context, tx *Transaction) error
- func (tm *TransactionManager) ExecuteInTransaction(ctx context.Context, fn func(ctx context.Context) error) error
- func (tm *TransactionManager) GlobalDBHeaderVersion(ctx context.Context) uint64
- func (tm *TransactionManager) GlobalPageVersion(ctx context.Context, pageIdx PageIndex) uint64
- func (tm *TransactionManager) RollbackTransaction(ctx context.Context, tx *Transaction)
- func (tm *TransactionManager) SetCheckpointFunc(fn func() error)
- type TransactionStatus
- type TransactionalPager
- func (tp *TransactionalPager) AddFreePage(ctx context.Context, pageIdx PageIndex) error
- func (tp *TransactionalPager) GetFreePage(ctx context.Context) (*Page, error)
- func (tp *TransactionalPager) GetOverflowPage(ctx context.Context, pageIdx PageIndex) (*Page, error)
- func (tp *TransactionalPager) ModifyPage(ctx context.Context, pageIdx PageIndex) (*Page, error)
- func (tp *TransactionalPager) ReadPage(ctx context.Context, pageIdx PageIndex) (*Page, error)
- type TxPager
- type TxPagerFactory
- type UnionClause
- type UniqueIndex
- type WAL
- type WALConfig
- type WALIndex
- func (wi *WALIndex) Has(pageIdx PageIndex) bool
- func (wi *WALIndex) Lookup(pageIdx PageIndex) ([]byte, bool)
- func (wi *WALIndex) MaxPageIndex() PageIndex
- func (wi *WALIndex) Rebuild(frames []WALReadFrame)
- func (wi *WALIndex) Reset()
- func (wi *WALIndex) Size() int
- func (wi *WALIndex) Update(pageIdx PageIndex, data []byte)
- type WALPage
- type WALReadFrame
- type WriteInfo
- type WritePage
Constants ¶
const ( // DatabaseHeaderMagic identifies a MiniSQL database file. DatabaseHeaderMagic = "minisql\x00" // DatabaseFileFormatVersion identifies the current on-disk file header format. DatabaseFileFormatVersion = uint32(1) )
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 )
const ( // MaxInlineRowIDs ... MaxInlineRowIDs = 4 // MaxOverflowRowIDsPerPage ... MaxOverflowRowIDsPerPage = 510 // (4096 - 1 - 8 ) / 8 )
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.
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 )
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 )
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.
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.
const ICellSize = 12 // (8+4)
ICellSize is the serialised byte size of an ICell (8-byte key + 4-byte child pointer).
const MaxIndexKeySize = 255
MaxIndexKeySize is the maximum number of bytes allowed for a single index key.
const MinimumIndexCells = 4
MinimumIndexCells is the minimum number of cells required in an index node. TODO - this is not used currently
const PageCacheSize = 2000
PageCacheSize is the default maximum number of pages to keep in memory.
const RightChildNotSet = math.MaxUint32
RightChildNotSet is the sentinel value indicating an internal node has no right child yet.
Variables ¶
var ErrDuplicateKey = errors.New("duplicate key")
ErrDuplicateKey ...
var ErrNoMoreRows = errors.New("no more rows")
ErrNoMoreRows ...
var ErrNotFound = errors.New("not found")
ErrNotFound ...
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.
var ErrTxConflict = errors.New("transaction conflict detected")
ErrTxConflict is returned when an optimistic concurrency check fails at commit time.
var FunctionNow = Function{Name: nowFunctionName}
FunctionNow ...
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) )
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 ¶
IsValidCondition checks that all fields of the condition are set
func NewPager ¶
NewPager opens the database file and initialises the pager. maxCachedPages sets the maximum number of pages to keep in cache (0 = use default).
func RecoverFromWAL ¶ added in v0.12.0
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 ¶
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.
ArithOp constants.
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 ...
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) 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.
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
FieldIsNotNull creates a field IS NOT NULL condition.
func FieldIsNull ¶
FieldIsNull creates a field IS NULL condition.
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 ¶
Cursor is a position within a table's B+ tree used to traverse or modify rows.
func (*Cursor) LeafNodeInsert ¶
LeafNodeInsert inserts a row at the cursor's current position, splitting the leaf node if necessary.
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 ¶
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
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) ExecuteStatement ¶
ExecuteStatement executes a single statement and returns the result
func (*Database) GetDDLSaver ¶
GetDDLSaver returns the DDLSaver interface backed by this database.
func (*Database) GetFileName ¶
GetFileName returns the database file name
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 ¶
ListTableNames lists names of all tables in the database
func (*Database) PrepareStatement ¶
PrepareStatement parses and caches a SQL statement, returning the parsed Statement.
func (*Database) PrepareStatements ¶
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 ¶
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 ¶
Vacuum compacts the database file by copying all live data into a fresh file, then atomically replacing the original. The algorithm is:
- Create a temporary database file with its own pager.
- Acquire the exclusive database write lock, blocking all concurrent reads and writes for the duration.
- Recreate every table schema (tables first, indexes second) in the temp DB.
- Copy every row from the live DB into the temp DB.
- Flush and close both the temp DB and the live DB.
- Safe atomic file swap: a. Rename live → live.bak b. Rename temp → live (on failure, restore live from live.bak) c. Remove live.bak
- 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 ...
Direction constants define the sort order for ORDER BY clauses.
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
Columns returns all column names referenced by this expression.
func (*Expr) Eval ¶ added in v0.4.0
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.
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
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.
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.
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]) FindRowIDs ¶
FindRowIDs ...
func (*Index[T]) ScanAll ¶
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]) SeekLastKey ¶
SeekLastKey returns the largest key in the index, used for autoincrement primary keys.
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 (*IndexCell[T]) ReplaceRowID ¶
ReplaceRowID ...
type IndexCursor ¶
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 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 ¶
NewIndexNode creates a new IndexNode with the given uniqueness flag and optional initial cells.
func NewRootIndexNode ¶
NewRootIndexNode ...
func (*IndexNode[T]) AppendCells ¶
AppendCells ...
func (*IndexNode[T]) AtLeastHalfFull ¶
AtLeastHalfFull ...
func (*IndexNode[T]) AvailableSpace ¶
AvailableSpace ...
func (*IndexNode[T]) Child ¶
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]) DeleteKeyAndRightChild ¶
DeleteKeyAndRightChild removes the key at idx plus the right child pointer from the index node.
func (*IndexNode[T]) GetRightChildByIndex ¶
GetRightChildByIndex ...
func (*IndexNode[T]) HasSpaceForKey ¶
HasSpaceForKey ...
func (*IndexNode[T]) PrependCell ¶
PrependCell ...
func (*IndexNode[T]) RemoveLastCell ¶
RemoveLastCell ...
func (*IndexNode[T]) RowIDs ¶
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]) SplitInHalves ¶
SplitInHalves ...
type IndexNodeHeader ¶
type IndexNodeHeader struct {
IsRoot bool
IsLeaf bool
Parent PageIndex
Keys uint32
RightChild PageIndex
}
IndexNodeHeader ...
type IndexOverflowPage ¶
type IndexOverflowPage struct {
Header IndexOverflowPageHeader
RowIDs []RowID
}
IndexOverflowPage ...
func (*IndexOverflowPage) Marshal ¶
func (h *IndexOverflowPage) Marshal(buf []byte) error
Marshal ...
func (*IndexOverflowPage) RemoveLastRowID ¶
func (h *IndexOverflowPage) RemoveLastRowID() RowID
RemoveLastRowID ...
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 ...
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
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 (*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) 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) 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) MoreThanHalfFull ¶
func (n *InternalNode) MoreThanHalfFull(maxIcells int) bool
MoreThanHalfFull ...
type InternalNodeHeader ¶
InternalNodeHeader ...
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
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".
type Iterator ¶
type Iterator struct {
// contains filtered or unexported fields
}
Iterator ...
func NewIterator ¶
NewIterator ...
type Join ¶
type Join struct {
Type JoinType
TableName string
TableAlias string
Conditions Conditions
Joins []Join
}
Join ...
type JoinColumnPair ¶
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 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 (*LeafNode) Clone ¶
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) HasSpaceForRow ¶
HasSpaceForRow ...
func (*LeafNode) PrepareModifyCell ¶
PrepareModifyCell ensures the cell at idx is copy-on-write safe before modification.
type LeafNodeHeader ¶
LeafNodeHeader ...
type LogicOp ¶
type LogicOp int
LogicOp represents a boolean logic operator (AND or OR) used in a ConditionNode.
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) LastCondition ¶
LastCondition returns the last condition in the last group, if any.
func (OneOrMore) UpdateLast ¶
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.
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 )
type OverflowPage ¶
type OverflowPage struct {
Header OverflowPageHeader
Data []byte
}
OverflowPage ...
type OverflowPageHeader ¶
type OverflowPageHeader struct {
NextPage PageIndex // 0 if last page
DataSize uint32 // Actual data size in this page
}
OverflowPageHeader ...
type Page ¶
type Page struct {
Index PageIndex
OverflowPage *OverflowPage
FreePage *FreePage
InternalNode *InternalNode
LeafNode *LeafNode
IndexNode any
IndexOverflowNode *IndexOverflowPage
}
Page ...
type PageSaver ¶
type PageSaver interface {
SavePage(context.Context, PageIndex, *Page)
SaveHeader(context.Context, DatabaseHeader)
SetWALIndex(*WALIndex)
Flusher
}
PageSaver ...
type PageUnmarshaler ¶
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 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
type RangeBound ¶
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 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 ¶
CheckOneOrMore checks whether row satisfies one or more sets of conditions (cond1 AND cond2) OR (cond3 and cond4) ... etc
func (Row) GetValuesForColumns ¶
func (r Row) GetValuesForColumns(columns []Column) ([]OptionalValue, bool)
GetValuesForColumns ...
func (Row) NullBitmask ¶
NullBitmask returns a bitmask representing which columns are NULL
func (Row) SetValue ¶
func (r Row) SetValue(name string, value OptionalValue) (Row, bool)
SetValue returns true if value has changed
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 ...
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.
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 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 ¶
BindArguments ...
func (Statement) ColumnByName ¶
ColumnByName ...
func (Statement) InsertValuesForColumns ¶
func (s Statement) InsertValuesForColumns(insertIdx int, columns ...Column) []OptionalValue
InsertValuesForColumns ...
func (Statement) IsSelectAggregate ¶
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) IsSelectGroupBy ¶
IsSelectGroupBy returns true when the SELECT has a GROUP BY clause.
func (Statement) NumPlaceholders ¶
NumPlaceholders returns the number of placeholder parameters (?) in the statement.
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 ¶
StatementResult ...
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) ColumnByName ¶
ColumnByName ...
func (*Table) DeleteKey ¶
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) HasIndexOnColumn ¶
HasIndexOnColumn ...
func (*Table) HasIndexOnColumns ¶
HasIndexOnColumns ...
func (*Table) IndexByName ¶
func (t *Table) IndexByName(name string) (BTreeIndex, bool)
IndexByName ...
func (*Table) IndexColumnsByIndexName ¶
IndexColumnsByIndexName ...
func (*Table) IndexInfoByColumnName ¶
IndexInfoByColumnName ...
func (*Table) IndexInfoByColumns ¶
IndexInfoByColumns looks up an index whose columns (in order) exactly match the given slice.
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 ¶
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 ¶
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 ¶
RemoveSecondaryIndex ...
func (*Table) Seek ¶
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) SeekNextRowID ¶
SeekNextRowID returns cursor pointing at the position after the last row ID plus a new row ID to insert
func (*Table) SetSecondaryIndex ¶
func (t *Table) SetSecondaryIndex(name string, columns []Column, index BTreeIndex)
SetSecondaryIndex ...
type TableOption ¶
type TableOption func(*Table)
TableOption ...
func WithSecondaryIndex ¶
func WithSecondaryIndex(index SecondaryIndex) TableOption
WithSecondaryIndex ...
type TableProvider ¶
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 (*TextPointer) Marshal ¶
func (tp *TextPointer) Marshal(buf []byte, i uint64) error
Marshal ...
func (TextPointer) String ¶
func (tp TextPointer) String() string
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 ¶
FromMicroseconds constructs a Time from microseconds since 2000-01-01 00:00:00 UTC.
func MustParseTimestamp ¶
MustParseTimestamp parses a timestamp string and panics on error.
func ParseTimestamp ¶
ParseTimestamp parses a PostgreSQL-style timestamp string into a Time value.
func (Time) AddInterval ¶ added in v0.11.0
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) TotalMicroseconds ¶
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):
- Write every unique page in the WAL to its correct offset in dbFile.
- fsync dbFile.
- Truncate the WAL file and write fresh salts (invalidates stale frames).
- 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 ¶
ModifyPage returns a writable copy of the page at pageIdx, creating one if it doesn't exist in the write set.
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 ¶
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 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
CreateWAL creates a new WAL file (truncating any existing file at that path).
func OpenWAL ¶ added in v0.12.0
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
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
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
Close closes the underlying WAL file handle without removing it.
func (*WAL) Delete ¶ added in v0.12.0
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
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.
type WALConfig ¶ added in v0.12.0
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:
- Created empty at database open via NewWALIndex.
- Populated from the WAL file via Rebuild when a non-empty WAL is found.
- Updated after each successful AppendTransaction via Update.
- 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
Has reports whether pageIdx has a committed WAL entry in the index.
func (*WALIndex) Lookup ¶ added in v0.12.0
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
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
Size returns the number of unique page indices currently in the index.
type WALPage ¶ added in v0.12.0
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
WALReadFrame is a single validated, committed frame returned by ReadAllFrames.
Source Files
¶
- analyze.go
- compare.go
- composite_key.go
- condition.go
- condition_node.go
- config.go
- covering_index.go
- cursor.go
- database.go
- database_options.go
- database_schema.go
- delete.go
- expr.go
- free_page.go
- header.go
- index.go
- index_cursor.go
- index_node.go
- index_overflow.go
- index_pager.go
- index_scan.go
- insert.go
- integrity_check.go
- internal_node.go
- interval.go
- leaf_node.go
- like.go
- minisql.go
- node.go
- overflow_page.go
- page.go
- pager.go
- pager_factory.go
- ports.go
- pragma.go
- query_plan.go
- query_plan_join.go
- query_plan_order.go
- query_plan_stats.go
- row.go
- row_heap.go
- select.go
- sort.go
- stmt.go
- stmt_join.go
- stmt_result.go
- sync_file.go
- table.go
- table_pager.go
- table_primary_key.go
- table_secondary_index.go
- table_unique_index.go
- text_pointer.go
- timestamp.go
- transaction.go
- transaction_manager.go
- transaction_pager.go
- update.go
- vacuum.go
- wal.go
- wal_index.go