/**
* The SQLite limits a Durable Object enforces and node does not (#1741).
*
* A vertical's `ctx.sql` runs on `better-sqlite3` in every local suite and on a Durable
* Object's SQLite when it is deployed, and the DO's build sets several limits far below
* stock SQLite's. A statement over one passed every node suite and failed only on a
* deployed scope — `customer/get` in an adopter vertical counted rows with a 29-term
* `UNION ALL` and broke on the first hosted call. #1655 closed the same gap for a `LIKE`
* pattern (`tools/vitest/like-pattern-limit.cjs`, which has to patch the driver because
* `better-sqlite3` exposes no `sqlite3_limit`). Three of the four limits below can be judged
* from the statement text, so the adapter judges them itself, and a vertical's OWN suite sees
* what a Durable Object sees. The pattern limit cannot: a pattern is often built at run time,
* and judging it exactly means replacing `like()` on every connection, a JavaScript call per
* row that also switches off SQLite's `LIKE` prefix index optimisation. That cost is fine in a
* test preload and not in an adapter self-hosters run, so it stays a preload's job — published
* as `@substrat-run/adapter-sqlite/testing` (#1770), on by default in the scaffold, so a
* vertical opts in the same way for the one limit the adapter itself cannot judge.
*
* The values are MEASURED, not read from documentation:
* `packages/adapter-cloudflare/test/do-sql-limits.test.ts` drives a real Durable Object's
* SQL to each limit and pins the value and the refusal message it gave. If workerd moves
* one, that test goes red first.
*
* | limit | value | DO's refusal |
* |-------------------------------|----------------|-----------------------------------------------------|
* | terms in one compound SELECT | 5 | `too many terms in compound SELECT` |
* | bound parameters | 100 | `too many SQL variables at offset N` |
* | statement length | 100 000 bytes | `statement too long` (`SQLITE_TOOBIG`) |
* | `LIKE`/`GLOB` pattern length | 50 bytes | `LIKE or GLOB pattern too complex` (not judged here: preload only) |
* | columns in a table | 100 | `too many columns on
` |
* | columns in a result set | 100 | `too many columns in result set` |
*
* A TABLE's width cannot be judged from the text — a `SELECT *` is as wide as the tables under it,
* and a table is as wide as its migrations left it — so the node adapter reads it from the
* schema AFTER a migration or runtime DDL ran (#1811). A result set is judged twice: the
* outermost width from the driver's prepared statement (which sees a `*`), and every select
* core's WRITTEN columns from the text, because the limit is on every core and the driver
* reports only the outermost (`SELECT c0 FROM (SELECT 0, …, 100)` is refused hosted). What
* neither sees is a `*` inside an inner SELECT: that gap is documented, not judged.
*
* What is NOT a limit, measured: a multi-row `VALUES` list — SQLite does not count its rows
* as compound terms; 5 000 rows ran on the DO. So `INSERT … VALUES (…),(…),…` is bounded by
* the parameter count and the statement length only.
*
* Judged here, from the text, exactly as SQLite counts:
* - **compound terms** — `UNION`, `UNION ALL`, `INTERSECT` and `EXCEPT` at one parenthesis
* level chain their operands into one compound; the limit is on the operands (operators + 1).
* A subquery, a CTE body and a view body each start their own count.
* - **bound parameters** — SQLite's own numbering: each `?` takes the next number, `?N`
* takes N, a `:name`/`@name`/`$name` takes the next number the first time it is seen. The
* limit is on the highest number, not on how many are written or how many are bound.
* - **statement length** — the whole string the caller passed, in UTF-8 bytes (a multi-
* statement string counts once, as on the DO).
*
* The messages are the DO's own, suffix included, so a suite that matches on one matches
* both adapters. Only MODULE-facing SQL is wrapped: platform-internal statements are the
* platform's own responsibility, and they already run on a real DO in the workerd suites.
*/
import type { ScopedSql } from './scope-host.js';
/** The limits a Durable Object's SQLite enforces — measured, see the file header. */
export declare const DO_SQL_LIMITS: {
/** Terms (operands) in one compound `SELECT`. */
readonly compoundTerms: 5;
/** Bound parameters — the highest parameter number — in one statement. */
readonly boundParameters: 100;
/** Statement length, in UTF-8 bytes, of the whole string handed to `sql.exec`. */
readonly statementBytes: 100000;
/** `LIKE`/`GLOB` pattern length, in UTF-8 bytes. Enforced by `tools/vitest/like-pattern-limit.cjs`. */
readonly likePatternBytes: 50;
/** Columns in one table, and in one result set. Measured by a 1–2001 binary search on workerd (#1811). */
readonly columns: 100;
};
/**
* Refuse a statement a Durable Object's SQLite would refuse for its length, its compound
* `SELECT` terms, or its bound parameters. Throws the DO's own message.
*
* Not in the kernel's index, but exported from this module on purpose:
* `tools/vitest/sql-limits.cjs` requires `dist/sql-limits.js` by file path to judge every
* statement a node suite prepares, so dropping this `export` would break that preload.
*/
export declare function assertWithinSqlLimits(sql: string): void;
/**
* The refusal of a result set wider than `DO_SQL_LIMITS.columns`: the DO's own words, then what
* the DO does not say. (A DO names a table it refuses `sqlite_altertab_` for an `ADD COLUMN`,
* so the two adapters do not share the table message exactly; a suite matches its prefix.)
*/
export declare const tooManyResultColumns: (width: number) => string;
/** The refusal of a table wider than `DO_SQL_LIMITS.columns`, counted as the DO counts. */
export declare const tooManyTableColumns: (table: string, width: number) => string;
/**
* Wrap a module-facing `ScopedSql` so every statement passes `assertWithinSqlLimits` first.
* The node adapter wraps `ctx.sql` in it; the DO needs no wrapper — its SQLite is the
* source of these limits.
*/
export declare function guardSqlLimits(inner: ScopedSql): ScopedSql;
//# sourceMappingURL=sql-limits.d.ts.map