public final class TrialInputGuard extends Object
TBaseType.trialSizeLimitBytes()
bytes.String input has no wire format, so it is measured in
CHARACTERS, ignoring leading whitespace: at most the same limit.String to a fresh parser, which measures it
again. Every earlier revision of this gate therefore needed a way to tell
"caller ingestion" from "internal re-parse" (explicit marks, then a
ThreadLocal parse depth), and every such mechanism was itself a source of
defects: a missed mark refused a valid 8,118-byte DB2 procedure; a
UTF-16 function accepted at 6,968 raw bytes had its 10,283-UTF-8-byte body
silently dropped.
Measuring Strings in characters removes the problem instead of managing
it. Every charset encodes a character in at least one byte, so an input
accepted under the byte cap has at most limit characters -- and any
substring of it fewer still. Every internal re-parse of ingested text
therefore passes arithmetically, with no marks, no thread state, and no list
of sites to keep complete. Leading whitespace is ignored because internal
re-parses prepend newlines/spaces to preserve the original line/column
coordinates (TBaseType.stringBlock), and that padding is not input.
The tolerated cost runs in the harmless direction only: a caller-supplied String of multi-byte characters (e.g. 10,000 CJK characters, ~30KB as UTF-8) is accepted in a trial build. An oversized input slipping through a trial gate is a far smaller cost than a valid input being refused and its parse silently lost (owner decision 2026-07-28).
UnsupportedOperationException; a BOM stripped before counting let a
10,001-byte stream through; a cached lexer kept the previous input's charset
and refused a valid 6,000-byte ASCII input. All of those are the same
mistake. This class measures a byte source as it actually exists -- bytes,
before any decoding -- so none of them can recur.
cap + 1 bytes. Reaching cap + 1 means the input is over
the cap and is refused; otherwise the snapshot IS the whole input and
downstream consumes it, so the source is never read twice.IOException while measuring is reported as an I/O failure,
never as an accepted short input. A partial read that then fails must
not look like a small legal input.Every method is a no-op in full builds, where TBaseType.full_edition
is a compile-time constant and the guarded blocks are removed entirely.
| Modifier and Type | Class and Description |
|---|---|
static class |
TrialInputGuard.Result
Outcome of measuring one input: allowed (optionally carrying the snapshot
that downstream must consume in place of the original source), refused, or
failed with I/O.
|
| Modifier and Type | Method and Description |
|---|---|
static TrialInputGuard.Result |
checkStream(InputStream source)
Measure a byte-backed source by reading at most
cap + 1 bytes. |
static TrialInputGuard.Result |
checkText(String sqlText)
Measure a
String input in characters, ignoring leading
whitespace. |
static boolean |
tokenTextExceedsCap(TSourceTokenList tokens)
Measure caller-supplied token text -- the one input with no source to read,
reachable through
doExtractRawStatements. |
public static TrialInputGuard.Result checkText(String sqlText)
String input in characters, ignoring leading
whitespace. Returns refused when the count exceeds the cap. Never
consumes anything, and never re-encodes: characters, not bytes, are what
keep internal re-parses of already-ingested text inside the cap (see the
class comment).public static TrialInputGuard.Result checkStream(InputStream source)
cap + 1 bytes.
On success the returned snapshot holds the ENTIRE input and the caller
must use it instead of source, which is now at EOF. File length is
deliberately NOT consulted: a file can change between a stat and a read,
and reading the same stream that feeds decoding removes that race along
with any disagreement between the two.
public static boolean tokenTextExceedsCap(TSourceTokenList tokens)
doExtractRawStatements. Counted in characters
like any other String input; the running total lets a huge token list
fail fast without joining it.