What the in-memory sandbox runs. Statements are parsed by pg_query_go,
the Postgres parser packaged for Go, so every Postgres syntactic construct
parses; a statement whose shape the sandbox doesn’t model is then rejected
with sandbox sql: unsupported: <feature> — whether the rejection happens
while converting the parse tree or while executing.
For the Postgres backend, this page does not apply — that backend runs full Postgres. See the sandbox concept page for the split.
Accepted statements
The executor accepts four top-level statement kinds: SELECT, INSERT, UPDATE, DELETE. Input is one statement per call; multi-statement input (SELECT 1; SELECT 2) is rejected.
SELECT
SELECT proj [, proj ...]
[ FROM "schema"."table" ]
[ WHERE pred ]
[ ORDER BY col [ASC|DESC] [NULLS FIRST|LAST] [, ...] ]
[ LIMIT { $N | int_literal } ]
[ OFFSET { $N | int_literal } ]A projection is one of:
- A bare column reference:
"col". *— expanded against the catalog into one bare-column projection per declared column, in declared order.t.*(qualified star) is accepted and treated the same.- An expression with a required alias:
expr AS alias. The supported expressions are vector distance (col <=> $N::vector) and JSON extract (col -> 'k' -> 'k' ->> 'k'). - The window-total form
COUNT(*) OVER () AS alias. Only this one window shape is supported;PARTITION BYandORDER BYinsideOVERare rejected.
A FROM clause is optional. SELECT 1 and SELECT now() (no FROM) evaluate the projection once and return one row.
INSERT
INSERT INTO "schema"."table" (col [, col ...])
VALUES (expr [, expr ...])
[ ON CONFLICT (col [, col ...])
( DO NOTHING | DO UPDATE SET col = expr [, ...] ) ]
[ RETURNING col [, col ...] ]ON CONFLICT ON CONSTRAINT name is rejected (use the inline column list). Multi-row INSERT (VALUES (a), (b)) is rejected — codegen-emitted writes never produce it.
The ON CONFLICT DO UPDATE SET clause may reference the proposed row’s columns via EXCLUDED.col. EXCLUDED is detected case-insensitively.
UPDATE
UPDATE "schema"."table"
SET col = expr [, col = expr ...]
[ WHERE pred ]UPDATE ... FROM and UPDATE ... RETURNING are not supported.
DELETE
DELETE FROM "schema"."table"
[ WHERE pred ]DELETE ... USING and DELETE ... RETURNING are not supported.
Predicates
pred covers single-column comparison, null tests, ANY-membership, JSON-extract comparison, and grouped boolean expressions:
| Shape | Notes |
|---|---|
col = expr |
Also <, <=, >, >=, <>, !=. |
col IS [NOT] NULL |
|
col = ANY ($N) |
RHS must be $N; the bound value is a Go slice ([]int64, []string, etc.). |
col -> 'k' ->> 'k' = expr |
JSON extract chain; the final operator decides whether the comparison runs against text or subtree. |
( pred AND pred ... ) |
Top-level AND chains flatten into a flat list of predicates. |
( pred OR pred ... ) |
Wrapped in an OR group. |
NOT (pred) is not supported.
Expressions
Expressions appear in INSERT values, UPDATE SET, the right side of comparisons, projections-with-alias, and ORDER BY:
| Shape | Notes |
|---|---|
$N |
Placeholder. Position is 1-indexed. |
'string' |
String literal. |
123 / -123 |
Integer literal. Other literal kinds (boolean, NULL, float) are not supported. |
now() |
The clock. Returns the simulator’s configured clock when Deterministic is on, otherwise wall-time. |
COALESCE($N::type, default) |
Two-argument only. The type cast on the first argument is parsed but discarded; the executor relies on Go-side typing. |
EXCLUDED.col |
Only inside ON CONFLICT DO UPDATE SET. |
col -> 'k' ->> 'k' |
JSON extract chain, in projection or ORDER BY position. The final operator determines whether the result is text or a subtree. |
col <=> $N::vector |
Vector distance. Operators: <=> cosine, <-> L2, <#> inner product. PG 17’s <+> hamming is parsed but rejected. |
$N::type |
Type cast. Discarded — Go-side bind values are already typed. |
What is not supported
Every shape below is rejected with sandbox sql: unsupported: <feature>.
FROM clause:
JOINof any kind. Single-table FROM only.- Multi-table
FROM "a", "b". - Subqueries in FROM (
FROM (SELECT ...) sub). - Table aliases (
FROM "t" AS "x").
A table-qualified column reference ("t"."col") is accepted, with only the trailing col honoured.
Clauses:
WITH/WITH RECURSIVE(CTEs).GROUP BY,HAVING.UNION,INTERSECT,EXCEPT.WINDOWclauses other thanCOUNT(*) OVER ().FETCH ... WITH TIES.FOR UPDATE,FOR SHARE, locking clauses generally.
Statement modifiers:
RETURNINGon UPDATE or DELETE.USINGon DELETE;FROMon UPDATE.- ON CONFLICT
ON CONSTRAINT(use the column list form). - Multi-row INSERT VALUES.
Expressions and predicates:
NOTpredicates.- Function calls other than the recognised special-cases (
COALESCE,now()). - Boolean literals (
TRUE/FALSE). - Bare
NULLliterals.
Errors
Rejections carry the prefix sandbox sql: unsupported — unsupported shapes and SQL that does not parse alike. A catalog miss reports as sandbox: unknown table without the prefix. The prefix is not a reliable “not at runtime” signal: some execution-time rejections, such as an unimplemented function call, carry it too.
Behavioural pins
- Empty input (
"", whitespace-only, comment-only) —sandbox sql: unsupported: empty SQL. - Multi-statement input —
sandbox sql: unsupported: multiple statements. - Trailing semicolons — accepted, treated as the statement terminator.
- Leading or interleaved comments (
--,/* */) — parsed and skipped. - Quoted identifiers — case preserved.
"Foo"is distinct from"foo". - Unquoted identifiers — lowercased by the parser, matching PG behaviour.
Foobecomesfoo. - Schema qualification — the catalog keys tables by
schema.name. Entities declared with atable "schema.name"override use the override; otherwise the catalog key isatlantis.<namespace>_<entity>(codegen’s canonical form).
Related
- The sandbox — backend split, state model.
- Sandbox HTTP API — programmatic surface.
- Use the sandbox — console walkthrough.
- The typed query surface — generated code’s predicate tree, separate from the sandbox SQL surface.