MVP+9: Initial SQL Layer - Implementation Plan
Status: Completed baseline. Focused SQL/CLI tests, workspace tests, and workspace Clippy pass. Deferred SQL scope requires separate evidence or a follow-up plan. Target MVP: MVP+9 (Stage 5 query layer) Depends on: MVP+0 through MVP+8 complete and tested Primary references: docs/Specifications/Tosumu Software Design Document.md Stage 5, docs/Specifications/Tosumu Software Design Document.md query-layer notes, current PageStore and CLI surfaces
1. Executive Summary
This plan is intentionally narrower than a "small database with SQL" rewrite.
The goal of MVP+9 is to prove three things:
- A SQL surface can sit above the existing storage engine without violating layer boundaries.
- Parsing, semantic checking, planning, and execution can be kept separate.
- Prepared statements and planner output can exist without teaching
tosumu-coreabout SQL concepts.
The baseline implementation should target the current stable storage boundary: PageStore.
It should not reach into Pager directly, should not use debug-only traversal as the canonical query path, and should not assume new on-disk reserved pages unless the format and core APIs are changed first.
Recommended baseline:
- New crate:
tosumu-sql - Executor over
tosumu_core::page_store::PageStore - Catalog stored in a reserved key namespace inside the existing KV surface
- Supported statements:
CREATE TABLE,INSERT,SELECT ... WHERE pk = ? - Prepared statements supported
- Planner implemented, but only for shapes the baseline can actually execute safely
- CLI entrypoint:
tosumu sql
Deferred from the baseline:
- physical reserved catalog page
- per-table root pages
- direct
BTreeorPagermanipulation from the SQL layer - arbitrary
WHEREpredicates - full-table scan execution as the canonical SQL path
tosumu audit- joins, aggregates, secondary indexes, MVCC,
VACUUM
1.1 Implementation Checklist
Legend: [x] complete, [ ] remaining or intentionally deferred.
Use this as the default execution order. Do not skip ahead unless a prior item is complete or explicitly blocked.
Before writing code
- [x] Re-read
docs/Specifications/Tosumu Software Design Document.mdStage 5 and this plan before starting implementation work. - [x] Confirm the namespace-backed baseline is still the intended model.
- [x] Record the task objective and starting assumptions in this plan.
Phase 1: crate scaffold
- [x] Add
crates/tosumu-sql/to the workspace. - [x] Create
lib.rs,ast.rs,value.rs, anderror.rs. - [x] Add the smallest compiling public API skeleton first.
- [x] Run focused crate tests during implementation.
Phase 2: parser pipeline
- [x] Implement the lexer (17 tests).
- [x] Implement the parser for baseline grammar only.
- [x] Add unit tests for supported statements.
- [x] Add rejection tests for unsupported grammar.
- [x] Re-run narrow validation before moving on.
Phase 3: catalog and row encoding
- [x] Implement reserved SQL key helpers.
- [x] Implement catalog serialization/deserialization.
- [x] Implement row key and row payload codecs.
- [x] Add round-trip tests for catalog and row codecs.
- [x] Re-run narrow validation before moving on.
Phase 4: semantic checker and planner ✅ COMPLETE
- [x] Implement semantic validation for
CREATE TABLE,INSERT, andSELECT ... WHERE pk = ?. - [x] Implement the minimal planner for supported query shapes only.
- [x] Return
UnsupportedQueryShapefor unsupported plans rather than inventing scan behavior. - [x] Re-run narrow validation before moving on.
Phase 5: executor over PageStore ✅ COMPLETE
- [x] Implement execution over
PageStoreonly. - [x] Use
PageStore::transaction(...)where multi-step mutation needs atomicity. - [x] Do not call
Pagerdirectly. - [x] Do not use
scan_physical()as the SQL query path. - [x] Add integration tests for
CREATE TABLE -> INSERT -> SELECT ... WHERE pk = ?. - [x] Re-run narrow validation before moving on.
Phase 6: prepared statements and CLI ✅ COMPLETE
- [x] Implement
prepare()without holding a long-lived mutable DB borrow. - [x] Implement
execute_prepared()with bound values passed at execution time. - [x] Add
tosumu sqltotosumu-cli. - [x] Add CLI tests for parsing, rendering, success, and unsupported-query failures.
- [x] Add
tosumu sql --explainwithout executing the statement. - [x] Run
cargo clippy --workspace --all-targets -- -D warnings. - [x] Complete a fresh
cargo test --workspacerun without stopping the slow core tests.
Phase 7: MVP+9 follow-ons ✅ COMPLETE
- [x] Support
DELETE ... WHERE pk = ?. - [x] Support primary-key literal lookups.
- [x] Surface
SELECT *warnings. - [x] Add
--explainplan output. - [x] Add lexer/parser property tests for arbitrary UTF-8 input.
Stop and escalate if any of these become necessary
- [ ] Adding a reserved physical catalog page
- [ ] Adding per-table root pages
- [ ] Adding direct
PagerorBTreeinternal dependencies totosumu-sql - [ ] Adding general full-table scan support to make unsupported SQL "work"
- [ ] Pulling Stage 6 or Stage 7 ideas into MVP+9 baseline
Before yielding incomplete work
- [x] Record findings, decisions, files touched, validations, blockers, and the next step in this plan.
- [x] Note whether the current state is safe to resume from or needs cleanup first.
2. Non-Negotiable Constraints
These constraints exist to keep the SQL layer compatible with both the current codebase and the design principles.
2.1 Layering
Required dependency direction:
The SQL layer must not depend on CLI, TUI, or WPF-specific code.
2.2 Storage boundary
The MVP+9 executor should use PageStore as its storage boundary.
Do not:
- call
Pagerdirectly fromtosumu-sql - depend on
BTreecrate-private transaction internals - treat
scan_physical()as the canonical SQL row scan path
Reason:
PageStoreis the current high-level public owner of put/get/delete/scan/transaction behavior.scan_physical()is explicitly documented as a debugging and verification surface, not a relational execution primitive.
2.3 MVP discipline
Do not widen MVP+9 with Stage 6 or Stage 7 ideas.
Specifically out of scope for the baseline:
- service or daemon work
- witness, freshness-anchor, or network-aware SQL features
- optimizer work beyond a tiny plan classifier
- statistics, histograms, or
ANALYZE - schema migrations beyond what is required for the first SQL catalog entries
2.4 No fake format stories
Do not claim a reserved page, separate root page, or multiple logical table roots unless the plan also includes the core and format work required to make that true.
The current engine has one root page per store. Any plan that assumes more than that must either:
- add a core prerequisite phase first, or
- use the current single-tree KV surface honestly.
This document recommends option 2 for MVP+9 baseline.
3. Current Codebase Facts That Shape The Plan
These facts are important because they determine what is realistic without a core refactor.
3.1 Stable current boundary: PageStore
PageStore already exposes:
putgetdeletescanscan_rangetransaction
That makes it the correct substrate for a first SQL layer.
3.2 Current root-page model
Today a new BTree allocates a root page and stores that root in pager metadata.
There is no public API for "open a different logical table tree by root page" from the SQL layer.
Implication:
- a per-table root-page design is not a free add-on
- it requires explicit core and format work before SQL executor coding starts
3.3 Current query-layer intent in DESIGN
The design already expects:
- SQL string -> lexer -> parser -> AST -> semantic checker -> planner -> executor
- prepared statements based on AST nodes with
Parameter(usize) - planner output before execution
The revised plan preserves that shape.
4. Selected MVP+9 Storage Model
4.1 Selected baseline: namespace-backed catalog and rows
For MVP+9 baseline, store SQL metadata and row data inside the existing KV tree through reserved key prefixes.
This avoids inventing a new root-page model before the query layer exists.
Recommended reserved namespaces:
__sql_catalog__/table/<table_name> -> serialized TableDef
__sql_catalog__/meta/version -> catalog format version
__sql_row__/<table_name>/<encoded_pk> -> serialized row payload
Properties:
- no new page types
- no special reserved physical page
- no new public core API required for multiple roots
- easy to inspect using existing KV and debug tooling
- easy to migrate later if the project introduces dedicated table roots
4.2 Why this is the recommended baseline
This approach matches the current engine better because:
- the current engine already stores opaque key-value pairs well
- table namespacing can be expressed at the SQL layer
- catalog access can be implemented entirely through
PageStore - it keeps
tosumu-corefree of SQL semantics during the first implementation
4.3 What this baseline does not claim
This baseline does not claim:
- one B+ tree per table
- a dedicated system catalog page
- direct root-page ownership by SQL tables
If the project wants those properties, that should be a separate prerequisite phase before SQL executor work begins.
4.4 Future-compatible catalog payload
Even though the baseline uses one KV tree, the catalog payload can still include optional future-facing fields such as root_page.
Recommended rule:
- baseline implementation stores
root_page: None - future multi-root implementation may populate it
That keeps the catalog shape forward-compatible without lying about current storage behavior.
5. Scope
5.1 Baseline in scope
- new
tosumu-sqlcrate - SQL lexer
- SQL parser
- AST types
- semantic checker
- small planner
- executor over
PageStore - prepared statements
CREATE TABLEINSERTSELECT ... WHERE pk = ?- CLI subcommand:
tosumu sql
5.2 Follow-ons implemented inside MVP+9
DELETE ... WHERE pk = ?SELECT ... WHERE pk = <literal>in addition to bound parameters--explainoutput for the SQL command
5.3 Explicitly out of scope for baseline
- arbitrary predicates over non-PK columns without a PK point lookup
- arbitrary boolean combinations,
LIKE, andIN - full table scans as a user-visible success path
- joins
- aggregates
- secondary indexes
- catalog-on-reserved-page format work
tosumu audit- JSON audit output
- planner row-count estimates derived from page counts
5.4 Error policy for unsupported SQL
Unsupported queries should fail explicitly with a stable SQL-layer error.
Do not silently degrade unsupported shapes into whole-database scans.
Examples that should return UnsupportedQueryShape in baseline:
SELECT * FROM userswithout a required primary-key equality predicateSELECT * FROM users WHERE email = ?SELECT * FROM users WHERE id = ? OR name = ?SELECT * FROM users WHERE id = ? AND name = ? OR email = ?DELETE FROM users
6. Crate Structure
crates/
├── tosumu-core/
├── tosumu-cli/
└── tosumu-sql/
├── Cargo.toml
└── src/
├── lib.rs
├── ast.rs
├── lexer.rs
├── parser.rs
├── semantic.rs
├── planner.rs
├── executor.rs
├── catalog.rs
├── row_codec.rs
├── value.rs
└── error.rs
Module responsibilities:
ast.rs: statement and expression typeslexer.rs: SQL tokenizerparser.rs: recursive descent parsersemantic.rs: schema-aware validationplanner.rs: classify supported vs unsupported query shapesexecutor.rs: execute plans throughPageStorecatalog.rs: catalog key encoding, schema storage, lookuprow_codec.rs: row serialization and projection decodingvalue.rs: SQL value representation and coercion helperserror.rs: SQL-layer error type with structured mapping into core errorslib.rs: public API surface
7. Public API Shape
The public API should avoid long-lived mutable borrows held inside prepared statements.
Recommended shape:
pub struct SqlDatabase {
store: tosumu_core::page_store::PageStore,
}
pub struct PreparedStatement {
stmt: Stmt,
parameter_count: usize,
}
pub enum QueryResult {
Rows {
columns: Vec<String>,
rows: Vec<Vec<Value>>,
},
Affected {
rows: usize,
},
}
pub struct ExecutionOutcome {
pub result: QueryResult,
pub warnings: Vec<PlanWarning>,
}
impl SqlDatabase {
pub fn open(path: &Path) -> Result<Self, SqlError>;
pub fn prepare(&self, sql: &str) -> Result<PreparedStatement, SqlError>;
pub fn execute_prepared(
&mut self,
stmt: &PreparedStatement,
bindings: &[Value],
) -> Result<ExecutionOutcome, SqlError>;
pub fn execute(&mut self, sql: &str) -> Result<ExecutionOutcome, SqlError>;
}
Why this shape:
prepare(&self)can parse and count parameters without borrowing the database mutably- statement reuse does not pin a mutable database borrow
- semantic checking and planning can still run at execute time against the current catalog
8. SQL Surface For Baseline
8.1 Supported statements
Baseline statement set:
CREATE TABLE <ident> (
<pk_name> INTEGER|TEXT|BLOB PRIMARY KEY,
<col_name> INTEGER|TEXT|BLOB,
...
)
INSERT INTO <ident> VALUES (...)
SELECT <projection> FROM <ident> WHERE <pk_name> = ?
SELECT <projection> FROM <ident> WHERE <pk_name> = <literal>
Recommended baseline restriction:
- exactly one primary key column
- no implicit rowid
- no null primary key
- no expression evaluation beyond literal and parameter substitution
projectionmay be*or an explicit column list, but only for primary-key equality lookups
8.2 AST shape
Keep the AST narrower than the previous draft.
Recommended baseline AST:
pub enum Stmt {
CreateTable {
name: String,
columns: Vec<ColumnDef>,
},
Insert {
table: String,
values: Vec<Expr>,
},
Select {
table: String,
columns: Projection,
predicate: Option<Expr>,
},
Delete {
table: String,
predicate: Option<Expr>,
},
}
pub enum Projection {
All,
Named(Vec<String>),
}
pub enum Expr {
Literal(Value),
Column(String),
Eq(Box<Expr>, Box<Expr>),
Parameter(usize),
}
Important note:
Deletemay exist in the AST now for forward compatibility- baseline execution support for
Deleteis optional and should come after create/insert/select are stable - do not implement arbitrary boolean expressions or scan-based predicates in baseline
8.3 Parser grammar
Keep the grammar deliberately tiny:
Stmt -> CreateTable | Insert | Select | Delete
CreateTable -> CREATE TABLE ident '(' ColumnDef (',' ColumnDef)* ')'
ColumnDef -> ident TypeName ('PRIMARY' 'KEY')?
TypeName -> INTEGER | TEXT | BLOB
Insert -> INSERT INTO ident VALUES '(' Expr (',' Expr)* ')'
Select -> SELECT Projection FROM ident WHERE EqExpr
Delete -> DELETE FROM ident WHERE EqExpr
Projection -> '*' | ident (',' ident)*
EqExpr -> Operand '=' Operand
Operand -> Literal | ident | '?'
Parser rules:
- accept only single-statement input
- optional trailing semicolon is fine
- reject unsupported grammar early instead of producing a huge AST for later rejection
9. Catalog Model
9.1 Catalog keys
Recommended keys:
9.2 Catalog value
Recommended TableDef payload:
pub struct TableDef {
pub name: String,
pub columns: Vec<ColumnDef>,
pub primary_key_index: usize,
pub root_page: Option<u64>,
}
root_page remains None in the baseline single-tree implementation.
9.3 Catalog serialization
Use a small explicit binary format owned by tosumu-sql.
Do not introduce serde as a dependency for MVP+9 unless there is a compelling reason.
Recommended wire shape:
[version: u8]
[table_name_len: u16][table_name bytes]
[column_count: u16]
[pk_index: u16]
[root_page_present: u8]
[root_page: u64 if present]
repeat column_count times:
[name_len: u16][name bytes]
[type_tag: u8]
[is_primary_key: u8]
9.4 Catalog lifecycle
CREATE TABLEchecks for existing catalog entry- on success it writes one catalog record through
PageStore::put - no separate catalog bootstrap page is needed
- if no
__sql_catalog__/meta/versionkey exists, initialize it lazily on first SQL write
10. Row Encoding Model
10.1 Row keys
Recommended key format:
This keeps SQL rows out of the user-facing raw KV namespace while still using the existing storage engine honestly.
10.2 Row values
Store non-key column values in a compact binary row payload.
Recommended baseline row format:
[version: u8]
[column_count: u16]
repeat column_count times:
[type_tag: u8]
[payload_len: u32]
[payload bytes]
The primary key may be duplicated in the row payload for simplicity in MVP+9. That is acceptable for the first implementation because clarity beats space efficiency here.
In the namespace-backed MVP+9 baseline, inserting an existing primary key overwrites
the stored row because PageStore::put has upsert semantics. This behavior is explicit
and covered by an integration test; uniqueness-enforcement changes are deferred.
10.3 Value types
Baseline SQL types:
INTEGERTEXTBLOB
Defer REAL and NULL unless the team explicitly wants them in the first cut.
Reason:
REALadds coercion and comparison edge casesNULLforces early three-valued logic questions- neither is required to prove the parser/planner/executor pipeline
11. Semantic Checking
The semantic checker should validate everything it can before any storage mutation starts.
Recommended checks:
11.1 CREATE TABLE
- table name is not empty
- table name does not use reserved SQL namespaces
- column names are unique
- exactly one primary key exists
- column types are supported in baseline
11.2 INSERT
- table exists
- value count matches column count
- primary key value is present and type-correct
- no parameter remains unbound at execution time
11.3 SELECT
- table exists
- projected columns exist
- predicate shape is exactly
pk_column = <literal|parameter> SELECT *is allowed only when that primary-key equality predicate is present
11.4 DELETE
- same predicate restrictions as baseline
SELECT - only enable once delete execution support is explicitly turned on
Recommended SQL errors:
TableNotFoundColumnNotFoundDuplicateColumnMissingPrimaryKeyUnsupportedTypeUnsupportedQueryShapeBindingCountMismatchTypeMismatch
12. Planner
12.1 Baseline planner scope
The baseline planner should classify only the shapes the executor can actually run.
Recommended plan enum:
pub enum PlanNode {
CreateTable { table: String },
InsertRow { table: String, pk: Value },
PkLookup { table: String, pk: Value, projection: Projection },
DeleteByPk { table: String, pk: Value },
}
Recommended warning enum:
12.2 Important baseline rule
If the planner cannot produce one of the plan nodes above, it should return UnsupportedQueryShape.
Do not manufacture FullScan as a success path yet.
12.3 Why full scans are deferred
The earlier draft proposed full scans based on scan_physical() and estimated row counts from page counts.
That should be removed from the baseline because:
scan_physical()is a debug/verification traversal, not a canonical query primitivepage_count * constantis not a trustworthy row estimate for SQL planning- a "successful" full scan path would broaden MVP+9 considerably
If a logical SQL scan path is added later, it should be designed explicitly, not inherited accidentally from a debug API.
13. Executor
13.1 Baseline executor boundary
The executor owns:
- catalog lookup
- row-key encoding
- row-value serialization and decoding
- projection shaping
- mapping SQL errors to structured results
It should call PageStore methods only.
13.2 Execution strategies
| Plan | Execution |
|---|---|
CreateTable |
Write catalog entry through PageStore::put |
InsertRow |
Encode row key + row payload, then PageStore::put |
PkLookup |
Encode row key, PageStore::get, decode row, project columns |
DeleteByPk |
Encode row key, PageStore::delete |
13.3 Transaction use
Use PageStore::transaction(...) for multi-step mutations where needed.
Examples:
CREATE TABLEmay need to initialize catalog version and table entry atomicallyINSERTmay eventually want to maintain row count metadata atomically
If row-count bookkeeping is not implemented in baseline, keep mutations even simpler.
13.4 What the executor must not do
- inspect page headers directly
- call
Pager::allocate - call
BTreecrate-private transaction helpers - reserve physical page 1
14. Prepared Statements
14.1 Preparation model
prepare() should:
- lex and parse SQL
- count
?parameters - store the AST
It should not require a mutable database borrow.
14.2 Execution model
execute_prepared() should:
- validate binding count
- substitute parameter values into a transient bound AST or evaluation context
- run semantic checking against the current catalog
- plan
- execute
14.3 Binding rules
Recommended baseline:
- positional parameters only
- 1-based binding index at API edge if that is more SQL-like, or 0-based if consistency with Rust APIs is preferred
- document the choice explicitly and test it
Do not keep mutable binding state inside a database-borrowing statement object unless there is a strong reason to do so.
15. CLI Integration
15.1 Baseline CLI command
Add a new subcommand to tosumu-cli:
Recommended follow-on flag:
15.2 Baseline CLI output
For successful PK lookup:
For unsupported query shape:
$ tosumu sql db.tsm "SELECT * FROM users"
error[SQL_UNSUPPORTED_QUERY_SHAPE]: baseline SQL supports only primary-key equality lookups
15.3 No audit command in baseline
Do not add tosumu audit in MVP+9 baseline.
Reason:
- it is a separate diagnostics product surface
- it broadens scope beyond the query pipeline
- existing inspect/verify tooling already owns the low-level diagnostic story
If audit work is desired later, it should become its own milestone and design section.
16. Implementation Phases
Phase 0: Design sync for the selected model
Do this before writing code.
- Update the nearest design notes so the docs do not keep promising a reserved catalog page for the first implementation.
- Keep the namespace-backed baseline as the default unless the user explicitly reopens the storage-model decision.
- If a future task reopens the question and prefers per-table roots, stop and write a core prerequisite plan before coding the SQL executor.
Gate: no coding until the design-doc sync for the selected namespace-backed model is landed.
Phase 1: Crate skeleton and AST
- create
crates/tosumu-sql - add
lib.rs,ast.rs,value.rs,error.rs - define baseline statement, expression, projection, and value types
- add unit tests for AST helpers and parameter counting
Phase 2: Lexer and parser
- implement tokenizer
- implement parser for baseline grammar only
- reject multi-statement input and unsupported syntax early
- add unit tests for happy-path and rejection-path parsing
- add property tests that valid baseline inputs tokenize and parse without panic
Phase 3: Catalog and row codec
- implement catalog key helpers
- implement catalog serialization and deserialization
- implement row key encoding
- implement row payload encoding and decoding
- add unit tests for round-trip encoding
Phase 4: Semantic checker and planner
- implement schema validation
- implement query-shape validation
- implement narrow planner for supported plans only
- add tests for each supported and rejected statement shape
Phase 5: Executor over PageStore
- implement
SqlDatabase - implement
execute()andexecute_prepared() - use
PageStoreonly - add integration tests for create/insert/select-by-pk round-trip
Phase 6: CLI integration
- add
sqlsubcommand totosumu-cli - render row output and structured errors cleanly
- add CLI tests for supported and unsupported SQL
Phase 8: Post-MVP+9 SQL surface
- [x] Add broader explicit projection coverage and documentation.
- [x] Add constrained richer predicates (
AND,OR, comparison operators). - [ ] Decide whether logical scan support belongs before or after MVP+10.
The predicate extension supports pk = value AND column = value point lookups
(with the primary-key equality first), including != and ordered residual
comparisons (<, <=, >, >=) over same-type INTEGER, TEXT, or BLOB values.
It also supports pk = value OR pk = value as a multi-point lookup, preserving
term order and avoiding duplicate rows. Arbitrary OR expressions remain deferred.
17. Testing Strategy
17.1 Unit tests
- [x] lexer tokenization of keywords, identifiers, literals, punctuation, and
? - [x] parser success cases for create/insert/select-by-pk
- [x] parser rejection for unsupported grammar
- [x] catalog serialization round-trip
- [x] row codec round-trip
- [x] semantic checker success and failure paths
- [x] planner classification success and failure paths
17.2 Property tests
- [x] lexer/parser never panic on arbitrary UTF-8 inputs
- [x] catalog and row codecs round-trip for generated values within supported type bounds
- [x] prepared statement parameter counting matches bound placeholders
17.3 Integration tests
- [x]
CREATE TABLEthenINSERTthenSELECT ... WHERE pk = ? - [x] prepared statement reuse across multiple bindings
- [x] duplicate table creation rejected
- [x] duplicate PK overwrite semantics match the documented baseline upsert policy
- [x] unsupported full-scan query rejected with the expected SQL error
- [x] PK
ORmulti-point SELECT and DELETE preserve term order and deduplicate keys
17.4 CLI tests
- [x]
tosumu sqlparses and executes a baseline point lookup - [x] unsupported shape maps to a stable boundary error
- [x] explain mode prints the plan before execution, without mutating the database
17.5 Validation commands
Required validation once implementation begins:
cargo test -p tosumu-sql
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
18. Acceptance Criteria
Baseline MVP+9 progress:
- [x]
tosumu-sqlexists as a separate crate with no CLI/TUI dependencies. - [x]
CREATE TABLE,INSERT, andSELECT ... WHERE pk = ?work through the SQL surface. - [x] Prepared statements work without holding a long-lived mutable database borrow.
- [x] The executor uses
PageStore, notPager, and notscan_physical()as its SQL execution path. - [x] Unsupported query shapes fail explicitly instead of silently degrading to scans.
- [x]
cargo test -p tosumu-sqlpasses (117unit tests plus 1 doc test at last validation). - [x]
cargo test --workspacecompletes successfully in the current branch. - [x]
cargo clippy --workspace --all-targets -- -D warningspasses. - [x] The namespace-backed catalog design is documented and implemented.
19. Known Follow-On Work After MVP+9
These are not baseline tasks.
19.1 Table-aware storage refactor
If the project still wants per-table root pages and a physical system catalog page, that should be a dedicated follow-on design and core milestone.
That work would likely require:
- format updates
- core APIs for opening or owning multiple logical trees
- migration strategy for namespace-backed SQL rows, if baseline ships first
19.2 Logical scan support
If full-table scans become desirable later, they should use an explicit logical row traversal owned by a stable storage boundary.
Do not promote scan_physical() into that role by accident.
19.3 Richer SQL
Only after the constrained baseline is stable:
- secondary indexes
- arbitrary non-PK predicates and logical scans
- joins
- aggregates
- statistics and estimates
20. Open Questions
These should be resolved explicitly, not by code drift.
- ~~Should baseline SQL support
DELETE ... WHERE pk = ?, or should delete wait until after create/insert/select are stable?~~ → Resolved: DELETE is in the AST and parser; execution can follow in Phase 5. - ~~Should the baseline include
TEXTandBLOBimmediately, or landINTEGERfirst and add the others once the pipeline is proven?~~ → Resolved: All three types (INTEGER, TEXT, BLOB) are supported from the start. - ~~Should
SELECT *be supported in the baseline, or should projections require explicit column names until row decoding is settled?~~ → Resolved:SELECT *is supported; projections require explicit column names only when that makes sense for the executor.
21. Current Implementation Status (updated 2026-08-03)
Completed
All baseline MVP+9 implementation phases and repository-level validation are complete.
Implementation summary:
- Phase 1: Crate scaffold — complete.
- Phase 2: Lexer/parser baseline grammar — complete, including arbitrary-input property tests.
- Phase 3: Catalog and row codecs — complete with round-trip tests.
- Phase 4: Semantic checker and planner — complete with schema-aware validation.
- Phase 5: Executor over PageStore — complete for create, insert, select, and delete.
- Phase 6: Prepared statements and CLI — complete, including structured errors and result rendering.
- Phase 7: MVP+9 follow-ons — complete, including literal PK lookup, SELECT * warnings, and --explain.
- Phase 8: Constrained predicates — complete for PK-plus-residual filters and PK OR multi-point lookups.
Latest focused validation:
| Crate | Tests | Status |
|-------|-------|--------|
| tosumu-cli | 95 unit + 1 integration | ✅ |
| tosumu-sql | 117 unit + 1 doc test | ✅ |
| tosumu-core | 175 passed + 3 ignored | ✅ |
| Workspace Clippy | all targets | ✅ |
| Full workspace tests | passed; core suite finished in 293.94s | ✅ |
Key fixes applied during implementation:
- PRIMARY KEY lexer peek logic (byte-level indexing fix)
- Catalog root_page deserialization offset (wire-format correction)
- parse_select_or_delete double-advance bug (split into parse_select_stmt)
- Executor test DB initialization (PageStore::create for new databases)
- Added SqlDatabase::create public API method
Next Steps
The MVP+9 baseline is complete. Remaining tracked work:
- Decide whether logical scan support belongs before or after MVP+10.