SQL Generators
The SQL generator layer converts an AnalyzedQuery (from the SQL Parser) into a database-specific SQL string. It is split into a shared module that handles standard SQL and per-backend modules that handle dialect differences.
Shared
The shared module (server/src/sql_shared.rs) contains logic that is identical across all backends:
create_query— assembles the final SQL string from theAnalyzedQueryAST:SELECT,FROM,WHERE,ORDER BY,LIMIT, andOFFSETclauses. It accepts adisplay_exprcallback so each backend can plug in its own expression renderer.display_common_expr— renders standard SQL expressions that work the same everywhere: identifiers, literals, boolean predicates (IS TRUE,IS NULL, etc.),IN,BETWEEN, binary operators,LIKE/ILIKE/SIMILAR TO,CAST,::, math functions (CEIL,FLOOR), string functions (POSITION,SUBSTRING,TRIM,OVERLAY), nested/tuple/array/interval expressions. ReturnsNonefor dialect-specific expressions (EXTRACT,AT TIME ZONE,TypedString,TRY_CAST,SafeCast), letting each backend handle those.format_value— formats SQL value literals (strings, numbers, booleans, NULL, placeholders) with proper escaping.
DuckDB
The DuckDB generator (server/src/sql_duckdb.rs) calls display_common_expr first and only handles what falls through:
EXTRACT→date_part('field', expr)(DuckDB’s preferred syntax).AT TIME ZONE→ standardexpr AT TIME ZONE 'tz'.TypedString→'value'::type(double-colon cast).TRY_CAST→ supported natively.SafeCast→ rejected (not available in DuckDB).
This file also contains the test suite that exercises all expression types through the parse → analyze → generate pipeline.
PostgreSQL
The PostgreSQL generator (server/src/sql_postgresql.rs) follows the same pattern — shared handler first, then Postgres-specific overrides:
EXTRACT→ standardEXTRACT(field FROM expr).AT TIME ZONE→ standardexpr AT TIME ZONE 'tz'.TypedString→'value'::type(same as DuckDB).TRY_CASTandSafeCast→ both rejected (not available in PostgreSQL).
ClickHouse
The ClickHouse generator (server/src/sql_clickhouse.rs) has the most overrides because ClickHouse’s SQL dialect diverges further from standard SQL. Some overrides are checked before calling the shared handler to intercept expressions that would otherwise be handled differently:
SIMILAR TO→ rejected (not supported).POSITION→ rewritten toposition(haystack, needle)(ClickHouse uses reversed argument order).OVERLAY→ synthesized asconcat(substring(…), replacement, substring(…))since ClickHouse lacks nativeOVERLAY.::(double-colon cast) → rewritten asCAST(expr AS type).EXTRACT→ standardEXTRACT(field FROM expr).AT TIME ZONE→toTimezone(expr, 'tz').TypedString→CAST('value' AS type).TRY_CASTandSafeCast→ both rejected.
Adding a New Backend
To support a new database dialect, create a new sql_<backend>.rs file that:
- Calls
create_querywith a backend-specificdisplay_exprcallback. - In that callback, tries
display_common_exprfirst. - Handles any dialect-specific expressions that returned
Nonefrom the shared handler, or overrides expressions before calling it when the backend needs different behavior.