Skip to content

Sandbox SQL coverage

What the in-memory sandbox runs: statements parse via pg_query_go, and a shape the sandbox doesn't model is rejected as unsupported.

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 BY and ORDER BY inside OVER are 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:

  • JOIN of 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.
  • WINDOW clauses other than COUNT(*) OVER ().
  • FETCH ... WITH TIES.
  • FOR UPDATE, FOR SHARE, locking clauses generally.

Statement modifiers:

  • RETURNING on UPDATE or DELETE.
  • USING on DELETE; FROM on UPDATE.
  • ON CONFLICT ON CONSTRAINT (use the column list form).
  • Multi-row INSERT VALUES.

Expressions and predicates:

  • NOT predicates.
  • Function calls other than the recognised special-cases (COALESCE, now()).
  • Boolean literals (TRUE / FALSE).
  • Bare NULL literals.

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 inputsandbox 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. Foo becomes foo.
  • Schema qualification — the catalog keys tables by schema.name. Entities declared with a table "schema.name" override use the override; otherwise the catalog key is atlantis.<namespace>_<entity> (codegen’s canonical form).
Navigation

Type to search…

↑↓ navigate↵ selectEsc close