SQLGlot Python
Produce dialect-explicit SQLGlot code that treats SQL as a typed syntax tree,
preserves caller ownership, separates syntactic rewrite from semantic proof, and
fails visibly when translation is unsupported.
Boundary
Use this skill when the implementation imports SQLGlot or explicitly needs its
parser/transpiler/AST. SQLGlot does not execute against the target database and
is not an authorization sandbox, query optimizer for physical performance, or
substitute for database parameters. Use the database's own tooling for runtime
plans and execution semantics.
Know the objects before editing
| Object |
Meaning |
Use it for |
| Dialect |
Parser and generator rules for a SQL family. |
Interpreting source tokens and emitting target syntax. |
Expression |
One AST node with named child arguments and parent/tree relationships. |
Semantic inspection, construction, and transformation. |
| Statement expression |
Root node such as Select, Insert, Create, or Command. |
Classifying allowed jobs and preserving statement boundaries. |
Identifier |
A name whose quoting and normalization depend on dialect. |
Tables, columns, aliases, and other identifiers—not data values. |
Literal / placeholder node |
A typed SQL value or bind marker in the AST. |
Values; keep runtime user data parameterized by the executor. |
| Scope |
A query-resolution context for sources, projections, subqueries, and CTEs. |
Analysis that cannot be correct from local node search alone. |
| Schema mapping |
Table/column type information supplied by the caller. |
Qualification, star expansion, type annotation, and type-sensitive rewrites. |
parse_one returns one root expression; parse preserves a multi-statement
sequence. .sql(dialect=...) generates text from an AST. transpile combines
source parsing and target generation, but syntactic success is not proof of
equivalent behavior in the target engine. Expression methods can mutate nodes
or return changed trees; copy a caller-owned tree before modifying it unless
in-place mutation is the declared API. Read the AST and dialect
model.
Ordered workflow
- Recover the contract: one or many statements, known source dialect, target
dialect, allowed statement/node classes, required semantic preservation,
available schema, output formatting, and error policy.
- Pass
read= whenever the source dialect is known. Do not let the SQLGlot
superset dialect guess vendor syntax.
- Parse once. Reject parse errors and disallowed roots before traversing or
transforming.
- Use
Expression classes, find_all, scopes, builders, or transform; never
use regex/string replacement for structural SQL edits.
- Supply schema and qualify/type-annotate only when the transformation needs
name or type resolution. Do not invent missing catalog facts.
- Copy before changing a tree whose original must remain available.
- Generate with an explicit target dialect and a strict unsupported-feature
policy. Preserve statement count and ordering.
- Reparse generated SQL in the target dialect, then run target-engine tests
when semantic equivalence matters.
Choose by intent
| Need |
Use |
Required guard |
| Parse exactly one known statement |
parse_one(sql, read=...) |
Establish that a one-statement boundary is intended. |
| Preserve a script's statements |
parse(sql, read=...) |
Validate every root; do not inspect only the first. |
| Find local syntax nodes |
find / find_all with exp classes |
Local traversal is not column resolution. |
| Resolve sources/columns across CTEs/subqueries |
Scope/optimizer qualification utilities |
Supply schema/catalog facts where required. |
| Rewrite nodes recursively |
Expression.transform or explicit AST replacement |
Preserve parentage and copy policy; test nested cases. |
| Construct SQL |
sqlglot.exp nodes/builders |
Keep identifiers distinct from literals and bind parameters. |
| Translate dialects |
transpile(read=..., write=...) or parse then .sql(dialect=...) |
Raise/report unsupported constructs; validate target semantics. |
| Canonical logical AST |
supported optimizer entry point with schema |
Not physical query-performance tuning. |
Read the operation map before choosing parsing,
building, scope analysis, transformation, optimization, or generation APIs.
Canonical strict transpilation
import sqlglot
from sqlglot import ErrorLevel
def transpile_script(sql: str, source: str, target: str) -> list[str]:
if not source or not target:
raise ValueError("source and target dialects are required")
return sqlglot.transpile(
sql,
read=source,
write=target,
unsupported_level=ErrorLevel.RAISE,
pretty=True,
)
The list preserves the possibility of multiple statements and rejects known
unsupported generation rather than warning and emitting a degraded query.
Callers that accept only one statement must check len(result) == 1. Reparse
each output with read=target; execute representative queries in the target
engine before claiming semantic equivalence.
Canonical structural inspection
from sqlglot import exp, parse_one
def selected_columns(sql: str, dialect: str) -> tuple[str, ...]:
tree = parse_one(sql, read=dialect)
if not isinstance(tree, exp.Select):
raise ValueError(f"expected SELECT, got {type(tree).__name__}")
return tuple(node.sql(dialect=dialect) for node in tree.expressions)
This inspects projection expressions rather than regex-matching commas or
column-like tokens. It does not claim to resolve *, aliases, or source columns;
that requires scopes and often schema qualification.
High-risk rules
Dialects and semantics
- Always specify the source dialect when known and target dialect when
generating. Identifier case, quoting, function names, date arithmetic, casts,
arrays, JSON, and null behavior can differ.
- Treat unsupported warnings as failures for correctness-critical translation.
A successful parse means the syntax was represented, not that every target
construct has an equivalent.
- Type-sensitive transpilation and optimization need schema information. If the
catalog is unavailable, preserve the construct or return an uncertainty;
never fabricate column types.
- SQLGlot optimization is logical canonicalization, not target physical-plan
tuning. Benchmark or inspect the actual engine for performance claims.
AST mutation and resolution
- Match nodes by class and semantic arguments, not
str(node). Preserve
comments and formatting only to the degree the selected generator supports;
regenerated SQL is not a textual round trip.
- Copy before mutation when a function promises not to alter its input. Test
nested subqueries, CTE shadowing, aliases, quoted identifiers, stars, and
correlated references.
find_all(exp.Column) finds syntax nodes but does not resolve which table
supplies them. Use scope/qualification analysis for lineage or authorization.
- Construct identifiers with identifier helpers/nodes and values with literals
or executor placeholders. Never turn untrusted text into an expression by
parsing it merely to avoid quoting.
Security boundary
Parsing SQL does not make it safe to execute. If only read-only queries are
allowed, inspect every parsed statement and all prohibited node classes, reject
commands the parser represents generically, enforce database credentials and
resource limits, and bind data values at execution. Treat AST allowlisting as
defense in depth, not the sole authorization layer.
Run the installed-API inspector, read version and API
grounding, then apply the AST verification
matrix.
Completion gate
Do not declare completion until source and target dialects are explicit or a
documented unknown branch exists; multi-statement input cannot bypass checks;
allowed root/node classes are enforced; mutations honor ownership; identifiers
and values remain distinct; schema-dependent transforms have real schema;
unsupported generation is surfaced; target output reparses; nested/quoted/CTE
fixtures pass; and semantic or performance claims are verified in the target
database rather than inferred from SQLGlot alone.
References
- AST and dialect model
- Operation map
- Version and API grounding
- Testing SQLGlot transformations
1---2name: sqlglot-python3description: Write, review, debug, or test Python code that parses, inspects, transforms, builds, qualifies, optimizes, formats, or transpiles SQL with SQLGlot.4---56# SQLGlot Python78Produce dialect-explicit SQLGlot code that treats SQL as a typed syntax tree,9preserves caller ownership, separates syntactic rewrite from semantic proof, and10fails visibly when translation is unsupported.1112## Boundary1314Use this skill when the implementation imports SQLGlot or explicitly needs its15parser/transpiler/AST. SQLGlot does not execute against the target database and16is not an authorization sandbox, query optimizer for physical performance, or17substitute for database parameters. Use the database's own tooling for runtime18plans and execution semantics.1920## Know the objects before editing2122| Object | Meaning | Use it for |23|---|---|---|24| Dialect | Parser and generator rules for a SQL family. | Interpreting source tokens and emitting target syntax. |25| `Expression` | One AST node with named child arguments and parent/tree relationships. | Semantic inspection, construction, and transformation. |26| Statement expression | Root node such as `Select`, `Insert`, `Create`, or `Command`. | Classifying allowed jobs and preserving statement boundaries. |27| `Identifier` | A name whose quoting and normalization depend on dialect. | Tables, columns, aliases, and other identifiers—not data values. |28| `Literal` / placeholder node | A typed SQL value or bind marker in the AST. | Values; keep runtime user data parameterized by the executor. |29| Scope | A query-resolution context for sources, projections, subqueries, and CTEs. | Analysis that cannot be correct from local node search alone. |30| Schema mapping | Table/column type information supplied by the caller. | Qualification, star expansion, type annotation, and type-sensitive rewrites. |3132`parse_one` returns one root expression; `parse` preserves a multi-statement33sequence. `.sql(dialect=...)` generates text from an AST. `transpile` combines34source parsing and target generation, but syntactic success is not proof of35equivalent behavior in the target engine. Expression methods can mutate nodes36or return changed trees; copy a caller-owned tree before modifying it unless37in-place mutation is the declared API. Read [the AST and dialect38model](references/object-model.md).3940## Ordered workflow41421. Recover the contract: one or many statements, known source dialect, target43 dialect, allowed statement/node classes, required semantic preservation,44 available schema, output formatting, and error policy.452. Pass `read=` whenever the source dialect is known. Do not let the SQLGlot46 superset dialect guess vendor syntax.473. Parse once. Reject parse errors and disallowed roots before traversing or48 transforming.494. Use `Expression` classes, `find_all`, scopes, builders, or `transform`; never50 use regex/string replacement for structural SQL edits.515. Supply schema and qualify/type-annotate only when the transformation needs52 name or type resolution. Do not invent missing catalog facts.536. Copy before changing a tree whose original must remain available.547. Generate with an explicit target dialect and a strict unsupported-feature55 policy. Preserve statement count and ordering.568. Reparse generated SQL in the target dialect, then run target-engine tests57 when semantic equivalence matters.5859## Choose by intent6061| Need | Use | Required guard |62|---|---|---|63| Parse exactly one known statement | `parse_one(sql, read=...)` | Establish that a one-statement boundary is intended. |64| Preserve a script's statements | `parse(sql, read=...)` | Validate every root; do not inspect only the first. |65| Find local syntax nodes | `find` / `find_all` with `exp` classes | Local traversal is not column resolution. |66| Resolve sources/columns across CTEs/subqueries | Scope/optimizer qualification utilities | Supply schema/catalog facts where required. |67| Rewrite nodes recursively | `Expression.transform` or explicit AST replacement | Preserve parentage and copy policy; test nested cases. |68| Construct SQL | `sqlglot.exp` nodes/builders | Keep identifiers distinct from literals and bind parameters. |69| Translate dialects | `transpile(read=..., write=...)` or parse then `.sql(dialect=...)` | Raise/report unsupported constructs; validate target semantics. |70| Canonical logical AST | supported optimizer entry point with schema | Not physical query-performance tuning. |7172Read [the operation map](references/operations.md) before choosing parsing,73building, scope analysis, transformation, optimization, or generation APIs.7475## Canonical strict transpilation7677```python78import sqlglot79from sqlglot import ErrorLevel808182def transpile_script(sql: str, source: str, target: str) -> list[str]:83 if not source or not target:84 raise ValueError("source and target dialects are required")85 return sqlglot.transpile(86 sql,87 read=source,88 write=target,89 unsupported_level=ErrorLevel.RAISE,90 pretty=True,91 )92```9394The list preserves the possibility of multiple statements and rejects known95unsupported generation rather than warning and emitting a degraded query.96Callers that accept only one statement must check `len(result) == 1`. Reparse97each output with `read=target`; execute representative queries in the target98engine before claiming semantic equivalence.99100## Canonical structural inspection101102```python103from sqlglot import exp, parse_one104105106def selected_columns(sql: str, dialect: str) -> tuple[str, ...]:107 tree = parse_one(sql, read=dialect)108 if not isinstance(tree, exp.Select):109 raise ValueError(f"expected SELECT, got {type(tree).__name__}")110 return tuple(node.sql(dialect=dialect) for node in tree.expressions)111```112113This inspects projection expressions rather than regex-matching commas or114column-like tokens. It does not claim to resolve `*`, aliases, or source columns;115that requires scopes and often schema qualification.116117## High-risk rules118119### Dialects and semantics120121- Always specify the source dialect when known and target dialect when122 generating. Identifier case, quoting, function names, date arithmetic, casts,123 arrays, JSON, and null behavior can differ.124- Treat unsupported warnings as failures for correctness-critical translation.125 A successful parse means the syntax was represented, not that every target126 construct has an equivalent.127- Type-sensitive transpilation and optimization need schema information. If the128 catalog is unavailable, preserve the construct or return an uncertainty;129 never fabricate column types.130- SQLGlot optimization is logical canonicalization, not target physical-plan131 tuning. Benchmark or inspect the actual engine for performance claims.132133### AST mutation and resolution134135- Match nodes by class and semantic arguments, not `str(node)`. Preserve136 comments and formatting only to the degree the selected generator supports;137 regenerated SQL is not a textual round trip.138- Copy before mutation when a function promises not to alter its input. Test139 nested subqueries, CTE shadowing, aliases, quoted identifiers, stars, and140 correlated references.141- `find_all(exp.Column)` finds syntax nodes but does not resolve which table142 supplies them. Use scope/qualification analysis for lineage or authorization.143- Construct identifiers with identifier helpers/nodes and values with literals144 or executor placeholders. Never turn untrusted text into an expression by145 parsing it merely to avoid quoting.146147### Security boundary148149Parsing SQL does not make it safe to execute. If only read-only queries are150allowed, inspect every parsed statement and all prohibited node classes, reject151commands the parser represents generically, enforce database credentials and152resource limits, and bind data values at execution. Treat AST allowlisting as153defense in depth, not the sole authorization layer.154155Run [the installed-API inspector](scripts/inspect_sqlglot.py), read [version and API156grounding](references/version-grounding.md), then apply [the AST verification157matrix](references/testing.md).158159## Completion gate160161Do not declare completion until source and target dialects are explicit or a162documented unknown branch exists; multi-statement input cannot bypass checks;163allowed root/node classes are enforced; mutations honor ownership; identifiers164and values remain distinct; schema-dependent transforms have real schema;165unsupported generation is surfaced; target output reparses; nested/quoted/CTE166fixtures pass; and semantic or performance claims are verified in the target167database rather than inferred from SQLGlot alone.168169## References170171- [AST and dialect model](references/object-model.md)172- [Operation map](references/operations.md)173- [Version and API grounding](references/version-grounding.md)174- [Testing SQLGlot transformations](references/testing.md)