code wiki / (root) / nx_sqlite_rows.nx

nx_sqlite_rows.nx source

↩ module page · 1112 lines · 46181 B

1// nx_sqlite_rows.nx -- SOVEREIGN SQLite ROW READER (rung 2) + seg-store PLANE LANDER. 2// 3// RUNG 1 (_hdl_build/_sqlite_read_authored.nx) walks the b-tree and decodes sqlite_master, and declares 4// its own honest limit: "local payload only -- overflow pages not followed yet ... full row/column reads 5// = rung 2". THIS IS RUNG 2: full row+column reads WITH the overflow-page chain, so any row of any size 6// comes out byte-exact. 7// 8// WHY (2026-07-23, F916 re-aimed by the F1010 SOTA reframe): the legacy Elder platform's knowledge lives 9// in SQLite (content.db 390MB: outfits/poses/locations rule mesh + 200k-row batch_history). It is NOT 10// ported as a runtime rule engine (measured: prompt words cap at ~85% semantics / 50% geometry / 0% 11// identity) -- it is MINED AS A DATASET: an L1 semantic prior + a learning corpus + an eval set. This 12// organ is the sovereign read path for that mine. READ-ONLY: it never writes to the SQLite file. 13// 14// VERBS 15// tables <db> list tables: name, rootpage, rows 16// rows <db> <table> [max] dump rows TSV-ish (NULL=\N, tab/nl/backslash escaped) 17// plane <db> <table> <store-prefix> land rows into a seg-store plane, ONE segment per table: 18// key <table>:<rowid> -> canonical NXR1 record (absent field == 19// SQL NULL, so NULL survives losslessly), plus <table>:meta 20// selftest gate, verdict=GREEN|RED 21// 22// ENVELOPE (declared, never silent): row payload cap 8MiB · <=256 cols · REAL rendered to 3 decimals 23// (out-of-range -> x<hex>, never a wrong number) · BLOBs emitted raw (embedded NUL truncates a plane 24// value -- text/int tables are the target; blob-safe values = a later rung) · a table lands in ONE 25// segment (writer cap 128MiB). 26// NOTE (DRY): sqr_rec_field duplicates mv_rec_field's NXR1 walk (2nd copy; at a 3rd, extract to a lib). 27// license_tier: ORIGINAL Read-only, no hw writes (Rule 26). 28import "nx_syscalls.nx" 29import "nx_canon_cid.nx" 30import "nx_seg_store.nx" 31const SQR_MAGIC_2047: i64 = 2047 32const SQR_MAGIC_4503599627370495: i64 = 4503599627370495 33const SQR_MAGIC_4503599627370496: i64 = 4503599627370496 34const SQR_MAGIC_1075: i64 = 1075 35const SQR_MAGIC_1048576: i64 = 1048576 36const SQR_MAGIC_65000: i64 = 65000 37const SQR_MAGIC_21329: i64 = 21329 38const SQR_MAGIC_65536: i64 = 65536 39const SQR_MAGIC_1024: i64 = 1024 40const SQR_MAGIC_4096: i64 = 4096 41const SQR_MAGIC_20000: i64 = 20000 42 43const SQR_MAXCOL: i64 = 256 44const SQR_ROWCAP: i64 = 8388608 45const SQR_ARENA: i64 = 8388608 46const SQR_NAMES: i64 = 65536 47const SQR_WCAP: i64 = 134217728 48const SQR_LINE: i64 = 8388608 49 50// ctx slots 51const CX_MODE: i64 = 0 52const CX_ROWS: i64 = 1 53const CX_MAX: i64 = 2 54const CX_DB: i64 = 3 55const CX_PS: i64 = 4 56const CX_USE: i64 = 5 57const CX_PAY: i64 = 6 58const CX_OFFS: i64 = 7 59const CX_LENS: i64 = 8 60const CX_TYPS: i64 = 9 61const CX_NCOL: i64 = 10 62const CX_NAMB: i64 = 11 63const CX_NAMO: i64 = 12 64const CX_W: i64 = 13 65const CX_TAB: i64 = 14 66const CX_KEYS: i64 = 15 67const CX_VALS: i64 = 16 68const CX_AREN: i64 = 17 69const CX_REC: i64 = 18 70const CX_KBUF: i64 = 19 71const CX_ERR: i64 = 20 72const CX_LINE: i64 = 21 73const CX_MINR: i64 = 22 74const CX_MAXR: i64 = 23 75const CX_ALIA: i64 = 24 76// capture mode (3): pull ONE column of ONE rowid out for gate assertions 77const CX_CAPID: i64 = 25 78const CX_CAPCOL: i64 = 26 79const CX_CAPP: i64 = 27 80const CX_CAPL: i64 = 28 81const CX_CAPT: i64 = 29 82const CX_CAPV: i64 = 30 83// chunked planing: a table larger than the writer must land as MULTIPLE segments, not fail closed 84// (token_position_log is 42.9M rows -- roughly 8GB of records; one segment could never hold it). 85const CX_PFX: i64 = 31 86const CX_SEGN: i64 = 32 87// ROW-RANGE planing: `plane <db> <t> <pfx> [skip] [count]`. The sovereign toolchain frees lazily in 88// places (see nx_galx_thumb's header: "a single process MUST NOT decode many images ... FORKS one child 89// per image -- the kernel reclaims every mmap on child exit"). MEASURED here 2026-07-23: one process 90// planing beauty_evaluations (568,944 rows) climbed to 10.09GB RSS and was SIGKILLed by the OOM killer, 91// while 306,266 rows peaked at 6.0GB and survived -- growth tracks ROWS, not DB size. So a big table is 92// planed as N range invocations; each fresh process gives every page back on exit. 93const CX_SKIP: i64 = 33 94const CX_SEEN: i64 = 34 95const SQR_FLUSH: i64 = 100663296 // flush a batch past 96MiB (writer cap is 128MiB) 96 97func sqr_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 98func sqr_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 99func sqr_cat(d: *u8, o: i64, s: *u8) -> i64 { var p: i64 = o; var i: i64 = 0; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } return p } 100func sqr_ch(d: *u8, o: i64, c: i64) -> i64 { d[o] = c as u8; return o + 1 } 101func sqr_eq(a: *u8, b: *u8) -> i64 { 102 var i: i64 = 0 103 while 1 == 1 { 104 if a[i] != b[i] { return 0 } 105 if a[i] == (0 as u8) { return 1 } 106 i = i + 1 107 } 108 return 0 109} 110func sqr_udec(d: *u8, o: i64, v: i64) -> i64 { 111 if v == 0 { d[o] = 48 as u8; return o + 1 } 112 var div: i64 = 1 113 var m: i64 = v 114 while m >= 10 { div = div * 10; m = m / 10 } 115 var p: i64 = o 116 var rest: i64 = v 117 while div > 0 { 118 let dg: i64 = rest / div 119 d[p] = (48 + dg) as u8 120 rest = rest - dg * div 121 div = div / 10 122 p = p + 1 123 } 124 return p 125} 126func sqr_sdec(d: *u8, o: i64, v: i64) -> i64 { 127 if v < 0 { d[o] = 45 as u8; return sqr_udec(d, o + 1, 0 - v) } 128 return sqr_udec(d, o, v) 129} 130func sqr_hex(d: *u8, o: i64, v: i64) -> i64 { 131 let h: *u8 = "0123456789abcdef" as *u8 132 var p: i64 = o 133 var i: i64 = 15 134 while i >= 0 { 135 let nib: i64 = (v >> (i * 4)) & 15 136 d[p] = h[nib] 137 p = p + 1 138 i = i - 1 139 } 140 return p 141} 142 143// ---- SQLite primitives ---- 144func sqr_atoi(s: *u8) -> i64 { 145 var v: i64 = 0 146 var i: i64 = 0 147 while s[i] != (0 as u8) { 148 let c: i64 = s[i] as i64 149 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } 150 i = i + 1 151 } 152 return v 153} 154func sqr_be16(p: *u8, o: i64) -> i64 { let a: i64 = p[o]; let b: i64 = p[o + 1]; return (a << 8) | b } 155func sqr_be32(p: *u8, o: i64) -> i64 { 156 let a: i64 = p[o]; let b: i64 = p[o + 1]; let c: i64 = p[o + 2]; let d: i64 = p[o + 3] 157 return (((((a << 8) | b) << 8) | c) << 8) | d 158} 159func sqr_varint(p: *u8, o: i64, lenout: *i64) -> i64 { 160 var v: i64 = 0 161 var i: i64 = 0 162 while i < 8 { 163 let b: i64 = p[o + i] 164 if b < 128 { v = (v << 7) | b; lenout[0] = i + 1; return v } 165 v = (v << 7) | (b - 128) 166 i = i + 1 167 } 168 let b9: i64 = p[o + 8] 169 v = (v << 8) | b9 170 lenout[0] = 9 171 return v 172} 173func sqr_stsize(st: i64) -> i64 { 174 if st == 0 { return 0 } 175 if st == 1 { return 1 } 176 if st == 2 { return 2 } 177 if st == 3 { return 3 } 178 if st == 4 { return 4 } 179 if st == 5 { return 6 } 180 if st == 6 { return 8 } 181 if st == 7 { return 8 } 182 if st == 8 { return 0 } 183 if st == 9 { return 0 } 184 if st >= 12 { 185 let m: i64 = st % 2 186 if m == 0 { return (st - 12) / 2 } 187 return (st - 13) / 2 188 } 189 return 0 190} 191// big-endian TWOS-COMPLEMENT integer of n bytes (explicit sign fix -- never relies on >> semantics) 192func sqr_sint(p: *u8, o: i64, n: i64) -> i64 { 193 var v: i64 = 0 194 var i: i64 = 0 195 while i < n { v = (v << 8) | (p[o + i] as i64); i = i + 1 } 196 if n < 8 { 197 if n > 0 { 198 var sb: i64 = 1 199 var k: i64 = 0 200 while k < n * 8 - 1 { sb = sb * 2; k = k + 1 } 201 if (v & sb) != 0 { v = v - sb * 2 } 202 } 203 } 204 return v 205} 206func sqr_page(db: *u8, ps: i64, pgno: i64) -> *u8 { let base: i64 = db as i64; return (base + (pgno - 1) * ps) as *u8 } 207 208// IEEE754 double -> value*1000 (3 decimals). okbox[0]=1 ok, 0 = out of representable range. 209func sqr_f64_milli(bits: i64, okbox: *i64) -> i64 { 210 okbox[0] = 1 211 let sign: i64 = (bits >> 63) & 1 212 let exp: i64 = (bits >> 52) & SQR_MAGIC_2047 213 let man: i64 = bits & SQR_MAGIC_4503599627370495 214 if exp == 0 { return 0 } 215 if exp == SQR_MAGIC_2047 { okbox[0] = 0; return 0 } 216 let m: i64 = man + SQR_MAGIC_4503599627370496 217 let e: i64 = exp - SQR_MAGIC_1075 218 var r: i64 = 0 219 if e >= 0 { 220 if e > 9 { okbox[0] = 0; return 0 } 221 r = m * 1000 222 var i: i64 = 0 223 while i < e { r = r * 2; i = i + 1 } 224 } else { 225 let sh: i64 = 0 - e 226 if sh > 62 { return 0 } 227 r = (m * 1000) >> sh 228 } 229 if sign == 1 { r = 0 - r } 230 return r 231} 232func sqr_emit_f64(d: *u8, o: i64, bits: i64) -> i64 { 233 let ok: *i64 = sys_mmap(16) as *i64 234 let mv: i64 = sqr_f64_milli(bits, ok) 235 if ok[0] == 0 { var p: i64 = sqr_ch(d, o, 120); return sqr_hex(d, p, bits) } 236 var v: i64 = mv 237 var p2: i64 = o 238 if v < 0 { p2 = sqr_ch(d, p2, 45); v = 0 - v } 239 p2 = sqr_udec(d, p2, v / 1000) 240 p2 = sqr_ch(d, p2, 46) 241 let frac: i64 = v % 1000 242 p2 = sqr_ch(d, p2, 48 + (frac / 100)) 243 p2 = sqr_ch(d, p2, 48 + ((frac / 10) % 10)) 244 p2 = sqr_ch(d, p2, 48 + (frac % 10)) 245 return p2 246} 247 248// ---- payload assembly (LOCAL + OVERFLOW CHAIN) = the rung-2 keystone ---- 249// returns payload length, or -1 on cap/format failure; ridbox[0] = rowid 250func sqr_assemble(db: *u8, ps: i64, usable: i64, pg: *u8, coff: i64, out: *u8, cap: i64, ridbox: *i64) -> i64 { 251 let lp: *i64 = sys_mmap(16) as *i64 252 var o: i64 = coff 253 let plen: i64 = sqr_varint(pg, o, lp) 254 o = o + lp[0] 255 let rid: i64 = sqr_varint(pg, o, lp) 256 o = o + lp[0] 257 ridbox[0] = rid 258 sys_munmap(lp as *u8, 16) 259 if plen < 0 { return 0 - 1 } 260 if plen > cap { return 0 - 1 } 261 // SQLite table-leaf local-payload formula (file-format spec section 1.6) 262 let x: i64 = usable - 35 263 var local: i64 = plen 264 if plen > x { 265 let mmin: i64 = ((usable - 12) * 32 / 255) - 23 266 let k: i64 = mmin + ((plen - mmin) % (usable - 4)) 267 if k <= x { local = k } else { local = mmin } 268 } 269 var w: i64 = 0 270 var i: i64 = 0 271 while i < local { out[w] = pg[o + i]; w = w + 1; i = i + 1 } 272 if local < plen { 273 var nxt: i64 = sqr_be32(pg, o + local) 274 while nxt != 0 { 275 if w >= plen { nxt = 0 } else { 276 let op: *u8 = sqr_page(db, ps, nxt) 277 let nn: i64 = sqr_be32(op, 0) 278 let avail: i64 = usable - 4 279 var j: i64 = 0 280 while j < avail { 281 if w < plen { out[w] = op[4 + j]; w = w + 1 } 282 j = j + 1 283 } 284 nxt = nn 285 } 286 } 287 } 288 if w != plen { return 0 - 1 } 289 return plen 290} 291 292// record header -> per-column serial type + data offset/len. returns ncols, -1 on overflow of MAXCOL. 293func sqr_decode(pay: *u8, plen: i64, offs: *i64, lens: *i64, typs: *i64) -> i64 { 294 let lp: *i64 = sys_mmap(16) as *i64 295 var o: i64 = 0 296 let hlen: i64 = sqr_varint(pay, o, lp) 297 o = o + lp[0] 298 var n: i64 = 0 299 var dat: i64 = hlen 300 var bad: i64 = 0 301 while o < hlen { 302 if n >= SQR_MAXCOL { bad = 1; o = hlen } else { 303 let st: i64 = sqr_varint(pay, o, lp) 304 o = o + lp[0] 305 typs[n] = st 306 offs[n] = dat 307 let sz: i64 = sqr_stsize(st) 308 lens[n] = sz 309 dat = dat + sz 310 n = n + 1 311 } 312 } 313 sys_munmap(lp as *u8, 16) 314 if bad == 1 { return 0 - 1 } 315 if dat > plen { return 0 - 1 } 316 return n 317} 318 319// ---- sqlite_master: name -> rootpage + CREATE sql (5 columns) ---- 320// finds table `want`; returns rootpage (0 = not found). sqlbox/sqllen receive the CREATE TABLE text. 321func sqr_master_find(db: *u8, ps: i64, usable: i64, pgno: i64, want: *u8, sqlbuf: *u8, sqllen: *i64) -> i64 { 322 let pg: *u8 = sqr_page(db, ps, pgno) 323 var hdr: i64 = 0 324 if pgno == 1 { hdr = 100 } 325 let pt: i64 = pg[hdr] 326 let ncell: i64 = sqr_be16(pg, hdr + 3) 327 if pt == 5 { 328 var i: i64 = 0 329 var found: i64 = 0 330 while i < ncell { 331 if found == 0 { 332 let cp: i64 = sqr_be16(pg, hdr + 12 + 2 * i) 333 let r: i64 = sqr_master_find(db, ps, usable, sqr_be32(pg, cp), want, sqlbuf, sqllen) 334 if r > 0 { found = r } 335 } 336 i = i + 1 337 } 338 if found == 0 { found = sqr_master_find(db, ps, usable, sqr_be32(pg, hdr + 8), want, sqlbuf, sqllen) } 339 return found 340 } 341 if pt != 13 { return 0 } 342 let pay: *u8 = sys_mmap(SQR_MAGIC_1048576) 343 let offs: *i64 = sys_mmap(8 * SQR_MAXCOL) as *i64 344 let lens: *i64 = sys_mmap(8 * SQR_MAXCOL) as *i64 345 let typs: *i64 = sys_mmap(8 * SQR_MAXCOL) as *i64 346 let rid: *i64 = sys_mmap(16) as *i64 347 var res: i64 = 0 348 var i2: i64 = 0 349 while i2 < ncell { 350 if res == 0 { 351 let cp2: i64 = sqr_be16(pg, hdr + 8 + 2 * i2) 352 let plen: i64 = sqr_assemble(db, ps, usable, pg, cp2, pay, SQR_MAGIC_1048576, rid) 353 if plen > 0 { 354 let nc: i64 = sqr_decode(pay, plen, offs, lens, typs) 355 if nc >= 5 { 356 // col0 type ('table'), col1 name, col3 rootpage, col4 sql 357 var istab: i64 = 0 358 if lens[0] == 5 { 359 let t0: i64 = offs[0] 360 if pay[t0] == (116 as u8) { if pay[t0+1] == (97 as u8) { if pay[t0+2] == (98 as u8) { if pay[t0+3] == (108 as u8) { if pay[t0+4] == (101 as u8) { istab = 1 } } } } } 361 } 362 if istab == 1 { 363 var nameeq: i64 = 1 364 let wl: i64 = sqr_len(want) 365 if lens[1] != wl { nameeq = 0 } else { 366 var k: i64 = 0 367 while k < wl { if pay[offs[1] + k] != want[k] { nameeq = 0 } k = k + 1 } 368 } 369 if nameeq == 1 { 370 var rp: i64 = 0 371 if typs[3] == 9 { rp = 1 } 372 if typs[3] >= 1 { if typs[3] <= 6 { rp = sqr_sint(pay, offs[3], lens[3]) } } 373 var sl: i64 = lens[4] 374 if sl > SQR_MAGIC_65000 { sl = SQR_MAGIC_65000 } 375 var j: i64 = 0 376 while j < sl { sqlbuf[j] = pay[offs[4] + j]; j = j + 1 } 377 sqlbuf[sl] = 0 as u8 378 sqllen[0] = sl 379 res = rp 380 } 381 } 382 } 383 } 384 } 385 i2 = i2 + 1 386 } 387 sys_munmap(pay, SQR_MAGIC_1048576) 388 sys_munmap(offs as *u8, 8 * SQR_MAXCOL) 389 sys_munmap(lens as *u8, 8 * SQR_MAXCOL) 390 sys_munmap(typs as *u8, 8 * SQR_MAXCOL) 391 sys_munmap(rid as *u8, 16) 392 return res 393} 394 395// list every table (name + rootpage) -- for the `tables` verb 396func sqr_master_list(db: *u8, ps: i64, usable: i64, pgno: i64, names: *u8, npos: *i64, noff: *i64, roots: *i64, cnt: *i64) -> i64 { 397 let pg: *u8 = sqr_page(db, ps, pgno) 398 var hdr: i64 = 0 399 if pgno == 1 { hdr = 100 } 400 let pt: i64 = pg[hdr] 401 let ncell: i64 = sqr_be16(pg, hdr + 3) 402 if pt == 5 { 403 var i: i64 = 0 404 while i < ncell { 405 let cp: i64 = sqr_be16(pg, hdr + 12 + 2 * i) 406 sqr_master_list(db, ps, usable, sqr_be32(pg, cp), names, npos, noff, roots, cnt) 407 i = i + 1 408 } 409 sqr_master_list(db, ps, usable, sqr_be32(pg, hdr + 8), names, npos, noff, roots, cnt) 410 return 0 411 } 412 if pt != 13 { return 0 } 413 let pay: *u8 = sys_mmap(SQR_MAGIC_1048576) 414 let offs: *i64 = sys_mmap(8 * SQR_MAXCOL) as *i64 415 let lens: *i64 = sys_mmap(8 * SQR_MAXCOL) as *i64 416 let typs: *i64 = sys_mmap(8 * SQR_MAXCOL) as *i64 417 let rid: *i64 = sys_mmap(16) as *i64 418 var i2: i64 = 0 419 while i2 < ncell { 420 let cp2: i64 = sqr_be16(pg, hdr + 8 + 2 * i2) 421 let plen: i64 = sqr_assemble(db, ps, usable, pg, cp2, pay, SQR_MAGIC_1048576, rid) 422 if plen > 0 { 423 let nc: i64 = sqr_decode(pay, plen, offs, lens, typs) 424 if nc >= 4 { 425 var istab: i64 = 0 426 if lens[0] == 5 { 427 let t0: i64 = offs[0] 428 if pay[t0] == (116 as u8) { if pay[t0+1] == (97 as u8) { if pay[t0+2] == (98 as u8) { if pay[t0+3] == (108 as u8) { if pay[t0+4] == (101 as u8) { istab = 1 } } } } } 429 } 430 if istab == 1 { 431 let k: i64 = cnt[0] 432 noff[k] = npos[0] 433 var j: i64 = 0 434 while j < lens[1] { names[npos[0] + j] = pay[offs[1] + j]; j = j + 1 } 435 names[npos[0] + lens[1]] = 0 as u8 436 npos[0] = npos[0] + lens[1] + 1 437 var rp: i64 = 0 438 if typs[3] == 9 { rp = 1 } 439 if typs[3] >= 1 { if typs[3] <= 6 { rp = sqr_sint(pay, offs[3], lens[3]) } } 440 roots[k] = rp 441 cnt[0] = k + 1 442 } 443 } 444 } 445 i2 = i2 + 1 446 } 447 sys_munmap(pay, SQR_MAGIC_1048576) 448 sys_munmap(offs as *u8, 8 * SQR_MAXCOL) 449 sys_munmap(lens as *u8, 8 * SQR_MAXCOL) 450 sys_munmap(typs as *u8, 8 * SQR_MAXCOL) 451 sys_munmap(rid as *u8, 16) 452 return 0 453} 454 455// ---- CREATE TABLE sql -> column names (+ which column is the INTEGER PRIMARY KEY rowid alias) ---- 456func sqr_upch(c: i64) -> i64 { if c >= 97 { if c <= 122 { return c - 32 } } return c } 457// does seg[s..e) contain the uppercase word w? 458func sqr_hasword(sql: *u8, s: i64, e: i64, w: *u8) -> i64 { 459 let wl: i64 = sqr_len(w) 460 var i: i64 = s 461 while i + wl <= e { 462 var m: i64 = 1 463 var j: i64 = 0 464 while j < wl { if sqr_upch(sql[i + j] as i64) != (w[j] as i64) { m = 0 } j = j + 1 } 465 if m == 1 { return 1 } 466 i = i + 1 467 } 468 return 0 469} 470func sqr_isname(c: i64) -> i64 { 471 if c >= 48 { if c <= 57 { return 1 } } 472 if c >= 65 { if c <= 90 { return 1 } } 473 if c >= 97 { if c <= 122 { return 1 } } 474 if c == 95 { return 1 } 475 return 0 476} 477// returns ncols; names -> nul-separated, noff -> offsets; aliasbox[0] = rowid-alias col index (-1 none) 478func sqr_parse_cols(sql: *u8, sqllen: i64, names: *u8, noff: *i64, aliasbox: *i64) -> i64 { 479 aliasbox[0] = 0 - 1 480 var i: i64 = 0 481 var open: i64 = 0 - 1 482 while i < sqllen { 483 if open < 0 { if sql[i] == (40 as u8) { open = i } } 484 i = i + 1 485 } 486 if open < 0 { return 0 } 487 var n: i64 = 0 488 var npos: i64 = 0 489 var depth: i64 = 0 490 var segs: i64 = open + 1 491 var p: i64 = open + 1 492 var go: i64 = 1 493 while go == 1 { 494 if p >= sqllen { go = 0 } 495 if go == 1 { 496 let c: i64 = sql[p] as i64 497 var cut: i64 = 0 498 if c == 40 { depth = depth + 1 } 499 if c == 41 { 500 if depth == 0 { cut = 1; go = 0 } else { depth = depth - 1 } 501 } 502 if depth == 0 { if c == 44 { cut = 1 } } 503 if cut == 1 { 504 // segment [segs, p) -- first identifier token is the column name 505 // NOTE: exit these scans with a FLAG, never by clobbering the index (the 506 // "s = p + 999" trick lost the real position -> every column name came out 507 // empty; caught by gate T2 on first run). 508 var s: i64 = segs 509 var sd: i64 = 0 510 while sd == 0 { 511 if s >= p { sd = 1 } else { 512 let cc: i64 = sql[s] as i64 513 var sk: i64 = 0 514 if cc == 32 { sk = 1 } 515 if cc == 10 { sk = 1 } 516 if cc == 9 { sk = 1 } 517 if cc == 13 { sk = 1 } 518 if cc == 34 { sk = 1 } 519 if cc == 96 { sk = 1 } 520 if cc == 91 { sk = 1 } 521 if sk == 1 { s = s + 1 } else { sd = 1 } 522 } 523 } 524 var e: i64 = s 525 var ed: i64 = 0 526 while ed == 0 { 527 if e >= p { ed = 1 } else { 528 if sqr_isname(sql[e] as i64) == 1 { e = e + 1 } else { ed = 1 } 529 } 530 } 531 var kw: i64 = 0 532 if sqr_hasword(sql, s, e, "CONSTRAINT" as *u8) == 1 { kw = 1 } 533 if sqr_hasword(sql, s, e, "PRIMARY" as *u8) == 1 { kw = 1 } 534 if sqr_hasword(sql, s, e, "UNIQUE" as *u8) == 1 { kw = 1 } 535 if sqr_hasword(sql, s, e, "CHECK" as *u8) == 1 { kw = 1 } 536 if sqr_hasword(sql, s, e, "FOREIGN" as *u8) == 1 { kw = 1 } 537 if e > s { if kw == 0 { if n < SQR_MAXCOL { 538 noff[n] = npos 539 var j: i64 = s 540 while j < e { names[npos] = sql[j]; npos = npos + 1; j = j + 1 } 541 names[npos] = 0 as u8 542 npos = npos + 1 543 // INTEGER PRIMARY KEY in this segment == the rowid alias (stored NULL in the record) 544 if sqr_hasword(sql, s, p, "INTEGER" as *u8) == 1 { 545 if sqr_hasword(sql, s, p, "PRIMARY" as *u8) == 1 { aliasbox[0] = n } 546 } 547 n = n + 1 548 } } } 549 segs = p + 1 550 } 551 p = p + 1 552 } 553 } 554 return n 555} 556 557// NXR1 field read (DRY note in header: 2nd copy of mv_rec_field's walk) 558func sqr_r32(p: *u8, o: i64) -> i64 { 559 let a: i64 = p[o]; let b: i64 = p[o+1]; let c: i64 = p[o+2]; let d: i64 = p[o+3] 560 return (((((a << 8) | b) << 8) | c) << 8) | d 561} 562func sqr_rec_field(rec: *u8, reclen: i64, key: *u8, outp: *i64, outl: *i64) -> i64 { 563 if reclen < 8 { return 0 } 564 if rec[0] != (78 as u8) { return 0 } 565 let klen: i64 = sqr_len(key) 566 let n: i64 = sqr_r32(rec, 4) 567 var off: i64 = 8 568 var i: i64 = 0 569 while i < n { 570 let kl: i64 = sqr_r32(rec, off); off = off + 4 571 let kp: i64 = off; off = off + kl 572 let vl: i64 = sqr_r32(rec, off); off = off + 4 573 let vp: i64 = off; off = off + vl 574 if kl == klen { 575 var m: i64 = 1 576 var c: i64 = 0 577 while c < kl { if rec[kp + c] != key[c] { m = 0 } c = c + 1 } 578 if m == 1 { outp[0] = (rec as i64) + vp; outl[0] = vl; return 1 } 579 } 580 i = i + 1 581 } 582 return 0 583} 584 585// dump every field of an NXR1 record (the `get` verb's printer) 586func sqr_rec_dump(rec: *u8, reclen: i64) -> i64 { 587 if reclen < 8 { return 0 } 588 if rec[0] != (78 as u8) { sqr_puts("NX-SQR NOT-NXR1\n" as *u8); return 0 } 589 let n: i64 = sqr_r32(rec, 4) 590 let line: *u8 = sys_mmap(SQR_LINE) 591 var off: i64 = 8 592 var i: i64 = 0 593 while i < n { 594 let kl: i64 = sqr_r32(rec, off); off = off + 4 595 let kp: i64 = off; off = off + kl 596 let vl: i64 = sqr_r32(rec, off); off = off + 4 597 let vp: i64 = off; off = off + vl 598 var o: i64 = 0 599 var j: i64 = 0 600 while j < kl { line[o] = rec[kp + j]; o = o + 1; j = j + 1 } 601 o = sqr_ch(line, o, 61) 602 j = 0 603 while j < vl { 604 let b: i64 = rec[vp + j] as i64 605 if b == 10 { o = sqr_cat(line, o, "\\n" as *u8) } else { o = sqr_ch(line, o, b) } 606 j = j + 1 607 } 608 o = sqr_ch(line, o, 10) 609 sys_write(1, line, o) 610 i = i + 1 611 } 612 sys_munmap(line, SQR_LINE) 613 return n 614} 615 616// ---- per-row handler (dump / plane) ---- 617func sqr_row(ctx: *i64, rowid: i64, nrec: i64) -> i64 { 618 let mode: i64 = ctx[CX_MODE] 619 // range window: SEEN counts every row the walk reaches; ROWS counts only emitted ones, so the 620 // walk's max-rows stop still means "emitted", and skip+count carve a clean, resumable slice. 621 ctx[CX_SEEN] = ctx[CX_SEEN] + 1 622 if ctx[CX_SEEN] <= ctx[CX_SKIP] { return 0 } 623 ctx[CX_ROWS] = ctx[CX_ROWS] + 1 624 if ctx[CX_MINR] == 0 { ctx[CX_MINR] = rowid } 625 ctx[CX_MAXR] = rowid 626 if mode == 0 { return 0 } 627 let pay: *u8 = ctx[CX_PAY] as *u8 628 let offs: *i64 = ctx[CX_OFFS] as *i64 629 let lens: *i64 = ctx[CX_LENS] as *i64 630 let typs: *i64 = ctx[CX_TYPS] as *i64 631 let names: *u8 = ctx[CX_NAMB] as *u8 632 let noff: *i64 = ctx[CX_NAMO] as *i64 633 let ncol: i64 = ctx[CX_NCOL] 634 let alias: i64 = ctx[CX_ALIA] 635 var nc: i64 = nrec 636 if ncol > 0 { if ncol < nc { nc = ncol } } 637 if mode == 3 { 638 if rowid == ctx[CX_CAPID] { 639 let cc: i64 = ctx[CX_CAPCOL] 640 if cc < nrec { 641 ctx[CX_CAPT] = typs[cc] 642 ctx[CX_CAPL] = lens[cc] 643 ctx[CX_CAPV] = 0 644 if typs[cc] >= 1 { if typs[cc] <= 6 { ctx[CX_CAPV] = sqr_sint(pay, offs[cc], lens[cc]) } } 645 let cb: *u8 = ctx[CX_CAPP] as *u8 646 var j3: i64 = 0 647 while j3 < lens[cc] { cb[j3] = pay[offs[cc] + j3]; j3 = j3 + 1 } 648 } 649 } 650 return 0 651 } 652 if mode == 1 { 653 let line: *u8 = ctx[CX_LINE] as *u8 654 var o: i64 = sqr_udec(line, 0, rowid) 655 var c: i64 = 0 656 while c < nc { 657 o = sqr_ch(line, o, 9) 658 let st: i64 = typs[c] 659 var handled: i64 = 0 660 if st == 0 { 661 if c == alias { o = sqr_udec(line, o, rowid) } else { o = sqr_cat(line, o, "\\N" as *u8) } 662 handled = 1 663 } 664 if handled == 0 { if st == 8 { o = sqr_ch(line, o, 48); handled = 1 } } 665 if handled == 0 { if st == 9 { o = sqr_ch(line, o, 49); handled = 1 } } 666 if handled == 0 { if st <= 6 { o = sqr_sdec(line, o, sqr_sint(pay, offs[c], lens[c])); handled = 1 } } 667 if handled == 0 { if st == 7 { o = sqr_emit_f64(line, o, sqr_sint(pay, offs[c], 8)); handled = 1 } } 668 if handled == 0 { 669 var j: i64 = 0 670 while j < lens[c] { 671 let b: i64 = pay[offs[c] + j] as i64 672 if b == 9 { o = sqr_cat(line, o, "\\t" as *u8) } else { 673 if b == 10 { o = sqr_cat(line, o, "\\n" as *u8) } else { 674 if b == 92 { o = sqr_cat(line, o, "\\\\" as *u8) } else { o = sqr_ch(line, o, b) } 675 } 676 } 677 j = j + 1 678 } 679 } 680 c = c + 1 681 } 682 o = sqr_ch(line, o, 10) 683 sys_write(1, line, o) 684 return 0 685 } 686 // mode 2 -- land one NXR1 record (absent field == SQL NULL, lossless) 687 let keys: *i64 = ctx[CX_KEYS] as *i64 688 let vals: *i64 = ctx[CX_VALS] as *i64 689 let arena: *u8 = ctx[CX_AREN] as *u8 690 var ap: i64 = 0 691 var nf: i64 = 0 692 var c2: i64 = 0 693 while c2 < nc { 694 let st: i64 = typs[c2] 695 var skip: i64 = 0 696 if st == 0 { if c2 != alias { skip = 1 } } 697 if skip == 0 { 698 let vstart: i64 = ap 699 if st == 0 { ap = sqr_udec(arena, ap, rowid) } else { 700 if st == 8 { ap = sqr_ch(arena, ap, 48) } else { 701 if st == 9 { ap = sqr_ch(arena, ap, 49) } else { 702 if st <= 6 { ap = sqr_sdec(arena, ap, sqr_sint(pay, offs[c2], lens[c2])) } else { 703 if st == 7 { ap = sqr_emit_f64(arena, ap, sqr_sint(pay, offs[c2], 8)) } else { 704 var j2: i64 = 0 705 while j2 < lens[c2] { arena[ap] = pay[offs[c2] + j2]; ap = ap + 1; j2 = j2 + 1 } 706 } 707 } 708 } 709 } 710 } 711 arena[ap] = 0 as u8 712 ap = ap + 1 713 keys[nf] = ((names as i64) + noff[c2]) 714 vals[nf] = (arena as i64) + vstart 715 nf = nf + 1 716 } 717 c2 = c2 + 1 718 } 719 let rec: *u8 = ctx[CX_REC] as *u8 720 let rl: i64 = canon_encode(keys, vals, nf, rec) 721 let kbuf: *u8 = ctx[CX_KBUF] as *u8 722 var ko: i64 = sqr_cat(kbuf, 0, ctx[CX_TAB] as *u8) 723 ko = sqr_ch(kbuf, ko, 58) 724 ko = sqr_udec(kbuf, ko, rowid) 725 kbuf[ko] = 0 as u8 726 let w: *i64 = ctx[CX_W] as *i64 727 if ss_add(w, 1, kbuf, rec, rl) < 0 { ctx[CX_ERR] = 1 } 728 // chunked planing: commit + start a fresh writer once the batch is large, so an arbitrarily 729 // large table lands as N segments instead of hitting the writer cap and failing closed. 730 // Keys are unique per row, so splitting across segments stays correct for readers. 731 if ctx[CX_ERR] == 0 { 732 if w[1] > SQR_FLUSH { 733 let pfx: *u8 = ctx[CX_PFX] as *u8 734 if ss_commit(pfx, w, ss_next_segid(pfx)) != 0 { ctx[CX_ERR] = 4 } else { 735 sys_munmap(w[0] as *u8, w[2]) 736 sys_munmap(w as *u8, 32) 737 ctx[CX_W] = (ss_begin_cap(SQR_WCAP)) as i64 738 ctx[CX_SEGN] = ctx[CX_SEGN] + 1 739 } 740 } 741 } 742 return 0 743} 744 745// ---- b-tree walk ---- 746func sqr_walk(ctx: *i64, pgno: i64) -> i64 { 747 if ctx[CX_ERR] != 0 { return 0 } 748 let db: *u8 = ctx[CX_DB] as *u8 749 let ps: i64 = ctx[CX_PS] 750 let usable: i64 = ctx[CX_USE] 751 let pg: *u8 = sqr_page(db, ps, pgno) 752 var hdr: i64 = 0 753 if pgno == 1 { hdr = 100 } 754 let pt: i64 = pg[hdr] 755 let ncell: i64 = sqr_be16(pg, hdr + 3) 756 if pt == 5 { 757 var i: i64 = 0 758 while i < ncell { 759 let cp: i64 = sqr_be16(pg, hdr + 12 + 2 * i) 760 sqr_walk(ctx, sqr_be32(pg, cp)) 761 i = i + 1 762 } 763 sqr_walk(ctx, sqr_be32(pg, hdr + 8)) 764 return 0 765 } 766 if pt != 13 { return 0 } 767 let pay: *u8 = ctx[CX_PAY] as *u8 768 let offs: *i64 = ctx[CX_OFFS] as *i64 769 let lens: *i64 = ctx[CX_LENS] as *i64 770 let typs: *i64 = ctx[CX_TYPS] as *i64 771 let rid: *i64 = sys_mmap(16) as *i64 772 var i2: i64 = 0 773 while i2 < ncell { 774 var stop: i64 = 0 775 if ctx[CX_MAX] > 0 { if ctx[CX_ROWS] >= ctx[CX_MAX] { stop = 1 } } 776 if ctx[CX_ERR] != 0 { stop = 1 } 777 if stop == 0 { 778 let cp2: i64 = sqr_be16(pg, hdr + 8 + 2 * i2) 779 let plen: i64 = sqr_assemble(db, ps, usable, pg, cp2, pay, SQR_ROWCAP, rid) 780 if plen < 0 { ctx[CX_ERR] = 2 } else { 781 let nc: i64 = sqr_decode(pay, plen, offs, lens, typs) 782 if nc < 0 { ctx[CX_ERR] = 3 } else { sqr_row(ctx, rid[0], nc) } 783 } 784 } 785 i2 = i2 + 1 786 } 787 sys_munmap(rid as *u8, 16) 788 return 0 789} 790 791// ---- open + prep ---- 792// OPEN = READ-ONLY FILE-BACKED MMAP (sys_map_file: PROT_READ, MAP_PRIVATE, zero-copy, lazy pages). 793// ★MEASURED, AND IT REFUTED HALF MY REASON FOR THE SWAP (2026-07-23, tracking.db 6.3GB over WSL /mnt/c): 794// sys_read_file 525s / 6,184,448KB RSS sys_map_file 694s / 5,394,176KB RSS 795// So mapping is ~32% SLOWER for a FULL scan and only ~13% lighter -- because `tables` counts rows in 796// every table, i.e. it touches essentially every page, so lazy paging buys nothing and page-fault 797// overhead over the 9p mount costs real time. Kept anyway, for two reasons that DO hold: 798// (1) SELECTIVE access (one table, or `get` by key) touches a tiny fraction of pages -- that is where 799// mapping wins, and it is the shape the F942 mine will actually use; 800// (2) PROT_READ makes "never mutate the source DB" true BY CONSTRUCTION (a write faults). 801// If a full-corpus scan ever becomes the hot path, offer read-file as an opt-in flag rather than 802// re-litigating this -- the numbers above are the record. 803func sqr_open(path: *u8, dbbox: *i64, psbox: *i64, usebox: *i64) -> i64 { 804 let lenp: *i64 = sys_mmap(16) as *i64 805 let db: *u8 = sys_map_file(path, lenp) 806 if (db as i64) == 0 { return 0 - 1 } 807 if lenp[0] < 512 { return 0 - 2 } 808 if sqr_be16(db, 0) != SQR_MAGIC_21329 { return 0 - 3 } 809 var ps: i64 = sqr_be16(db, 16) 810 if ps == 1 { ps = SQR_MAGIC_65536 } 811 dbbox[0] = db as i64 812 psbox[0] = ps 813 usebox[0] = ps - (db[20] as i64) 814 return lenp[0] 815} 816func sqr_ctx_new() -> *i64 { 817 let ctx: *i64 = sys_mmap(8 * 40) as *i64 818 var i: i64 = 0 819 while i < 40 { ctx[i] = 0; i = i + 1 } 820 ctx[CX_PAY] = (sys_mmap(SQR_ROWCAP)) as i64 821 ctx[CX_OFFS] = (sys_mmap(8 * SQR_MAXCOL)) as i64 822 ctx[CX_LENS] = (sys_mmap(8 * SQR_MAXCOL)) as i64 823 ctx[CX_TYPS] = (sys_mmap(8 * SQR_MAXCOL)) as i64 824 ctx[CX_NAMB] = (sys_mmap(SQR_NAMES)) as i64 825 ctx[CX_NAMO] = (sys_mmap(8 * SQR_MAXCOL)) as i64 826 ctx[CX_KEYS] = (sys_mmap(8 * SQR_MAXCOL)) as i64 827 ctx[CX_VALS] = (sys_mmap(8 * SQR_MAXCOL)) as i64 828 ctx[CX_AREN] = (sys_mmap(SQR_ARENA)) as i64 829 ctx[CX_REC] = (sys_mmap(SQR_ARENA)) as i64 830 ctx[CX_KBUF] = (sys_mmap(SQR_MAGIC_1024)) as i64 831 ctx[CX_LINE] = (sys_mmap(SQR_LINE)) as i64 832 ctx[CX_CAPP] = (sys_mmap(SQR_MAGIC_1048576)) as i64 833 ctx[CX_ALIA] = 0 - 1 834 return ctx 835} 836 837// ---- selftest ---- 838func sqr_tooth(name: *u8, ok: i64, pass: *i64) -> i64 { 839 sqr_puts(name) 840 if ok == 1 { sqr_puts(": PASS\n" as *u8); pass[0] = pass[0] + 1 } else { sqr_puts(": FAIL\n" as *u8) } 841 return 0 842} 843func sqr_selftest() -> i64 { 844 let pass: *i64 = sys_mmap(16) as *i64 845 pass[0] = 0 846 // deterministic re-runs: drop the T8 scratch plane (data files, never a lock file) 847 let nb0: *u8 = sys_mmap(256) 848 sys_unlinkat("sqrgate-manifest.txt" as *u8) 849 var sg: i64 = 0 850 while sg < 4 { 851 var no: i64 = sqr_cat(nb0, 0, "sqrgate-seg-" as *u8) 852 no = sqr_udec(nb0, no, sg) 853 let base: i64 = no 854 no = sqr_cat(nb0, base, ".docs" as *u8); nb0[no] = 0 as u8; sys_unlinkat(nb0) 855 no = sqr_cat(nb0, base, ".idx" as *u8); nb0[no] = 0 as u8; sys_unlinkat(nb0) 856 no = sqr_cat(nb0, base, ".pos" as *u8); nb0[no] = 0 as u8; sys_unlinkat(nb0) 857 sg = sg + 1 858 } 859 let dbb: *i64 = sys_mmap(16) as *i64 860 let psb: *i64 = sys_mmap(16) as *i64 861 let usb: *i64 = sys_mmap(16) as *i64 862 let fx: *u8 = "sqr_fixture.db" as *u8 863 let sz: i64 = sqr_open(fx, dbb, psb, usb) 864 var t0: i64 = 0 865 if sz > 0 { if psb[0] == SQR_MAGIC_4096 { t0 = 1 } } 866 sqr_tooth("T0 open+magic+pagesize" as *u8, t0, pass) 867 // FAIL LOUD, never SIGSEGV: without the fixture every later tooth would deref a null db 868 // (hit live 2026-07-23 running the gate from a cwd with no fixture -> exit 139). 869 if t0 == 0 { 870 sqr_puts("nx_sqlite_rows selftest T=8 PASS=0 verdict=RED (fixture sqr_fixture.db absent in cwd)\n" as *u8) 871 return 1 872 } 873 let db: *u8 = dbb[0] as *u8 874 let ps: i64 = psb[0] 875 let usable: i64 = usb[0] 876 let sqlbuf: *u8 = sys_mmap(SQR_MAGIC_65536) 877 let sqll: *i64 = sys_mmap(16) as *i64 878 let rootS: i64 = sqr_master_find(db, ps, usable, 1, "t_small" as *u8, sqlbuf, sqll) 879 var t1: i64 = 0 880 if rootS > 0 { if sqll[0] > 10 { t1 = 1 } } 881 sqr_tooth("T1 master_find t_small root+sql" as *u8, t1, pass) 882 // T2 columns parsed + rowid alias detected 883 let ctx: *i64 = sqr_ctx_new() 884 let alias: *i64 = sys_mmap(16) as *i64 885 let nco: i64 = sqr_parse_cols(sqlbuf, sqll[0], ctx[CX_NAMB] as *u8, ctx[CX_NAMO] as *i64, alias) 886 var t2: i64 = 0 887 if nco == 4 { if alias[0] == 0 { 888 let nb: *u8 = ctx[CX_NAMB] as *u8 889 let no: *i64 = ctx[CX_NAMO] as *i64 890 if sqr_eq(((nb as i64) + no[1]) as *u8, "name" as *u8) == 1 { 891 if sqr_eq(((nb as i64) + no[3]) as *u8, "note" as *u8) == 1 { t2 = 1 } 892 } 893 } } 894 sqr_tooth("T2 parse_cols 4 + rowid-alias" as *u8, t2, pass) 895 // T3 count t_small == 3 896 ctx[CX_DB] = db as i64; ctx[CX_PS] = ps; ctx[CX_USE] = usable 897 ctx[CX_MODE] = 0; ctx[CX_ROWS] = 0; ctx[CX_MAX] = 0; ctx[CX_ERR] = 0 898 sqr_walk(ctx, rootS) 899 var t3: i64 = 0 900 if ctx[CX_ROWS] == 3 { if ctx[CX_ERR] == 0 { t3 = 1 } } 901 sqr_tooth("T3 count t_small == 3" as *u8, t3, pass) 902 // T4 count t_many == 1000 (exercises INTERIOR-page recursion) 903 let rootM: i64 = sqr_master_find(db, ps, usable, 1, "t_many" as *u8, sqlbuf, sqll) 904 ctx[CX_MODE] = 0; ctx[CX_ROWS] = 0; ctx[CX_ERR] = 0 905 sqr_walk(ctx, rootM) 906 var t4: i64 = 0 907 if ctx[CX_ROWS] == 1000 { if ctx[CX_ERR] == 0 { t4 = 1 } } 908 sqr_tooth("T4 count t_many == 1000 (interior)" as *u8, t4, pass) 909 // T5 = THE RUNG-2 KEYSTONE: a 20000-byte value spanning OVERFLOW PAGES comes back byte-exact. 910 // Rule-verified (char i == 'a' + i%26) so the tooth cannot drift against a baked constant. 911 ctx[CX_MODE] = 3; ctx[CX_ROWS] = 0; ctx[CX_ERR] = 0; ctx[CX_MAX] = 0 912 ctx[CX_CAPID] = 3; ctx[CX_CAPCOL] = 3; ctx[CX_CAPL] = 0 - 1 913 sqr_walk(ctx, rootS) 914 var t5: i64 = 0 915 if ctx[CX_CAPL] == SQR_MAGIC_20000 { 916 let cb: *u8 = ctx[CX_CAPP] as *u8 917 var bad: i64 = 0 918 var i5: i64 = 0 919 while i5 < SQR_MAGIC_20000 { 920 if (cb[i5] as i64) != (97 + (i5 % 26)) { bad = 1 } 921 i5 = i5 + 1 922 } 923 if bad == 0 { t5 = 1 } 924 } 925 sqr_tooth("T5 OVERFLOW 20000B byte-exact" as *u8, t5, pass) 926 // T6 two's-complement sign extension (qty == -42, stored as a 1-byte int) 927 ctx[CX_MODE] = 3; ctx[CX_ROWS] = 0; ctx[CX_CAPID] = 2; ctx[CX_CAPCOL] = 2; ctx[CX_CAPV] = 0 928 sqr_walk(ctx, rootS) 929 var t6: i64 = 0 930 if ctx[CX_CAPV] == (0 - 42) { t6 = 1 } 931 sqr_tooth("T6 negative int == -42" as *u8, t6, pass) 932 // T7 SQL NULL survives as serial-type 0 (so the plane can omit the field = lossless NULL) 933 ctx[CX_MODE] = 3; ctx[CX_ROWS] = 0; ctx[CX_CAPID] = 1; ctx[CX_CAPCOL] = 3; ctx[CX_CAPT] = 0 - 1 934 sqr_walk(ctx, rootS) 935 var t7: i64 = 0 936 if ctx[CX_CAPT] == 0 { t7 = 1 } 937 sqr_tooth("T7 NULL serial-type 0" as *u8, t7, pass) 938 // T8 PLANE ROUND-TRIP: land t_small, then ss_get it back -- the overflow value must survive 939 // INTO the plane and come back byte-exact, and a NULL column must be ABSENT (lossless NULL). 940 let pfx: *u8 = "sqrgate-" as *u8 941 ctx[CX_MODE] = 2; ctx[CX_ROWS] = 0; ctx[CX_ERR] = 0; ctx[CX_MAX] = 0 942 ctx[CX_NCOL] = nco; ctx[CX_ALIA] = alias[0]; ctx[CX_TAB] = "t_small" as *u8 as i64 943 ctx[CX_PFX] = pfx as i64 // chunk-flush needs the prefix even when it will not fire 944 ctx[CX_W] = (ss_begin_cap(SQR_WCAP)) as i64 945 sqr_walk(ctx, rootS) 946 var t8: i64 = 0 947 if ctx[CX_ERR] == 0 { 948 let wg: *i64 = ctx[CX_W] as *i64 949 if ss_commit(pfx, wg, ss_next_segid(pfx)) == 0 { 950 let po: *i64 = sys_mmap(16) as *i64 951 let lo: *i64 = sys_mmap(16) as *i64 952 if ss_get(pfx, "t_small:3" as *u8, po, lo) == 1 { 953 let fp: *i64 = sys_mmap(16) as *i64 954 let fl: *i64 = sys_mmap(16) as *i64 955 if sqr_rec_field(po[0] as *u8, lo[0], "note" as *u8, fp, fl) == 1 { 956 if fl[0] == SQR_MAGIC_20000 { 957 let nb: *u8 = fp[0] as *u8 958 var bad8: i64 = 0 959 var i8: i64 = 0 960 while i8 < SQR_MAGIC_20000 { 961 if (nb[i8] as i64) != (97 + (i8 % 26)) { bad8 = 1 } 962 i8 = i8 + 1 963 } 964 // NULL note on rowid 1 must be ABSENT from that record 965 if ss_get(pfx, "t_small:1" as *u8, po, lo) == 1 { 966 if sqr_rec_field(po[0] as *u8, lo[0], "note" as *u8, fp, fl) == 0 { 967 if bad8 == 0 { t8 = 1 } 968 } 969 } 970 } 971 } 972 } 973 } 974 } 975 sqr_tooth("T8 plane round-trip 20000B + NULL-absent" as *u8, t8, pass) 976 let vb: *u8 = sys_mmap(256) 977 var vo: i64 = sqr_cat(vb, 0, "nx_sqlite_rows selftest T=9 PASS=" as *u8) 978 vo = sqr_udec(vb, vo, pass[0]) 979 if pass[0] == 9 { vo = sqr_cat(vb, vo, " verdict=GREEN" as *u8) } else { vo = sqr_cat(vb, vo, " verdict=RED" as *u8) } 980 vo = sqr_ch(vb, vo, 10) 981 sys_write(1, vb, vo) 982 if pass[0] == 9 { return 0 } 983 return 1 984} 985 986func main(argc: i64, argv: *i64) -> i64 { 987 if argc < 2 { 988 sqr_puts("usage: nx_sqlite_rows tables <db> | rows <db> <table> [max] | plane <db> <table> <prefix> | selftest\n" as *u8) 989 return 2 990 } 991 let verb: *u8 = (argv[1]) as *u8 992 if sqr_eq(verb, "selftest" as *u8) == 1 { return sqr_selftest() } 993 // get <prefix> <key> -- read one planed record back (a plane you cannot read is not a deliverable) 994 if sqr_eq(verb, "get" as *u8) == 1 { 995 if argc < 4 { sqr_puts("usage: get <prefix> <key>\n" as *u8); return 2 } 996 let po: *i64 = sys_mmap(16) as *i64 997 let lo: *i64 = sys_mmap(16) as *i64 998 let rc: i64 = ss_get((argv[2]) as *u8, (argv[3]) as *u8, po, lo) 999 if rc < 0 { sqr_puts("NX-SQR NO-SUCH-KEY\n" as *u8); return 4 } 1000 if rc == 0 { sqr_puts("NX-SQR TOMBSTONED\n" as *u8); return 0 } 1001 sqr_rec_dump(po[0] as *u8, lo[0]) 1002 return 0 1003 } 1004 if argc < 3 { sqr_puts("missing <db>\n" as *u8); return 2 } 1005 let path: *u8 = (argv[2]) as *u8 1006 let dbb: *i64 = sys_mmap(16) as *i64 1007 let psb: *i64 = sys_mmap(16) as *i64 1008 let usb: *i64 = sys_mmap(16) as *i64 1009 let sz: i64 = sqr_open(path, dbb, psb, usb) 1010 if sz < 0 { sqr_puts("NX-SQR OPEN-FAIL (unreadable or not a sqlite file)\n" as *u8); return 3 } 1011 let db: *u8 = dbb[0] as *u8 1012 let ps: i64 = psb[0] 1013 let usable: i64 = usb[0] 1014 let ctx: *i64 = sqr_ctx_new() 1015 ctx[CX_DB] = db as i64; ctx[CX_PS] = ps; ctx[CX_USE] = usable 1016 let sqlbuf: *u8 = sys_mmap(SQR_MAGIC_65536) 1017 let sqll: *i64 = sys_mmap(16) as *i64 1018 if sqr_eq(verb, "tables" as *u8) == 1 { 1019 let names: *u8 = sys_mmap(SQR_NAMES) 1020 let noff: *i64 = sys_mmap(8 * SQR_MAGIC_4096) as *i64 1021 let roots: *i64 = sys_mmap(8 * SQR_MAGIC_4096) as *i64 1022 let cnt: *i64 = sys_mmap(16) as *i64 1023 let npos: *i64 = sys_mmap(16) as *i64 1024 cnt[0] = 0; npos[0] = 0 1025 sqr_master_list(db, ps, usable, 1, names, npos, noff, roots, cnt) 1026 let line: *u8 = sys_mmap(SQR_MAGIC_4096) 1027 var i: i64 = 0 1028 while i < cnt[0] { 1029 ctx[CX_MODE] = 0; ctx[CX_ROWS] = 0; ctx[CX_MAX] = 0; ctx[CX_ERR] = 0 1030 if roots[i] > 0 { sqr_walk(ctx, roots[i]) } 1031 var o: i64 = sqr_cat(line, 0, ((names as i64) + noff[i]) as *u8) 1032 o = sqr_ch(line, o, 9) 1033 o = sqr_udec(line, o, roots[i]) 1034 o = sqr_ch(line, o, 9) 1035 o = sqr_udec(line, o, ctx[CX_ROWS]) 1036 o = sqr_ch(line, o, 10) 1037 sys_write(1, line, o) 1038 i = i + 1 1039 } 1040 return 0 1041 } 1042 if argc < 4 { sqr_puts("missing <table>\n" as *u8); return 2 } 1043 let table: *u8 = (argv[3]) as *u8 1044 let root: i64 = sqr_master_find(db, ps, usable, 1, table, sqlbuf, sqll) 1045 if root <= 0 { sqr_puts("NX-SQR NO-SUCH-TABLE\n" as *u8); return 4 } 1046 let alias: *i64 = sys_mmap(16) as *i64 1047 let nco: i64 = sqr_parse_cols(sqlbuf, sqll[0], ctx[CX_NAMB] as *u8, ctx[CX_NAMO] as *i64, alias) 1048 ctx[CX_NCOL] = nco 1049 ctx[CX_ALIA] = alias[0] 1050 ctx[CX_TAB] = table as i64 1051 if sqr_eq(verb, "rows" as *u8) == 1 { 1052 ctx[CX_MODE] = 1 1053 if argc >= 5 { 1054 var mx: i64 = 0 1055 let a4: *u8 = (argv[4]) as *u8 1056 var k: i64 = 0 1057 while a4[k] != (0 as u8) { mx = mx * 10 + ((a4[k] as i64) - 48); k = k + 1 } 1058 ctx[CX_MAX] = mx 1059 } 1060 sqr_walk(ctx, root) 1061 return 0 1062 } 1063 if sqr_eq(verb, "plane" as *u8) == 1 { 1064 if argc < 5 { sqr_puts("missing <prefix>\n" as *u8); return 2 } 1065 let prefix: *u8 = (argv[4]) as *u8 1066 ctx[CX_MODE] = 2 1067 ctx[CX_PFX] = prefix as i64 1068 if argc >= 6 { ctx[CX_SKIP] = sqr_atoi((argv[5]) as *u8) } 1069 if argc >= 7 { ctx[CX_MAX] = sqr_atoi((argv[6]) as *u8) } 1070 ctx[CX_W] = (ss_begin_cap(SQR_WCAP)) as i64 1071 sqr_walk(ctx, root) 1072 if ctx[CX_ERR] != 0 { sqr_puts("NX-SQR PLANE-ABORT (walk error, nothing committed)\n" as *u8); return 5 } 1073 // meta record: only on a FULL run -- a ranged slice must never overwrite <table>:meta with 1074 // partial counts (the driver logs slice counts instead). Declared, not silent. 1075 var fullrun: i64 = 0 1076 if ctx[CX_SKIP] == 0 { if ctx[CX_MAX] == 0 { fullrun = 1 } } 1077 let keys: *i64 = ctx[CX_KEYS] as *i64 1078 let vals: *i64 = ctx[CX_VALS] as *i64 1079 let arena: *u8 = ctx[CX_AREN] as *u8 1080 var ap: i64 = 0 1081 let v0: i64 = ap; ap = sqr_udec(arena, ap, ctx[CX_ROWS]); arena[ap] = 0 as u8; ap = ap + 1 1082 let v1: i64 = ap; ap = sqr_udec(arena, ap, nco); arena[ap] = 0 as u8; ap = ap + 1 1083 let v2: i64 = ap; ap = sqr_udec(arena, ap, ctx[CX_MINR]); arena[ap] = 0 as u8; ap = ap + 1 1084 let v3: i64 = ap; ap = sqr_udec(arena, ap, ctx[CX_MAXR]); arena[ap] = 0 as u8; ap = ap + 1 1085 keys[0] = "rows" as *u8 as i64; vals[0] = (arena as i64) + v0 1086 keys[1] = "cols" as *u8 as i64; vals[1] = (arena as i64) + v1 1087 keys[2] = "minrow" as *u8 as i64; vals[2] = (arena as i64) + v2 1088 keys[3] = "maxrow" as *u8 as i64; vals[3] = (arena as i64) + v3 1089 let rec: *u8 = ctx[CX_REC] as *u8 1090 let rl: i64 = canon_encode(keys, vals, 4, rec) 1091 let kbuf: *u8 = ctx[CX_KBUF] as *u8 1092 var ko: i64 = sqr_cat(kbuf, 0, table) 1093 ko = sqr_cat(kbuf, ko, ":meta" as *u8) 1094 kbuf[ko] = 0 as u8 1095 let w: *i64 = ctx[CX_W] as *i64 1096 if fullrun == 1 { if ss_add(w, 1, kbuf, rec, rl) < 0 { sqr_puts("NX-SQR META-ADD-FAIL\n" as *u8); return 6 } } 1097 let segid: i64 = ss_next_segid(prefix) 1098 if ss_commit(prefix, w, segid) != 0 { sqr_puts("NX-SQR COMMIT-FAIL\n" as *u8); return 7 } 1099 let line: *u8 = sys_mmap(SQR_MAGIC_1024) 1100 var o: i64 = sqr_cat(line, 0, "NX-SQR PLANED table=" as *u8) 1101 o = sqr_cat(line, o, table) 1102 o = sqr_cat(line, o, " rows=" as *u8); o = sqr_udec(line, o, ctx[CX_ROWS]) 1103 o = sqr_cat(line, o, " cols=" as *u8); o = sqr_udec(line, o, nco) 1104 o = sqr_cat(line, o, " segs=" as *u8); o = sqr_udec(line, o, ctx[CX_SEGN] + 1) 1105 o = sqr_cat(line, o, " lastseg=" as *u8); o = sqr_udec(line, o, segid) 1106 o = sqr_ch(line, o, 10) 1107 sys_write(1, line, o) 1108 return 0 1109 } 1110 sqr_puts("unknown verb\n" as *u8) 1111 return 2 1112}