BQL · TachyonDB

Binary Query Language · 1‑byte opcodes · jump‑table dispatch · no string parsing
⚡ 1‑Byte Opcodes 🚫 Not Interpreted 📦 Compact vs SQL 🎯 Direct Jump Table ✅ Live Wire AUTH = FNV placeholder
Stunt Grok Jockey Tony (@tswain555 on X)
Docs curated with BML · 25 September 2026

✅ What is live today

Authoritative source: TachyonDB PROTOCOL.md. Two builds speak the same wire: tachyon8 (ARM64) and tachyond (x64). Page put/get tests are green on Snapdragon.

AreaStatusNotes
Wire framing Live Length‑prefixed frames; handshake magic TYDB; little‑endian
BQL bytecode client payload Live Raw opcodes — no SQL/JSON text on the wire
Core KV + filter ops Live GET / PUT / ALL / GT / LT / EQU / ORDER_BY / LIMIT / OFFSET / AND / OR / NOT
Stack immediates Live PUSH_I32 / PUSH_I64 / PUSH_F64 / PUSH_STR / LOAD_CONST_0..15 / POP / DUP
Schema ops Live CREATE_TYPE / DROP_TYPE / KEY / TYPE / FIELD / DELETE / COUNT
Txn fences Fence BEGIN / COMMIT / ROLLBACK are no‑op fences (single‑threaded server)
AUTH / STATUS / PING / END Live AUTH is FNV placeholder — not cryptographic (see honesty note)
Pages (URLChannel / BML bodies) Live PAGE_PUT (0x33) / PAGE_GET (0x34) as DATA_BYTE_ARRAY by path
EXT space Partial JOIN / SPLIT / REINDEX / COMPRESS / FLUSH / SHUTDOWN codes defined; FLUSH drives snapshot
Persistence Snapshot snapshot.tdb authoritative; journal is marker‑only (no rich replay yet)
Listen bind Localhost Default 127.0.0.1 — do not bind 0.0.0.0 until AUTH is cryptographic
⚠️ Honest AUTH note

Current AUTH hashes with FNV‑1a64 over salt "Tachyon!" || password. Default credentials: admin / tachyon. This is a placeholder, not a security boundary. Cryptographic AUTH (Ed25519 / AES direction already present in Channels) is roadmap item #1.

🔷 BQL is binary, not interpreted

Unlike SQL or JSON query languages that rely on text parsing, tokenization, and AST generation, BQL encodes operations as binary bytecodes. Common commands occupy just 1 byte (0x00–0xFE). There is no runtime lexical analysis — the byte stream is executed directly via a 256‑entry jump table.

💡 Core idea
// SQL (text): dozens of bytes, needs parsing
"SELECT name FROM players WHERE health > 50"

// BQL: push value, set field, compare, scan — raw bytes
PUSH_I32 50 · FIELD health · GT · ALL · GET name · END
// No lexer. No keyword table. Opcode → handler.

Why it matters: cycles spent on string comparisons, keyword recognition, and grammar validation disappear. BQL opcodes map directly to native handlers (jmp [op_table + rax*8] on the hot path).

✅ Fully binary stream ✅ No VARCHAR tokens ✅ 1‑byte for common ops ✅ Deterministic execution

🔌 Wire protocol (TYDB)

  1. On connect, server sends one length‑prefixed handshake frame: u32le length (= 12) + payload u32le magic='TYDB' (0x42445954), u8 version=1, u8 pad[3], u32le features=0.
  2. Every subsequent message is a frame: u32le length + payload.
  3. Client request payload = raw BQL bytecode (no text wrapper).
  4. Server response payload: u32le status · u32le row_count · repeated ChannelData cells [u8 type][u32le len][len bytes].

Little‑endian throughout. Single‑threaded server; many concurrent clients via select().

Status codes

CodeNameCodeName
0OK7OOM
1AUTH8IO
2BAD_OPCODE9PROTOCOL
3STACK10DENIED
4NOT_FOUND11TXN
5EXISTS12INTERNAL
6SCHEMA13TOO_LARGE

Index / buckets

Default branch width = 24 → 16,777,216 buckets. Bucket entry = 4‑byte arena offset → 64 MiB table (offsets address a 4 GiB arena; collision chains live in the arena). Integer keys use the low 24 bits; other keys fold with FNV‑1a to 24 bits.

📖 1‑byte opcode map — TachyonDB (authoritative)

Every opcode triggers a precompiled handler. Dispatch is a 256‑entry jump table — no string switch.

OpcodeMnemonicStack / immediates
0x00NOP—
0x01GET[field_id:u8] → value; emits cell
0x02PUTvalue →; writes keyed record
0x03ALLscan type with optional filter; emits rows
0x04GTfilter: FIELD f; PUSH v; GT
0x05LTsame pattern
0x06EQUsame pattern
0x07ORDER_BY1[field_id:u8]
0x08ORDER_BY2[f1][f2]
0x09LIMITint →
0x0AOFFSETint →
0x0BAND(bool, bool) → bool
0x0COR(bool, bool) → bool
0x0DNOTbool → bool
0x0EPUSH_I32[i32le] → int
0x0FPUSH_I64[i64le] → long
0x10–0x1FLOAD_CONST_0..15→ int (immediate small constants)
0x20PUSH_STR[u16le len][bytes] → CHAR_ARRAY cell ptr
0x21POPx →
0x22DUPx → x x
0x23CREATE_TYPE[nlen][name][nfields]{[flen][name][cd]}* → type_id
0x24DROP_TYPE[type_id]
0x25DELETEkeyed delete
0x26COUNT→ int
0x27BEGINtxn fence (no‑op; single‑threaded)
0x28COMMITtxn fence
0x29ROLLBACKtxn fence
0x2AAUTH[ulen][user][plen][pass] — FNV placeholder
0x2BSTATUSemits uptime, queries, records, buckets_used
0x2CPING→ 1
0x2DENDhalt OK
0x2EKEYstr → sets current key
0x2FTYPE[type_id:u8]
0x30FIELD[field_id:u8] (0xFF = whole blob PUT)
0x31PUSH_F64[f64le]
0x33PAGE_PUT[u16le path_len][path][u32le body_len][body]
0x34PAGE_GET[u16le path_len][path]
0xFEEXT[u16le code] — extended dispatch
⚡ Illustrative size contrast (not a microbench)
// Intent: GET field where value > 50, then END
// SQL text:  "SELECT name FROM players WHERE health > 50"  → ~40+ bytes of ASCII
// BQL bytes: PUSH_I32 + FIELD + GT + ALL/GET pattern + END → a handful of bytes
// Exact length depends on field/type encoding — the win is zero parsing + tiny wire.

🔌 Extended 16‑bit opcodes (after 0xFE)

Rare / admin operations stay off the hot 1‑byte path. Prefix with OP_EXT (0xFE), then a little‑endian 16‑bit code.

CodeMnemonicUse
0x0001JOINCross‑record relation
0x0002SPLITBreak a prior join
0x0003REINDEXRebuild indexes
0x0004COMPRESSCompression trigger
0x0005FLUSHWrite snapshot (snapshot.tdb)
0x0006SHUTDOWNGraceful server stop
Binary layout
// FLUSH snapshot — 3 bytes
[0xFE] [0x05] [0x00]   // OP_EXT + 0x0005 little-endian

// JOIN — 3 bytes + args
[0xFE] [0x01] [0x00]   // OP_EXT + 0x0001

Tradeoff: keeping rare ops in the 16‑bit escape leaves the common case lean without capping future commands.

📄 Pages — URLChannel / BML bodies

Page bodies are stored as DATA_BYTE_ARRAY (type 8) keyed by a UTF‑8 path. Internal type id for page records is 0xFE (not a wire ChannelData code).

OpNameRequestResponse
0x33 PAGE_PUT [u16le path_len][path][u32le body_len][body] status; row_count=0
0x34 PAGE_GET [u16le path_len][path] status; one DATA_BYTE_ARRAY cell, or NOT_FOUND (4)

Typical sequence (after handshake + AUTH)

  1. PAGE_PUT path + body → status 0
  2. PAGE_GET same path → status 0, cell type=8, bytes identical
  3. Missing path → status 4 (NOT_FOUND), no cell
  4. EXT FLUSH then restart → same PAGE_GET still returns the body (snapshot)

Empty bodies (body_len=0) are valid. Tested sizes include 0, 100, 16348, 16349, 70000, and 1 MiB. Bodies larger than max_page (config default 16 MiB; clamped 64 KiB..64 MiB) return status 13 (TOO_LARGE). Per‑connection I/O buffers start at 8 KiB and grow on demand. Frames prefer one TCP segment (TCP_NODELAY).

📦 ChannelData — type packing on the wire

Aligned with channels7 defines.h. On the Tachyon wire:

Correction vs older docs

Do not treat bit 6 as signed or bit 7 as string‑compress on the Tachyon wire. Those flags belonged to an older Channel packing sketch and are wrong for this protocol.

Bits:  7     6     5     4     3     2     1     0
      +-----+-----+-----+-----+-----+-----+-----+-----+
      |   memory kind   |        type code 0..31      |
      +-----+-----+-----+-----+-----+-----+-----+-----+
CodeNameCodeName
0DATA_BYTE8DATA_BYTE_ARRAY
1DATA_SHORT9–15*_ARRAY
2DATA_CHAR (16‑bit)16–23*_2D_ARRAY
3DATA_INT24–31*_3D_ARRAY
4DATA_LONG
5DATA_FLOAT
6DATA_DOUBLE
7DATA_OBJECT

BML / page bodies use DATA_BYTE_ARRAY (8) keyed by path. Zero string conversion on the hot path — the type byte selects the handler.

📏 Compactness vs SQL strings

SQL sends human‑readable keywords as ASCII/UTF‑8. BQL replaces each keyword with a 1‑byte opcode. Result: much smaller wire payloads and zero parsing cost on the server.

Query intentSQL (illustrative)BQL shapeWhy it wins
Fetch one field ~20–30 bytes of text GET + field_id (+ TYPE/KEY as needed) No tokenizer
Filter + AND “WHERE … AND …” prose FIELD · PUSH · GT/LT/EQU · AND Compare ops are 1 byte each
Order + limit “ORDER BY … LIMIT …” ORDER_BY1 · LIMIT Pagination without keyword bloat
Store a page body REST/JSON multipart or SQL BLOB dance PAGE_PUT path + raw bytes Direct binary cell
0 parsing

BQL eliminates string scanning on the query path. Cost is opcode dispatch + native handlers — not µs tables invented for marketing.

Qualitative wins that matter in practice: smaller frames on constrained links, predictable latency (no planner surprises), and no SQL‑injection surface because there is no SQL string to inject into.

📊 Measured — Tachyon PAGE vs SQLite BLOB (Snapdragon)

Real numbers only · 25 September 2026 · DESKTOP-2QI0DQ0 · Snapdragon 7c Gen 2 @ 2.55 GHz · Windows on ARM · native ARM64 tachyon8 + benches (not x64 emulation).

Wire / server only Cont, URLChannel, and the Display sit above these numbers — do not quote this table as end‑to‑end Cont throughput.

Fair page/BLOB store comparison: Tachyon = persistent TCP loopback + BQL PAGE_* on 127.0.0.1:7447. SQLite = in‑process library (file WAL or :memory:) — no socket. This is not a SQL‑parse contest and not the same IPC.

n=2000 (1 MiB: n=200); 50 warm‑up ops discarded; SQLite 3.42.0, journal_mode=WAL, synchronous=NORMAL.

SideOpSizeops/secp50p99
Tachyon8 TCPPAGE_GET16 B21970.344 ms1.206 ms
Tachyon8 TCPPAGE_PUT16 B21510.288 ms1.232 ms
Tachyon8 TCPPAGE_GET4 KiB22170.297 ms1.225 ms
Tachyon8 TCPPAGE_PUT4 KiB20200.323 ms1.360 ms
Tachyon8 TCPPAGE_GET1 MiB1984.161 ms9.757 ms
SQLite file WALSELECT BLOB16 B940660.006 ms0.037 ms
SQLite file WALINSERT OR REPLACE16 B29080.066 ms1.459 ms
SQLite file WALSELECT BLOB4 KiB348990.009 ms0.074 ms
SQLite file WALINSERT OR REPLACE4 KiB16800.105 ms1.568 ms
SQLite file WALSELECT BLOB1 MiB5150.907 ms8.509 ms
How to read it

SQLite SELECT wins on latency because there is no round‑trip. On PUT‑ish work, Tachyon PAGE_PUT 4 KiB (2020 ops/s) beat file SQLite INSERT 4 KiB (1680 ops/s) on this run — arena + TCP vs WAL/disk. Payload compactness vs SQL strings is a separate win (opcodes, not keywords).

Earlier Linux‑native loopback baseline (different CPU): PAGE_GET 4 KiB ≈ 5307 ops/s, p50 0.059 ms — Snapdragon 7c Gen 2 is slower as expected. Full raw log kept with the publish tree.

⚙️ Execution: 256‑entry jump table

The BQL VM uses a static array of handlers. Fetching an opcode becomes a single indexed jump. On x64/ARM64 assembler builds this is literally jmp [op_table + rax*8]. The table fits in a few KB and stays L1‑friendly.

Conceptual dispatch
typedef void (*bql_handler)(VMState*);
static const bql_handler dispatch[256] = {
    [0x00] = op_nop,
    [0x01] = op_get,
    [0x02] = op_put,
    [0x03] = op_all,
    [0x33] = op_page_put,
    [0x34] = op_page_get,
    [0xFE] = op_ext,
    // ...
};

while (!vm_halt) {
    uint8_t opcode = *vm->ip++;
    dispatch[opcode](vm);
}

Not interpreted in the text sense: there is no lexer, no grammar walk, no keyword strcmp. It is threaded binary code with a fixed opcode → handler map.

⚖️ Honest assessment — strengths & realities

✅ Advantages

  • Speed path: no lexical analysis — dispatch straight to handlers.
  • Compactness: tiny network payload (IoT, game servers, page stores).
  • Security shape: binary protocol removes classic SQL injection.
  • Deterministic: same bytecode → same execution path.
  • Cache‑friendly: jump table + contiguous instruction stream.
  • Language agnostic: any client that can emit bytes can speak BQL.
  • Same wire, two CPUs: tachyon8 (ARM64) and tachyond (x64).

⚠️ Tradeoffs & limitations

  • Not human‑readable: debugging needs hex dumps / a disassembler (roadmap #10).
  • Encoder required: humans should not hand‑hex; a small C encoder library is planned.
  • AUTH placeholder: FNV is not crypto — localhost bind until replaced.
  • Journal marker‑only: durability today = snapshot; rich WAL replay is next.
  • Txn fences only: BEGIN/COMMIT/ROLLBACK do not isolate concurrent writers (server is single‑threaded).
  • Tooling gap: fewer explorers than PostgreSQL/MySQL — expected for a young wire.
📌 Verdict

BQL is not a drop‑in SQL replacement for ad‑hoc analytics. It shines as the machine query language for TachyonDB / Channels / Cont — high‑throughput page stores, keyed records, and binary pipelines where parsing tax and payload bloat hurt. For analyst SQL, use SQL. For your stack’s hot path, BQL is the right shape.

🚀 Recommended next capabilities

Priority order for Cont / URLChannel / TachyonDB hardening. Each item earns its bit cost — frequency packing still rules.

#1 Cryptographic AUTH

Replace FNV placeholder with real crypto already in the Channels direction (Ed25519 / AES, in‑tree). Only after this is solid should the server bind beyond 127.0.0.1.

#2 Real WAL / journal replay

Snapshot‑only durability works; marker‑only journal does not. Replayable journal = crash recovery without rewriting the whole image every time.

#3 PAGE_DELETE + PAGE_LIST / PAGE_STAT

Hygiene for Cont / URLChannel: remove stale paths, list what is stored, and report size/mtime without a full GET.

#4 Aggregates as 1‑byte ops: SUM / AVG / MIN / MAX

These are frequent enough to deserve single‑byte opcodes — same packing rule that kept GET/PUT lean.

#5 Secondary indexes

Beyond the default 24‑bit primary buckets — either EXT codes or new 1‑byte ops once the access pattern is proven.

#6 Structured record path + small C encoder

Fully exercise CREATE_TYPE + GET/PUT fields with a tiny encoder library so humans never hand‑hex bytecode.

#7 Chunked / streaming PAGE

Huge bodies without forcing a single monolithic frame up to max_page.

#8 Multi‑user ACL / pod‑scoped keys

After crypto AUTH: who may read/write which key space.

#9 Peer sync / replication frame

Cont multi‑machine: replicate pages and keyed records without inventing a second protocol.

#10 BQL disassembler + hex dump tool

Closes the debugging gap the old docs already called out — make bytecode readable again for humans.

🎯 Design philosophy

BQL embraces that machines speak binary, not English. One‑byte opcodes for the common case, 16‑bit EXT for the rare case, ChannelData packed so type selection is a branch — not a string compare.

⚡ 1‑byte = 1 instruction 🔌 TYDB handshake 📄 PAGE_PUT / PAGE_GET 🔧 EXT via 0xFE
Hits--