Repository navigation
docs: architecture diagram, current CLI screenshot and a shorter README #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
8b49636
docs: architecture diagram, current CLI screenshot and a shorter README
hskl18 fb72626
docs: list the WHERE operators and fix the storage link in the usage …
hskl18 892e344
docs: draw the diagram's group boxes without a fill
hskl18 0540ee1
docs: correct the diagram and README points a review found
hskl18 c3aafb3
docs: tighten wording from the second review and say how the diagram …
hskl18 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,151 +1,68 @@ | ||
| # SQL in C++ | ||
|
|
||
| SQL in C++ 2.0 is an educational relational database engine and command-line DSL implemented from first principles. | ||
| It parses a focused subset of SQL, persists records in checksummed pages, maintains persistent B+ tree indexes, recovers atomic single-writer statements through a WAL, and evaluates compound filters with a shunting-yard pipeline. | ||
| A small relational database engine written from scratch in C++17. | ||
| It parses a focused subset of SQL, stores each table in checksummed 4 KB pages, keeps a B+ tree index for every field, and recovers each statement atomically after a crash through a write-ahead log. | ||
|
|
||
| I wrote the first version in 2023 while learning C++ and rebuilt the storage engine in 2026. | ||
| The [`original-2023`](https://github.com/hskl18/SQL/tree/original-2023) tag keeps the first version. | ||
|
|
||
|  | ||
|  | ||
|
|
||
| ## What it supports | ||
|
|
||
| - `CREATE TABLE` with an ordered field list. | ||
| - `INSERT INTO` with quoted or unquoted values. | ||
| - `SELECT *` and projected field lists. | ||
| - `WHERE` filters using `=`, `!=`, `<`, `<=`, `>`, and `>=`. | ||
| - Compound `AND` and `OR` expressions with parentheses. | ||
| - Checksummed paged persistence across separate CLI sessions. | ||
| - Persistent per-field B+ tree indexes. | ||
| - Crash recovery for atomic single-writer statements. | ||
| - Copy-first migration from the v1 fixed-width format. | ||
| - Batch execution from the sample command files in `batch/`. | ||
|
|
||
| This project is intentionally smaller than a production SQL database. | ||
| It does not implement joins, multi-statement transactions, schemas, query planning, updates, or deletes. | ||
| Values are stored and ordered as strings, so numeric-looking values use lexical comparison semantics. | ||
|
|
||
| ## Architecture | ||
|
|
||
| | Component | Responsibility | | ||
| | --- | --- | | ||
| | `includes/tokenizer` | Converts command text into lexical tokens with a state machine. | | ||
| | `includes/parser` | Validates the supported grammar and builds a parse tree. | | ||
| | `includes/shunting_yard` | Converts compound filter expressions to postfix form. | | ||
| | `includes/map` | Implements B+ tree-backed maps and multimaps. | | ||
| | `includes/binary_files` | Reads the legacy v1 fixed-width format. | | ||
| | `includes/storage` | Owns v2 pages, persistent indexes, checksums, WAL, and recovery. | | ||
| | `includes/table` | Owns table persistence, indexes, projections, and selections. | | ||
| | `includes/sql` | Coordinates parsing and table operations through the public `SQL` interface. | | ||
| *A session in the CLI from a local Release build, November 13, 2026.* | ||
|
|
||
| Storage invariants, query semantics, and deliberate limits are documented in [DESIGN.md](DESIGN.md). | ||
| ## Quick start | ||
|
|
||
| ## Build | ||
|
|
||
| You need a C++17 compiler and CMake 3.20 or newer. | ||
| You need a C++17 compiler and CMake 3.20 or newer; the build has no third-party dependency and downloads nothing. | ||
|
|
||
| ```bash | ||
| cmake -S . -B build -DCMAKE_BUILD_TYPE=Release | ||
| cmake --build build --parallel | ||
| ``` | ||
|
|
||
| The build has no downloaded test framework or other third-party dependency. | ||
|
|
||
| ## Test | ||
|
|
||
| ```bash | ||
| ctest --test-dir build --output-on-failure | ||
| ``` | ||
|
|
||
| The test executables verify SQL behavior, persistent incremental B+ tree splits, stable untouched pages, WAL ordering, dynamically enumerated crash boundaries, corruption rejection, idempotent recovery, migration equivalence, maximum-width rows, CLI inspection, parser safety, and both repository batch fixtures. | ||
| Tests run in an isolated build directory, so they do not leave database files in the source tree. | ||
|
|
||
| To run the tests under AddressSanitizer and UndefinedBehaviorSanitizer: | ||
|
|
||
| ```bash | ||
| cmake -S . -B build-sanitized \ | ||
| -DCMAKE_BUILD_TYPE=Debug \ | ||
| -DBUILD_TESTING=ON \ | ||
| -DSQL_ENABLE_SANITIZERS=ON \ | ||
| -DCMAKE_COMPILE_WARNING_AS_ERROR=ON | ||
| cmake --build build-sanitized --parallel | ||
| ctest --test-dir build-sanitized --output-on-failure | ||
| ``` | ||
|
|
||
| ## Run the CLI | ||
|
|
||
| ```bash | ||
| ./build/run_sql | ||
| ``` | ||
|
|
||
| Type `end` to exit and `cls` to clear the terminal. | ||
| The CLI writes each table to `<table>.sql2` and uses `<table>.sql2-wal` during a mutating statement. | ||
| It reports missing tables, invalid projections, wrong row arity, duplicate schemas, malformed filters, corrupt pages, and corrupt WAL records without terminating the session. | ||
|
|
||
| Example session: | ||
| Type `end` to exit and `cls` to clear the screen. | ||
|
|
||
| ```text | ||
| SQL>> create table student fields first, last, major, age | ||
| SQL>> insert into student values Ada, Lovelace, Math, 36 | ||
| SQL>> insert into student values Grace, Hopper, CS, 30 | ||
| SQL>> select first, major from student where major = CS | ||
| SQL>> end | ||
| ``` | ||
|
|
||
| ## Query grammar | ||
|
|
||
| ```text | ||
| create table <table> fields <field> [, <field> ...] | ||
| insert into <table> values <value> [, <value> ...] | ||
| select <* | field [, field ...]> from <table> | ||
| [where <field> <operator> <value> | ||
| [<and | or> <field> <operator> <value> ...]] | ||
| ``` | ||
|
|
||
| Quote values that contain spaces, such as `"Mary Ann"`. | ||
| Quoted values may contain spaces, numbers, and punctuation, but escaped double quotes are not supported. | ||
|
|
||
| ## Version and storage inspection | ||
|
|
||
| ```bash | ||
| ./build/run_sql --version | ||
| ./build/run_sql --inspect-storage student | ||
| ``` | ||
|
|
||
| Inspection validates checksums and structural bounds without applying or clearing a pending WAL. | ||
| ## Architecture | ||
|
|
||
| ## Migrate a v1 table | ||
| <picture> | ||
| <source media="(prefers-color-scheme: dark)" srcset="docs/architecture-dark.svg"> | ||
| <img alt="A command goes from the CLI through the tokenizer and parser to the table, which filters through the shunting-yard step and a B+ tree index per field. The storage layer keeps checksummed 4 KB pages; it writes the after-image to the WAL and syncs it, then writes the dirty pages to the table file, and opening a table recovers from a complete WAL record. The v1 migration tool copies old .bin files into the new format." src="docs/architecture-light.svg"> | ||
| </picture> | ||
|
|
||
| Inspect a legacy table without writing anything: | ||
| The table answers a `WHERE` filter from the per-field B+ tree indexes after the shunting-yard step turns the filter into postfix form. | ||
| Each statement that changes a table first writes its complete after-image to `<table>.sql2-wal` and syncs it, and only then writes the changed pages to `<table>.sql2`. | ||
| A crash before the WAL write leaves the old table, a crash after the WAL is synced recovers the new table on open, and a torn WAL record makes the open fail with a corruption error instead of guessing. | ||
|
|
||
| ```bash | ||
| ./build/sql_migrate_v1 --dry-run student | ||
| ``` | ||
| ## What it supports | ||
|
|
||
| Migrate it to `student.sql2`: | ||
| - `CREATE TABLE`, `INSERT INTO`, and `SELECT` with `*` or a field list. | ||
| - `WHERE` with `=`, `!=`, `<`, `<=`, `>`, `>=`, and `AND` and `OR` with parentheses. | ||
| - Tables that persist across CLI sessions, with page, index, and WAL corruption rejected on open. | ||
| - Batch runs from the sample command files in `batch/`. | ||
| - Copy-first migration from the 2023 fixed-width format. | ||
|
|
||
| ```bash | ||
| ./build/sql_migrate_v1 student | ||
| ``` | ||
| It has no joins, multi-statement transactions, schemas, query planning, updates, or deletes, and it has no locking, so run only one writer at a time. | ||
| Values are stored and compared as strings, so `9` sorts after `10`. | ||
|
|
||
| The migration reads the v1 `.bin` and `_fields.bin` files read-only, writes an exclusively owned temporary v2 image, reopens and compares every row, rechecks the source bytes, then atomically links the verified destination without replacement. | ||
| It never modifies or deletes the v1 source. | ||
| Use `--destination <path>` to choose another destination and note that existing destinations are rejected. | ||
| ## Tests | ||
|
|
||
| ## Persistence boundaries | ||
| The CTest suite covers SQL behavior, parser safety, B+ tree splits, stable untouched pages, WAL ordering, a crash at every traced write and fsync, corruption rejection, recovery that can run twice, v1 migration, maximum-width rows, the CLI, and both batch fixtures. | ||
| Tests run in the build directory and leave no database files in the source tree. | ||
| CI runs a Release build and the suite on Linux. | ||
|
|
||
| - Tables contain between 1 and 64 uniquely named fields. | ||
| - Identifiers contain letters, digits, and underscores and cannot start with a digit. | ||
| - Each value is at most 100 bytes, and rows may cross page boundaries. | ||
| - An insert must provide exactly one value per field. | ||
| - Values longer than 100 bytes are rejected before a write. | ||
| - Existing tables cannot be overwritten by another `CREATE TABLE` command. | ||
| - Page, index, schema, row, and WAL corruption fail closed when a table is opened. | ||
| - V1 tables can be queried read-only and must be migrated before new inserts. | ||
| - The durability scope is one process, one writer, and one atomic statement at a time. | ||
| ## Documentation | ||
|
|
||
| The exact byte layout, recovery ordering, checksums, and compatibility boundary are documented in [docs/storage-v2.md](docs/storage-v2.md). | ||
| - [Usage](docs/usage.md): the full grammar, the CLI's files and errors, storage inspection, v1 migration, limits, and the sanitizer build. | ||
| - [Design and invariants](DESIGN.md): the command path, source layout, and storage and query rules. | ||
| - [Storage format v2](docs/storage-v2.md): the byte layout, checksums, and recovery order. | ||
|
|
||
| ## License | ||
|
|
||
| This project is available under the [MIT License](LICENSE). | ||
| [MIT](LICENSE) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| flowchart TB | ||
| subgraph query["Query path"] | ||
| direction LR | ||
| CLI["run_sql CLI<br/>or batch file"] --> Parser["Tokenizer and parser<br/>state machine, parse tree"] | ||
| Parser --> Table["Table<br/>insert, select, projection"] | ||
| Table -->|"WHERE"| Filter["Shunting-yard<br/>postfix filter"] | ||
| Filter --> Index["B+ tree index<br/>one per field"] | ||
| end | ||
| subgraph storage["Storage"] | ||
| direction LR | ||
| Pages["Page buffer<br/>checksummed<br/>4 KB pages"] -->|"1. after-image, fsync"| WAL[("table.sql2-wal")] | ||
| Pages -->|"2. dirty pages"| Data[("table.sql2")] | ||
| WAL -.->|"recover on open"| Data | ||
| Legacy[("v1 .bin files")] -->|"read-only, copy-first"| Migrate["sql_migrate_v1"] | ||
| Migrate --> Data | ||
| end | ||
| query -->|"rows and index pages"| storage | ||
| %% Edit this file; the owner renders architecture-light.svg and architecture-dark.svg from it with a shared theme. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| # Using SQL in C++ | ||
|
|
||
| This page holds the details behind the [README](../README.md): the full grammar, the CLI's files and errors, storage inspection, v1 migration, persistence limits, and the sanitizer build. | ||
|
|
||
| ## Run the CLI | ||
|
|
||
| ```bash | ||
| ./build/run_sql | ||
| ``` | ||
|
|
||
| Type `end` to exit and `cls` to clear the terminal. | ||
| The CLI writes each table to `<table>.sql2` and uses `<table>.sql2-wal` during a mutating statement. | ||
| It reports missing tables, invalid projections, wrong row arity, duplicate schemas, malformed filters, corrupt pages, and corrupt WAL records without terminating the session. | ||
|
|
||
| Example session: | ||
|
|
||
| ```text | ||
| SQL>> create table student fields first, last, major, age | ||
| SQL>> insert into student values Ada, Lovelace, Math, 36 | ||
| SQL>> insert into student values Grace, Hopper, CS, 30 | ||
| SQL>> select first, major from student where major = CS | ||
| SQL>> end | ||
| ``` | ||
|
|
||
| ## Query grammar | ||
|
|
||
| ```text | ||
| create table <table> fields <field> [, <field> ...] | ||
| insert into <table> values <value> [, <value> ...] | ||
| select <* | field [, field ...]> from <table> | ||
| [where <field> <operator> <value> | ||
| [<and | or> <field> <operator> <value> ...]] | ||
| ``` | ||
|
|
||
| `<operator>` is one of `=`, `!=`, `<`, `<=`, `>`, or `>=`, and parentheses group `and` and `or` terms. | ||
|
|
||
| Quote values that contain spaces, such as `"Mary Ann"`. | ||
| Quoted values may contain spaces, numbers, and punctuation, but escaped double quotes are not supported. | ||
|
|
||
| ## Version and storage inspection | ||
|
|
||
| ```bash | ||
| ./build/run_sql --version | ||
| ./build/run_sql --inspect-storage student | ||
| ``` | ||
|
|
||
| Inspection validates checksums and structural bounds without applying or clearing a pending WAL. | ||
|
|
||
| ## Migrate a v1 table | ||
|
|
||
| Inspect a legacy table without writing anything: | ||
|
|
||
| ```bash | ||
| ./build/sql_migrate_v1 --dry-run student | ||
| ``` | ||
|
|
||
| Migrate it to `student.sql2`: | ||
|
|
||
| ```bash | ||
| ./build/sql_migrate_v1 student | ||
| ``` | ||
|
|
||
| The migration reads the v1 `.bin` and `_fields.bin` files read-only, writes an exclusively owned temporary v2 image, reopens and compares every row, rechecks the source bytes, then atomically links the verified destination without replacement. | ||
| It never modifies or deletes the v1 source. | ||
| Use `--destination <path>` to choose another destination and note that existing destinations are rejected. | ||
|
|
||
| ## Persistence boundaries | ||
|
|
||
| - Tables contain between 1 and 64 uniquely named fields. | ||
| - Identifiers contain letters, digits, and underscores and cannot start with a digit. | ||
| - Each value is at most 100 bytes, and rows may cross page boundaries. | ||
| - An insert must provide exactly one value per field. | ||
| - Values longer than 100 bytes are rejected before a write. | ||
| - Existing tables cannot be overwritten by another `CREATE TABLE` command. | ||
| - Page, index, schema, row, and WAL corruption fail closed when a table is opened. | ||
| - V1 tables can be queried read-only and must be migrated before new inserts. | ||
| - The durability scope is one process, one writer, and one atomic statement at a time. | ||
|
|
||
| The exact byte layout, recovery ordering, checksums, and compatibility boundary are documented in [storage-v2.md](storage-v2.md). | ||
|
|
||
| ## Sanitizer build | ||
|
|
||
| To run the tests under AddressSanitizer and UndefinedBehaviorSanitizer: | ||
|
|
||
| ```bash | ||
| cmake -S . -B build-sanitized \ | ||
| -DCMAKE_BUILD_TYPE=Debug \ | ||
| -DBUILD_TESTING=ON \ | ||
| -DSQL_ENABLE_SANITIZERS=ON \ | ||
| -DCMAKE_COMPILE_WARNING_AS_ERROR=ON | ||
| cmake --build build-sanitized --parallel | ||
| ctest --test-dir build-sanitized --output-on-failure | ||
| ``` | ||
Binary file not shown.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.