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}