1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//! inillucent's command surface: the shell, the command table, and what reads them.
//!
//! Invariant: **there is one command table and every front end reads it.**
//! A verb-shaped `inillucent` binary and an MCP server were added beside
//! the `sqlite3`-shaped shell that was already here, and the reason all three
//! live in one crate is that the alternative - a second list of commands, kept
//! in step by whoever remembers - is the failure mode `drivers/README.md`
//! describes for `java.sql.DatabaseMetaData`: a list nobody runs decays into a
//! list of claims that were true once.
//!
//! So [`command::COMMANDS`] is the table, [`command::run`] executes an entry,
//! and the three binaries are adapters over it:
//!
//! | binary | what it is |
//! |---|---|
//! | `inillucent-shell` | the `sqlite3`-shaped REPL. Unchanged by this ticket. |
//! | `inillucent` | the verbs, for a script and for a person who is not in a REPL. |
//! | `inillucent-mcp` | the same verbs as MCP tools, for an agent. |
//!
//! The layer below all of them is [`shell::Shell`], which is itself an adapter:
//! every statement it runs goes through the public `inillucent` facade and it
//! never reaches past it. The command table does not reach past the shell for
//! the same reason - a third path to the same data is a third set of answers,
//! and the difference is only ever found by somebody who trusted one of them.
// **`deny` rather than `forbid`, for one file (task-1932, H11).**
// `interrupt.rs` installs a console control handler so that Ctrl+C stops a
// statement rather than the process, and there is no way to be told about
// Ctrl+C in the standard library: both platforms offer one FFI call. Every
// other file in this crate is still refused the word, `interrupt.rs` is
// named in `policy.rs`'s `UNSAFE_ALLOWED`, and both of its `unsafe` blocks
// carry their own SAFETY note.
/// How much stack a statement is given, in bytes.
///
/// **A statement the parser accepts must not overflow any later stage
/// (task-1979, section 5.3).** `SELECT abs(abs(...(1)...))` 300 deep ended the
/// process with `thread 'main' has overflowed its stack` and exit code
/// 0xC00000FD, in debug and in release, on the command line and on the MCP
/// server - where it ends the server for every client. The declared limits are
/// SQLite's own, `ExprDepth` 1000 and `ParserDepth` 2500, and the binaries
/// carry a 1 MiB stack reserve read from the PE header, so the limit could
/// never be the thing that fired.
///
/// **Measured on this build rather than guessed.** Nesting `abs()` on the
/// default 1 MiB main thread overflows between 34 and 38 levels in a debug
/// build, so one level of parse, bind, plan and execute costs about 29 KiB
/// there - the deepest and most expensive of the two builds, which is the one
/// to size against. `ExprDepth` at 1000 therefore needs about 29 MiB, and 64
/// MiB is that with a margin of more than two.
///
/// **Reserved, not spent.** A thread's stack is reserved address space that
/// the operating system commits a page at a time as it is used, on Windows and
/// on Linux alike, so a program that never writes a deep expression pays for
/// none of this. Raising the *limits* instead would move the crash rather than
/// remove it, which is why the stack is sized to the limit and not the other
/// way round.
pub const STATEMENT_STACK: usize = 64 << 20;
/// Runs a program's whole body on a thread with [`STATEMENT_STACK`] bytes of
/// stack, and returns what it produced.
///
/// **The whole body rather than one request**, because the engine is `!Send`:
/// a `Database` holds `Rc`s and cannot be moved to a thread once it exists, so
/// the thread is taken first and the database is opened on it. What that buys
/// is the same thing per-request threads would: the depth limits are against a
/// stack this crate chose rather than against whatever the linker's default
/// reserve happened to be.
///
/// **A plain function rather than a closure**, so that a machine which cannot
/// start a thread can still run the body where it is - `Builder::spawn`
/// consumes a closure whether or not it succeeds, and a function pointer is
/// `Copy`. The three programs that call this each hand it their own `run`.
///
/// @param body - what to run
// The one module allowed the word, and only for the two calls that install a
// console control handler. See its own header.