Skip to main content

trino-sql-validator

Fast Trino SQL syntax validator — a Python library whose core is written in Rust and compiled to a native extension via PyO3 + maturin.

Installable from PyPI:

pip install trino-sql-validator

Quickstart

from trino_sql_validator import analyze_statements, validate, validate_file

# A string with one or many statements
result = validate("SELECT 1; SELECT * FROM t WHERE a > 0;")
assert result.valid
assert result.statement_count == 2

# Invalid SQL returns a value, never raises
result = validate("SELECT * FORM t")
assert not result.valid
print(result.error)          # e.g. "Expected: end of statement, found: FORM at line 1, column 10"
print(result.error.line)     # 1

# Validate a file
result = validate_file("queries.sql", dialect="trino")

# Opt-in per-statement metadata; indexes are zero-based
analysis = analyze_statements("EXPLAIN SELECT 1; CALL system.custom_proc()")
assert analysis.validation.valid
assert analysis.statements[0].kind == "explain"
assert analysis.statements[0].inner_kind == "query"
assert analysis.statements[1].kind == "call"

Invalid SQL (and files containing it) is returned as a ValidationResult; it is not raised as an exception. Only genuine misuse (unknown dialect, unreadable file) raises.

Advisory warnings

For dialect="trino", validate() also checks that every function called and every data type used in the SQL exists in the documented Trino catalog. Unknown names are reported as non-fatal warnings — valid stays True because syntax is fine:

result = validate("SELECT marh(1.5)")       # round() misspelled
assert result.valid
print(result.warnings)                      # (FunctionWarning(name='marh', line=1, column=8),)
print(result.unknown_functions)             # ['marh']

result = validate("CREATE TABLE t (a bignum, b bigint)")  # bigint vs bignum
print(result.warnings[0])                   # TypeWarning(name='bignum', line=1, column=19)
print(result.unknown_types)                 # ['bignum']

result = validate("SELECT sum() OVER ()")
assert not result.valid
print(result.function_argument_warnings[0]) # sum expects 1 argument; got 0

result = validate("SELECT min(), max(1, 2, 3)")
assert not result.valid
assert len(result.function_argument_warnings) == 2

# A single call returns the first error AND all diagnostics
result = validate("SELECT sum(); SELECT min()")
assert not result.valid
print(result.error)                         # first error: sum()
print(result.function_argument_warnings)    # both sum() and min()

# Opt into the advisory behavior from 0.22.0 if needed
assert validate("SELECT sum()", function_arguments="warn").valid

# Preserve the syntax-only behavior from versions through 0.21.x
assert validate("SELECT sum()", function_arguments="off").valid

The contextual words ALL, OVER, PARTITION, RETURN, and AT are valid non-reserved Trino identifiers, but are easy to confuse with surrounding SQL syntax. Using one as an alias therefore produces a non-fatal AliasWarning; quote the alias to make the identifier intent explicit and suppress the warning:

result = validate("SELECT orderdate AS At")
assert result.valid
print(result.warnings[0])                   # ambiguous unquoted alias 'at' at line 1, column 21
print(result.ambiguous_aliases)             # ['at']

assert validate('SELECT orderdate AS "At"').warnings == ()

AT is also used by the temporal operators AT TIME ZONE and AT LOCAL. Those operator forms do not produce alias warnings.

Trino's 83 reserved keywords are stricter: an unquoted reserved alias is a syntax error, including after an explicit AS. Double quotes turn the word into a valid delimited identifier in aliases, object names, and column references; single quotes do not:

assert not validate("SELECT 1 AS where").valid
assert validate('SELECT 1 AS "where"').valid

assert validate('CREATE TABLE dwh_team."FROM" AS SELECT 1 AS "ALTER"').valid
assert validate(
    'SELECT "FROM"."ALTER" FROM dwh_team."FROM" AS "FROM"'
).valid

The catalogs are auto-generated from the Trino docs and check name existence. Version 0.22.0 additionally checks documented argument counts for 45 unqualified built-in aggregate functions, including sum, avg, min, max, min_by, max_by, statistical aggregates, map aggregates, and digest aggregates. Since 0.23.0, ordinary validate(sql) defaults to function_arguments="error": a mismatch makes the result invalid and preserves all diagnostics in warnings. error reports the first argument-count error; function_argument_warnings lists all of them. "warn" and "off" remain explicit options for advisory and syntax-only behavior. This is a curated rule rather than general overload resolution: argument types, functions outside the registry, precision/scale, and semantic correctness still require Trino. hive/generic dialects skip these checks. False positives are possible if a deployed Trino adds plugin functions/types beyond the docs.

Unknown names and ambiguous aliases remain advisory on their own. When parsing fails, no complete AST is available and warnings is empty. For compatibility, any invalid result has statement_count=0; analyze_statements() still exposes the source-derived statement list and the first error's statement index.

For catalog name checking, inline WITH FUNCTION names are exempt only within their own query scope, while qualified calls with the same final name are still checked. The argument-count rule is narrower and skips qualified calls because it does not perform name resolution. Procedure names in CALL and ALTER TABLE ... EXECUTE are not scalar functions and therefore do not produce FunctionWarning; their existence, parameters, arity, permissions, and connector availability require a Trino coordinator and are out of scope.

Statement metadata

analyze_statements() is an opt-in API that returns the unchanged ValidationResult together with a tuple of StatementInfo. Each entry contains a zero-based index, source span, source-derived kind, and (for EXPLAIN or PREPARE) an inner_kind when it can be identified. On invalid multi-statement input, error_statement_index identifies the source statement when the parser provided a location. Existing validate() and validate_file() return types are unchanged.

dbt and Jinja templates

Jinja/dbt SQL is supported by default. validate() and validate_file() use jinja="auto" to mask Jinja expressions, statements, and comments before parsing while preserving line numbers and file structure. This supports constructs such as {{ ref("orders") }} and {{ var("catalog") }} without requiring a dbt installation or project context. Use jinja="mask" as an explicit spelling of the same mode.

Use jinja="reject" to pass the original template directly to the SQL parser. Masking cannot determine SQL generated by control-flow blocks, macros, or adapter semantics; render those cases with dbt and validate the rendered SQL for complete coverage. If masking changes the input, function argument-count diagnostics are disabled to avoid inferring arity from an unrendered template.

Dialects

  • "trino" (default) — Trino-flavored with a custom override tuned for current Trino syntax, including Iceberg branches/time travel, complex nested types, routines, table functions, SQL/JSON, and Trino-specific DDL.
  • "hive" and "generic" — offered as permissive alternates.

Known limitations

sqlparser-rs (the parser we use) performs syntax validation, not semantic analysis. It may accept SQL that Trino would reject at analysis time (unknown columns/tables, duplicate columns), and it can reject exotic Trino-specific DDL. The validator has targeted compatibility parsing for documented Trino syntax, including nested ROW/ARRAY/MAP types, but it does not replace Trino's semantic analyzer. See plan/roadmap.md for the path toward stricter Trino fidelity.

Parser fidelity is checked reproducibly against direct-string cases extracted from Apache Trino's parser tests. With ordinary Java strings and text blocks, the pinned Trino 483 audit currently accepts 484/484 statements, 238/238 expressions, 68/68 types, the extracted Functions/Routines subset, and rejects 23/23 direct negative statements. The remaining error-suite differences are documented semantic or wrapper-boundary exceptions. Exact source and corpus hashes make changed, missing, or stale baseline cases fail the audit. These figures and the 553 independently checked positive fixture statements describe measured corpora, not complete Trino grammar or connector behavior. SQL embedded inside ordinary string literals, JSON paths, WKT, dynamic SQL, and unrendered macro output is intentionally opaque rather than recursively parsed.

An optional offline differential audit compares the same fixtures and Trino 483 corpus with pinned SQLGlot 30.19.0. SQLGlot is neither a runtime dependency nor an alternative validity backend; its full-AST, Command fallback, and error outcomes are tracked separately to identify candidates for native improvements.

The native Trino SqlParser oracle and grammar inventory are development tools, not parser backends. Importing or using the package never starts Java, Maven, SQLGlot, Docker, or a subprocess. The reproducible oracle uses JDK 25 and records the input, preparation, Java runtime, harness, class, and dependency-JAR hashes for every run. Its current corpus contains 1,040 independently labelled inputs. The grammar inventory fingerprints Trino's grammar, SqlParser, embedded PostProcessor, and AstBuilder; it records all 144 parser rules and 708 top-level alternatives without claiming complete branch coverage. The same Rust core can also be compiled as an rlib without PyO3 for unit and fuzz testing.

To keep invalid or adversarial input from exhausting the native parser stack, validation rejects a statement after 4,096 significant SQL tokens, nesting deeper than 256 groups or routine blocks, and an input after 65,536 significant tokens. The failure is returned as an ordinary invalid ValidationResult; when the limiting token has a source position, that position is included in the error. Semicolon-separated statements have independent per-statement budgets.

Development

See AGENTS.md for setup, internal conventions, and release steps. The current automated suite contains 5,201 pytest cases and 91 Rust unit tests. It includes a 28-case LF/CRLF transformation matrix, six native-labelled token deletion mutations, and 18 committed seeds for three bounded fuzz targets. Key commands:

python3 -m venv .venv && source .venv/bin/activate
pip install -U pip maturin && pip install -e ".[dev]"
maturin develop          # build + install native ext into the venv
cargo test               # Rust tests
pytest -q                # Python tests
cargo fmt --check        # formatting
cargo clippy --all-targets -- -D warnings
# optional differential parser audit
pip install -e ".[sqlglot-audit]"
python tools/audit_sqlglot.py --baseline \
  plan/sqlglot_30_19_0_trino_483_audit_baseline.json --fail-on-regression
python tools/extract_functions.py --ref 483 --check
python tools/extract_types.py --ref 483 --check
python tools/audit_upstream_parsers.py --baseline plan/trino_483_audit_baseline.json --fail-on-regression

License

MIT

Comparison with SQLGlot

trino-sql-validator and SQLGlot solve different problems. This library focuses on strict, fast validation of Trino syntax and returns a small validation result with Trino-specific catalog warnings. SQLGlot provides a rich AST and is a better fit for formatting, rewriting, lineage, and translation between SQL dialects, but its parser is deliberately permissive and is not a strict Trino validity oracle.

The reproducible audit below compares trino-sql-validator 0.22.0 with SQLGlot 30.19.0 against project fixtures and parser cases extracted from Trino 483. “SQLGlot accepted” includes its Command fallback, which preserves an unsupported statement as text without fully parsing it. “Full AST” excludes that fallback.

Audit set or capability trino-sql-validator SQLGlot
553 valid project fixture statements 553 accepted 544 accepted; 441 produced a full AST
236 invalid project fixture statements 236 rejected 132 produced an error; 22 became Command; 82 produced an AST and were accepted
484 valid Trino 483 statements 484 accepted 454 accepted; 255 produced a full AST
238 valid Trino 483 expressions 238 accepted 221 accepted
68 valid Trino 483 types 68 accepted 48 accepted
23 directly invalid Trino 483 statements 23 rejected 5 produced a parse/token error; the other 18 became Command
Primary use Trino syntax validation, source locations, statement metadata, function/type warnings Multi-dialect AST, transformation, generation, optimization, and lineage
Runtime Rust native extension with parser resource limits Python, with an optional compiled distribution
Invalid-input API Returns ValidationResult; invalid SQL does not raise Normally reports ParseError/TokenError, depending on the selected error level
Jinja/dbt input Length-preserving masking is built in No equivalent contract in the audited parse path

The measured corpora are regression benchmarks, not proof of complete Trino grammar coverage. SQLGlot remains an optional offline audit dependency and is not used by validate() at runtime. Confirmed SQLGlot findings are checked against the native Trino parser before being implemented in the Rust parser. See the full SQLGlot audit for methodology, known mismatches, and detailed results.

Metadata

Release files for trino-sql-validator 0.23.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for trino-sql-validator 0.23.0
File Size Uploaded Provenance
trino_sql_validator-0.23.0.tar.gz 420.9 kB Without provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for trino-sql-validator 0.23.0
File
trino_sql_validator-0.23.0-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
trino_sql_validator-0.23.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details
trino_sql_validator-0.23.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details
trino_sql_validator-0.23.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
trino_sql_validator-0.23.0-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 13.5 MB

Release files / trino_sql_validator-0.23.0.tar.gz

Download URL trino_sql_validator-0.23.0.tar.gz
Size 420.9 kB
Tags Source
SHA-256 checksum
How to use checksums
fc83ade9f3a51614f2720baff7bc3f6a3e33a6e2f03e710c3e33a0d8463a3042
BLAKE2b-256 checksum
How to use checksums
d9beb7dad3c160fadb90931096cb8b6ee0b2fefdd41d7af471363ae2d3b9406c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / trino_sql_validator-0.23.0-cp310-abi3-win_amd64.whl

Download URL trino_sql_validator-0.23.0-cp310-abi3-win_amd64.whl
Size 2.7 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
79bf93904679ae9d23c2515cbe62805a6c9071af85fd41c9a3bcbacabd150c5c
BLAKE2b-256 checksum
How to use checksums
c0086cfda354b0bcb2e6c250bcc05681de9557515db62caf47e00015ec0b303a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / trino_sql_validator-0.23.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL trino_sql_validator-0.23.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 2.7 MB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
b0139ffb477b1ef77d00ae895f6162bac4843341fc9c6417e0defc959d7b894f
BLAKE2b-256 checksum
How to use checksums
cc42ce2ffa12a4da68638866775b148c0743509589ce4fde3bd4fd09030f50eb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / trino_sql_validator-0.23.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL trino_sql_validator-0.23.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 2.6 MB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
9af834b4b42984785e2a0200fa05d9866a896d67912c1a3328a8cad7a16f8304
BLAKE2b-256 checksum
How to use checksums
fc4e7a53544cf608269f27a9e16c5cda8745de70444a4f44c1aa7a49c97d7bb9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / trino_sql_validator-0.23.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL trino_sql_validator-0.23.0-cp310-abi3-macosx_11_0_arm64.whl
Size 2.4 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
3a26abb230fb0ba4c52c896261e4d794c96234e4cbb0a4b05f6174f4e8690031
BLAKE2b-256 checksum
How to use checksums
936522a33a6656a788fdaf27b4ce1cd4c1c2ea076e5357f69563465af2159a4f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / trino_sql_validator-0.23.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL trino_sql_validator-0.23.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 2.6 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
2deafc3b2825c57967d0afa63c36c03189cda99bfda8884c3a27ed5496d16a71
BLAKE2b-256 checksum
How to use checksums
10cc9e3b207e10eb2876be0ca9639693cc90000179ab95f732188d87e50d572c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Security for trino-sql-validator 0.23.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page