What the grammar decides
Most of what dfmt does is not an option, and cannot be one: it is read off the grammar of the dialect. One grammar generates the parser, the renderer and the typed tree, and the same grammar labels every field of every construct with its role. The layout engine has no rule that names SELECT, or JOIN, or UNION; it reads the roles. Here are five consequences you will meet on the first file you format, none of which has a setting.
A keyword run is one word
A keyword, plus any keywords after it that open nothing of their own, is one word as far as layout
is concerned. union all is one operator, group by one clause head, left outer join one join.
None of them splits across lines, at any width: a run wider than the margin overflows it, because
there is no width at which splitting union all is the better answer.
select a from t1 union all select b from t2select a
from t1
union all
select b
from t2The run is judged from the grammar alone: a field joins it only if everything it can hold is a
keyword. That is why select distinct is not a run: distinct on (...) is one of the things
distinct can be.
A set operator joins two whole queries
The grammar declares that a set operator leads a line. It stands between two complete queries and belongs to neither, so when the operation comes apart the operands come apart together and the operator marks the seam, instead of hiding at the start of the second query's first line. An operation that fits has no seam to mark and stays on one line.
select alpha_column, beta_column, gamma_column from first_table union all select 1, 2, 3select alpha_column, beta_column, gamma_column
from first_table
union all
select 1, 2, 3A one-token clause is still a clause
limit 10 is a clause with a one-token body. A formatter that counts tokens sees a couple of
keywords and lets them ride the line above; one that reads the grammar sees a peer of from and
order by, and gives it its own line at the clause column.
select some_long_column_name_a, some_long_column_name_b, some_long_column_name_c from t order by some_long_column_name_a limit 10select some_long_column_name_a, some_long_column_name_b, some_long_column_name_c
from t
order by some_long_column_name_a
limit 10A paren is spaced only where the grammar says
One rule decides the space before an opening bracket: none, unless the production declares one.
count(x) and call my_proc(1, 2) glue; x in (1, 2) and over (order by a) are spaced because
their productions say so. The rule is the same in every dialect that has the construct.
call my_proc (1, 2)call my_proc(1, 2)Inside a lexical unit, whitespace is content
@MyStage/Data/Year=2024/ is a path into cloud storage, and Snowflake lexes it as one unit: a space
anywhere inside it is a syntax error. A formatter may move whitespace freely because whitespace
between tokens is insignificant; inside a lexical unit it is not whitespace, it is content, and the
grammar says so on the production. dfmt leaves the path exactly as written.
copy into MyTable from @MyStage/Data/Year=2024/ file_format = (type = csv)copy into MyTable from @MyStage/Data/Year=2024/ file_format = (type = csv)An operator chain breaks at its operators
a || b || c is nested two deep in the tree, but as far as layout is concerned it is one chain of
operands with operators between them. The grammar's role labels say so, and the chain is flattened
before it is laid out, so a chain that has to come apart breaks at every operator at once rather
than nesting one break inside the last. The operator leads the line it belongs to.
select first_name || ' ' || middle_name || ' ' || last_name || ' (' || department || ')' as display_name from employeesselect
first_name
|| ' '
|| middle_name
|| ' '
|| last_name
|| ' ('
|| department
|| ')' as display_name
from employeesA chain that fits keeps its line
There is no seam to mark, so the chain stays flat.
select first_name || ' ' || last_name from employeesselect first_name || ' ' || last_name from employeesArithmetic is the same chain
+ and - are read into the same flat chain as ||, so they break the same way. Here the first
three terms still fit together and only the last two operators lead lines of their own.
select base_price + tax_amount + shipping_fee - discount - returns_amount as total from ordersselect
base_price + tax_amount + shipping_fee
- discount
- returns_amount as total
from ordersA short arithmetic chain stays flat
select base_price + tax_amount + shipping_fee - discount as total from ordersselect base_price + tax_amount + shipping_fee - discount as total from orders