LCOV - code coverage report
Current view: top level - dashql-core/src/formatter - mod.rs Coverage Total Hit
Test: DashQL d805a4b Lines: 92.2 % 2308 2129
Test Date: 2026-11-09 20:22:13

            Line data    Source code
       1              : //! The SQL formatter.
       2              : //!
       3              : //! The formatter visits the AST in post-order and builds a document for every node in a
       4              : //! [`FormattingProgram`], so the documents of the children always exist when a parent is visited.
       5              : //! Nodes that cannot be formatted are rendered as `'<NODE_TYPE>'` placeholders and recorded as
       6              : //! unformattable. The statements are then rendered with the comments of the script in between.
       7              : //!
       8              : //! The output keeps the quirks listed in docs/design/core_quirks.md. The statement formatters live in
       9              : //! the submodules, one per statement kind.
      10              : 
      11              : mod comments;
      12              : mod create;
      13              : mod delete;
      14              : mod explain;
      15              : mod insert;
      16              : mod pgq;
      17              : pub mod program;
      18              : mod select;
      19              : 
      20              : pub use program::*;
      21              : 
      22              : use dashql_parser::attrs;
      23              : use dashql_buffers::formatting::{FormattingConfigT, FormattingDialect, FormattingMode};
      24              : use dashql_buffers::parser::{
      25              :     AttributeKey, CharacterType, ColumnConstraint, ConstraintAttribute, ExpressionOperator, ExtractTarget,
      26              :     GroupByItemType, IntervalType, JoinType, KeyActionCommand, KeyActionTrigger, KeyMatch, KnownFunction, Node,
      27              :     NodeType, NumericType, OrderDirection, OrderNullRule, RowLockingBlockBehavior, RowLockingStrength, SampleCountUnit,
      28              :     SubqueryQuantifier, SymbolSpan, TableConstraint, TempType, TrimDirection, WindowBoundDirection, WindowBoundMode,
      29              :     WindowRangeMode,
      30              : };
      31              : use dashql_parser::parser::context::resolve_text_span;
      32              : use dashql_parser::parser::ParsedScript;
      33              : use dashql_parser::scanner::ScannedScript;
      34              : use dashql_parser::span::TextSpan;
      35              : use std::cell::{Cell, RefCell};
      36              : 
      37              : type K = AttributeKey;
      38              : 
      39              : #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
      40              : pub enum FormattingAssociativity {
      41              :     Left,
      42              :     Right,
      43              :     #[default]
      44              :     NonAssoc,
      45              : }
      46              : 
      47              : use FormattingAssociativity as Associativity;
      48              : 
      49              : /// The formatting state of an AST node
      50              : #[derive(Clone, Copy, Debug, Default)]
      51              : pub struct FormattingNodeState {
      52              :     /// The operator precedence of an n-ary expression or its argument array, 0 if none
      53              :     pub precedence: usize,
      54              :     /// The operator associativity of an n-ary expression or its argument array
      55              :     pub associativity: FormattingAssociativity,
      56              :     /// Must the n-ary expression be parenthesized within its parent expression?
      57              :     pub needs_parentheses: bool,
      58              :     /// Is the node the root of a statement, or the statement of an EXPLAIN?
      59              :     pub is_statement_root: bool,
      60              :     /// The formatted document of the node
      61              :     pub reg: FmtReg,
      62              : }
      63              : 
      64        27005 : fn get_operator_precedence(op: ExpressionOperator) -> (usize, Associativity) {
      65              :     use ExpressionOperator as O;
      66        27005 :     match op {
      67          805 :         O::OR => (3, Associativity::Left),
      68         3332 :         O::AND => (4, Associativity::Left),
      69           93 :         O::NOT => (5, Associativity::Right),
      70              :         O::IS_NULL
      71              :         | O::NOT_NULL
      72              :         | O::IS_TRUE
      73              :         | O::IS_FALSE
      74              :         | O::IS_UNKNOWN
      75              :         | O::IS_DISTINCT_FROM
      76              :         | O::IS_OF
      77              :         | O::IS_NOT_TRUE
      78              :         | O::IS_NOT_FALSE
      79              :         | O::IS_NOT_UNKNOWN
      80              :         | O::IS_NOT_DISTINCT_FROM
      81              :         | O::IS_NOT_OF
      82              :         | O::EQUAL
      83              :         | O::NOT_EQUAL
      84              :         | O::GREATER_EQUAL
      85              :         | O::GREATER_THAN
      86              :         | O::LESS_EQUAL
      87        14612 :         | O::LESS_THAN => (6, Associativity::NonAssoc),
      88              :         O::BETWEEN_SYMMETRIC
      89              :         | O::BETWEEN_ASYMMETRIC
      90              :         | O::NOT_BETWEEN_SYMMETRIC
      91              :         | O::NOT_BETWEEN_ASYMMETRIC
      92              :         | O::IN
      93              :         | O::NOT_IN
      94              :         | O::GLOB
      95              :         | O::NOT_GLOB
      96              :         | O::LIKE
      97              :         | O::NOT_LIKE
      98              :         | O::ILIKE
      99              :         | O::NOT_ILIKE
     100              :         | O::SIMILAR_TO
     101              :         | O::NOT_SIMILAR_TO
     102         2847 :         | O::OVERLAPS => (7, Associativity::NonAssoc),
     103         2729 :         O::PLUS | O::MINUS => (12, Associativity::Left),
     104         2261 :         O::MULTIPLY | O::DIVIDE | O::MODULUS => (13, Associativity::Left),
     105           24 :         O::XOR => (14, Associativity::Left),
     106           12 :         O::AT_TIMEZONE => (15, Associativity::Left),
     107            9 :         O::COLLATE => (16, Associativity::Left),
     108          274 :         O::NEGATE => (17, Associativity::Right),
     109            0 :         O::TYPECAST => (20, Associativity::Left),
     110              :         // Unknown operators get precedence 0, non-associative (see docs/design/core_quirks.md)
     111            7 :         _ => (0, Associativity::NonAssoc),
     112              :     }
     113        27005 : }
     114              : 
     115              : /// Break before AND and OR, after every other operator
     116        23826 : fn breaks_before_operator(op: ExpressionOperator) -> bool {
     117        23826 :     matches!(op, ExpressionOperator::OR | ExpressionOperator::AND)
     118        23826 : }
     119              : 
     120        27122 : fn get_operator_text(op: ExpressionOperator) -> &'static str {
     121              :     use ExpressionOperator as O;
     122        27122 :     match op {
     123          274 :         O::NEGATE => "-",
     124           93 :         O::NOT => "not",
     125         1895 :         O::PLUS => "+",
     126          852 :         O::MINUS => "-",
     127         1376 :         O::MULTIPLY => "*",
     128          873 :         O::DIVIDE => "/",
     129           12 :         O::MODULUS => "%",
     130         3332 :         O::AND => "and",
     131          805 :         O::OR => "or",
     132              :         // The `^` of the grammar, the exponentiation of Hyper and PostgreSQL (`#` would be their bitwise xor)
     133           24 :         O::XOR => "^",
     134        12080 :         O::EQUAL => "=",
     135          159 :         O::NOT_EQUAL => "<>",
     136          315 :         O::LESS_THAN => "<",
     137         1119 :         O::GREATER_THAN => ">",
     138          489 :         O::LESS_EQUAL => "<=",
     139          222 :         O::GREATER_EQUAL => ">=",
     140          117 :         O::LIKE => "like",
     141           30 :         O::NOT_LIKE => "not like",
     142            9 :         O::ILIKE => "ilike",
     143            9 :         O::NOT_ILIKE => "not ilike",
     144            9 :         O::SIMILAR_TO => "similar to",
     145            6 :         O::NOT_SIMILAR_TO => "not similar to",
     146           12 :         O::OVERLAPS => "overlaps",
     147           12 :         O::GLOB => "glob",
     148           18 :         O::NOT_GLOB => "not glob",
     149          105 :         O::IS_NULL => "is null",
     150          102 :         O::NOT_NULL => "is not null",
     151            9 :         O::IS_TRUE => "is true",
     152            9 :         O::IS_FALSE => "is false",
     153            9 :         O::IS_UNKNOWN => "is unknown",
     154            9 :         O::IS_NOT_TRUE => "is not true",
     155            9 :         O::IS_NOT_FALSE => "is not false",
     156            9 :         O::IS_NOT_UNKNOWN => "is not unknown",
     157           15 :         O::IS_DISTINCT_FROM => "is distinct from",
     158           15 :         O::IS_NOT_DISTINCT_FROM => "is not distinct from",
     159         1086 :         O::IN => "in",
     160           18 :         O::NOT_IN => "not in",
     161         1482 :         O::BETWEEN_ASYMMETRIC => "between",
     162           21 :         O::BETWEEN_SYMMETRIC => "between symmetric",
     163           33 :         O::NOT_BETWEEN_ASYMMETRIC => "not between",
     164           21 :         O::NOT_BETWEEN_SYMMETRIC => "not between symmetric",
     165            9 :         O::COLLATE => "collate",
     166           12 :         O::AT_TIMEZONE => "at time zone",
     167            7 :         O::DEFAULT => "default",
     168            0 :         _ => "",
     169              :     }
     170        27122 : }
     171              : 
     172         2175 : fn get_known_function_text(function: KnownFunction) -> &'static str {
     173              :     use KnownFunction as F;
     174         2175 :     match function {
     175            3 :         F::COLLATION_FOR => "collation for",
     176            9 :         F::CURRENT_DATE => "current_date",
     177           24 :         F::CURRENT_TIME => "current_time",
     178           36 :         F::CURRENT_TIMESTAMP => "current_timestamp",
     179           18 :         F::LOCALTIME => "localtime",
     180           18 :         F::LOCALTIMESTAMP => "localtimestamp",
     181            9 :         F::CURRENT_ROLE => "current_role",
     182            9 :         F::CURRENT_USER => "current_user",
     183            9 :         F::SESSION_USER => "session_user",
     184            9 :         F::USER => "user",
     185            9 :         F::CURRENT_CATALOG => "current_catalog",
     186            9 :         F::CURRENT_SCHEMA => "current_schema",
     187         1122 :         F::CAST => "cast",
     188           81 :         F::EXTRACT => "extract",
     189           18 :         F::OVERLAY => "overlay",
     190           15 :         F::POSITION => "position",
     191          255 :         F::SUBSTRING => "substring",
     192           15 :         F::TREAT => "treat",
     193           81 :         F::TRIM => "trim",
     194           15 :         F::NULLIF => "nullif",
     195          402 :         F::COALESCE => "coalesce",
     196            9 :         F::TRY_CAST => "try_cast",
     197            0 :         _ => "",
     198              :     }
     199         2175 : }
     200              : 
     201              : /// The value of an enum node
     202        97256 : fn value_u8(node: &Node) -> u8 {
     203        97256 :     node.children_begin_or_value() as u8
     204        97256 : }
     205              : 
     206              : /// Is the node a true BOOL?
     207        30635 : fn is_true(node: Option<&Node>) -> bool {
     208        30635 :     node.is_some_and(|n| n.node_type() == NodeType::BOOL && n.children_begin_or_value() != 0)
     209        30635 : }
     210              : 
     211              : /// A part of the formatted script
     212              : #[derive(Clone, Copy, Debug)]
     213              : enum OutputPart {
     214              :     /// A parsed statement without errors, the index in the statements of the parsed script
     215              :     Statement(usize),
     216              :     /// A statement with syntax errors, the text span that is copied as written
     217              :     Damaged(TextSpan),
     218              : }
     219              : 
     220              : /// The SQL formatter
     221              : pub struct Formatter<'a> {
     222              :     /// The scanned script
     223              :     scanned: &'a ScannedScript,
     224              :     /// Emit executable literals instead of obfuscated literal markers?
     225              :     replace_obfuscated_literals: bool,
     226              :     /// The parsed script
     227              :     parsed: &'a ParsedScript,
     228              :     /// The AST nodes of the parsed script
     229              :     ast: &'a [Node],
     230              :     /// The formatting config of the current run
     231              :     config: FormattingConfigT,
     232              :     /// The document arena that holds the formatted nodes
     233              :     fmt: FormattingProgram<'a>,
     234              :     /// The formatting states, indexed by AST node id
     235              :     node_states: Vec<FormattingNodeState>,
     236              :     /// The ids of the nodes that were rendered as placeholders
     237              :     unformattable_nodes: RefCell<Vec<u32>>,
     238              :     /// Was a part of the script with syntax errors copied as written?
     239              :     copied_damaged_text: Cell<bool>,
     240              : }
     241              : 
     242              : impl<'a> Formatter<'a> {
     243         4398 :     pub fn new(parsed: &'a ParsedScript) -> Self {
     244         4398 :         let mut formatter = Self {
     245         4398 :             scanned: &parsed.scanned,
     246         4398 :             replace_obfuscated_literals: false,
     247         4398 :             parsed,
     248         4398 :             ast: &parsed.nodes,
     249         4398 :             config: FormattingConfigT::default(),
     250         4398 :             fmt: FormattingProgram::new(),
     251         4398 :             node_states: vec![FormattingNodeState::default(); parsed.nodes.len()],
     252         4398 :             unformattable_nodes: RefCell::new(Vec::new()),
     253         4398 :             copied_damaged_text: Cell::new(false),
     254         4398 :         };
     255         4398 :         formatter.mark_statement_roots();
     256         4398 :         formatter
     257         4398 :     }
     258              : 
     259              :     /// Emit executable literals instead of the obfuscated literal markers of Hyper
     260            6 :     pub fn replace_obfuscated_literals(&mut self) {
     261            6 :         self.replace_obfuscated_literals = true;
     262            6 :     }
     263              : 
     264         5606 :     pub fn estimate_formatted_size(&self) -> usize {
     265         5606 :         self.scanned.text.len() + 64
     266         5606 :     }
     267              : 
     268              :     /// The nodes that could not be formatted by the last call of `format` or `format_node_at`
     269          634 :     pub fn unformattable_nodes(&self) -> Vec<u32> {
     270          634 :         self.unformattable_nodes.borrow().clone()
     271          634 :     }
     272              : 
     273              :     /// Was everything formatted? Parts with syntax errors are copied as written and nodes that cannot be
     274              :     /// formatted are rendered as placeholders.
     275         2064 :     pub fn is_fully_formatted(&self) -> bool {
     276         2064 :         self.unformattable_nodes.borrow().is_empty() && !self.copied_damaged_text.get()
     277         2064 :     }
     278              : 
     279              :     /// Format the script
     280         5598 :     pub fn format(&mut self, config: &FormattingConfigT) -> String {
     281         5598 :         bytes_to_string(self.format_bytes(config))
     282         5598 :     }
     283              : 
     284              :     /// Format the script, the output may contain partial UTF-8 sequences where comments were wrapped
     285         5606 :     pub fn format_bytes(&mut self, config: &FormattingConfigT) -> Vec<u8> {
     286         5606 :         self.prepare(config);
     287         5606 :         self.mark_statement_roots();
     288         5606 :         self.prepare_precedence();
     289       460776 :         for i in 0..self.ast.len() {
     290       460776 :             self.identify_parentheses(self.ast.len() - 1 - i);
     291       460776 :         }
     292         5606 :         self.build_docs();
     293         5606 :         self.write_output()
     294         5606 :     }
     295              : 
     296              :     /// Format a single node (without the statement roots that only `format` marks)
     297          375 :     pub fn format_node_at(&mut self, node_id: usize, config: &FormattingConfigT) -> String {
     298          375 :         if node_id >= self.ast.len() {
     299            1 :             return String::new();
     300          374 :         }
     301          374 :         self.prepare(config);
     302          374 :         self.prepare_precedence();
     303         1880 :         for i in 0..self.ast.len() {
     304         1880 :             self.identify_parentheses(self.ast.len() - 1 - i);
     305         1880 :         }
     306          374 :         self.build_docs();
     307          374 :         self.render(self.node_states[node_id].reg)
     308          375 :     }
     309              : 
     310         5980 :     fn prepare(&mut self, config: &FormattingConfigT) {
     311         5980 :         self.config = config.clone();
     312         5980 :         self.fmt.reset();
     313         5980 :         self.fmt.set_config(config);
     314         5980 :         self.node_states.clear();
     315         5980 :         self.node_states.resize(self.ast.len(), FormattingNodeState::default());
     316         5980 :         self.unformattable_nodes.borrow_mut().clear();
     317         5980 :         self.copied_damaged_text.set(false);
     318         5980 :     }
     319              : 
     320        10004 :     fn mark_statement_roots(&mut self) {
     321        10379 :         for statement in &self.parsed.statements {
     322        10379 :             if (statement.root as usize) < self.node_states.len() {
     323        10379 :                 self.node_states[statement.root as usize].is_statement_root = true;
     324        10379 :                 self.mark_explain_inner_statement_root(statement.root as usize);
     325        10379 :             }
     326              :         }
     327        10004 :     }
     328              : 
     329        10379 :     fn mark_explain_inner_statement_root(&mut self, root_id: usize) {
     330        10379 :         let root_node = &self.ast[root_id];
     331        10379 :         if root_node.node_type() != NodeType::OBJECT_EXT_EXPLAIN {
     332        10139 :             return;
     333          240 :         }
     334          240 :         if let Some(child) = self.children(root_node).iter().find(|c| c.attribute_key() == K::EXT_EXPLAIN_STATEMENT) {
     335          240 :             let inner_id = self.node_id(child);
     336          240 :             if inner_id < self.node_states.len() {
     337          240 :                 self.node_states[inner_id].is_statement_root = true;
     338          240 :             }
     339            0 :         }
     340        10379 :     }
     341              : 
     342              :     // -----------------------------------------------------------------------------------------
     343              :     // AST access
     344              :     // -----------------------------------------------------------------------------------------
     345              : 
     346              :     /// The id of a node of the AST
     347       237160 :     fn node_id(&self, node: &Node) -> usize {
     348       237160 :         (node as *const Node as usize - self.ast.as_ptr() as usize) / std::mem::size_of::<Node>()
     349       237160 :     }
     350              : 
     351       209749 :     fn state(&self, node: &Node) -> &FormattingNodeState {
     352       209749 :         &self.node_states[self.node_id(node)]
     353       209749 :     }
     354              : 
     355              :     /// The document of a node
     356       209749 :     fn reg(&self, node: &Node) -> FmtReg {
     357       209749 :         self.state(node).reg
     358       209749 :     }
     359              : 
     360              :     /// The children of a node (`ast.subspan(children_begin_or_value, children_count)`)
     361       271426 :     fn children(&self, node: &Node) -> &'a [Node] {
     362       271426 :         let count = node.children_count() as usize;
     363       271426 :         if count == 0 {
     364          135 :             return &[];
     365       271291 :         }
     366       271291 :         let begin = node.children_begin_or_value() as usize;
     367       271291 :         &self.ast[begin..begin + count]
     368       271426 :     }
     369              : 
     370              :     /// The documents of the elements of an array
     371       158917 :     fn array_regs(&self, node: &Node) -> Vec<FmtReg> {
     372       158917 :         let count = node.children_count() as usize;
     373       158917 :         if count == 0 {
     374          162 :             return Vec::new();
     375       158755 :         }
     376       158755 :         let begin = node.children_begin_or_value() as usize;
     377       158755 :         self.node_states[begin..begin + count].iter().map(|s| s.reg).collect()
     378       158917 :     }
     379              : 
     380              :     /// Look up attributes of an object.
     381              :     ///
     382              :     /// A single key finds the first child with that key, several keys find the last child with each
     383              :     /// key (see docs/design/core_quirks.md).
     384         1244 :     fn attrs<const N: usize>(&self, node: &Node, keys: [AttributeKey; N]) -> [Option<&'a Node>; N] {
     385         1244 :         let mut out = [None; N];
     386         2488 :         for child in self.children(node) {
     387         4978 :             for (slot, key) in out.iter_mut().zip(keys.iter()) {
     388         4978 :                 if child.attribute_key() == *key {
     389         2488 :                     *slot = Some(child);
     390         2488 :                     if N == 1 {
     391            1 :                         return out;
     392         2487 :                     }
     393         2490 :                 }
     394              :             }
     395              :         }
     396         1243 :         out
     397         1244 :     }
     398              : 
     399              :     /// The text of a symbol span
     400       129185 :     fn text_at(&self, span: &SymbolSpan) -> &'a str {
     401       129185 :         let text: &'a str = &self.scanned.text;
     402       129185 :         let ts = resolve_text_span(text, &self.scanned.symbols, *span);
     403       129185 :         let begin = (ts.offset as usize).min(text.len());
     404       129185 :         let end = (begin + ts.length as usize).min(text.len());
     405       129185 :         &text[begin..end]
     406       129185 :     }
     407              : 
     408        12477 :     fn is_pretty(&self) -> bool {
     409        12477 :         self.config.mode == FormattingMode::PRETTY
     410        12477 :     }
     411              : 
     412              :     /// ForceBreak in pretty mode, `otherwise` in the other modes
     413        10242 :     fn pretty_policy(&self, otherwise: FormattingJoinPolicy) -> FormattingJoinPolicy {
     414        10242 :         if self.is_pretty() {
     415         3290 :             FormattingJoinPolicy::ForceBreak
     416              :         } else {
     417         6952 :             otherwise
     418              :         }
     419        10242 :     }
     420              : 
     421              :     // -----------------------------------------------------------------------------------------
     422              :     // Precedence
     423              :     // -----------------------------------------------------------------------------------------
     424              : 
     425         5980 :     fn prepare_precedence(&mut self) {
     426       462656 :         for i in 0..self.ast.len() {
     427       462656 :             let node = &self.ast[i];
     428       462656 :             if node.node_type() != NodeType::OBJECT_SQL_NARY_EXPRESSION {
     429       435501 :                 continue;
     430        27155 :             }
     431        27155 :             let [op_node, args_node] = attrs!(self.children(node), [K::SQL_EXPRESSION_OPERATOR, K::SQL_EXPRESSION_ARGS]);
     432        27155 :             let Some(op_node) = op_node else { continue };
     433              : 
     434        27155 :             let (precedence, associativity) = if op_node.node_type() == NodeType::ENUM_SQL_EXPRESSION_OPERATOR {
     435        27005 :                 get_operator_precedence(ExpressionOperator(value_u8(op_node)))
     436          150 :             } else if matches!(op_node.node_type(), NodeType::OPERATOR | NodeType::ARRAY) {
     437          150 :                 (11, Associativity::Left)
     438              :             } else {
     439            0 :                 continue;
     440              :             };
     441        27155 :             let state = &mut self.node_states[i];
     442        27155 :             state.precedence = precedence;
     443        27155 :             state.associativity = associativity;
     444        27155 :             if let Some(args_node) = args_node {
     445        27148 :                 let args_id = self.node_id(args_node);
     446        27148 :                 let args_state = &mut self.node_states[args_id];
     447        27148 :                 args_state.precedence = precedence;
     448        27148 :                 args_state.associativity = associativity;
     449        27149 :             }
     450              :         }
     451         5980 :     }
     452              : 
     453       462656 :     fn identify_parentheses(&mut self, node_id: usize) {
     454       462656 :         let node = &self.ast[node_id];
     455       462656 :         if node.node_type() != NodeType::OBJECT_SQL_NARY_EXPRESSION {
     456       435501 :             return;
     457        27155 :         }
     458        27155 :         let parent_id = node.parent() as usize;
     459        27155 :         if parent_id >= self.ast.len() {
     460            0 :             return;
     461        27155 :         }
     462        27155 :         let parent = &self.ast[parent_id];
     463        27155 :         if parent.node_type() != NodeType::ARRAY {
     464         8122 :             return;
     465        19033 :         }
     466        19033 :         let args_begin = parent.children_begin_or_value() as usize;
     467        19033 :         let args_count = parent.children_count() as usize;
     468        19033 :         if node_id < args_begin || node_id >= args_begin + args_count {
     469            0 :             return;
     470        19033 :         }
     471              : 
     472        19033 :         let arg_index = node_id - args_begin;
     473        19033 :         let parent_state = self.node_states[parent_id];
     474        19033 :         let state = &mut self.node_states[node_id];
     475        19033 :         let need_parens = if args_count == 1 {
     476           15 :             true
     477              :         } else {
     478        19018 :             let left_or_none = matches!(parent_state.associativity, Associativity::Left | Associativity::NonAssoc);
     479        19018 :             let right_or_none = matches!(parent_state.associativity, Associativity::Right | Associativity::NonAssoc);
     480        19018 :             state.precedence < parent_state.precedence
     481        18065 :                 || (state.precedence == parent_state.precedence
     482          567 :                     && ((arg_index == 0 && right_or_none)
     483          561 :                         || (arg_index == args_count - 1 && left_or_none)
     484          525 :                         || (arg_index > 0 && arg_index + 1 < args_count)))
     485              :         };
     486        19033 :         state.needs_parentheses = need_parens;
     487       462656 :     }
     488              : 
     489              :     // -----------------------------------------------------------------------------------------
     490              :     // Leaves and lists
     491              :     // -----------------------------------------------------------------------------------------
     492              : 
     493       128374 :     fn format_leaf(&self, node: &'a Node) -> FmtReg {
     494       128374 :         let text = self.text_at(node.symbol_span());
     495       128374 :         if self.replace_obfuscated_literals {
     496           12 :             let text_offset = resolve_text_span(&self.scanned.text, &self.scanned.symbols, *node.symbol_span()).offset;
     497           12 :             if let Some(literal) = self.find_obfuscated_literal(text_offset) {
     498            0 :                 return self.fmt.verbatim(&literal.replacement);
     499           12 :             }
     500       128362 :         }
     501       128374 :         if matches!(node.node_type(), NodeType::BOOL | NodeType::LITERAL_NULL | NodeType::OPERATOR) {
     502         4208 :             return self.fmt.text(text);
     503       124166 :         }
     504       124166 :         self.fmt.verbatim(text)
     505       128374 :     }
     506              : 
     507              :     /// The obfuscated literal whose marker starts at a text offset
     508           12 :     fn find_obfuscated_literal(&self, offset: u32) -> Option<&'a dashql_parser::scanner::ObfuscatedLiteral> {
     509           12 :         let literals: &'a [dashql_parser::scanner::ObfuscatedLiteral] = &self.scanned.obfuscated_literals;
     510           12 :         let i = literals.partition_point(|l| l.location.offset < offset);
     511           12 :         literals.get(i).filter(|l| l.location.offset == offset)
     512           12 :     }
     513              : 
     514           20 :     fn format_unimplemented(&self, node: &Node) -> FmtReg {
     515           20 :         self.unformattable_nodes.borrow_mut().push(self.node_id(node) as u32);
     516           20 :         let type_name = node.node_type().variant_name().unwrap_or("");
     517           20 :         let f = &self.fmt;
     518           20 :         f.concat(&[f.text("'<"), f.verbatim(type_name), f.text(">'")])
     519           20 :     }
     520              : 
     521              :     /// Format a node or record the child as unformattable (`reg_or_placeholder`)
     522         6208 :     fn reg_or_placeholder(&self, child: &Node) -> FmtReg {
     523         6208 :         let reg = self.reg(child);
     524         6208 :         if reg == 0 {
     525            0 :             return self.format_unimplemented(child);
     526         6208 :         }
     527         6208 :         reg
     528         6208 :     }
     529              : 
     530        66310 :     fn comma_separators(&self) -> (FmtReg, FmtReg) {
     531        66310 :         let f = &self.fmt;
     532        66310 :         let inline_separator = f.text(", ");
     533        66310 :         let break_separator = f.concat(&[f.text(","), f.break_()]);
     534        66310 :         (inline_separator, break_separator)
     535        66310 :     }
     536              : 
     537        58963 :     fn format_comma_list(&self, node: &Node, indent_after_breaks: bool) -> FmtReg {
     538        58963 :         let parts = self.array_regs(node);
     539        58963 :         let (inline_separator, break_separator) = self.comma_separators();
     540        58963 :         self.fmt.join(&parts, inline_separator, break_separator, None, indent_after_breaks)
     541        58963 :     }
     542              : 
     543              :     /// A comma-separated join that breaks on overflow
     544         6406 :     fn comma_join_on_overflow(&self, items: &[FmtReg], indent_after_breaks: bool) -> FmtReg {
     545         6406 :         let (inline_separator, break_separator) = self.comma_separators();
     546         6406 :         self.fmt.join(
     547         6406 :             items,
     548         6406 :             inline_separator,
     549         6406 :             break_separator,
     550         6406 :             Some(FormattingJoinPolicy::BreakOnOverflow),
     551         6406 :             indent_after_breaks,
     552              :         )
     553         6406 :     }
     554              : 
     555              :     /// A space-separated join
     556        18797 :     fn space_join(&self, items: &[FmtReg], policy: FormattingJoinPolicy, indent_after_breaks: bool) -> FmtReg {
     557        18797 :         let f = &self.fmt;
     558        18797 :         f.join(items, f.text(" "), f.break_(), Some(policy), indent_after_breaks)
     559        18797 :     }
     560              : 
     561        69686 :     fn format_qualified_name(&self, node: &Node) -> FmtReg {
     562        69686 :         let f = &self.fmt;
     563              :         // An index like `a[1]` follows its name without a dot
     564        69686 :         let mut parts: Vec<FmtReg> = Vec::new();
     565        79146 :         for (child, reg) in self.children(node).iter().zip(self.array_regs(node)) {
     566        79146 :             match parts.pop() {
     567         9460 :                 Some(previous) if child.node_type() == NodeType::OBJECT_SQL_INDIRECTION_INDEX => {
     568           81 :                     parts.push(f.concat(&[previous, reg]))
     569              :                 }
     570         9379 :                 Some(previous) => {
     571         9379 :                     parts.push(previous);
     572         9379 :                     parts.push(reg);
     573         9379 :                 }
     574        69686 :                 None => parts.push(reg),
     575              :             }
     576              :         }
     577        69686 :         if parts.is_empty() {
     578            0 :             return self.fmt.empty();
     579        69686 :         }
     580        69686 :         let inline_separator = f.text(".");
     581        69686 :         let break_separator = f.concat(&[f.break_(), f.text(".")]);
     582        69686 :         f.join(&parts, inline_separator, break_separator, None, true)
     583        69686 :     }
     584              : 
     585              :     /// The fields of an object in parentheses, with one field per line if they don't fit on one
     586           99 :     fn format_vararg_object(&self, node: &Node) -> FmtReg {
     587           99 :         if node.children_count() == 0 {
     588            9 :             return self.fmt.text("()");
     589           90 :         }
     590           90 :         self.fmt.parenthesized_list(self.format_comma_list(node, false))
     591           99 :     }
     592              : 
     593       129507 :     fn format_array(&self, node: &'a Node) -> FmtReg {
     594       129507 :         let f = &self.fmt;
     595       129507 :         if node.attribute_key() == K::NONE {
     596         1083 :             let parent_id = node.parent() as usize;
     597         1083 :             let parent = self.ast.get(parent_id);
     598         1083 :             let parent_key = parent.map(|p| p.attribute_key());
     599         1083 :             if parent_key == Some(K::SQL_SELECT_VALUES) {
     600          126 :                 return f.parenthesized(self.format_comma_list(node, true));
     601          957 :             }
     602          957 :             if parent_key == Some(K::SQL_EXPRESSION_ARGS) {
     603          798 :                 return self.format_comma_list(node, true);
     604          159 :             }
     605              :             // An object in an array of varargs
     606          159 :             if parent_key == Some(K::EXT_VARARG_ARRAY_VALUES) {
     607           27 :                 return self.format_vararg_object(node);
     608          132 :             }
     609          132 :             if parent_key == Some(K::SQL_ROW_LOCKING_OF) {
     610           24 :                 return self.format_qualified_name(node);
     611          108 :             }
     612          108 :             if parent_key == Some(K::SQL_GRAPH_MATCH_PATTERNS) {
     613          108 :                 let parts = self.array_regs(node);
     614          108 :                 return f.join(&parts, f.empty(), f.break_(), Some(FormattingJoinPolicy::BreakOnOverflow), true);
     615            0 :             }
     616            0 :             if parent.is_some_and(|p| p.node_type() == NodeType::OBJECT_SQL_NARY_EXPRESSION) {
     617            0 :                 return self.format_comma_list(node, true);
     618            0 :             }
     619       128424 :         }
     620              : 
     621       128424 :         match node.attribute_key() {
     622              :             K::SQL_SELECT_TARGETS
     623              :             | K::SQL_SELECT_FROM
     624              :             | K::SQL_SELECT_GROUPS
     625              :             | K::SQL_SELECT_ORDER
     626              :             | K::SQL_WINDOW_FRAME_PARTITION
     627              :             | K::SQL_WINDOW_FRAME_ORDER
     628              :             | K::SQL_FUNCTION_WITHIN_GROUP
     629              :             | K::SQL_FUNCTION_ARGUMENTS
     630              :             | K::SQL_FUNCTION_ORDER
     631              :             | K::SQL_EXPRESSION_ARGS
     632              :             | K::SQL_DESCRIPTOR_COLUMNS
     633              :             | K::SQL_ROW_TYPE_FIELDS
     634              :             | K::SQL_CASE_CLAUSES
     635              :             | K::SQL_CREATE_TABLE_ELEMENTS
     636              :             | K::SQL_CREATE_AS_COLUMNS
     637              :             | K::SQL_VIEW_COLUMNS
     638              :             | K::SQL_CREATE_FUNCTION_PARAMS
     639              :             | K::SQL_SELECT_WINDOWS
     640              :             | K::SQL_SELECT_ROW_LOCKING
     641              :             | K::SQL_ROW_LOCKING_OF
     642              :             | K::SQL_GROUP_BY_ITEM_ARG
     643              :             | K::SQL_NUMERIC_TYPE_MODIFIERS
     644              :             | K::SQL_GENERIC_TYPE_MODIFIERS
     645              :             | K::SQL_TYPENAME_ARRAY
     646              :             | K::SQL_ATTACH_DATABASE_OPTIONS
     647              :             | K::SQL_INSERT_COLUMNS
     648              :             | K::SQL_INSERT_RETURNING
     649              :             | K::SQL_DELETE_USING
     650              :             | K::SQL_DELETE_RETURNING
     651              :             | K::SQL_CTE_COLUMNS
     652              :             | K::SQL_GRAPH_ELEMENT_TABLE_LABELS
     653              :             | K::SQL_GRAPH_MATCH_PATTERNS
     654              :             | K::SQL_RESULT_TARGET_EXCLUDE
     655              :             | K::SQL_TYPETEST_TYPES
     656              :             | K::SQL_FUNCTION_TABLE_ROWS_FROM
     657              :             | K::SQL_COLUMN_DEF_OPTIONS
     658              :             | K::SQL_CTE_OPTIONS
     659              :             | K::SQL_CONST_CAST_FUNC_ARGS_LIST
     660              :             | K::SQL_ROWSFROM_ITEM_COLUMNS
     661              :             | K::SQL_TABLE_CONSTRAINT_DEFINITION
     662        54027 :             | K::SQL_COLUMN_CONSTRAINT_DEFINITION => self.format_comma_list(node, true),
     663              :             K::SQL_PROPERTY_GRAPH_VERTEX_TABLES
     664              :             | K::SQL_PROPERTY_GRAPH_EDGE_TABLES
     665              :             | K::SQL_GRAPH_ELEMENT_TABLE_KEY
     666              :             | K::SQL_GRAPH_VERTEX_REFERENCE_KEY
     667              :             | K::SQL_GRAPH_VERTEX_REFERENCE_COLUMNS
     668              :             | K::SQL_GRAPH_PROPERTIES_COLUMNS
     669              :             | K::SQL_GRAPH_PROPERTIES_EXCLUDE
     670          465 :             | K::SQL_GRAPH_TABLE_COLUMNS => self.format_comma_list(node, false),
     671              :             K::SQL_SUBQUERY_OPERATOR | K::SQL_DEFINITION_ARG_VALUE | K::SQL_EXPRESSION_OPERATOR => {
     672           21 :                 self.format_operator_path(node)
     673              :             }
     674          864 :             K::SQL_TABLE_CONSTRAINT_ATTRIBUTES | K::SQL_COLUMN_DEF_CONSTRAINTS => self.format_space_list(node),
     675          175 :             K::EXT_EXPLAIN_OPTIONS | K::SQL_CALL_ARGS => self.format_comma_list(node, false),
     676              :             K::EXT_EXPLAIN_EXPRESSIONS => {
     677            9 :                 let parts = self.array_regs(node);
     678            9 :                 let (inline_separator, break_separator) = self.comma_separators();
     679            9 :                 f.join(&parts, inline_separator, break_separator, Some(FormattingJoinPolicy::ForceBreak), false)
     680              :             }
     681           72 :             K::EXT_VARARG_FIELD_VALUE | K::SQL_FUNCTION_ARG_VALUE => self.format_vararg_object(node),
     682           15 :             K::SQL_GENERIC_OPTION_VALUE => f.parenthesized(self.format_comma_list(node, true)),
     683          117 :             K::SQL_INDIRECTION_PATH | K::SQL_SELECT_EXPRESSION_INDIRECTION => self.format_indirection_path(node),
     684              :             K::SQL_ROW_EXPRESSION_VALUES | K::SQL_ARRAY_EXPRESSION_VALUES => {
     685          363 :                 let values = self.array_regs(node);
     686          759 :                 if values.iter().any(|&v| v == 0) {
     687            0 :                     return self.format_unimplemented(node);
     688          363 :                 }
     689          363 :                 self.comma_join_on_overflow(&values, true)
     690              :             }
     691              :             K::SQL_WINDOW_FRAME_BOUNDS => {
     692          126 :                 let bounds = self.array_regs(node);
     693          126 :                 if bounds.len() == 1 && bounds[0] != 0 {
     694           30 :                     return bounds[0];
     695           96 :                 }
     696           96 :                 if bounds.len() == 2 && bounds[0] != 0 && bounds[1] != 0 {
     697           96 :                     return f.concat(&[f.text("between "), bounds[0], f.text(" and "), bounds[1]]);
     698            0 :                 }
     699            0 :                 self.format_unimplemented(node)
     700              :             }
     701              :             K::SQL_SELECT_VALUES => {
     702           81 :                 let rows = self.array_regs(node);
     703          126 :                 if rows.iter().any(|&r| r == 0) {
     704            0 :                     return self.format_unimplemented(node);
     705           81 :                 }
     706           81 :                 let policy = self.pretty_policy(FormattingJoinPolicy::BreakOnOverflow);
     707           81 :                 let indent_after_breaks = !self.is_pretty();
     708           81 :                 let (inline_separator, break_separator) = self.comma_separators();
     709           81 :                 f.join(&rows, inline_separator, break_separator, Some(policy), indent_after_breaks)
     710              :             }
     711              :             K::SQL_TEMP_NAME
     712              :             | K::SQL_CREATE_TABLE_NAME
     713              :             | K::SQL_FUNCTION_NAME
     714              :             | K::SQL_CONST_CAST_FUNC_NAME
     715              :             | K::SQL_COLUMN_CONSTRAINT_COLLATE
     716              :             | K::SQL_TABLEREF_NAME
     717              :             | K::SQL_PARAMETER_NAME
     718              :             | K::SQL_TABLE_CONSTRAINT_REFERENCES_NAME
     719              :             | K::SQL_COLUMN_REF_PATH
     720              :             | K::SQL_COLUMN_DEF_COLLATE
     721              :             | K::SQL_CREATE_AS_NAME
     722              :             | K::SQL_VIEW_NAME
     723              :             | K::SQL_CREATE_FUNCTION_NAME
     724              :             | K::SQL_DROP_NAME
     725              :             | K::SQL_ALTER_TABLE_NAME
     726              :             | K::SQL_ALTER_ACTION_NEW_TABLE
     727              :             | K::SQL_SCHEMA_NAME
     728              :             | K::SQL_CALL_NAME
     729              :             | K::EXT_VARARG_FIELD_KEY
     730        69662 :             | K::SQL_GRAPH_TABLE_GRAPH => self.format_qualified_name(node),
     731              :             K::SQL_SELECT_DISTINCT
     732              :             | K::SQL_SELECT_WITH_CTES
     733              :             | K::SQL_COMBINE_INPUT
     734              :             | K::SQL_JOIN_INPUT
     735              :             | K::SQL_TABLE_CONSTRAINT_COLUMNS
     736              :             | K::SQL_TABLE_CONSTRAINT_REFERENCES_COLUMNS
     737              :             | K::SQL_JOIN_USING
     738              :             | K::SQL_FUNCTION_TRIM_INPUT
     739              :             | K::SQL_ALIAS_COLUMN_NAMES
     740              :             | K::SQL_ALIAS_COLUMN_DEFS
     741              :             | K::EXT_VARARG_ARRAY_VALUES
     742         2412 :             | K::SQL_ALTER_TABLE_ACTIONS => self.format_comma_list(node, true),
     743           15 :             _ => self.format_unimplemented(node),
     744              :         }
     745       129507 :     }
     746              : 
     747              :     // -----------------------------------------------------------------------------------------
     748              :     // Table references
     749              :     // -----------------------------------------------------------------------------------------
     750              : 
     751        13180 :     fn format_table_ref(&self, node: &'a Node) -> FmtReg {
     752        13180 :         let f = &self.fmt;
     753        13180 :         let [name, alias, table, lateral, sample, only] = attrs!(self.children(node), [
     754              :                 K::SQL_TABLEREF_NAME,
     755              :                 K::SQL_TABLEREF_ALIAS,
     756              :                 K::SQL_TABLEREF_TABLE,
     757              :                 K::SQL_TABLEREF_LATERAL,
     758              :                 K::SQL_TABLEREF_SAMPLE,
     759              :                 K::SQL_TABLEREF_ONLY,
     760              :             ],
     761              :         );
     762              : 
     763        13180 :         let mut base_reg = 0;
     764        13180 :         if let Some(table) = table {
     765         1947 :             base_reg = self.reg(table);
     766         1947 :             if table.node_type() == NodeType::OBJECT_SQL_SELECT {
     767          918 :                 base_reg = f.parenthesized(base_reg);
     768         1029 :             }
     769        11233 :         } else if let Some(name) = name {
     770        11233 :             base_reg = self.reg(name);
     771        11233 :         }
     772        13180 :         if base_reg == 0 {
     773            0 :             return self.format_unimplemented(node);
     774        13180 :         }
     775        13180 :         if is_true(only) {
     776            9 :             base_reg = f.concat(&[f.text("only "), base_reg]);
     777        13171 :         }
     778        13180 :         if is_true(lateral) {
     779           48 :             base_reg = f.concat(&[f.text("lateral "), base_reg]);
     780        13132 :         }
     781        13180 :         if let Some(alias) = alias {
     782         2490 :             let alias_reg = self.reg(alias);
     783         2490 :             if alias_reg == 0 {
     784            0 :                 return self.format_unimplemented(node);
     785         2490 :             }
     786         2490 :             base_reg = f.concat(&[base_reg, f.text(" "), alias_reg]);
     787        10690 :         }
     788        13180 :         if let Some(sample) = sample {
     789           57 :             let sample_reg = self.reg(sample);
     790           57 :             if sample_reg == 0 {
     791            0 :                 return self.format_unimplemented(node);
     792           57 :             }
     793           57 :             base_reg = f.concat(&[base_reg, f.text(" "), sample_reg]);
     794        13123 :         }
     795        13180 :         base_reg
     796        13180 :     }
     797              : 
     798           51 :     fn format_into(&self, node: &'a Node) -> FmtReg {
     799           51 :         let f = &self.fmt;
     800           51 :         let [temp, name] = attrs!(self.children(node), [K::SQL_TEMP_TYPE, K::SQL_TEMP_NAME]);
     801           51 :         let Some(name) = name else { return self.format_unimplemented(node) };
     802           51 :         let mut parts = vec![f.text("into ")];
     803           51 :         if let Some(temp) = temp {
     804           51 :             if TempType(value_u8(temp)) != TempType::NONE {
     805            3 :                 parts.push(self.reg(temp));
     806            3 :                 parts.push(f.text(" "));
     807           48 :             }
     808            0 :         }
     809           51 :         parts.push(self.reg(name));
     810           51 :         f.concat(&parts)
     811           51 :     }
     812              : 
     813           78 :     fn format_window_def(&self, node: &'a Node) -> FmtReg {
     814           78 :         let f = &self.fmt;
     815           78 :         let [name, frame] = attrs!(self.children(node), [K::SQL_WINDOW_DEF_NAME, K::SQL_WINDOW_DEF_FRAME]);
     816           78 :         let (Some(name), Some(frame)) = (name, frame) else { return self.format_unimplemented(node) };
     817              :         // An empty window specification is still a pair of parentheses
     818           78 :         let frame_reg = self.reg(frame);
     819           78 :         let frame_reg = if frame_reg == 0 { f.text("()") } else { f.parenthesized(frame_reg) };
     820           78 :         f.concat(&[self.reg(name), f.text(" as "), frame_reg])
     821           78 :     }
     822              : 
     823           81 :     fn format_row_locking_strength(&self, node: &'a Node) -> FmtReg {
     824           81 :         let text = match RowLockingStrength(value_u8(node)) {
     825           33 :             RowLockingStrength::UPDATE => "for update",
     826           12 :             RowLockingStrength::NO_KEY_UPDATE => "for no key update",
     827           12 :             RowLockingStrength::SHARE => "for share",
     828           12 :             RowLockingStrength::KEY_SHARE => "for key share",
     829           12 :             RowLockingStrength::READ_ONLY => "for read only",
     830            0 :             _ => return self.format_unimplemented(node),
     831              :         };
     832           81 :         self.fmt.text(text)
     833           81 :     }
     834              : 
     835           30 :     fn format_row_locking_block_behavior(&self, node: &'a Node) -> FmtReg {
     836           30 :         let text = match RowLockingBlockBehavior(value_u8(node)) {
     837           15 :             RowLockingBlockBehavior::NOWAIT => "nowait",
     838           15 :             RowLockingBlockBehavior::SKIP_LOCKED => "skip locked",
     839            0 :             _ => return self.format_unimplemented(node),
     840              :         };
     841           30 :         self.fmt.text(text)
     842           30 :     }
     843              : 
     844           81 :     fn format_row_locking(&self, node: &'a Node) -> FmtReg {
     845           81 :         let f = &self.fmt;
     846           81 :         let [strength, of, behavior] =
     847           81 :             attrs!(self.children(node), [K::SQL_ROW_LOCKING_STRENGTH, K::SQL_ROW_LOCKING_OF, K::SQL_ROW_LOCKING_BLOCK_BEHAVIOR]);
     848           81 :         let Some(strength) = strength else { return self.format_unimplemented(node) };
     849           81 :         let mut parts = vec![self.reg(strength)];
     850           81 :         if let Some(of) = of.filter(|of| of.children_count() > 0) {
     851           18 :             parts.push(f.text(" of "));
     852           18 :             parts.push(self.reg(of));
     853           63 :         }
     854           81 :         if let Some(behavior) = behavior {
     855           30 :             parts.push(f.text(" "));
     856           30 :             parts.push(self.reg(behavior));
     857           54 :         }
     858           81 :         f.concat(&parts)
     859           81 :     }
     860              : 
     861          105 :     fn format_sample_unit(&self, node: &'a Node) -> FmtReg {
     862          105 :         let text = match SampleCountUnit(value_u8(node)) {
     863           72 :             SampleCountUnit::PERCENT => "%",
     864           33 :             SampleCountUnit::ROWS => " rows",
     865            0 :             _ => return self.format_unimplemented(node),
     866              :         };
     867          105 :         self.fmt.text(text)
     868          105 :     }
     869              : 
     870          105 :     fn format_sample(&self, node: &'a Node, table_sample: bool) -> FmtReg {
     871          105 :         let f = &self.fmt;
     872          105 :         let [value, unit, function, repeat, seed] = attrs!(self.children(node), [
     873              :                 K::SQL_SAMPLE_COUNT_VALUE,
     874              :                 K::SQL_SAMPLE_COUNT_UNIT,
     875              :                 K::SQL_SAMPLE_FUNCTION,
     876              :                 K::SQL_SAMPLE_REPEAT,
     877              :                 K::SQL_SAMPLE_SEED,
     878              :             ],
     879              :         );
     880          105 :         let (Some(value), Some(unit)) = (value, unit) else { return self.format_unimplemented(node) };
     881              : 
     882              :         // Hyper only knows the word PERCENT for a table sample, DuckDB's `using sample` also takes `%`
     883          105 :         let is_percent = unit.node_type() == NodeType::ENUM_SQL_SAMPLE_UNIT_TYPE
     884          105 :             && SampleCountUnit(value_u8(unit)) == SampleCountUnit::PERCENT;
     885          105 :         let unit_reg = if table_sample && is_percent { f.text(" percent") } else { self.reg(unit) };
     886          105 :         let count = f.concat(&[self.reg(value), unit_reg]);
     887          105 :         let mut body = count;
     888          105 :         match (function, seed) {
     889            9 :             (Some(function), Some(seed)) => {
     890            9 :                 let args = f.concat(&[self.reg(function), f.text(", "), self.reg(seed)]);
     891            9 :                 body = f.concat(&[count, f.text(" "), f.parenthesized(args)]);
     892            9 :             }
     893           78 :             (Some(function), None) => body = f.concat(&[self.reg(function), f.parenthesized(count)]),
     894           18 :             _ => {}
     895              :         }
     896          105 :         if let Some(repeat) = repeat {
     897           24 :             body = f.concat(&[body, f.text(" repeatable "), f.parenthesized(self.reg(repeat))]);
     898           81 :         }
     899          105 :         f.concat(&[f.text(if table_sample { "tablesample " } else { "using sample " }), body])
     900          105 :     }
     901              : 
     902          690 :     fn format_joined_table(&self, node: &'a Node) -> FmtReg {
     903          690 :         let f = &self.fmt;
     904          690 :         let [inputs, join_type, join_on, join_using] =
     905          690 :             attrs!(self.children(node), [K::SQL_JOIN_INPUT, K::SQL_JOIN_TYPE, K::SQL_JOIN_ON, K::SQL_JOIN_USING]);
     906          690 :         let (Some(inputs), Some(join_type)) = (inputs, join_type) else { return self.format_unimplemented(node) };
     907          690 :         if inputs.node_type() != NodeType::ARRAY || inputs.children_count() != 2 {
     908            0 :             return self.format_unimplemented(node);
     909          690 :         }
     910              : 
     911          690 :         let left_reg = self.reg(&self.ast[inputs.children_begin_or_value() as usize]);
     912          690 :         let right_reg = self.reg(&self.ast[inputs.children_begin_or_value() as usize + 1]);
     913          690 :         if left_reg == 0 || right_reg == 0 {
     914            0 :             return self.format_unimplemented(node);
     915          690 :         }
     916              : 
     917          690 :         let join_text = match JoinType(value_u8(join_type)) {
     918           63 :             JoinType::NONE => "cross join",
     919          213 :             JoinType::INNER => "join",
     920          216 :             JoinType::LEFT | JoinType::OUTER_LEFT => "left join",
     921           12 :             JoinType::RIGHT | JoinType::OUTER_RIGHT => "right join",
     922           30 :             JoinType::FULL | JoinType::OUTER_FULL => "full join",
     923           39 :             JoinType::SEMI => "semi join",
     924           39 :             JoinType::ANTI => "anti join",
     925           30 :             JoinType::NATURAL_INNER => "natural join",
     926           24 :             JoinType::NATURAL_LEFT | JoinType::NATURAL_OUTER_LEFT => "natural left join",
     927           12 :             JoinType::NATURAL_RIGHT | JoinType::NATURAL_OUTER_RIGHT => "natural right join",
     928           12 :             JoinType::NATURAL_FULL | JoinType::NATURAL_OUTER_FULL => "natural full join",
     929            0 :             _ => return self.format_unimplemented(node),
     930              :         };
     931              : 
     932          690 :         let mut join_clause_parts = vec![f.concat(&[f.text(join_text), f.text(" "), right_reg])];
     933          690 :         if let Some(join_on) = join_on {
     934          531 :             let on_reg = self.reg(join_on);
     935          531 :             if on_reg == 0 {
     936            0 :                 return self.format_unimplemented(node);
     937          531 :             }
     938          531 :             join_clause_parts.push(f.concat(&[f.text("on "), on_reg]));
     939          159 :         } else if let Some(join_using) = join_using {
     940           18 :             let using_reg = self.reg(join_using);
     941           18 :             if using_reg == 0 {
     942            0 :                 return self.format_unimplemented(node);
     943           18 :             }
     944           18 :             join_clause_parts.push(f.concat(&[f.text("using "), f.parenthesized(using_reg)]));
     945          141 :         }
     946          690 :         let join_clause = self.space_join(&join_clause_parts, FormattingJoinPolicy::BreakOnOverflow, true);
     947              : 
     948          690 :         let clause_policy = self.pretty_policy(FormattingJoinPolicy::BreakAllOrNone);
     949          690 :         let mut is_left_nested_join = false;
     950          690 :         let table_ref_id = node.parent() as usize;
     951          690 :         if table_ref_id < self.ast.len() {
     952          690 :             let parent_id = self.ast[table_ref_id].parent() as usize;
     953          690 :             is_left_nested_join = parent_id < self.ast.len()
     954          690 :                 && self.ast[parent_id].node_type() == NodeType::ARRAY
     955          690 :                 && self.ast[parent_id].attribute_key() == K::SQL_JOIN_INPUT
     956          231 :                 && table_ref_id == self.ast[parent_id].children_begin_or_value() as usize;
     957            0 :         }
     958          690 :         self.space_join(&[left_reg, join_clause], clause_policy, !is_left_nested_join)
     959          690 :     }
     960              : 
     961         3879 :     fn format_group_by_item(&self, node: &'a Node) -> FmtReg {
     962         3879 :         let f = &self.fmt;
     963         3879 :         let [item_type, arg] = attrs!(self.children(node), [K::SQL_GROUP_BY_ITEM_TYPE, K::SQL_GROUP_BY_ITEM_ARG]);
     964         3879 :         let Some(item_type) = item_type.filter(|t| t.node_type() == NodeType::ENUM_SQL_GROUP_BY_ITEM_TYPE) else {
     965            0 :             return f.empty();
     966              :         };
     967         3879 :         let arg_reg = match arg {
     968         3873 :             Some(arg) if arg.node_type() != NodeType::NONE => self.reg(arg),
     969            6 :             _ => 0,
     970              :         };
     971         3879 :         let wrap = |keyword: &'static str| {
     972           90 :             if arg_reg == 0 {
     973            0 :                 return f.empty();
     974           90 :             }
     975           90 :             f.concat(&[f.text(keyword), f.parenthesized(arg_reg)])
     976           90 :         };
     977         3879 :         match GroupByItemType(value_u8(item_type)) {
     978         3786 :             GroupByItemType::EXPRESSION => arg_reg,
     979            3 :             GroupByItemType::EMPTY => f.text("()"),
     980            3 :             GroupByItemType::CUBE => wrap("cube"),
     981           84 :             GroupByItemType::ROLLUP => wrap("rollup"),
     982            3 :             GroupByItemType::GROUPING_SETS => wrap("grouping sets"),
     983            0 :             _ => f.empty(),
     984              :         }
     985         3879 :     }
     986              : 
     987              :     // -----------------------------------------------------------------------------------------
     988              :     // Types
     989              :     // -----------------------------------------------------------------------------------------
     990              : 
     991         3030 :     fn format_type_name(&self, node: &'a Node) -> FmtReg {
     992         3030 :         let f = &self.fmt;
     993         3030 :         let [type_node, array, setof] =
     994         3030 :             attrs!(self.children(node), [K::SQL_TYPENAME_TYPE, K::SQL_TYPENAME_ARRAY, K::SQL_TYPENAME_SETOF]);
     995         3030 :         let Some(type_node) = type_node else { return self.format_unimplemented(node) };
     996              : 
     997         3030 :         let mut type_reg = self.reg(type_node);
     998         3030 :         if let Some(array) = array.filter(|a| a.node_type() == NodeType::ARRAY) {
     999              :             // Hyper does not accept row(...)[], only array(row(...))
    1000           57 :             let row_element = type_node.node_type() == NodeType::OBJECT_SQL_ROW_TYPE;
    1001              :             // The keyword form `text array` has no children, a type without array has no text
    1002           57 :             let keyword_form = array.children_count() == 0 && array.symbol_span().length() > 0;
    1003           57 :             let bounds: Vec<Option<&Node>> =
    1004           57 :                 if keyword_form { vec![None] } else { self.children(array).iter().map(Some).collect() };
    1005           60 :             for bound in bounds {
    1006           60 :                 let unbounded = bound.map_or(true, |b| b.node_type() == NodeType::BOOL);
    1007           60 :                 if self.config.dialect == FormattingDialect::TRINO {
    1008            6 :                     if !unbounded {
    1009            0 :                         return self.format_unimplemented(node);
    1010            6 :                     }
    1011            6 :                     type_reg = f.concat(&[f.text("array("), type_reg, f.text(")")]);
    1012           54 :                 } else if row_element && unbounded {
    1013            6 :                     type_reg = f.concat(&[f.text("array("), type_reg, f.text(")")]);
    1014            6 :                 } else {
    1015           48 :                     let bound_reg = bound.filter(|b| b.node_type() != NodeType::BOOL).map_or(f.empty(), |b| self.reg(b));
    1016           48 :                     type_reg = f.concat(&[type_reg, f.text("["), bound_reg, f.text("]")]);
    1017              :                 }
    1018              :             }
    1019         2973 :         }
    1020              : 
    1021         3030 :         let mut parts = Vec::with_capacity(2);
    1022         3030 :         if is_true(setof) {
    1023            3 :             parts.push(f.text("setof "));
    1024         3027 :         }
    1025         3030 :         parts.push(type_reg);
    1026         3030 :         f.concat(&parts)
    1027         3030 :     }
    1028              : 
    1029          191 :     fn format_interval_type_enum(&self, node: &'a Node) -> FmtReg {
    1030          191 :         if node.node_type() != NodeType::ENUM_SQL_INTERVAL_TYPE {
    1031            0 :             return self.format_unimplemented(node);
    1032          191 :         }
    1033          191 :         match crate::analyzer::sql_types::interval_keyword(IntervalType(value_u8(node))) {
    1034          191 :             Some(text) => self.fmt.text(text),
    1035            0 :             None => self.format_unimplemented(node),
    1036              :         }
    1037          191 :     }
    1038              : 
    1039              :     /// The type of `interval '1' day` is the interval qualifier alone, a type name needs the keyword
    1040          215 :     fn format_interval_type(&self, node: &'a Node) -> FmtReg {
    1041          215 :         let f = &self.fmt;
    1042          215 :         let [interval_type, precision] = attrs!(self.children(node), [K::SQL_INTERVAL_TYPE, K::SQL_INTERVAL_PRECISION]);
    1043          215 :         let is_qualifier = node.attribute_key() == K::SQL_CONST_CAST_INTERVAL;
    1044          215 :         let mut parts = Vec::with_capacity(4);
    1045          215 :         if !is_qualifier {
    1046           57 :             parts.push(f.text("interval"));
    1047          158 :         }
    1048          215 :         if let Some(interval_type) = interval_type {
    1049          191 :             if !is_qualifier {
    1050           33 :                 parts.push(f.text(" "));
    1051          158 :             }
    1052          191 :             parts.push(self.reg(interval_type));
    1053           24 :         } else if is_qualifier {
    1054            0 :             return self.format_unimplemented(node);
    1055           24 :         }
    1056          215 :         if let Some(precision) = precision {
    1057           12 :             parts.push(f.parenthesized(self.reg(precision)));
    1058          203 :         }
    1059          215 :         f.concat(&parts)
    1060          215 :     }
    1061              : 
    1062           25 :     fn format_const_type_cast(&self, node: &'a Node) -> FmtReg {
    1063           25 :         let f = &self.fmt;
    1064           25 :         let [type_node, value] = attrs!(self.children(node), [K::SQL_CONST_CAST_TYPE, K::SQL_CONST_CAST_VALUE]);
    1065           25 :         let (Some(type_node), Some(value)) = (type_node, value) else { return self.format_unimplemented(node) };
    1066              :         // Trino reads the time zone of a timestamp or time literal from its text, its literals have no zone in the type
    1067           25 :         if self.config.dialect == FormattingDialect::TRINO {
    1068            1 :             if let Some(keyword) = self.zoned_time_type(type_node) {
    1069            1 :                 let value_reg = self.reg(value);
    1070            1 :                 if value_reg == 0 {
    1071            0 :                     return self.format_unimplemented(node);
    1072            1 :                 }
    1073            1 :                 return f.concat(&[f.text(keyword), f.text(" "), value_reg]);
    1074            0 :             }
    1075           24 :         }
    1076           24 :         let type_reg = self.reg(type_node);
    1077           24 :         let value_reg = self.reg(value);
    1078           24 :         if type_reg == 0 || value_reg == 0 {
    1079            0 :             return self.format_unimplemented(node);
    1080           24 :         }
    1081           24 :         f.concat(&[type_reg, f.text(" "), value_reg])
    1082           25 :     }
    1083              : 
    1084              :     /// The keyword of a timestamp or time type with a time zone, `timestamp with time zone` is `timestamp`
    1085            1 :     fn zoned_time_type(&self, type_node: &'a Node) -> Option<&'static str> {
    1086            1 :         let [element] = attrs!(self.children(type_node), [K::SQL_TYPENAME_TYPE]);
    1087            1 :         let element = element?;
    1088            1 :         let [tz] = attrs!(self.children(element), [K::SQL_TIME_TYPE_WITH_TIMEZONE]);
    1089            1 :         let zoned = tz.is_some_and(|t| t.node_type() == NodeType::BOOL && t.children_begin_or_value() != 0);
    1090            1 :         match element.node_type() {
    1091            1 :             NodeType::OBJECT_SQL_TIMESTAMP_TYPE if zoned => Some("timestamp"),
    1092            0 :             NodeType::OBJECT_SQL_TIME_TYPE if zoned => Some("time"),
    1093            0 :             _ => None,
    1094              :         }
    1095            1 :     }
    1096              : 
    1097          173 :     fn format_const_interval_cast(&self, node: &'a Node) -> FmtReg {
    1098          173 :         let f = &self.fmt;
    1099          173 :         let [value, interval] = attrs!(self.children(node), [K::SQL_CONST_CAST_VALUE, K::SQL_CONST_CAST_INTERVAL]);
    1100          173 :         let Some(value) = value else { return self.format_unimplemented(node) };
    1101          173 :         let mut parts = vec![f.text("interval "), self.reg(value)];
    1102          173 :         if let Some(interval) = interval {
    1103          158 :             parts.push(f.text(" "));
    1104          158 :             parts.push(self.reg(interval));
    1105          158 :         }
    1106          173 :         f.concat(&parts)
    1107          173 :     }
    1108              : 
    1109              :     /// The arguments of a function call, None if an argument cannot be formatted
    1110         6623 :     fn format_call_arguments(&self, args: Option<&'a Node>) -> Option<Vec<FmtReg>> {
    1111         6623 :         let mut arg_items = Vec::new();
    1112         6623 :         if let Some(args) = args {
    1113         5998 :             if args.node_type() != NodeType::ARRAY {
    1114            0 :                 return None;
    1115         5998 :             }
    1116         7138 :             for arg in self.children(args) {
    1117         7138 :                 let reg = self.reg(arg);
    1118         7138 :                 if reg == 0 {
    1119            0 :                     return None;
    1120         7138 :                 }
    1121         7138 :                 arg_items.push(reg);
    1122              :             }
    1123          625 :         }
    1124         6623 :         Some(arg_items)
    1125         6623 :     }
    1126              : 
    1127          343 :     fn format_const_function_cast(&self, node: &'a Node) -> FmtReg {
    1128          343 :         let f = &self.fmt;
    1129          343 :         let [name, args, order, value] = attrs!(self.children(node), [
    1130              :                 K::SQL_CONST_CAST_FUNC_NAME,
    1131              :                 K::SQL_CONST_CAST_FUNC_ARGS_LIST,
    1132              :                 K::SQL_CONST_CAST_FUNC_ARGS_ORDER,
    1133              :                 K::SQL_CONST_CAST_VALUE,
    1134              :             ],
    1135              :         );
    1136          343 :         let (Some(name), Some(value)) = (name, value) else { return self.format_unimplemented(node) };
    1137          343 :         let mut name_reg = self.reg(name);
    1138              :         // Trino reads the time zone of a timestamp or time literal from its text, `timestamptz '...'` is `timestamp '...'`
    1139          343 :         if self.config.dialect == FormattingDialect::TRINO && args.is_none() {
    1140           16 :             match self.text_at(name.symbol_span()).to_ascii_lowercase().as_str() {
    1141           16 :                 "timestamptz" => name_reg = f.text("timestamp"),
    1142           15 :                 "timetz" => name_reg = f.text("time"),
    1143           15 :                 _ => {}
    1144              :             }
    1145          327 :         }
    1146          343 :         let value_reg = self.reg(value);
    1147          343 :         if name_reg == 0 || value_reg == 0 {
    1148            0 :             return self.format_unimplemented(node);
    1149          343 :         }
    1150              : 
    1151          343 :         let Some(arg_items) = self.format_call_arguments(args) else { return self.format_unimplemented(node) };
    1152          343 :         let mut call_parts = Vec::with_capacity(3);
    1153          343 :         if !arg_items.is_empty() {
    1154            9 :             call_parts.push(self.comma_join_on_overflow(&arg_items, true));
    1155          334 :         }
    1156          343 :         if let Some(order) = order {
    1157            0 :             let order_reg = self.reg(order);
    1158            0 :             if order_reg == 0 {
    1159            0 :                 return self.format_unimplemented(node);
    1160            0 :             }
    1161            0 :             call_parts.push(f.text(if call_parts.is_empty() { "order by " } else { " order by " }));
    1162            0 :             call_parts.push(order_reg);
    1163          343 :         }
    1164              : 
    1165          343 :         let mut call_reg = name_reg;
    1166          343 :         if !call_parts.is_empty() {
    1167            9 :             let call_body = f.concat(&call_parts);
    1168            9 :             if call_body == 0 {
    1169            0 :                 return self.format_unimplemented(node);
    1170            9 :             }
    1171            9 :             call_reg = f.concat(&[name_reg, f.parenthesized(call_body)]);
    1172          334 :         }
    1173          343 :         f.concat(&[call_reg, f.text(" "), value_reg])
    1174          343 :     }
    1175              : 
    1176         1494 :     fn format_numeric_type_base(&self, node: &'a Node) -> FmtReg {
    1177         1494 :         if node.node_type() != NodeType::ENUM_SQL_NUMERIC_TYPE {
    1178            0 :             return self.format_unimplemented(node);
    1179         1494 :         }
    1180         1494 :         let text = match NumericType(value_u8(node)) {
    1181            0 :             NumericType::INT1 => "tinyint",
    1182            9 :             NumericType::INT2 => "smallint",
    1183          875 :             NumericType::INT4 => "integer",
    1184           57 :             NumericType::INT8 => "bigint",
    1185           21 :             NumericType::FLOAT4 => "real",
    1186           15 :             NumericType::FLOAT8 => "double precision",
    1187          502 :             NumericType::NUMERIC => "numeric",
    1188           15 :             NumericType::BOOL => "boolean",
    1189            0 :             _ => return self.format_unimplemented(node),
    1190              :         };
    1191         1494 :         self.fmt.text(text)
    1192         1494 :     }
    1193              : 
    1194              :     /// `(m1, m2, ...)` of a type with modifiers
    1195          493 :     fn format_type_modifiers(&self, modifiers: &'a Node) -> FmtReg {
    1196          980 :         let values: Vec<FmtReg> = self.children(modifiers).iter().map(|m| self.reg(m)).collect();
    1197          493 :         let (inline_separator, break_separator) = self.comma_separators();
    1198          493 :         let joined = self.fmt.join(&values, inline_separator, break_separator, None, true);
    1199          493 :         self.fmt.parenthesized(joined)
    1200          493 :     }
    1201              : 
    1202          502 :     fn format_numeric_type(&self, node: &'a Node) -> FmtReg {
    1203          502 :         let [base, modifiers] = attrs!(self.children(node), [K::SQL_NUMERIC_TYPE_BASE, K::SQL_NUMERIC_TYPE_MODIFIERS]);
    1204          502 :         let Some(base) = base else { return self.format_unimplemented(node) };
    1205          502 :         let mut parts = vec![self.reg(base)];
    1206          502 :         if let Some(modifiers) = modifiers.filter(|m| m.node_type() == NodeType::ARRAY && m.children_count() > 0) {
    1207          490 :             parts.push(self.format_type_modifiers(modifiers));
    1208          490 :         }
    1209          502 :         self.fmt.concat(&parts)
    1210          502 :     }
    1211              : 
    1212          447 :     fn format_character_type_base(&self, node: &'a Node) -> FmtReg {
    1213          447 :         if node.node_type() != NodeType::ENUM_SQL_CHARACTER_TYPE {
    1214            0 :             return self.format_unimplemented(node);
    1215          447 :         }
    1216          447 :         let text = match CharacterType(value_u8(node)) {
    1217          246 :             CharacterType::VARCHAR => "varchar",
    1218          201 :             CharacterType::BLANK_PADDED_CHAR => "char",
    1219            0 :             _ => return self.format_unimplemented(node),
    1220              :         };
    1221          447 :         self.fmt.text(text)
    1222          447 :     }
    1223              : 
    1224          447 :     fn format_character_type(&self, node: &'a Node) -> FmtReg {
    1225          447 :         let f = &self.fmt;
    1226          447 :         let [character_type, length] = attrs!(self.children(node), [K::SQL_CHARACTER_TYPE, K::SQL_CHARACTER_TYPE_LENGTH]);
    1227          447 :         let Some(character_type) = character_type else { return self.format_unimplemented(node) };
    1228          447 :         let mut parts = vec![self.reg(character_type)];
    1229          447 :         if let Some(length) = length {
    1230          372 :             parts.push(f.parenthesized(self.reg(length)));
    1231          375 :         }
    1232          447 :         f.concat(&parts)
    1233          447 :     }
    1234              : 
    1235          795 :     fn format_generic_type(&self, node: &'a Node) -> FmtReg {
    1236          795 :         let f = &self.fmt;
    1237          795 :         let [name, modifiers] = attrs!(self.children(node), [K::SQL_GENERIC_TYPE_NAME, K::SQL_GENERIC_TYPE_MODIFIERS]);
    1238          795 :         let Some(name) = name else { return self.format_unimplemented(node) };
    1239              : 
    1240          795 :         let name_text = self.text_at(name.symbol_span());
    1241          795 :         if name_text.eq_ignore_ascii_case("array") {
    1242           57 :             if let Some(modifiers) = modifiers.filter(|m| m.node_type() == NodeType::ARRAY && m.children_count() == 1) {
    1243           57 :                 let element_node = &self.ast[modifiers.children_begin_or_value() as usize];
    1244           57 :                 let element = self.reg(element_node);
    1245              :                 // Hyper does not accept row(...)[], only array(row(...))
    1246           57 :                 let [element_type] = attrs!(self.children(element_node), [K::SQL_TYPENAME_TYPE]);
    1247           57 :                 let row_element = element_type.is_some_and(|t| t.node_type() == NodeType::OBJECT_SQL_ROW_TYPE);
    1248           57 :                 if self.config.dialect == FormattingDialect::HYPER && !row_element {
    1249           13 :                     return f.concat(&[element, f.text("[]")]);
    1250           44 :                 }
    1251           44 :                 return f.concat(&[f.text("array("), element, f.text(")")]);
    1252            0 :             }
    1253          738 :         }
    1254              : 
    1255          738 :         let mut parts = vec![self.reg(name)];
    1256          738 :         if let Some(modifiers) = modifiers.filter(|m| m.node_type() == NodeType::ARRAY && m.children_count() > 0) {
    1257            3 :             parts.push(self.format_type_modifiers(modifiers));
    1258          735 :         }
    1259          738 :         f.concat(&parts)
    1260          795 :     }
    1261              : 
    1262           72 :     fn format_timestamp_type(&self, node: &'a Node) -> FmtReg {
    1263           72 :         let f = &self.fmt;
    1264           72 :         let [precision, with_tz] = attrs!(self.children(node), [K::SQL_TIME_TYPE_PRECISION, K::SQL_TIME_TYPE_WITH_TIMEZONE]);
    1265           72 :         let is_time = node.node_type() == NodeType::OBJECT_SQL_TIME_TYPE;
    1266           72 :         let mut parts = vec![f.text(if is_time { "time" } else { "timestamp" })];
    1267           72 :         if let Some(precision) = precision {
    1268           24 :             parts.push(f.parenthesized(self.reg(precision)));
    1269           48 :         }
    1270           72 :         if is_true(with_tz) {
    1271           33 :             parts.push(f.text(" with time zone"));
    1272           51 :         }
    1273           72 :         f.concat(&parts)
    1274           72 :     }
    1275              : 
    1276              :     // -----------------------------------------------------------------------------------------
    1277              :     // Ordering and enums
    1278              :     // -----------------------------------------------------------------------------------------
    1279              : 
    1280         3942 :     fn format_order(&self, node: &'a Node) -> FmtReg {
    1281         3942 :         let [value, direction, nullrule] =
    1282         3942 :             attrs!(self.children(node), [K::SQL_ORDER_VALUE, K::SQL_ORDER_DIRECTION, K::SQL_ORDER_NULLRULE]);
    1283         3942 :         let Some(value) = value else { return self.format_unimplemented(node) };
    1284         3942 :         let mut parts = vec![self.reg(value)];
    1285         3942 :         if let Some(direction) = direction {
    1286          498 :             parts.push(self.reg(direction));
    1287         3444 :         }
    1288         3942 :         if let Some(nullrule) = nullrule {
    1289         1473 :             parts.push(self.reg(nullrule));
    1290         2469 :         }
    1291         3942 :         self.space_join(&parts, FormattingJoinPolicy::BreakAllOrNone, true)
    1292         3942 :     }
    1293              : 
    1294          498 :     fn format_order_direction(&self, node: &'a Node) -> FmtReg {
    1295          498 :         if node.node_type() != NodeType::ENUM_SQL_ORDER_DIRECTION {
    1296            0 :             return self.format_unimplemented(node);
    1297          498 :         }
    1298          498 :         let text = match OrderDirection(value_u8(node)) {
    1299           87 :             OrderDirection::ASCENDING => "asc",
    1300          411 :             OrderDirection::DESCENDING => "desc",
    1301            0 :             _ => return self.format_unimplemented(node),
    1302              :         };
    1303          498 :         self.fmt.text(text)
    1304          498 :     }
    1305              : 
    1306         1473 :     fn format_order_null_rule(&self, node: &'a Node) -> FmtReg {
    1307         1473 :         if node.node_type() != NodeType::ENUM_SQL_ORDER_NULL_RULE {
    1308            0 :             return self.format_unimplemented(node);
    1309         1473 :         }
    1310         1473 :         let text = match OrderNullRule(value_u8(node)) {
    1311         1449 :             OrderNullRule::NULLS_FIRST => "nulls first",
    1312           24 :             OrderNullRule::NULLS_LAST => "nulls last",
    1313            0 :             _ => return self.format_unimplemented(node),
    1314              :         };
    1315         1473 :         self.fmt.text(text)
    1316         1473 :     }
    1317              : 
    1318           81 :     fn format_extract_target(&self, node: &'a Node) -> FmtReg {
    1319           81 :         if node.node_type() != NodeType::ENUM_SQL_EXTRACT_TARGET {
    1320            0 :             return self.format_unimplemented(node);
    1321           81 :         }
    1322           81 :         let text = match ExtractTarget(value_u8(node)) {
    1323           42 :             ExtractTarget::YEAR => "year",
    1324            6 :             ExtractTarget::MONTH => "month",
    1325           15 :             ExtractTarget::DAY => "day",
    1326            6 :             ExtractTarget::HOUR => "hour",
    1327            6 :             ExtractTarget::MINUTE => "minute",
    1328            6 :             ExtractTarget::SECOND => "second",
    1329            0 :             _ => return self.format_unimplemented(node),
    1330              :         };
    1331           81 :         self.fmt.text(text)
    1332           81 :     }
    1333              : 
    1334           66 :     fn format_trim_direction(&self, node: &'a Node) -> FmtReg {
    1335           66 :         if node.node_type() != NodeType::ENUM_SQL_TRIM_TARGET {
    1336            0 :             return self.format_unimplemented(node);
    1337           66 :         }
    1338           66 :         let text = match TrimDirection(value_u8(node)) {
    1339           39 :             TrimDirection::BOTH => "both",
    1340           15 :             TrimDirection::LEADING => "leading",
    1341           12 :             TrimDirection::TRAILING => "trailing",
    1342            0 :             _ => return self.format_unimplemented(node),
    1343              :         };
    1344           66 :         self.fmt.text(text)
    1345           66 :     }
    1346              : 
    1347              :     // -----------------------------------------------------------------------------------------
    1348              :     // References and rows
    1349              :     // -----------------------------------------------------------------------------------------
    1350              : 
    1351        50753 :     fn format_column_ref(&self, node: &'a Node) -> FmtReg {
    1352        50753 :         let [path] = attrs!(self.children(node), [K::SQL_COLUMN_REF_PATH]);
    1353        50753 :         match path {
    1354        50753 :             Some(path) => self.reg(path),
    1355            0 :             None => self.format_unimplemented(node),
    1356              :         }
    1357        50753 :     }
    1358              : 
    1359          300 :     fn format_parameter_ref(&self, node: &'a Node) -> FmtReg {
    1360          300 :         let [prefix, name] = attrs!(self.children(node), [K::SQL_PARAMETER_PREFIX, K::SQL_PARAMETER_NAME]);
    1361          300 :         let Some(prefix) = prefix else { return self.format_unimplemented(node) };
    1362          300 :         let prefix_reg = self.reg(prefix);
    1363          300 :         if prefix_reg == 0 {
    1364            0 :             return self.format_unimplemented(node);
    1365          300 :         }
    1366              :         // Positional parameters (?) have no name
    1367          300 :         let Some(name) = name else { return prefix_reg };
    1368          240 :         let name_reg = self.reg(name);
    1369          240 :         if name_reg == 0 {
    1370            0 :             return self.format_unimplemented(node);
    1371          240 :         }
    1372          240 :         self.fmt.concat(&[prefix_reg, name_reg])
    1373          300 :     }
    1374              : 
    1375              :     /// `<keyword>(<attribute>)`, unformattable without the attribute
    1376          417 :     fn format_keyword_call(&self, node: &'a Node, key: AttributeKey, keyword: &'static str) -> FmtReg {
    1377          417 :         let [child] = attrs!(self.children(node), [key]);
    1378          417 :         let Some(child) = child else { return self.format_unimplemented(node) };
    1379          417 :         let child_reg = self.reg(child);
    1380          417 :         if child_reg == 0 {
    1381            0 :             return self.format_unimplemented(node);
    1382          417 :         }
    1383          417 :         let f = &self.fmt;
    1384          417 :         f.concat(&[f.text(keyword), f.parenthesized(child_reg)])
    1385          417 :     }
    1386              : 
    1387           36 :     fn format_relation_expression(&self, node: &'a Node) -> FmtReg {
    1388           36 :         self.format_keyword_call(node, K::SQL_TABLEREF_NAME, "table")
    1389           36 :     }
    1390              : 
    1391           42 :     fn format_descriptor(&self, node: &'a Node) -> FmtReg {
    1392           42 :         self.format_keyword_call(node, K::SQL_DESCRIPTOR_COLUMNS, "descriptor")
    1393           42 :     }
    1394              : 
    1395          108 :     fn format_indirection(&self, node: &'a Node) -> FmtReg {
    1396          108 :         let [value, path] = attrs!(self.children(node), [K::SQL_INDIRECTION_VALUE, K::SQL_INDIRECTION_PATH]);
    1397          108 :         let (Some(value), Some(path)) = (value, path) else { return self.format_unimplemented(node) };
    1398          108 :         let value_reg = self.reg(value);
    1399          108 :         let path_reg = self.reg(path);
    1400          108 :         if value_reg == 0 || path_reg == 0 {
    1401            0 :             return self.format_unimplemented(node);
    1402          108 :         }
    1403          108 :         self.fmt.concat(&[self.fmt.parenthesized(value_reg), path_reg])
    1404          108 :     }
    1405              : 
    1406          135 :     fn format_row_type(&self, node: &'a Node) -> FmtReg {
    1407          135 :         self.format_keyword_call(node, K::SQL_ROW_TYPE_FIELDS, "row")
    1408          135 :     }
    1409              : 
    1410          258 :     fn format_row_expression(&self, node: &'a Node) -> FmtReg {
    1411          258 :         let f = &self.fmt;
    1412          258 :         let [is_explicit, values] = attrs!(self.children(node), [K::SQL_ROW_EXPRESSION_EXPLICIT, K::SQL_ROW_EXPRESSION_VALUES]);
    1413          258 :         let Some(values) = values.filter(|v| v.node_type() == NodeType::ARRAY) else {
    1414            0 :             return self.format_unimplemented(node);
    1415              :         };
    1416          258 :         if values.children_count() == 0 {
    1417           12 :             return f.text("row()");
    1418          246 :         }
    1419          246 :         let values_reg = self.reg(values);
    1420          246 :         if values_reg == 0 {
    1421            0 :             return self.format_unimplemented(node);
    1422          246 :         }
    1423              :         // (x) is just x, so a single value always needs the row keyword
    1424          246 :         if is_explicit.is_some() || values.children_count() == 1 {
    1425          102 :             return f.concat(&[f.text("row"), f.parenthesized(values_reg)]);
    1426          144 :         }
    1427          144 :         f.parenthesized(values_reg)
    1428          258 :     }
    1429              : 
    1430              :     /// `array[...]` or `array(select ...)`
    1431          126 :     fn format_array_expression(&self, node: &'a Node) -> FmtReg {
    1432          126 :         let f = &self.fmt;
    1433          126 :         let [values, statement] =
    1434          126 :             attrs!(self.children(node), [K::SQL_ARRAY_EXPRESSION_VALUES, K::SQL_ARRAY_EXPRESSION_STATEMENT]);
    1435          126 :         if statement.is_some() {
    1436           24 :             return self.format_keyword_call(node, K::SQL_ARRAY_EXPRESSION_STATEMENT, "array");
    1437          102 :         }
    1438          102 :         let Some(values) = values.filter(|v| v.node_type() == NodeType::ARRAY) else {
    1439            0 :             return self.format_unimplemented(node);
    1440              :         };
    1441          102 :         if values.children_count() == 0 {
    1442           12 :             return f.text("array[]");
    1443           90 :         }
    1444           90 :         let values_reg = self.reg(values);
    1445           90 :         if values_reg == 0 {
    1446            0 :             return self.format_unimplemented(node);
    1447           90 :         }
    1448           90 :         f.concat(&[f.text("array"), f.bracketed(values_reg)])
    1449          126 :     }
    1450              : 
    1451              :     // -----------------------------------------------------------------------------------------
    1452              :     // Column definitions and constraints
    1453              :     // -----------------------------------------------------------------------------------------
    1454              : 
    1455         1502 :     fn format_column_def(&self, node: &'a Node) -> FmtReg {
    1456         1502 :         let f = &self.fmt;
    1457              :         #[rustfmt::skip]
    1458         1502 :         let [name, type_node, options, constraints, collate] = attrs!(self.children(node), [
    1459              :             K::SQL_COLUMN_DEF_NAME,
    1460              :             K::SQL_COLUMN_DEF_TYPE,
    1461              :             K::SQL_COLUMN_DEF_OPTIONS,
    1462              :             K::SQL_COLUMN_DEF_CONSTRAINTS,
    1463              :             K::SQL_COLUMN_DEF_COLLATE,
    1464              :         ]);
    1465         1502 :         let (Some(name), Some(type_node)) = (name, type_node) else { return self.format_unimplemented(node) };
    1466              : 
    1467         1502 :         let mut parts = Vec::with_capacity(6);
    1468         1502 :         parts.push(self.reg_or_placeholder(name));
    1469         1502 :         parts.push(f.text(" "));
    1470         1502 :         parts.push(self.reg_or_placeholder(type_node));
    1471         1502 :         if let Some(collate) = collate {
    1472           21 :             parts.push(f.text(" collate "));
    1473           21 :             parts.push(self.reg_or_placeholder(collate));
    1474         1481 :         }
    1475              : 
    1476         1502 :         if let Some(options) = options {
    1477           12 :             if options.node_type() != NodeType::ARRAY {
    1478            0 :                 parts.push(f.text(" "));
    1479            0 :                 parts.push(self.format_unimplemented(options));
    1480           12 :             } else if options.children_count() > 0 {
    1481           12 :                 let option_parts: Vec<FmtReg> =
    1482           15 :                     self.children(options).iter().map(|o| self.reg_or_placeholder(o)).collect();
    1483           12 :                 let option_list = self.comma_join_on_overflow(&option_parts, true);
    1484           12 :                 parts.push(f.text(" options "));
    1485           12 :                 parts.push(f.parenthesized(option_list));
    1486            0 :             }
    1487         1490 :         }
    1488              : 
    1489         1502 :         if let Some(constraints) = constraints {
    1490          804 :             if constraints.node_type() != NodeType::ARRAY {
    1491            0 :                 parts.push(f.text(" "));
    1492            0 :                 parts.push(self.format_unimplemented(constraints));
    1493          804 :             } else if constraints.children_count() > 0 {
    1494          804 :                 let constraint_parts: Vec<FmtReg> =
    1495          822 :                     self.children(constraints).iter().map(|c| self.reg_or_placeholder(c)).collect();
    1496          804 :                 let constraint_list = self.space_join(&constraint_parts, FormattingJoinPolicy::BreakOnOverflow, true);
    1497          804 :                 parts.push(f.text(" "));
    1498          804 :                 parts.push(constraint_list);
    1499            0 :             }
    1500          698 :         }
    1501         1502 :         f.concat(&parts)
    1502         1502 :     }
    1503              : 
    1504          219 :     fn format_table_constraint_type(&self, node: &'a Node) -> FmtReg {
    1505          219 :         if node.node_type() != NodeType::ENUM_SQL_TABLE_CONSTRAINT {
    1506            0 :             return self.format_unimplemented(node);
    1507          219 :         }
    1508          219 :         let text = match TableConstraint(value_u8(node)) {
    1509           36 :             TableConstraint::CHECK => "check",
    1510           45 :             TableConstraint::UNIQUE => "unique",
    1511          123 :             TableConstraint::PRIMARY_KEY => "primary key",
    1512           15 :             TableConstraint::FOREIGN_KEY => "foreign key",
    1513            0 :             _ => return self.format_unimplemented(node),
    1514              :         };
    1515          219 :         self.fmt.text(text)
    1516          219 :     }
    1517              : 
    1518           12 :     fn format_key_match(&self, node: &'a Node) -> FmtReg {
    1519           12 :         if node.node_type() != NodeType::ENUM_SQL_KEY_MATCH {
    1520            0 :             return self.format_unimplemented(node);
    1521           12 :         }
    1522           12 :         let text = match KeyMatch(value_u8(node)) {
    1523            6 :             KeyMatch::FULL => "match full",
    1524            3 :             KeyMatch::PARTIAL => "match partial",
    1525            3 :             KeyMatch::SIMPLE => "match simple",
    1526            0 :             _ => return self.format_unimplemented(node),
    1527              :         };
    1528           12 :         self.fmt.text(text)
    1529           12 :     }
    1530              : 
    1531           21 :     fn format_key_action_command(&self, node: &'a Node) -> FmtReg {
    1532           21 :         if node.node_type() != NodeType::ENUM_SQL_KEY_ACTION_COMMAND {
    1533            0 :             return self.format_unimplemented(node);
    1534           21 :         }
    1535           21 :         let text = match KeyActionCommand(value_u8(node)) {
    1536            3 :             KeyActionCommand::NO_ACTION => "no action",
    1537            3 :             KeyActionCommand::RESTRICT => "restrict",
    1538            6 :             KeyActionCommand::CASCADE => "cascade",
    1539            6 :             KeyActionCommand::SET_NULL => "set null",
    1540            3 :             KeyActionCommand::SET_DEFAULT => "set default",
    1541            0 :             _ => return self.format_unimplemented(node),
    1542              :         };
    1543           21 :         self.fmt.text(text)
    1544           21 :     }
    1545              : 
    1546           21 :     fn format_key_action_trigger(&self, node: &'a Node) -> FmtReg {
    1547           21 :         if node.node_type() != NodeType::ENUM_SQL_KEY_ACTION_TRIGGER {
    1548            0 :             return self.format_unimplemented(node);
    1549           21 :         }
    1550           21 :         let text = match KeyActionTrigger(value_u8(node)) {
    1551            9 :             KeyActionTrigger::UPDATE => "on update",
    1552           12 :             KeyActionTrigger::DELETE => "on delete",
    1553            0 :             _ => return self.format_unimplemented(node),
    1554              :         };
    1555           21 :         self.fmt.text(text)
    1556           21 :     }
    1557              : 
    1558           21 :     fn format_key_action(&self, node: &'a Node) -> FmtReg {
    1559           21 :         let [trigger, command] = attrs!(self.children(node), [K::SQL_KEY_ACTION_TRIGGER, K::SQL_KEY_ACTION_COMMAND]);
    1560           21 :         let (Some(trigger), Some(command)) = (trigger, command) else { return self.format_unimplemented(node) };
    1561           21 :         self.space_join(&[self.reg(trigger), self.reg(command)], FormattingJoinPolicy::BreakAllOrNone, true)
    1562           21 :     }
    1563              : 
    1564              :     /// A space-separated list of constraint parts
    1565          939 :     fn format_space_list(&self, list: &'a Node) -> FmtReg {
    1566          939 :         if list.node_type() != NodeType::ARRAY {
    1567            0 :             return self.format_unimplemented(list);
    1568          939 :         }
    1569          939 :         if list.children_count() == 0 {
    1570            0 :             return self.fmt.empty();
    1571          939 :         }
    1572          981 :         let parts: Vec<FmtReg> = self.children(list).iter().map(|c| self.reg_or_placeholder(c)).collect();
    1573          939 :         self.space_join(&parts, FormattingJoinPolicy::BreakOnOverflow, true)
    1574          939 :     }
    1575              : 
    1576          219 :     fn format_table_constraint(&self, node: &'a Node) -> FmtReg {
    1577          219 :         let f = &self.fmt;
    1578              :         #[rustfmt::skip]
    1579              :         let [
    1580          219 :             constraint_type, constraint_name, constraint_argument, constraint_index, constraint_columns,
    1581          219 :             constraint_references_name, constraint_references_columns, constraint_attributes, constraint_definition,
    1582          219 :             constraint_key_actions, constraint_key_match,
    1583          219 :         ] = attrs!(self.children(node), [
    1584              :                 K::SQL_TABLE_CONSTRAINT_TYPE,
    1585              :                 K::SQL_TABLE_CONSTRAINT_NAME,
    1586              :                 K::SQL_TABLE_CONSTRAINT_ARGUMENT,
    1587              :                 K::SQL_TABLE_CONSTRAINT_INDEX,
    1588              :                 K::SQL_TABLE_CONSTRAINT_COLUMNS,
    1589              :                 K::SQL_TABLE_CONSTRAINT_REFERENCES_NAME,
    1590              :                 K::SQL_TABLE_CONSTRAINT_REFERENCES_COLUMNS,
    1591              :                 K::SQL_TABLE_CONSTRAINT_ATTRIBUTES,
    1592              :                 K::SQL_TABLE_CONSTRAINT_DEFINITION,
    1593              :                 K::SQL_TABLE_CONSTRAINT_KEY_ACTIONS,
    1594              :                 K::SQL_TABLE_CONSTRAINT_KEY_MATCH,
    1595              :             ],
    1596              :         );
    1597          219 :         let Some(constraint_type) = constraint_type.filter(|t| t.node_type() == NodeType::ENUM_SQL_TABLE_CONSTRAINT)
    1598              :         else {
    1599            0 :             return self.format_unimplemented(node);
    1600              :         };
    1601          228 :         let or_placeholder = |child: Option<&'a Node>| match child {
    1602          216 :             Some(child) => self.reg_or_placeholder(child),
    1603            0 :             None => self.format_unimplemented(node),
    1604          216 :         };
    1605              : 
    1606          219 :         let mut parts = Vec::with_capacity(16);
    1607          219 :         if let Some(constraint_name) = constraint_name {
    1608           15 :             parts.push(f.text("constraint "));
    1609           15 :             parts.push(self.reg_or_placeholder(constraint_name));
    1610           15 :             parts.push(f.text(" "));
    1611          204 :         }
    1612              : 
    1613          219 :         let ctype = TableConstraint(value_u8(constraint_type));
    1614          219 :         parts.push(self.reg_or_placeholder(constraint_type));
    1615          219 :         match ctype {
    1616           36 :             TableConstraint::CHECK => {
    1617           36 :                 parts.push(f.text(" "));
    1618           36 :                 parts.push(f.parenthesized(or_placeholder(constraint_argument)));
    1619           36 :             }
    1620              :             TableConstraint::UNIQUE | TableConstraint::PRIMARY_KEY => {
    1621          168 :                 if let Some(constraint_index) = constraint_index {
    1622           18 :                     parts.push(f.text(" using index "));
    1623           18 :                     parts.push(self.reg_or_placeholder(constraint_index));
    1624          150 :                 } else {
    1625          150 :                     parts.push(f.text(" "));
    1626          150 :                     parts.push(f.parenthesized(or_placeholder(constraint_columns)));
    1627          150 :                 }
    1628              :             }
    1629              :             TableConstraint::FOREIGN_KEY => {
    1630           15 :                 parts.push(f.text(" "));
    1631           15 :                 parts.push(f.parenthesized(or_placeholder(constraint_columns)));
    1632           15 :                 parts.push(f.text(" references "));
    1633           15 :                 parts.push(or_placeholder(constraint_references_name));
    1634            9 :                 if let Some(columns) =
    1635           15 :                     constraint_references_columns.filter(|c| c.node_type() == NodeType::ARRAY && c.children_count() > 0)
    1636            9 :                 {
    1637            9 :                     parts.push(f.text(" "));
    1638            9 :                     parts.push(f.parenthesized(self.reg_or_placeholder(columns)));
    1639            9 :                 }
    1640              :             }
    1641            0 :             _ => {}
    1642              :         }
    1643              : 
    1644          219 :         if let Some(constraint_key_match) = constraint_key_match {
    1645           12 :             parts.push(f.text(" "));
    1646           12 :             parts.push(self.reg_or_placeholder(constraint_key_match));
    1647          207 :         }
    1648          219 :         if let Some(constraint_key_actions) = constraint_key_actions {
    1649           15 :             let actions = self.format_space_list(constraint_key_actions);
    1650           15 :             if actions != 0 {
    1651           15 :                 parts.push(f.text(" "));
    1652           15 :                 parts.push(actions);
    1653           15 :             }
    1654          204 :         }
    1655          219 :         if let Some(constraint_attributes) = constraint_attributes {
    1656           60 :             let attributes = self.format_space_list(constraint_attributes);
    1657           60 :             if attributes != 0 {
    1658           60 :                 parts.push(f.text(" "));
    1659           60 :                 parts.push(attributes);
    1660           60 :             }
    1661          159 :         }
    1662          219 :         if let Some(constraint_definition) = constraint_definition {
    1663           12 :             let definition = self.reg_or_placeholder(constraint_definition);
    1664           12 :             if definition != 0 {
    1665           12 :                 parts.push(f.text(" with "));
    1666           12 :                 parts.push(f.parenthesized(definition));
    1667           12 :             }
    1668          207 :         }
    1669          219 :         f.concat(&parts)
    1670          219 :     }
    1671              : 
    1672          816 :     fn format_column_constraint_type(&self, node: &'a Node) -> FmtReg {
    1673          816 :         if node.node_type() != NodeType::ENUM_SQL_COLUMN_CONSTRAINT {
    1674            0 :             return self.format_unimplemented(node);
    1675          816 :         }
    1676          816 :         let text = match ColumnConstraint(value_u8(node)) {
    1677          762 :             ColumnConstraint::NOT_NULL => "not null",
    1678            3 :             ColumnConstraint::NULL_ => "null",
    1679            6 :             ColumnConstraint::UNIQUE => "unique",
    1680            9 :             ColumnConstraint::PRIMARY_KEY => "primary key",
    1681           12 :             ColumnConstraint::CHECK => "check",
    1682           15 :             ColumnConstraint::DEFAULT => "default",
    1683            9 :             ColumnConstraint::COLLATE => "collate",
    1684            0 :             _ => return self.format_unimplemented(node),
    1685              :         };
    1686          816 :         self.fmt.text(text)
    1687          816 :     }
    1688              : 
    1689          816 :     fn format_column_constraint(&self, node: &'a Node) -> FmtReg {
    1690          816 :         let f = &self.fmt;
    1691              :         #[rustfmt::skip]
    1692              :         let [
    1693          816 :             constraint_type, constraint_name, constraint_value, constraint_no_inherit, constraint_definition,
    1694          816 :             constraint_collate,
    1695          816 :         ] = attrs!(self.children(node), [
    1696              :                 K::SQL_COLUMN_CONSTRAINT_TYPE,
    1697              :                 K::SQL_COLUMN_CONSTRAINT_NAME,
    1698              :                 K::SQL_COLUMN_CONSTRAINT_VALUE,
    1699              :                 K::SQL_COLUMN_CONSTRAINT_NO_INHERIT,
    1700              :                 K::SQL_COLUMN_CONSTRAINT_DEFINITION,
    1701              :                 K::SQL_COLUMN_CONSTRAINT_COLLATE,
    1702              :             ],
    1703              :         );
    1704          816 :         let Some(constraint_type) = constraint_type.filter(|t| t.node_type() == NodeType::ENUM_SQL_COLUMN_CONSTRAINT)
    1705              :         else {
    1706            0 :             return self.format_unimplemented(node);
    1707              :         };
    1708          816 :         let or_placeholder = |child: Option<&'a Node>| match child {
    1709           36 :             Some(child) => self.reg_or_placeholder(child),
    1710            0 :             None => self.format_unimplemented(node),
    1711           36 :         };
    1712              : 
    1713          816 :         let mut parts = Vec::with_capacity(8);
    1714          816 :         if let Some(constraint_name) = constraint_name {
    1715           12 :             parts.push(f.text("constraint "));
    1716           12 :             parts.push(self.reg_or_placeholder(constraint_name));
    1717           12 :             parts.push(f.text(" "));
    1718          804 :         }
    1719              : 
    1720          816 :         let ctype = ColumnConstraint(value_u8(constraint_type));
    1721          816 :         parts.push(self.reg_or_placeholder(constraint_type));
    1722          816 :         match ctype {
    1723              :             ColumnConstraint::CHECK => {
    1724           12 :                 parts.push(f.text(" "));
    1725           12 :                 parts.push(f.parenthesized(or_placeholder(constraint_value)));
    1726           12 :                 if is_true(constraint_no_inherit) {
    1727            3 :                     parts.push(f.text(" no inherit"));
    1728            9 :                 }
    1729              :             }
    1730           15 :             ColumnConstraint::DEFAULT => {
    1731           15 :                 parts.push(f.text(" "));
    1732           15 :                 parts.push(or_placeholder(constraint_value));
    1733           15 :             }
    1734            9 :             ColumnConstraint::COLLATE => {
    1735            9 :                 parts.push(f.text(" "));
    1736            9 :                 parts.push(or_placeholder(constraint_collate));
    1737            9 :             }
    1738          780 :             _ => {}
    1739              :         }
    1740              : 
    1741          816 :         if let Some(constraint_definition) = constraint_definition {
    1742            0 :             let def_reg = self.reg_or_placeholder(constraint_definition);
    1743            0 :             if def_reg != 0 {
    1744            0 :                 parts.push(f.text(" with "));
    1745            0 :                 parts.push(f.parenthesized(def_reg));
    1746            0 :             }
    1747          816 :         }
    1748          816 :         f.concat(&parts)
    1749          816 :     }
    1750              : 
    1751           75 :     fn format_constraint_attribute(&self, node: &'a Node) -> FmtReg {
    1752           75 :         if node.node_type() != NodeType::ENUM_SQL_CONSTRAINT_ATTRIBUTE {
    1753            0 :             return self.format_unimplemented(node);
    1754           75 :         }
    1755           75 :         let text = match ConstraintAttribute(value_u8(node)) {
    1756           18 :             ConstraintAttribute::DEFERRABLE => "deferrable",
    1757            9 :             ConstraintAttribute::NOT_DEFERRABLE => "not deferrable",
    1758            9 :             ConstraintAttribute::INITIALLY_DEFERRED => "initially deferred",
    1759            9 :             ConstraintAttribute::INITIALLY_IMMEDIATE => "initially immediate",
    1760           15 :             ConstraintAttribute::NOT_VALID => "not valid",
    1761           15 :             ConstraintAttribute::NO_INHERIT => "no inherit",
    1762            0 :             _ => return self.format_unimplemented(node),
    1763              :         };
    1764           75 :         self.fmt.text(text)
    1765           75 :     }
    1766              : 
    1767          312 :     fn format_generic_option(&self, node: &'a Node) -> FmtReg {
    1768          312 :         let f = &self.fmt;
    1769          312 :         let [key, value] = attrs!(self.children(node), [K::SQL_GENERIC_OPTION_KEY, K::SQL_GENERIC_OPTION_VALUE]);
    1770          312 :         let Some(key) = key else { return self.format_unimplemented(node) };
    1771          312 :         let key_reg = self.reg(key);
    1772          282 :         match value {
    1773          282 :             Some(value) if value.node_type() != NodeType::NONE => f.concat(&[key_reg, f.text(" "), self.reg(value)]),
    1774           30 :             _ => key_reg,
    1775              :         }
    1776          312 :     }
    1777              : 
    1778              :     // -----------------------------------------------------------------------------------------
    1779              :     // Functions
    1780              :     // -----------------------------------------------------------------------------------------
    1781              : 
    1782         6059 :     fn format_function_arg(&self, node: &'a Node) -> FmtReg {
    1783         6059 :         let f = &self.fmt;
    1784         6059 :         let [arg_name, arg_value] = attrs!(self.children(node), [K::SQL_FUNCTION_ARG_NAME, K::SQL_FUNCTION_ARG_VALUE]);
    1785         6059 :         let Some(arg_value) = arg_value else { return self.format_unimplemented(node) };
    1786         6059 :         let value_reg = self.reg(arg_value);
    1787         6059 :         if value_reg == 0 {
    1788            0 :             return self.format_unimplemented(node);
    1789         6059 :         }
    1790         6059 :         let Some(arg_name) = arg_name else { return value_reg };
    1791          295 :         let name_reg = self.reg(arg_name);
    1792          295 :         if name_reg == 0 {
    1793            0 :             return self.format_unimplemented(node);
    1794          295 :         }
    1795          295 :         f.concat(&[name_reg, f.text(" => "), value_reg])
    1796         6059 :     }
    1797              : 
    1798              :     /// `name(<a> <keyword> <b>)` of the special function syntaxes, None if a part is missing
    1799         1242 :     fn format_special_call(
    1800         1242 :         &self,
    1801         1242 :         name_reg: FmtReg,
    1802         1242 :         args: &'a Node,
    1803         1242 :         keys: [AttributeKey; 2],
    1804         1242 :         keyword: &'static str,
    1805         1242 :     ) -> Option<FmtReg> {
    1806         1242 :         let f = &self.fmt;
    1807         1242 :         let [a, b] = self.attrs(args, keys);
    1808         1242 :         let a_reg = self.reg(a?);
    1809         1242 :         let b_reg = self.reg(b?);
    1810         1242 :         if a_reg == 0 || b_reg == 0 {
    1811            0 :             return None;
    1812         1242 :         }
    1813         1242 :         Some(f.concat(&[name_reg, f.parenthesized(f.concat(&[a_reg, f.text(keyword), b_reg]))]))
    1814         1242 :     }
    1815              : 
    1816         8206 :     fn format_function_expression(&self, node: &'a Node) -> FmtReg {
    1817         8206 :         let f = &self.fmt;
    1818              :         #[rustfmt::skip]
    1819              :         let [
    1820         8206 :             star, all, distinct, variadic, over, within_group, filter, name, args, order, cast_args, extract_args,
    1821         8206 :             overlay_args, position_args, substring_args, treat_args, trim_args,
    1822         8206 :         ] = attrs!(self.children(node), [
    1823              :                 K::SQL_FUNCTION_ARGUMENTS_STAR,
    1824              :                 K::SQL_FUNCTION_ALL,
    1825              :                 K::SQL_FUNCTION_DISTINCT,
    1826              :                 K::SQL_FUNCTION_VARIADIC,
    1827              :                 K::SQL_FUNCTION_OVER,
    1828              :                 K::SQL_FUNCTION_WITHIN_GROUP,
    1829              :                 K::SQL_FUNCTION_FILTER,
    1830              :                 K::SQL_FUNCTION_NAME,
    1831              :                 K::SQL_FUNCTION_ARGUMENTS,
    1832              :                 K::SQL_FUNCTION_ORDER,
    1833              :                 K::SQL_FUNCTION_CAST_ARGS,
    1834              :                 K::SQL_FUNCTION_EXTRACT_ARGS,
    1835              :                 K::SQL_FUNCTION_OVERLAY_ARGS,
    1836              :                 K::SQL_FUNCTION_POSITION_ARGS,
    1837              :                 K::SQL_FUNCTION_SUBSTRING_ARGS,
    1838              :                 K::SQL_FUNCTION_TREAT_ARGS,
    1839              :                 K::SQL_FUNCTION_TRIM_ARGS,
    1840              :             ],
    1841              :         );
    1842         8206 :         let Some(name) = name else { return self.format_unimplemented(node) };
    1843         8206 :         if all.is_some() && distinct.is_some() {
    1844            0 :             return self.format_unimplemented(node);
    1845         8206 :         }
    1846              : 
    1847         8206 :         let known_function_text = || {
    1848         2175 :             if name.node_type() != NodeType::ENUM_SQL_KNOWN_FUNCTION {
    1849            0 :                 return None;
    1850         2175 :             }
    1851         2175 :             Some(get_known_function_text(KnownFunction(value_u8(name)))).filter(|t| !t.is_empty())
    1852         2175 :         };
    1853              : 
    1854         8206 :         if cast_args.is_some()
    1855         7075 :             || extract_args.is_some()
    1856         6994 :             || overlay_args.is_some()
    1857         6976 :             || position_args.is_some()
    1858         6961 :             || substring_args.is_some()
    1859         6862 :             || treat_args.is_some()
    1860         6847 :             || trim_args.is_some()
    1861              :         {
    1862         1440 :             let Some(name_text) = known_function_text() else { return self.format_unimplemented(node) };
    1863         1440 :             let name_reg = f.text(name_text);
    1864              : 
    1865         1440 :             let special = if let Some(cast_args) = cast_args {
    1866         1131 :                 self.format_special_call(
    1867         1131 :                     name_reg,
    1868         1131 :                     cast_args,
    1869         1131 :                     [K::SQL_FUNCTION_CAST_VALUE, K::SQL_FUNCTION_CAST_TYPE],
    1870              :                     " as ",
    1871              :                 )
    1872          309 :             } else if let Some(extract_args) = extract_args {
    1873           81 :                 self.format_special_call(
    1874           81 :                     name_reg,
    1875           81 :                     extract_args,
    1876           81 :                     [K::SQL_FUNCTION_EXTRACT_TARGET, K::SQL_FUNCTION_EXTRACT_INPUT],
    1877              :                     " from ",
    1878              :                 )
    1879          228 :             } else if let Some(position_args) = position_args {
    1880           15 :                 self.format_special_call(
    1881           15 :                     name_reg,
    1882           15 :                     position_args,
    1883           15 :                     [K::SQL_FUNCTION_POSITION_SEARCH, K::SQL_FUNCTION_POSITION_INPUT],
    1884              :                     " in ",
    1885              :                 )
    1886          213 :             } else if let Some(treat_args) = treat_args {
    1887           15 :                 self.format_special_call(
    1888           15 :                     name_reg,
    1889           15 :                     treat_args,
    1890           15 :                     [K::SQL_FUNCTION_TREAT_VALUE, K::SQL_FUNCTION_TREAT_TYPE],
    1891              :                     " as ",
    1892              :                 )
    1893          198 :             } else if let Some(substring_args) = substring_args {
    1894           99 :                 self.format_substring_args(name_reg, substring_args)
    1895           99 :             } else if let Some(trim_args) = trim_args {
    1896           81 :                 self.format_trim_args(name_reg, trim_args)
    1897           18 :             } else if let Some(overlay_args) = overlay_args {
    1898           18 :                 self.format_overlay_args(name_reg, overlay_args)
    1899              :             } else {
    1900            0 :                 None
    1901              :             };
    1902         1440 :             return special.unwrap_or_else(|| self.format_unimplemented(node));
    1903         6766 :         }
    1904              : 
    1905         6766 :         let name_reg = if name.node_type() == NodeType::ARRAY {
    1906         6031 :             self.reg(name)
    1907          735 :         } else if let Some(name_text) = known_function_text() {
    1908          735 :             f.text(name_text)
    1909              :         } else {
    1910            0 :             return self.format_unimplemented(node);
    1911              :         };
    1912         6766 :         if name_reg == 0 {
    1913            0 :             return self.format_unimplemented(node);
    1914         6766 :         }
    1915              : 
    1916         6766 :         let mut call_parts = Vec::with_capacity(4);
    1917         6766 :         if star.is_some() {
    1918          486 :             if args.is_some() || variadic.is_some() || all.is_some() || distinct.is_some() || order.is_some() {
    1919            0 :                 return self.format_unimplemented(node);
    1920          486 :             }
    1921          486 :             call_parts.push(f.text("*"));
    1922              :         } else {
    1923         6280 :             let Some(mut arg_items) = self.format_call_arguments(args) else { return self.format_unimplemented(node) };
    1924         6280 :             if let Some(variadic) = variadic {
    1925            6 :                 let variadic_reg = self.reg(variadic);
    1926            6 :                 if variadic_reg == 0 {
    1927            0 :                     return self.format_unimplemented(node);
    1928            6 :                 }
    1929            6 :                 arg_items.push(f.concat(&[f.text("variadic "), variadic_reg]));
    1930         6274 :             }
    1931         6280 :             if all.is_some() || distinct.is_some() {
    1932          123 :                 if arg_items.is_empty() {
    1933            0 :                     return self.format_unimplemented(node);
    1934          123 :                 }
    1935          123 :                 call_parts.push(f.text(if all.is_some() { "all " } else { "distinct " }));
    1936         6157 :             }
    1937         6280 :             if !arg_items.is_empty() {
    1938         5992 :                 call_parts.push(self.comma_join_on_overflow(&arg_items, true));
    1939         5992 :             }
    1940              :         }
    1941              : 
    1942         6766 :         if let Some(order) = order {
    1943           18 :             let order_reg = self.reg(order);
    1944           18 :             if order_reg == 0 {
    1945            0 :                 return self.format_unimplemented(node);
    1946           18 :             }
    1947           18 :             call_parts.push(f.text(if call_parts.is_empty() { "order by " } else { " order by " }));
    1948           18 :             call_parts.push(order_reg);
    1949         6748 :         }
    1950              : 
    1951         6766 :         let call_body = f.concat(&call_parts);
    1952         6766 :         let mut result = if call_body == 0 {
    1953          288 :             if name.node_type() == NodeType::ENUM_SQL_KNOWN_FUNCTION {
    1954          117 :                 name_reg
    1955              :             } else {
    1956          171 :                 f.concat(&[name_reg, f.text("()")])
    1957              :             }
    1958              :         } else {
    1959         6478 :             f.concat(&[name_reg, f.parenthesized(call_body)])
    1960              :         };
    1961              : 
    1962         6766 :         if let Some(filter) = filter {
    1963           21 :             let filter_reg = self.reg(filter);
    1964           21 :             if filter_reg == 0 {
    1965            0 :                 return self.format_unimplemented(node);
    1966           21 :             }
    1967           21 :             let body = f.concat(&[f.text("where "), filter_reg]);
    1968           21 :             result = f.concat(&[result, f.text(" filter "), f.parenthesized(body)]);
    1969         6745 :         }
    1970         6766 :         if let Some(within_group) = within_group {
    1971           21 :             let wg_reg = self.reg(within_group);
    1972           21 :             if wg_reg == 0 {
    1973            0 :                 return self.format_unimplemented(node);
    1974           21 :             }
    1975           21 :             let body = f.concat(&[f.text("order by "), wg_reg]);
    1976           21 :             result = f.concat(&[result, f.text(" within group "), f.parenthesized(body)]);
    1977         6745 :         }
    1978         6766 :         if let Some(over) = over {
    1979          393 :             let over_reg = self.reg(over);
    1980          393 :             result = if over_reg == 0 {
    1981            9 :                 f.concat(&[result, f.text(" over ()")])
    1982          384 :             } else if over.node_type() == NodeType::NAME {
    1983              :                 // A reference to a named window, `over w`
    1984           33 :                 f.concat(&[result, f.text(" over "), over_reg])
    1985              :             } else {
    1986          351 :                 f.concat(&[result, f.text(" over "), f.parenthesized(over_reg)])
    1987              :             };
    1988         6373 :         }
    1989         6766 :         result
    1990         8206 :     }
    1991              : 
    1992           99 :     fn format_substring_args(&self, name_reg: FmtReg, args: &'a Node) -> Option<FmtReg> {
    1993           99 :         let f = &self.fmt;
    1994           99 :         let [sub_input, sub_from, sub_for] = attrs!(self.children(args), [K::SQL_FUNCTION_SUBSTRING_INPUT, K::SQL_FUNCTION_SUBSTRING_FROM, K::SQL_FUNCTION_SUBSTRING_FOR],
    1995              :         );
    1996           99 :         let input_reg = self.reg(sub_input?);
    1997           99 :         if input_reg == 0 {
    1998            0 :             return None;
    1999           99 :         }
    2000              :         // `substring(x from 2)`, `substring(x for 3)` or both
    2001           99 :         let mut parts = vec![input_reg];
    2002           99 :         if let Some(sub_from) = sub_from {
    2003           87 :             let from_reg = self.reg(sub_from);
    2004           87 :             if from_reg == 0 {
    2005            0 :                 return None;
    2006           87 :             }
    2007           87 :             parts.push(f.text(" from "));
    2008           87 :             parts.push(from_reg);
    2009           12 :         }
    2010           99 :         if let Some(sub_for) = sub_for {
    2011           78 :             let for_reg = self.reg(sub_for);
    2012           78 :             if for_reg == 0 {
    2013            0 :                 return None;
    2014           78 :             }
    2015           78 :             parts.push(f.text(" for "));
    2016           78 :             parts.push(for_reg);
    2017           21 :         } else if sub_from.is_none() {
    2018            0 :             return None;
    2019           21 :         }
    2020           99 :         Some(f.concat(&[name_reg, f.parenthesized(f.concat(&parts))]))
    2021           99 :     }
    2022              : 
    2023           81 :     fn format_trim_args(&self, name_reg: FmtReg, args: &'a Node) -> Option<FmtReg> {
    2024           81 :         let f = &self.fmt;
    2025           81 :         let [trim_input, trim_dir, trim_chars] = attrs!(self.children(args), [K::SQL_FUNCTION_TRIM_INPUT, K::SQL_FUNCTION_TRIM_DIRECTION, K::SQL_FUNCTION_TRIM_CHARACTERS]);
    2026           81 :         let input_reg = self.reg(trim_input?);
    2027           81 :         if input_reg == 0 {
    2028            0 :             return None;
    2029           81 :         }
    2030           81 :         let mut parts = Vec::with_capacity(6);
    2031           81 :         if let Some(trim_dir) = trim_dir {
    2032           66 :             let dir_reg = self.reg(trim_dir);
    2033           66 :             if dir_reg == 0 {
    2034            0 :                 return None;
    2035           66 :             }
    2036           66 :             parts.push(dir_reg);
    2037           66 :             parts.push(f.text(" "));
    2038           15 :         }
    2039           81 :         if let Some(trim_chars) = trim_chars {
    2040           33 :             let chars_reg = self.reg(trim_chars);
    2041           33 :             if chars_reg == 0 {
    2042            0 :                 return None;
    2043           33 :             }
    2044           33 :             parts.push(chars_reg);
    2045           33 :             parts.push(f.text(" "));
    2046           48 :         }
    2047           81 :         if trim_dir.is_some() || trim_chars.is_some() {
    2048           66 :             parts.push(f.text("from "));
    2049           66 :         }
    2050           81 :         parts.push(input_reg);
    2051           81 :         Some(f.concat(&[name_reg, f.parenthesized(f.concat(&parts))]))
    2052           81 :     }
    2053              : 
    2054           18 :     fn format_overlay_args(&self, name_reg: FmtReg, args: &'a Node) -> Option<FmtReg> {
    2055           18 :         let f = &self.fmt;
    2056           18 :         let [ov_input, ov_placing, ov_from, ov_for] = attrs!(self.children(args), [
    2057              :                 K::SQL_FUNCTION_OVERLAY_INPUT,
    2058              :                 K::SQL_FUNCTION_OVERLAY_PLACING,
    2059              :                 K::SQL_FUNCTION_OVERLAY_FROM,
    2060              :                 K::SQL_FUNCTION_OVERLAY_FOR,
    2061              :             ],
    2062              :         );
    2063           18 :         let (ov_input, ov_placing, ov_from) = (ov_input?, ov_placing?, ov_from?);
    2064           18 :         let input_reg = self.reg(ov_input);
    2065           18 :         let placing_reg = self.reg(ov_placing);
    2066           18 :         let from_reg = self.reg(ov_from);
    2067           18 :         if input_reg == 0 || placing_reg == 0 || from_reg == 0 {
    2068            0 :             return None;
    2069           18 :         }
    2070           18 :         let mut parts = vec![input_reg, f.text(" placing "), placing_reg, f.text(" from "), from_reg];
    2071           18 :         if let Some(ov_for) = ov_for {
    2072            6 :             let for_reg = self.reg(ov_for);
    2073            6 :             if for_reg == 0 {
    2074            0 :                 return None;
    2075            6 :             }
    2076            6 :             parts.push(f.text(" for "));
    2077            6 :             parts.push(for_reg);
    2078           12 :         }
    2079           18 :         Some(f.concat(&[name_reg, f.parenthesized(f.concat(&parts))]))
    2080           18 :     }
    2081              : 
    2082          150 :     fn format_function_table(&self, node: &'a Node) -> FmtReg {
    2083          150 :         let f = &self.fmt;
    2084          150 :         let [function, rows_from, with_ordinality] = attrs!(self.children(node), [K::SQL_FUNCTION_TABLE_FUNCTION, K::SQL_FUNCTION_TABLE_ROWS_FROM, K::SQL_FUNCTION_TABLE_WITH_ORDINALITY],
    2085              :         );
    2086          150 :         let mut base_reg = 0;
    2087          150 :         if let Some(function) = function {
    2088          120 :             base_reg = self.reg(function);
    2089          120 :         } else if let Some(rows_from) = rows_from {
    2090           30 :             let items = self.array_regs(rows_from);
    2091           60 :             if items.iter().any(|&i| i == 0) {
    2092            0 :                 return self.format_unimplemented(node);
    2093           30 :             }
    2094           30 :             let list = self.comma_join_on_overflow(&items, true);
    2095           30 :             base_reg = f.concat(&[f.text("rows from "), f.parenthesized(list)]);
    2096            0 :         }
    2097          150 :         if base_reg == 0 {
    2098            0 :             return self.format_unimplemented(node);
    2099          150 :         }
    2100          150 :         if is_true(with_ordinality) {
    2101           12 :             base_reg = f.concat(&[base_reg, f.text(" with ordinality")]);
    2102          138 :         }
    2103          150 :         base_reg
    2104          150 :     }
    2105              : 
    2106              :     // -----------------------------------------------------------------------------------------
    2107              :     // Windows
    2108              :     // -----------------------------------------------------------------------------------------
    2109              : 
    2110          438 :     fn format_window_frame(&self, node: &'a Node) -> FmtReg {
    2111          438 :         let f = &self.fmt;
    2112          438 :         let [partition, order, mode, bounds, exclude, name] = attrs!(self.children(node), [
    2113              :                 K::SQL_WINDOW_FRAME_PARTITION,
    2114              :                 K::SQL_WINDOW_FRAME_ORDER,
    2115              :                 K::SQL_WINDOW_FRAME_MODE,
    2116              :                 K::SQL_WINDOW_FRAME_BOUNDS,
    2117              :                 K::SQL_WINDOW_FRAME_EXCLUDE,
    2118              :                 K::SQL_WINDOW_FRAME_NAME,
    2119              :             ],
    2120              :         );
    2121          438 :         if exclude.is_some() || mode.is_none() != bounds.is_none() {
    2122            0 :             return self.format_unimplemented(node);
    2123          438 :         }
    2124              : 
    2125          438 :         let mut clauses = Vec::with_capacity(4);
    2126          438 :         if let Some(name) = name {
    2127            9 :             let name_reg = self.reg(name);
    2128            9 :             if name_reg == 0 {
    2129            0 :                 return self.format_unimplemented(node);
    2130            9 :             }
    2131            9 :             clauses.push(name_reg);
    2132          429 :         }
    2133          438 :         if let Some(partition) = partition {
    2134          258 :             let part_reg = self.reg(partition);
    2135          258 :             if part_reg == 0 {
    2136            0 :                 return self.format_unimplemented(node);
    2137          258 :             }
    2138          258 :             clauses.push(f.concat(&[f.text("partition by "), part_reg]));
    2139          180 :         }
    2140          438 :         if let Some(order) = order {
    2141          279 :             let order_reg = self.reg(order);
    2142          279 :             if order_reg == 0 {
    2143            0 :                 return self.format_unimplemented(node);
    2144          279 :             }
    2145          279 :             clauses.push(f.concat(&[f.text("order by "), order_reg]));
    2146          159 :         }
    2147          438 :         if let (Some(mode), Some(bounds)) = (mode, bounds) {
    2148          126 :             let mode_reg = self.reg(mode);
    2149          126 :             let bounds_reg = self.reg(bounds);
    2150          126 :             if mode_reg == 0 || bounds_reg == 0 {
    2151            0 :                 return self.format_unimplemented(node);
    2152          126 :             }
    2153          126 :             clauses.push(f.concat(&[mode_reg, f.text(" "), bounds_reg]));
    2154          312 :         }
    2155          438 :         if clauses.is_empty() {
    2156           21 :             return f.empty();
    2157          417 :         }
    2158          417 :         self.space_join(&clauses, FormattingJoinPolicy::BreakOnOverflow, true)
    2159          438 :     }
    2160              : 
    2161          222 :     fn format_window_bound(&self, node: &'a Node) -> FmtReg {
    2162          222 :         let f = &self.fmt;
    2163          222 :         let [mode, direction, value] =
    2164          222 :             attrs!(self.children(node), [K::SQL_WINDOW_BOUND_MODE, K::SQL_WINDOW_BOUND_DIRECTION, K::SQL_WINDOW_BOUND_VALUE]);
    2165          222 :         let Some(mode) = mode else { return self.format_unimplemented(node) };
    2166          222 :         match (WindowBoundMode(value_u8(mode)), direction, value) {
    2167           75 :             (WindowBoundMode::UNBOUNDED, Some(direction), None) => {
    2168           75 :                 f.concat(&[self.reg(mode), f.text(" "), self.reg(direction)])
    2169              :             }
    2170           84 :             (WindowBoundMode::CURRENT_ROW, None, None) => self.reg(mode),
    2171           63 :             (WindowBoundMode::VALUE, Some(direction), Some(value)) => {
    2172           63 :                 f.concat(&[self.reg(value), f.text(" "), self.reg(direction)])
    2173              :             }
    2174            0 :             _ => self.format_unimplemented(node),
    2175              :         }
    2176          222 :     }
    2177              : 
    2178          222 :     fn format_window_bound_mode(&self, node: &'a Node) -> FmtReg {
    2179          222 :         match WindowBoundMode(value_u8(node)) {
    2180           75 :             WindowBoundMode::UNBOUNDED => self.fmt.text("unbounded"),
    2181           84 :             WindowBoundMode::CURRENT_ROW => self.fmt.text("current row"),
    2182           63 :             WindowBoundMode::VALUE => self.fmt.empty(),
    2183            0 :             _ => self.format_unimplemented(node),
    2184              :         }
    2185          222 :     }
    2186              : 
    2187          138 :     fn format_window_bound_direction(&self, node: &'a Node) -> FmtReg {
    2188          138 :         match WindowBoundDirection(value_u8(node)) {
    2189          114 :             WindowBoundDirection::PRECEDING => self.fmt.text("preceding"),
    2190           24 :             WindowBoundDirection::FOLLOWING => self.fmt.text("following"),
    2191            0 :             _ => self.format_unimplemented(node),
    2192              :         }
    2193          138 :     }
    2194              : 
    2195          126 :     fn format_window_range_mode(&self, node: &'a Node) -> FmtReg {
    2196          126 :         match WindowRangeMode(value_u8(node)) {
    2197           18 :             WindowRangeMode::RANGE => self.fmt.text("range"),
    2198           90 :             WindowRangeMode::ROWS => self.fmt.text("rows"),
    2199           18 :             WindowRangeMode::GROUPS => self.fmt.text("groups"),
    2200            0 :             _ => self.format_unimplemented(node),
    2201              :         }
    2202          126 :     }
    2203              : 
    2204              :     // -----------------------------------------------------------------------------------------
    2205              :     // Expressions
    2206              :     // -----------------------------------------------------------------------------------------
    2207              : 
    2208          108 :     fn format_alias(&self, node: &'a Node) -> FmtReg {
    2209          108 :         let f = &self.fmt;
    2210          108 :         let [name, col_names, col_defs] =
    2211          108 :             attrs!(self.children(node), [K::SQL_ALIAS_NAME, K::SQL_ALIAS_COLUMN_NAMES, K::SQL_ALIAS_COLUMN_DEFS]);
    2212          108 :         let Some(name) = name else { return self.format_unimplemented(node) };
    2213          108 :         let name_reg = self.reg(name);
    2214          108 :         if name_reg == 0 {
    2215            0 :             return self.format_unimplemented(node);
    2216          108 :         }
    2217          108 :         for columns in [col_names, col_defs].into_iter().flatten() {
    2218           66 :             if columns.node_type() == NodeType::ARRAY && columns.children_count() > 0 {
    2219           66 :                 let cols = self.format_comma_list(columns, true);
    2220           66 :                 return f.concat(&[name_reg, f.parenthesized(cols)]);
    2221            0 :             }
    2222              :         }
    2223           42 :         name_reg
    2224          108 :     }
    2225              : 
    2226          150 :     fn format_typecast_expression(&self, node: &'a Node) -> FmtReg {
    2227          150 :         let f = &self.fmt;
    2228          150 :         let [value, type_node] = attrs!(self.children(node), [K::SQL_TYPECAST_VALUE, K::SQL_TYPECAST_TYPE]);
    2229          150 :         let (Some(value), Some(type_node)) = (value, type_node) else { return self.format_unimplemented(node) };
    2230          150 :         let mut value_reg = self.reg(value);
    2231          150 :         let type_reg = self.reg(type_node);
    2232          150 :         if value_reg == 0 || type_reg == 0 {
    2233            0 :             return self.format_unimplemented(node);
    2234          150 :         }
    2235          150 :         if value.node_type() == NodeType::OBJECT_SQL_NARY_EXPRESSION {
    2236           18 :             value_reg = f.parenthesized(value_reg);
    2237          132 :         }
    2238          150 :         f.concat(&[value_reg, f.text("::"), type_reg])
    2239          150 :     }
    2240              : 
    2241         1248 :     fn format_case(&self, node: &'a Node) -> FmtReg {
    2242         1248 :         let f = &self.fmt;
    2243         1248 :         let [argument, clauses, default_value] =
    2244         1248 :             attrs!(self.children(node), [K::SQL_CASE_ARGUMENT, K::SQL_CASE_CLAUSES, K::SQL_CASE_DEFAULT]);
    2245         1248 :         let Some(clauses) = clauses else { return self.format_unimplemented(node) };
    2246              : 
    2247         1248 :         let mut parts = Vec::new();
    2248         1248 :         if let Some(argument) = argument {
    2249           45 :             let arg_reg = self.reg(argument);
    2250           45 :             if arg_reg == 0 {
    2251            0 :                 return self.format_unimplemented(node);
    2252           45 :             }
    2253           45 :             parts.push(f.concat(&[f.text("case "), arg_reg]));
    2254         1203 :         } else {
    2255         1203 :             parts.push(f.text("case"));
    2256         1203 :         }
    2257         1278 :         for clause in self.array_regs(clauses) {
    2258         1278 :             if clause == 0 {
    2259            0 :                 return self.format_unimplemented(node);
    2260         1278 :             }
    2261         1278 :             parts.push(clause);
    2262              :         }
    2263         1248 :         if let Some(default_value) = default_value {
    2264         1179 :             let default_reg = self.reg(default_value);
    2265         1179 :             if default_reg == 0 {
    2266            0 :                 return self.format_unimplemented(node);
    2267         1179 :             }
    2268         1179 :             parts.push(f.concat(&[f.text("else "), default_reg]));
    2269           69 :         }
    2270         1248 :         parts.push(f.text("end"));
    2271              : 
    2272         1248 :         if self.is_pretty() {
    2273          416 :             let body = self.space_join(&parts[..parts.len() - 1], FormattingJoinPolicy::ForceBreak, true);
    2274          416 :             return self.space_join(&[body, parts[parts.len() - 1]], FormattingJoinPolicy::ForceBreak, false);
    2275          832 :         }
    2276          832 :         self.space_join(&parts, FormattingJoinPolicy::BreakOnOverflow, true)
    2277         1248 :     }
    2278              : 
    2279         1278 :     fn format_case_clause(&self, node: &'a Node) -> FmtReg {
    2280         1278 :         let f = &self.fmt;
    2281         1278 :         let [when_value, then_value] = attrs!(self.children(node), [K::SQL_CASE_CLAUSE_WHEN, K::SQL_CASE_CLAUSE_THEN]);
    2282         1278 :         let (Some(when_value), Some(then_value)) = (when_value, then_value) else {
    2283            0 :             return self.format_unimplemented(node);
    2284              :         };
    2285         1278 :         let when_reg = self.reg(when_value);
    2286         1278 :         let then_reg = self.reg(then_value);
    2287         1278 :         if when_reg == 0 || then_reg == 0 {
    2288            0 :             return self.format_unimplemented(node);
    2289         1278 :         }
    2290         1278 :         f.concat(&[f.text("when "), when_reg, f.text(" then "), then_reg])
    2291         1278 :     }
    2292              : 
    2293          180 :     fn format_exists_expression(&self, node: &'a Node) -> FmtReg {
    2294          180 :         self.format_keyword_call(node, K::SQL_EXISTS_EXPRESSION_STATEMENT, "exists ")
    2295          180 :     }
    2296              : 
    2297              :     /// `OPERATOR(schema.op)`, the elements are the qualifying names and the operator
    2298           21 :     fn format_operator_path(&self, node: &'a Node) -> FmtReg {
    2299           21 :         let f = &self.fmt;
    2300           21 :         let parts = self.array_regs(node);
    2301           42 :         if parts.is_empty() || parts.iter().any(|&p| p == 0) {
    2302            0 :             return self.format_unimplemented(node);
    2303           21 :         }
    2304           21 :         let joined = f.join(&parts, f.text("."), f.text("."), None, false);
    2305           21 :         f.concat(&[f.text("operator"), f.parenthesized(joined)])
    2306           21 :     }
    2307              : 
    2308              :     /// `a = any (select ...)`
    2309           99 :     fn format_subquery_expression(&self, node: &'a Node) -> FmtReg {
    2310           99 :         let f = &self.fmt;
    2311              :         #[rustfmt::skip]
    2312           99 :         let [arg0, arg1, operator, quantifier] = attrs!(self.children(node), [
    2313              :             K::SQL_SUBQUERY_ARG0, K::SQL_SUBQUERY_ARG1, K::SQL_SUBQUERY_OPERATOR, K::SQL_SUBQUERY_QUANTIFIER,
    2314              :         ]);
    2315           99 :         let (Some(arg0), Some(arg1), Some(operator), Some(quantifier)) = (arg0, arg1, operator, quantifier) else {
    2316            3 :             return self.format_unimplemented(node);
    2317              :         };
    2318           96 :         let (arg0_reg, arg1_reg, op_reg) = (self.reg(arg0), self.reg(arg1), self.reg(operator));
    2319           96 :         if arg0_reg == 0 || arg1_reg == 0 || op_reg == 0 {
    2320            0 :             return self.format_unimplemented(node);
    2321           96 :         }
    2322              :         // The right hand side is either a subquery, which parenthesizes itself, or an expression
    2323           96 :         let arg1_reg =
    2324           96 :             if arg1.node_type() == NodeType::OBJECT_SQL_SELECT_EXPRESSION { arg1_reg } else { f.parenthesized(arg1_reg) };
    2325           96 :         f.concat(&[arg0_reg, f.text(" "), op_reg, f.text(" "), self.reg(quantifier), f.text(" "), arg1_reg])
    2326           99 :     }
    2327              : 
    2328           99 :     fn format_subquery_quantifier(&self, node: &'a Node) -> FmtReg {
    2329           99 :         let text = match SubqueryQuantifier(value_u8(node)) {
    2330           63 :             SubqueryQuantifier::ANY => "any",
    2331           18 :             SubqueryQuantifier::SOME => "some",
    2332           18 :             SubqueryQuantifier::ALL => "all",
    2333            0 :             _ => return self.format_unimplemented(node),
    2334              :         };
    2335           99 :         self.fmt.text(text)
    2336           99 :     }
    2337              : 
    2338              :     /// `[value]` or `[lower:upper]`, a missing bound of a slice stays empty
    2339           93 :     fn format_indirection_index(&self, node: &'a Node) -> FmtReg {
    2340           93 :         let f = &self.fmt;
    2341           93 :         let [value, lower, upper] = attrs!(self.children(node), [
    2342              :             K::SQL_INDIRECTION_INDEX_VALUE,
    2343              :             K::SQL_INDIRECTION_INDEX_LOWER_BOUND,
    2344              :             K::SQL_INDIRECTION_INDEX_UPPER_BOUND,
    2345              :         ]);
    2346          159 :         let reg_of = |bound: Option<&'a Node>| bound.map_or(f.empty(), |b| self.reg(b));
    2347           93 :         if let Some(value) = value {
    2348           15 :             return f.concat(&[f.text("["), self.reg(value), f.text("]")]);
    2349           78 :         }
    2350           78 :         f.concat(&[f.text("["), reg_of(lower), f.text(":"), reg_of(upper), f.text("]")])
    2351           93 :     }
    2352              : 
    2353              :     /// The elements of a path after a value: `.field` and `[index]`
    2354          117 :     fn format_indirection_path(&self, node: &'a Node) -> FmtReg {
    2355          117 :         let f = &self.fmt;
    2356          117 :         let mut parts = Vec::with_capacity(node.children_count() as usize * 2);
    2357          117 :         for element in self.children(node) {
    2358          117 :             let reg = self.reg(element);
    2359          117 :             match element.node_type() {
    2360          105 :                 NodeType::NAME if reg != 0 => {
    2361          105 :                     parts.push(f.text("."));
    2362          105 :                     parts.push(reg);
    2363          105 :                 }
    2364           12 :                 NodeType::OBJECT_SQL_INDIRECTION_INDEX if reg != 0 => parts.push(reg),
    2365            0 :                 _ => return self.format_unimplemented(node),
    2366              :             }
    2367              :         }
    2368          117 :         f.concat(&parts)
    2369          117 :     }
    2370              : 
    2371              :     /// `a is [not] of (type, ...)`
    2372           18 :     fn format_typetest_expression(&self, node: &'a Node) -> FmtReg {
    2373           18 :         let f = &self.fmt;
    2374           18 :         let [negate, value, types] =
    2375           18 :             attrs!(self.children(node), [K::SQL_TYPETEST_NEGATE, K::SQL_TYPETEST_VALUE, K::SQL_TYPETEST_TYPES]);
    2376           18 :         let (Some(value), Some(types)) = (value, types) else { return self.format_unimplemented(node) };
    2377           18 :         let (value_reg, types_reg) = (self.reg(value), self.reg(types));
    2378           18 :         if value_reg == 0 || types_reg == 0 {
    2379            0 :             return self.format_unimplemented(node);
    2380           18 :         }
    2381           18 :         let keyword = if is_true(negate) { " is not of " } else { " is of " };
    2382           18 :         f.concat(&[value_reg, f.text(keyword), f.parenthesized(types_reg)])
    2383           18 :     }
    2384              : 
    2385              :     /// `f(...) [as (column definitions)]` of `rows from (...)`
    2386           60 :     fn format_rows_from_item(&self, node: &'a Node) -> FmtReg {
    2387           60 :         let f = &self.fmt;
    2388           60 :         let [function, columns] = attrs!(self.children(node), [K::SQL_ROWSFROM_ITEM_FUNCTION, K::SQL_ROWSFROM_ITEM_COLUMNS]);
    2389           60 :         let Some(function) = function else { return self.format_unimplemented(node) };
    2390           60 :         let function_reg = self.reg(function);
    2391           60 :         if function_reg == 0 {
    2392            0 :             return self.format_unimplemented(node);
    2393           60 :         }
    2394           60 :         match columns.filter(|c| c.node_type() == NodeType::ARRAY) {
    2395           27 :             Some(columns) => f.concat(&[function_reg, f.text(" as "), f.parenthesized(self.reg(columns))]),
    2396           33 :             None => function_reg,
    2397              :         }
    2398           60 :     }
    2399              : 
    2400              :     /// `bit [varying] [(length)]`
    2401           30 :     fn format_bit_type(&self, node: &'a Node) -> FmtReg {
    2402           30 :         let f = &self.fmt;
    2403           30 :         let [varying, length] = attrs!(self.children(node), [K::SQL_BIT_TYPE_VARYING, K::SQL_BIT_TYPE_LENGTH]);
    2404           30 :         let mut parts = vec![f.text(if is_true(varying) { "bit varying" } else { "bit" })];
    2405           30 :         if let Some(length) = length {
    2406           18 :             parts.push(f.parenthesized(self.reg(length)));
    2407           18 :         }
    2408           30 :         f.concat(&parts)
    2409           30 :     }
    2410              : 
    2411              :     /// `key = value` of a definition list
    2412           12 :     fn format_definition_arg(&self, node: &'a Node) -> FmtReg {
    2413           12 :         let f = &self.fmt;
    2414           12 :         let [key, value] = attrs!(self.children(node), [K::SQL_DEFINITION_ARG_KEY, K::SQL_DEFINITION_ARG_VALUE]);
    2415           12 :         let Some(key) = key else { return self.format_unimplemented(node) };
    2416           12 :         let value_reg = match value {
    2417           12 :             Some(value) => self.reg(value),
    2418            0 :             None => f.text("none"),
    2419              :         };
    2420           12 :         if value_reg == 0 {
    2421            0 :             return self.format_unimplemented(node);
    2422           12 :         }
    2423           12 :         f.concat(&[self.reg(key), f.text(" = "), value_reg])
    2424           12 :     }
    2425              : 
    2426          846 :     fn format_cte(&self, node: &'a Node) -> FmtReg {
    2427          846 :         let f = &self.fmt;
    2428          846 :         let [name, columns, statement, graph, secure, options] = attrs!(self.children(node), [
    2429              :                 K::SQL_CTE_NAME,
    2430              :                 K::SQL_CTE_COLUMNS,
    2431              :                 K::SQL_CTE_STATEMENT,
    2432              :                 K::SQL_CTE_PROPERTY_GRAPH,
    2433              :                 K::SQL_CTE_SECURE,
    2434              :                 K::SQL_CTE_OPTIONS,
    2435              :             ],
    2436              :         );
    2437          846 :         let Some(name) = name else { return self.format_unimplemented(node) };
    2438          846 :         let Some(body_node) = statement.or(graph) else { return self.format_unimplemented(node) };
    2439          846 :         let name_reg = self.reg(name);
    2440          846 :         let body_reg = self.reg(body_node);
    2441          846 :         if name_reg == 0 || body_reg == 0 {
    2442            0 :             return self.format_unimplemented(node);
    2443          846 :         }
    2444              : 
    2445          846 :         let body = if graph.is_some_and(|g| g.children_count() == 0) {
    2446           45 :             f.text("()")
    2447          801 :         } else if self.is_pretty() {
    2448          267 :             f.concat(&[f.text("("), f.indented(f.concat(&[f.break_(), body_reg])), f.break_(), f.text(")")])
    2449              :         } else {
    2450          534 :             f.parenthesized(body_reg)
    2451              :         };
    2452              : 
    2453          846 :         let as_reg = if graph.is_some() {
    2454           90 :             f.text(" as property graph ")
    2455          756 :         } else if secure.is_some() {
    2456           12 :             f.text(" as secure ")
    2457              :         } else {
    2458          744 :             f.text(" as ")
    2459              :         };
    2460          846 :         let mut result = match columns.filter(|c| c.node_type() == NodeType::ARRAY && c.children_count() > 0) {
    2461           21 :             Some(columns) => {
    2462           21 :                 let cols_reg = self.reg(columns);
    2463           21 :                 if cols_reg == 0 {
    2464            0 :                     return self.format_unimplemented(columns);
    2465           21 :                 }
    2466           21 :                 f.concat(&[name_reg, f.text(" "), f.parenthesized(cols_reg), as_reg, body])
    2467              :             }
    2468          825 :             None => f.concat(&[name_reg, as_reg, body]),
    2469              :         };
    2470          846 :         if let Some(options) = options {
    2471           36 :             let options_reg = self.reg(options);
    2472           36 :             if options_reg == 0 {
    2473            0 :                 return self.format_unimplemented(options);
    2474           36 :             }
    2475           36 :             result = f.concat(&[result, f.text(" options "), f.parenthesized(options_reg)]);
    2476          810 :         }
    2477          846 :         result
    2478          846 :     }
    2479              : 
    2480        27122 :     fn format_expression_operator_type(&self, node: &'a Node) -> FmtReg {
    2481        27122 :         if node.node_type() != NodeType::ENUM_SQL_EXPRESSION_OPERATOR {
    2482            0 :             return self.format_unimplemented(node);
    2483        27122 :         }
    2484        27122 :         let text = get_operator_text(ExpressionOperator(value_u8(node)));
    2485        27122 :         if text.is_empty() {
    2486            0 :             return self.format_unimplemented(node);
    2487        27122 :         }
    2488        27122 :         self.fmt.text(text)
    2489        27122 :     }
    2490              : 
    2491        20560 :     fn format_result_target(&self, node: &'a Node) -> FmtReg {
    2492        20560 :         let f = &self.fmt;
    2493        20560 :         let [value, name, star, exclude] = attrs!(self.children(node), [
    2494              :                 K::SQL_RESULT_TARGET_VALUE,
    2495              :                 K::SQL_RESULT_TARGET_NAME,
    2496              :                 K::SQL_RESULT_TARGET_STAR,
    2497              :                 K::SQL_RESULT_TARGET_EXCLUDE,
    2498              :             ],
    2499              :         );
    2500        20560 :         if let Some(star) = star {
    2501         1377 :             if name.is_some() {
    2502            0 :                 return self.format_unimplemented(node);
    2503         1377 :             }
    2504         1377 :             if star.node_type() != NodeType::BOOL || star.children_begin_or_value() == 0 {
    2505            0 :                 return self.format_unimplemented(star);
    2506         1377 :             }
    2507         1377 :             let mut result = match value {
    2508           21 :                 Some(value) => f.concat(&[self.reg(value), f.text(".*")]),
    2509         1356 :                 None => f.text("*"),
    2510              :             };
    2511         1377 :             if let Some(exclude) = exclude {
    2512           12 :                 let exclude_reg = self.reg(exclude);
    2513           12 :                 if exclude_reg == 0 {
    2514            0 :                     return self.format_unimplemented(exclude);
    2515           12 :                 }
    2516           12 :                 result = if exclude.children_count() == 1 {
    2517            3 :                     f.concat(&[result, f.text(" exclude "), exclude_reg])
    2518              :                 } else {
    2519            9 :                     f.concat(&[result, f.text(" exclude "), f.parenthesized(exclude_reg)])
    2520              :                 };
    2521         1365 :             }
    2522         1377 :             return result;
    2523        19183 :         }
    2524        19183 :         let Some(value) = value else { return self.format_unimplemented(node) };
    2525        19183 :         let value_reg = self.reg(value);
    2526        19183 :         if value_reg == 0 {
    2527            0 :             return self.format_unimplemented(value);
    2528        19183 :         }
    2529        19183 :         let Some(name) = name else { return value_reg };
    2530         8182 :         let name_reg = self.reg(name);
    2531         8182 :         if name_reg == 0 {
    2532            0 :             return self.format_unimplemented(name);
    2533         8182 :         }
    2534         8182 :         f.concat(&[value_reg, f.text(" as "), name_reg])
    2535        20560 :     }
    2536              : 
    2537          816 :     fn format_select_expression(&self, node: &'a Node) -> FmtReg {
    2538          816 :         let [statement, indirection] =
    2539          816 :             attrs!(self.children(node), [K::SQL_SELECT_EXPRESSION_STATEMENT, K::SQL_SELECT_EXPRESSION_INDIRECTION]);
    2540          816 :         let Some(statement) = statement else { return self.format_unimplemented(node) };
    2541          816 :         let subquery = self.fmt.parenthesized(self.reg(statement));
    2542          816 :         match indirection.filter(|i| i.node_type() == NodeType::ARRAY && i.children_count() > 0) {
    2543            9 :             Some(indirection) => self.fmt.concat(&[subquery, self.reg(indirection)]),
    2544          807 :             None => subquery,
    2545              :         }
    2546          816 :     }
    2547              : 
    2548              :     /// Is a DEFAULT expression a value of an INSERT ... VALUES?
    2549            7 :     fn is_in_insert_values(&self, node: &Node) -> bool {
    2550            7 :         let mut parent_id = node.parent() as usize;
    2551            7 :         let mut depth = 0;
    2552           24 :         while parent_id < self.ast.len() && depth < self.ast.len() {
    2553           24 :             let parent = &self.ast[parent_id];
    2554           24 :             if parent.attribute_key() == K::SQL_INSERT_SOURCE {
    2555            6 :                 let [values] = attrs!(self.children(parent), [K::SQL_SELECT_VALUES]);
    2556            6 :                 return parent.node_type() == NodeType::OBJECT_SQL_SELECT && values.is_some();
    2557           18 :             }
    2558           18 :             if parent.node_type() == NodeType::OBJECT_SQL_INSERT {
    2559            0 :                 break;
    2560           18 :             }
    2561           18 :             let next_parent = parent.parent() as usize;
    2562           18 :             if next_parent == parent_id {
    2563            1 :                 break;
    2564           17 :             }
    2565           17 :             parent_id = next_parent;
    2566           17 :             depth += 1;
    2567              :         }
    2568            1 :         false
    2569            7 :     }
    2570              : 
    2571        27155 :     fn format_expression(&self, node_id: usize) -> FmtReg {
    2572        27155 :         let f = &self.fmt;
    2573        27155 :         let node = &self.ast[node_id];
    2574        27155 :         let state = self.node_states[node_id];
    2575              : 
    2576        27155 :         let [op_node, args_node] = attrs!(self.children(node), [K::SQL_EXPRESSION_OPERATOR, K::SQL_EXPRESSION_ARGS]);
    2577        27155 :         if let (Some(op_node), None) = (op_node, args_node) {
    2578            7 :             if op_node.node_type() == NodeType::ENUM_SQL_EXPRESSION_OPERATOR
    2579            7 :                 && ExpressionOperator(value_u8(op_node)) == ExpressionOperator::DEFAULT
    2580              :             {
    2581            7 :                 if !self.is_in_insert_values(node) {
    2582            1 :                     return self.format_unimplemented(node);
    2583            6 :                 }
    2584            6 :                 return self.reg(op_node);
    2585            0 :             }
    2586        27148 :         }
    2587        27148 :         let (Some(op_node), Some(args_node)) = (op_node, args_node) else { return self.format_unimplemented(node) };
    2588            0 :         if !matches!(
    2589        27148 :             op_node.node_type(),
    2590              :             NodeType::ENUM_SQL_EXPRESSION_OPERATOR | NodeType::OPERATOR | NodeType::ARRAY
    2591        27148 :         ) || args_node.node_type() != NodeType::ARRAY
    2592        27148 :             || args_node.children_count() == 0
    2593              :         {
    2594            0 :             return self.format_unimplemented(node);
    2595        27148 :         }
    2596              : 
    2597        27148 :         let known_operator = op_node.node_type() == NodeType::ENUM_SQL_EXPRESSION_OPERATOR;
    2598        27148 :         let op = if known_operator { ExpressionOperator(value_u8(op_node)) } else { ExpressionOperator::DEFAULT };
    2599        27148 :         let op_reg = self.reg(op_node);
    2600        27148 :         if op_reg == 0 {
    2601            0 :             return self.format_unimplemented(node);
    2602        27148 :         }
    2603              : 
    2604        27148 :         let args = self.array_regs(args_node);
    2605        27148 :         if !known_operator && args.len() != 2 {
    2606            0 :             return self.format_unimplemented(node);
    2607        27148 :         }
    2608              : 
    2609              :         use ExpressionOperator as O;
    2610        27148 :         let mut reg = if args.len() == 1 && known_operator {
    2611          631 :             match op {
    2612          274 :                 O::NEGATE => f.concat(&[op_reg, args[0]]),
    2613           93 :                 O::NOT => f.concat(&[op_reg, f.text(" "), args[0]]),
    2614              :                 O::IS_NULL
    2615              :                 | O::NOT_NULL
    2616              :                 | O::IS_TRUE
    2617              :                 | O::IS_FALSE
    2618              :                 | O::IS_UNKNOWN
    2619              :                 | O::IS_NOT_TRUE
    2620              :                 | O::IS_NOT_FALSE
    2621          261 :                 | O::IS_NOT_UNKNOWN => f.concat(&[args[0], f.text(" "), op_reg]),
    2622            3 :                 _ => f.concat(&[op_reg, f.text(" "), args[0]]),
    2623              :             }
    2624        26517 :         } else if args.len() == 3
    2625         2436 :             && known_operator
    2626          879 :             && matches!(
    2627         2436 :                 op,
    2628              :                 O::BETWEEN_ASYMMETRIC | O::NOT_BETWEEN_ASYMMETRIC | O::BETWEEN_SYMMETRIC | O::NOT_BETWEEN_SYMMETRIC
    2629              :             )
    2630              :         {
    2631         1557 :             f.concat(&[args[0], f.text(" "), op_reg, f.text(" "), args[1], f.text(" and "), args[2]])
    2632        24960 :         } else if args.len() == 2 && known_operator && matches!(op, O::IN | O::NOT_IN) {
    2633         1104 :             let mut rhs = args[1];
    2634         1104 :             let rhs_node = &self.ast[args_node.children_begin_or_value() as usize + 1];
    2635         1104 :             if rhs_node.node_type() == NodeType::ARRAY {
    2636          789 :                 let list = self.format_comma_list(rhs_node, true);
    2637          789 :                 rhs = f.parenthesized(list);
    2638          789 :             }
    2639         1104 :             f.concat(&[args[0], f.text(" "), op_reg, f.text(" "), rhs])
    2640        23856 :         } else if args.len() == 2 && known_operator && matches!(op, O::IS_DISTINCT_FROM | O::IS_NOT_DISTINCT_FROM) {
    2641           30 :             f.concat(&[args[0], f.text(" "), op_reg, f.text(" "), args[1]])
    2642              :         } else {
    2643        23826 :             let is_boolean_chain = known_operator && matches!(op, O::AND | O::OR);
    2644        23826 :             let inline_separator = f.concat(&[f.text(" "), op_reg, f.text(" ")]);
    2645        23826 :             let break_separator = if breaks_before_operator(op) {
    2646         4137 :                 f.concat(&[f.break_(), op_reg, f.text(" ")])
    2647              :             } else {
    2648        19689 :                 f.concat(&[f.text(" "), op_reg, f.break_()])
    2649              :             };
    2650        23826 :             let policy = if is_boolean_chain { None } else { Some(FormattingJoinPolicy::BreakOnOverflow) };
    2651        23826 :             f.join(&args, inline_separator, break_separator, policy, true)
    2652              :         };
    2653              : 
    2654        27148 :         if state.needs_parentheses {
    2655         1004 :             reg = f.parenthesized(reg);
    2656        26144 :         }
    2657        27148 :         reg
    2658        27155 :     }
    2659              : 
    2660              :     // -----------------------------------------------------------------------------------------
    2661              :     // Dispatch
    2662              :     // -----------------------------------------------------------------------------------------
    2663              : 
    2664       462656 :     fn format_node(&self, node_id: usize) -> FmtReg {
    2665       462656 :         let node: &'a Node = &self.ast[node_id];
    2666       462656 :         let f = &self.fmt;
    2667       462656 :         match node.node_type() {
    2668       129507 :             NodeType::ARRAY => self.format_array(node),
    2669         9066 :             NodeType::OBJECT_SQL_SELECT => self.format_select(node_id),
    2670           90 :             NodeType::OBJECT_SQL_INSERT => self.format_insert(node),
    2671           84 :             NodeType::OBJECT_SQL_DELETE => self.format_delete(node),
    2672          335 :             NodeType::OBJECT_SQL_CREATE => self.format_create(node_id),
    2673           39 :             NodeType::OBJECT_SQL_CREATE_AS => self.format_create_as(node),
    2674           24 :             NodeType::OBJECT_SQL_VIEW => self.format_view(node),
    2675           45 :             NodeType::OBJECT_SQL_CREATE_FUNCTION => self.format_create_function(node),
    2676           21 :             NodeType::OBJECT_SQL_DROP_TABLE => self.format_drop(node, true),
    2677           21 :             NodeType::OBJECT_SQL_DROP_VIEW => self.format_drop(node, false),
    2678          150 :             NodeType::OBJECT_SQL_ALTER_TABLE => self.format_alter_table(node, "alter table "),
    2679           18 :             NodeType::OBJECT_SQL_ALTER_VIEW => self.format_alter_table(node, "alter view "),
    2680           39 :             NodeType::OBJECT_SQL_CREATE_SCHEMA | NodeType::OBJECT_SQL_DROP_SCHEMA | NodeType::OBJECT_SQL_ALTER_SCHEMA => self.format_schema_statement(node),
    2681              :             NodeType::OBJECT_SQL_ALTER_ADD_COLUMN
    2682              :             | NodeType::OBJECT_SQL_ALTER_DROP_COLUMN
    2683              :             | NodeType::OBJECT_SQL_ALTER_RENAME_COLUMN
    2684              :             | NodeType::OBJECT_SQL_ALTER_RENAME_TABLE
    2685              :             | NodeType::OBJECT_SQL_ALTER_SET_SCHEMA
    2686          186 :             | NodeType::OBJECT_SQL_ALTER_COLUMN_TYPE => self.format_alter_table_action(node),
    2687           18 :             NodeType::OBJECT_SQL_ATTACH_DATABASE => self.format_attach_database(node),
    2688           18 :             NodeType::OBJECT_SQL_ATTACH_DATABASE_OPTION => self.format_attach_database_option(node),
    2689           57 :             NodeType::OBJECT_SQL_FUNCTION_PARAM => self.format_function_param(node),
    2690           24 :             NodeType::OBJECT_EXT_SET => self.format_set(node),
    2691          201 :             NodeType::OBJECT_EXT_VARARG_FIELD => self.format_vararg_field(node),
    2692          135 :             NodeType::OBJECT_EXT_EXPLAIN => self.format_explain(node_id),
    2693            9 :             NodeType::OBJECT_EXT_EXPLAIN_EXPRESSIONS => self.format_explain_expressions(node),
    2694          106 :             NodeType::OBJECT_SQL_CALL => self.format_call(node),
    2695        13180 :             NodeType::OBJECT_SQL_TABLEREF => self.format_table_ref(node),
    2696          690 :             NodeType::OBJECT_SQL_JOINED_TABLE => self.format_joined_table(node),
    2697          690 :             NodeType::ENUM_SQL_JOIN_TYPE => f.empty(),
    2698           51 :             NodeType::OBJECT_SQL_INTO => self.format_into(node),
    2699           78 :             NodeType::OBJECT_SQL_WINDOW_DEF => self.format_window_def(node),
    2700           81 :             NodeType::OBJECT_SQL_ROW_LOCKING => self.format_row_locking(node),
    2701           81 :             NodeType::ENUM_SQL_ROW_LOCKING_STRENGTH => self.format_row_locking_strength(node),
    2702           30 :             NodeType::ENUM_SQL_ROW_LOCKING_BLOCK_BEHAVIOR => self.format_row_locking_block_behavior(node),
    2703           48 :             NodeType::OBJECT_SQL_SELECT_SAMPLE => self.format_sample(node, false),
    2704           57 :             NodeType::OBJECT_SQL_TABLEREF_SAMPLE => self.format_sample(node, true),
    2705          105 :             NodeType::ENUM_SQL_SAMPLE_UNIT_TYPE => self.format_sample_unit(node),
    2706         3879 :             NodeType::OBJECT_SQL_GROUP_BY_ITEM => self.format_group_by_item(node),
    2707              :             NodeType::ENUM_SQL_GROUP_BY_ITEM_TYPE
    2708              :             | NodeType::ENUM_SQL_COMBINE_MODIFIER
    2709         4767 :             | NodeType::ENUM_SQL_COMBINE_OPERATION => f.empty(),
    2710         3942 :             NodeType::OBJECT_SQL_ORDER => self.format_order(node),
    2711          498 :             NodeType::ENUM_SQL_ORDER_DIRECTION => self.format_order_direction(node),
    2712         1473 :             NodeType::ENUM_SQL_ORDER_NULL_RULE => self.format_order_null_rule(node),
    2713          105 :             NodeType::ENUM_SQL_TEMP_TYPE => self.format_temp_type(node),
    2714           33 :             NodeType::ENUM_SQL_ON_COMMIT_OPTION => self.format_on_commit_option(node),
    2715         3030 :             NodeType::OBJECT_SQL_TYPENAME => self.format_type_name(node),
    2716          215 :             NodeType::OBJECT_SQL_INTERVAL_TYPE => self.format_interval_type(node),
    2717          191 :             NodeType::ENUM_SQL_INTERVAL_TYPE => self.format_interval_type_enum(node),
    2718          502 :             NodeType::OBJECT_SQL_NUMERIC_TYPE => self.format_numeric_type(node),
    2719         1494 :             NodeType::ENUM_SQL_NUMERIC_TYPE => self.format_numeric_type_base(node),
    2720          447 :             NodeType::OBJECT_SQL_CHARACTER_TYPE => self.format_character_type(node),
    2721          447 :             NodeType::ENUM_SQL_CHARACTER_TYPE => self.format_character_type_base(node),
    2722          795 :             NodeType::OBJECT_SQL_GENERIC_TYPE => self.format_generic_type(node),
    2723           72 :             NodeType::OBJECT_SQL_TIMESTAMP_TYPE | NodeType::OBJECT_SQL_TIME_TYPE => self.format_timestamp_type(node),
    2724        50753 :             NodeType::OBJECT_SQL_COLUMN_REF => self.format_column_ref(node),
    2725          300 :             NodeType::OBJECT_SQL_PARAMETER_REF => self.format_parameter_ref(node),
    2726           36 :             NodeType::OBJECT_SQL_RELATION_EXPR => self.format_relation_expression(node),
    2727           42 :             NodeType::OBJECT_SQL_DESCRIPTOR => self.format_descriptor(node),
    2728          108 :             NodeType::OBJECT_SQL_INDIRECTION => self.format_indirection(node),
    2729          135 :             NodeType::OBJECT_SQL_ROW_TYPE => self.format_row_type(node),
    2730          258 :             NodeType::OBJECT_SQL_ROW_EXPRESSION => self.format_row_expression(node),
    2731          126 :             NodeType::OBJECT_SQL_ARRAY_EXPRESSION => self.format_array_expression(node),
    2732          816 :             NodeType::OBJECT_SQL_SELECT_EXPRESSION => self.format_select_expression(node),
    2733        20560 :             NodeType::OBJECT_SQL_RESULT_TARGET => self.format_result_target(node),
    2734         1502 :             NodeType::OBJECT_SQL_COLUMN_DEF => self.format_column_def(node),
    2735          219 :             NodeType::ENUM_SQL_TABLE_CONSTRAINT => self.format_table_constraint_type(node),
    2736          219 :             NodeType::OBJECT_SQL_TABLE_CONSTRAINT => self.format_table_constraint(node),
    2737           12 :             NodeType::ENUM_SQL_KEY_MATCH => self.format_key_match(node),
    2738           21 :             NodeType::ENUM_SQL_KEY_ACTION_COMMAND => self.format_key_action_command(node),
    2739           21 :             NodeType::ENUM_SQL_KEY_ACTION_TRIGGER => self.format_key_action_trigger(node),
    2740           21 :             NodeType::OBJECT_SQL_KEY_ACTION => self.format_key_action(node),
    2741          816 :             NodeType::ENUM_SQL_COLUMN_CONSTRAINT => self.format_column_constraint_type(node),
    2742          816 :             NodeType::OBJECT_SQL_COLUMN_CONSTRAINT => self.format_column_constraint(node),
    2743           75 :             NodeType::ENUM_SQL_CONSTRAINT_ATTRIBUTE => self.format_constraint_attribute(node),
    2744           81 :             NodeType::ENUM_SQL_EXTRACT_TARGET => self.format_extract_target(node),
    2745           66 :             NodeType::ENUM_SQL_TRIM_TARGET => self.format_trim_direction(node),
    2746          312 :             NodeType::OBJECT_SQL_GENERIC_OPTION => self.format_generic_option(node),
    2747          108 :             NodeType::OBJECT_SQL_ALIAS => self.format_alias(node),
    2748          150 :             NodeType::OBJECT_SQL_TYPECAST_EXPRESSION => self.format_typecast_expression(node),
    2749         1248 :             NodeType::OBJECT_SQL_CASE => self.format_case(node),
    2750         1278 :             NodeType::OBJECT_SQL_CASE_CLAUSE => self.format_case_clause(node),
    2751          180 :             NodeType::OBJECT_SQL_EXISTS_EXPRESSION => self.format_exists_expression(node),
    2752           99 :             NodeType::OBJECT_SQL_SUBQUERY_EXPRESSION => self.format_subquery_expression(node),
    2753           99 :             NodeType::ENUM_SQL_SUBQUERY_QUANTIFIER => self.format_subquery_quantifier(node),
    2754           93 :             NodeType::OBJECT_SQL_INDIRECTION_INDEX => self.format_indirection_index(node),
    2755           18 :             NodeType::OBJECT_SQL_TYPETEST_EXPRESSION => self.format_typetest_expression(node),
    2756           60 :             NodeType::OBJECT_SQL_ROWSFROM_ITEM => self.format_rows_from_item(node),
    2757           30 :             NodeType::OBJECT_SQL_BIT_TYPE => self.format_bit_type(node),
    2758           12 :             NodeType::OBJECT_SQL_DEF_ARG => self.format_definition_arg(node),
    2759          846 :             NodeType::OBJECT_SQL_CTE => self.format_cte(node),
    2760           90 :             NodeType::OBJECT_SQL_PROPERTY_GRAPH => self.format_property_graph(node),
    2761          135 :             NodeType::OBJECT_SQL_GRAPH_ELEMENT_TABLE => self.format_graph_element_table(node),
    2762           96 :             NodeType::OBJECT_SQL_GRAPH_VERTEX_REFERENCE => self.format_graph_vertex_reference(node),
    2763          138 :             NodeType::OBJECT_SQL_GRAPH_LABEL => self.format_graph_label(node),
    2764          138 :             NodeType::OBJECT_SQL_GRAPH_PROPERTIES => self.format_graph_properties(node),
    2765           78 :             NodeType::OBJECT_SQL_GRAPH_PROPERTY => self.format_graph_property(node),
    2766          105 :             NodeType::OBJECT_SQL_GRAPH_TABLE => self.format_graph_table(node),
    2767          105 :             NodeType::OBJECT_SQL_GRAPH_MATCH => self.format_graph_match(node),
    2768          318 :             NodeType::OBJECT_SQL_GRAPH_PATH_ELEMENT => self.format_graph_path_element(node),
    2769           21 :             NodeType::OBJECT_SQL_GRAPH_QUANTIFIER => self.format_graph_quantifier(node),
    2770          288 :             NodeType::OBJECT_SQL_GRAPH_LABEL_EXPRESSION => self.format_graph_label_expression(node),
    2771           18 :             NodeType::OBJECT_SQL_GRAPH_ROWS => self.format_graph_rows(node),
    2772         8206 :             NodeType::OBJECT_SQL_FUNCTION_EXPRESSION => self.format_function_expression(node),
    2773              :             NodeType::OBJECT_SQL_FUNCTION_CAST_ARGS
    2774              :             | NodeType::OBJECT_SQL_FUNCTION_EXTRACT_ARGS
    2775              :             | NodeType::OBJECT_SQL_FUNCTION_OVERLAY_ARGS
    2776              :             | NodeType::OBJECT_SQL_FUNCTION_POSITION_ARGS
    2777              :             | NodeType::OBJECT_SQL_FUNCTION_SUBSTRING_ARGS
    2778              :             | NodeType::OBJECT_SQL_FUNCTION_TREAT_ARGS
    2779         1440 :             | NodeType::OBJECT_SQL_FUNCTION_TRIM_ARGS => f.empty(),
    2780         2175 :             NodeType::ENUM_SQL_KNOWN_FUNCTION => f.empty(),
    2781          150 :             NodeType::OBJECT_SQL_FUNCTION_TABLE => self.format_function_table(node),
    2782          438 :             NodeType::OBJECT_SQL_WINDOW_FRAME => self.format_window_frame(node),
    2783          222 :             NodeType::OBJECT_SQL_WINDOW_BOUND => self.format_window_bound(node),
    2784          222 :             NodeType::ENUM_SQL_WINDOW_BOUND_MODE => self.format_window_bound_mode(node),
    2785          138 :             NodeType::ENUM_SQL_WINDOW_BOUND_DIRECTION => self.format_window_bound_direction(node),
    2786          126 :             NodeType::ENUM_SQL_WINDOW_RANGE_MODE => self.format_window_range_mode(node),
    2787         6059 :             NodeType::OBJECT_SQL_FUNCTION_ARG => self.format_function_arg(node),
    2788           25 :             NodeType::OBJECT_SQL_CONST_TYPE_CAST => self.format_const_type_cast(node),
    2789          173 :             NodeType::OBJECT_SQL_CONST_INTERVAL_CAST => self.format_const_interval_cast(node),
    2790          343 :             NodeType::OBJECT_SQL_CONST_FUNCTION_CAST => self.format_const_function_cast(node),
    2791        27122 :             NodeType::ENUM_SQL_EXPRESSION_OPERATOR => self.format_expression_operator_type(node),
    2792        27155 :             NodeType::OBJECT_SQL_NARY_EXPRESSION => self.format_expression(node_id),
    2793           48 :             NodeType::OBJECT_EXT_VARARG_ARRAY => self.format_vararg_array(node),
    2794              :             NodeType::LITERAL_NULL
    2795              :             | NodeType::LITERAL_INTEGER
    2796              :             | NodeType::LITERAL_FLOAT
    2797              :             | NodeType::LITERAL_STRING
    2798              :             | NodeType::LITERAL_INTERVAL
    2799              :             | NodeType::BOOL
    2800              :             | NodeType::OPERATOR
    2801       128374 :             | NodeType::NAME => self.format_leaf(node),
    2802            0 :             _ => self.format_unimplemented(node),
    2803              :         }
    2804       462656 :     }
    2805              : 
    2806         5980 :     fn build_docs(&mut self) {
    2807       462656 :         for node_id in 0..self.ast.len() {
    2808       462656 :             let reg = self.format_node(node_id);
    2809       462656 :             self.node_states[node_id].reg = reg;
    2810       462656 :         }
    2811         5980 :     }
    2812              : 
    2813              :     // -----------------------------------------------------------------------------------------
    2814              :     // Output
    2815              :     // -----------------------------------------------------------------------------------------
    2816              : 
    2817         5980 :     fn render_options(&self) -> FormattingRenderOptions {
    2818         5980 :         FormattingRenderOptions {
    2819         5980 :             max_width: self.config.max_width as usize,
    2820         5980 :             indentation_width: self.config.indentation_width as usize,
    2821         5980 :             debug_mode: self.config.debug_mode,
    2822         5980 :             mode: self.config.mode,
    2823         5980 :             keyword_case: self.config.keyword_case,
    2824         5980 :         }
    2825         5980 :     }
    2826              : 
    2827          374 :     fn render(&self, reg: FmtReg) -> String {
    2828          374 :         self.fmt.render(reg, &self.render_options())
    2829          374 :     }
    2830              : 
    2831              :     /// The parts of the script in text order.
    2832              :     ///
    2833              :     /// The parser recovers from syntax errors by dropping the broken statement or by keeping a partial one.
    2834              :     /// Formatting these would silently remove or truncate what the user wrote, so every statement (the text up
    2835              :     /// to the next semicolon) with a scanner or parser error is copied as written.
    2836         5606 :     fn output_parts(&self) -> Vec<OutputPart> {
    2837              :         use dashql_parser::symbol_kind::{S_SEMICOLON, S_YYEOF};
    2838         5606 :         let symbols = &self.scanned.symbols;
    2839         5606 :         let statements = &self.parsed.statements;
    2840         5606 :         let mut parts = Vec::with_capacity(statements.len());
    2841              : 
    2842              :         // The symbol index ranges of the statements, each ends with a semicolon
    2843         5606 :         let mut chunks: Vec<(usize, usize)> = Vec::new();
    2844         5606 :         let mut begin = 0;
    2845       315485 :         for (i, symbol) in symbols.iter().enumerate() {
    2846       315485 :             if symbol.kind == S_SEMICOLON || symbol.kind == S_YYEOF {
    2847         8429 :                 if i > begin || symbol.kind == S_SEMICOLON {
    2848         5851 :                     chunks.push((begin, if symbol.kind == S_SEMICOLON { i + 1 } else { i }));
    2849         2578 :                 }
    2850         8429 :                 begin = i + 1;
    2851       307056 :             }
    2852              :         }
    2853         5606 :         let chunk_of_symbol = |symbol: usize| chunks.iter().position(|&(b, e)| symbol >= b && symbol < e);
    2854         5606 :         let mut damaged = vec![false; chunks.len()];
    2855         5606 :         for error in &self.parsed.errors {
    2856           30 :             let symbol = (error.location.offset() as usize).min(symbols.len().saturating_sub(1));
    2857           30 :             if let Some(chunk) = chunk_of_symbol(symbol).or(chunks.len().checked_sub(1)) {
    2858           30 :                 damaged[chunk] = true;
    2859           30 :             }
    2860              :         }
    2861         5606 :         for error in &self.scanned.errors {
    2862            3 :             let offset = error.location.offset;
    2863           12 :             let symbol = symbols.partition_point(|s| s.location.end() <= offset);
    2864            3 :             if let Some(chunk) = chunk_of_symbol(symbol).or(chunks.len().checked_sub(1)) {
    2865            3 :                 damaged[chunk] = true;
    2866            3 :             }
    2867              :         }
    2868              : 
    2869         5606 :         let mut next_statement = 0;
    2870         5851 :         for (chunk, &(begin, end)) in chunks.iter().enumerate() {
    2871         5851 :             let chunk_symbols = &symbols[begin..end];
    2872         5851 :             let begin_offset = chunk_symbols.first().map_or(0, |s| s.location.offset);
    2873              :             // The last statement may end in text that the scanner dropped, like an unterminated string
    2874         5851 :             let end_offset = match chunk_symbols.last() {
    2875         5851 :                 Some(last) if last.kind == S_SEMICOLON => last.location.end(),
    2876         3028 :                 _ => self.scanned.text.trim_end().len() as u32,
    2877              :             };
    2878         5851 :             let mut in_chunk = Vec::new();
    2879        11672 :             while next_statement < statements.len() {
    2880         6060 :                 let root = self.ast[statements[next_statement].root as usize];
    2881         6060 :                 let root_offset = resolve_text_span(&self.scanned.text, symbols, *root.symbol_span()).offset;
    2882         6060 :                 if root_offset >= end_offset {
    2883          239 :                     break;
    2884         5821 :                 }
    2885         5821 :                 in_chunk.push(next_statement);
    2886         5821 :                 next_statement += 1;
    2887              :             }
    2888         5851 :             let only_separator = chunk_symbols.len() == 1 && chunk_symbols[0].kind == S_SEMICOLON;
    2889         5851 :             if !damaged[chunk] && (!in_chunk.is_empty() || only_separator) {
    2890         5815 :                 parts.extend(in_chunk.into_iter().map(OutputPart::Statement));
    2891         5815 :             } else if !only_separator {
    2892           36 :                 parts.push(OutputPart::Damaged(TextSpan::new(begin_offset, end_offset - begin_offset)));
    2893           36 :             }
    2894              :         }
    2895         5606 :         parts
    2896         5606 :     }
    2897              : 
    2898         5606 :     fn write_output(&self) -> Vec<u8> {
    2899         5606 :         let options = self.render_options();
    2900         5606 :         let statements = &self.parsed.statements;
    2901         5606 :         let parts = self.output_parts();
    2902         5606 :         let mut output: Vec<u8> = Vec::with_capacity(self.estimate_formatted_size());
    2903              : 
    2904         5606 :         if self.config.debug_mode {
    2905            0 :             output.extend_from_slice(
    2906            0 :                 format!("/* indentation={}, max_width={} */\n", self.config.indentation_width, self.config.max_width)
    2907            0 :                     .as_bytes(),
    2908            0 :             );
    2909         5606 :         }
    2910              : 
    2911         5606 :         let input = self.scanned.text.as_bytes();
    2912         5606 :         let damaged_text = |span: &TextSpan| &input[span.offset as usize..span.end() as usize];
    2913         5822 :         if parts.iter().any(|p| matches!(p, OutputPart::Damaged(_))) {
    2914           30 :             self.copied_damaged_text.set(true);
    2915         5576 :         }
    2916              : 
    2917         5606 :         if self.config.mode == FormattingMode::INLINE {
    2918         1958 :             for (i, part) in parts.iter().enumerate() {
    2919         1958 :                 match part {
    2920         1944 :                     OutputPart::Statement(statement) => {
    2921         1944 :                         let root = statements[*statement].root as usize;
    2922         1944 :                         output.extend_from_slice(self.fmt.render(self.node_states[root].reg, &options).as_bytes());
    2923         1944 :                         output.push(b';');
    2924         1944 :                     }
    2925           14 :                     OutputPart::Damaged(span) => output.extend_from_slice(damaged_text(span)),
    2926              :                 }
    2927         1958 :                 if i + 1 < parts.len() {
    2928           85 :                     output.extend_from_slice(b"\n\n");
    2929         1873 :                 }
    2930              :             }
    2931         1873 :             return output;
    2932         3733 :         }
    2933              : 
    2934         3733 :         let comments = &self.scanned.comments[..];
    2935         3733 :         let max_width = self.config.max_width as usize;
    2936         3733 :         let descriptions = self.parsed.associate_descriptions();
    2937         4041 :         let ensure_line_break = |output: &mut Vec<u8>| {
    2938         4041 :             if !output.is_empty() && output.last() != Some(&b'\n') {
    2939          319 :                 output.push(b'\n');
    2940         3723 :             }
    2941         4041 :         };
    2942         3733 :         let mut comment_begin = 0;
    2943         3887 :         for (i, part) in parts.iter().enumerate() {
    2944         3887 :             if i > 0 {
    2945          154 :                 ensure_line_break(&mut output);
    2946          154 :                 output.push(b'\n');
    2947         3733 :             }
    2948         3887 :             let statement = match part {
    2949         3865 :                 OutputPart::Statement(statement) => *statement,
    2950           22 :                 OutputPart::Damaged(span) => {
    2951              :                     // Comments inside the damaged text are part of it
    2952           22 :                     let mut before_end = comment_begin;
    2953           25 :                     while before_end < comments.len() && comments[before_end].offset < span.offset {
    2954            3 :                         before_end += 1;
    2955            3 :                     }
    2956           22 :                     comments::append_comments(
    2957           22 :                         &mut output,
    2958           22 :                         input,
    2959           22 :                         &comments[comment_begin..before_end],
    2960           22 :                         max_width,
    2961           22 :                         Some(span.offset as usize),
    2962              :                     );
    2963           22 :                     ensure_line_break(&mut output);
    2964           22 :                     output.extend_from_slice(damaged_text(span));
    2965           22 :                     comment_begin = before_end;
    2966           25 :                     while comment_begin < comments.len() && comments[comment_begin].offset < span.end() {
    2967            3 :                         comment_begin += 1;
    2968            3 :                     }
    2969           22 :                     continue;
    2970              :                 }
    2971              :             };
    2972         3865 :             let root = statements[statement].root as usize;
    2973         3865 :             let description = &descriptions[statement];
    2974         3865 :             let root_span = resolve_text_span(&self.scanned.text, &self.scanned.symbols, *self.ast[root].symbol_span());
    2975         3865 :             let mut before_end = comment_begin;
    2976         4323 :             while before_end < comments.len() && comments[before_end].offset < root_span.offset {
    2977          458 :                 before_end += 1;
    2978          458 :             }
    2979         3865 :             let description_begin = description.description_begin as usize;
    2980         3865 :             if description.description_count > 0 && description_begin >= comment_begin {
    2981          169 :                 let leading_end = description_begin + description.description_count as usize;
    2982          169 :                 comments::append_comments(
    2983          169 :                     &mut output,
    2984          169 :                     input,
    2985          169 :                     &comments[comment_begin..description_begin],
    2986          169 :                     max_width,
    2987          169 :                     Some(comments[description_begin].offset as usize),
    2988          169 :                 );
    2989          169 :                 comments::append_description(
    2990          169 :                     &mut output,
    2991          169 :                     input,
    2992          169 :                     &comments[description_begin..leading_end],
    2993          169 :                     max_width,
    2994          169 :                     Some(root_span.offset as usize),
    2995          169 :                 );
    2996         3696 :             } else {
    2997         3696 :                 comments::append_comments(
    2998         3696 :                     &mut output,
    2999         3696 :                     input,
    3000         3696 :                     &comments[comment_begin..before_end],
    3001         3696 :                     max_width,
    3002         3696 :                     Some(root_span.offset as usize),
    3003         3696 :                 );
    3004         3696 :             }
    3005              : 
    3006         3865 :             ensure_line_break(&mut output);
    3007         3865 :             output.extend_from_slice(self.fmt.render(self.node_states[root].reg, &options).as_bytes());
    3008         3865 :             output.push(b';');
    3009              : 
    3010         3865 :             let statement_end = description.source_span.end() as usize;
    3011         3865 :             let mut within_end = before_end;
    3012         3906 :             while within_end < comments.len() && (comments[within_end].offset as usize) < statement_end {
    3013           41 :                 within_end += 1;
    3014           41 :             }
    3015         3865 :             comments::append_comments(&mut output, input, &comments[before_end..within_end], max_width, None);
    3016         3865 :             comment_begin = within_end;
    3017              :         }
    3018         3733 :         comments::append_comments(&mut output, input, &comments[comment_begin..], max_width, None);
    3019         3733 :         output
    3020         5606 :     }
    3021              : }
    3022              : 
    3023              : /// The formatted output as a string. Wrapped comments may split UTF-8 sequences, they are replaced
    3024              : /// with U+FFFD.
    3025         5598 : fn bytes_to_string(bytes: Vec<u8>) -> String {
    3026         5598 :     match String::from_utf8(bytes) {
    3027         5598 :         Ok(text) => text,
    3028            0 :         Err(e) => String::from_utf8_lossy(e.as_bytes()).into_owned(),
    3029              :     }
    3030         5598 : }
    3031              : 
    3032              : #[cfg(test)]
    3033              : mod tests {
    3034              :     use super::*;
    3035              :     use dashql_parser::parser::parse;
    3036              :     use dashql_parser::scanner::scan;
    3037              :     use std::sync::Arc;
    3038              : 
    3039            7 :     fn format(text: &str, mode: FormattingMode, max_width: u32) -> (String, Vec<u32>) {
    3040            7 :         let parsed = parse(Arc::new(scan(text, 0, 2)));
    3041            7 :         let mut formatter = Formatter::new(&parsed);
    3042            7 :         let mut config = FormattingConfigT::default();
    3043            7 :         config.mode = mode;
    3044            7 :         config.max_width = max_width;
    3045            7 :         config.indentation_width = 2;
    3046            7 :         let out = formatter.format(&config);
    3047            7 :         (out, formatter.unformattable_nodes())
    3048            7 :     }
    3049              : 
    3050              :     #[test]
    3051            1 :     fn formats_select() {
    3052            1 :         let (out, unformattable) = format("SELECT a,b FROM t WHERE a=1 AND b", FormattingMode::COMPACT, 120);
    3053            1 :         assert_eq!(out, "select a, b from t where a = 1 and b;");
    3054            1 :         assert!(unformattable.is_empty());
    3055            1 :         let (out, _) = format("select a, b from t where a = 1", FormattingMode::PRETTY, 120);
    3056            1 :         assert_eq!(out, "select a, b\nfrom t\nwhere a = 1;");
    3057            1 :     }
    3058              : 
    3059              :     #[test]
    3060            1 :     fn adds_parentheses_by_precedence() {
    3061            1 :         let (out, _) = format("select (1 + 2) * 3, 1 + 2 * 3, (a or b) and c", FormattingMode::INLINE, 120);
    3062            1 :         assert_eq!(out, "select (1 + 2) * 3, 1 + 2 * 3, (a or b) and c;");
    3063            1 :     }
    3064              : 
    3065              :     #[test]
    3066            1 :     fn copies_statements_with_syntax_errors() {
    3067            1 :         let (out, unformattable) = format("select  1; selec  1; select  2", FormattingMode::INLINE, 120);
    3068            1 :         assert_eq!(out, "select 1;\n\nselec  1;\n\nselect 2;");
    3069            1 :         assert!(unformattable.is_empty());
    3070              :         // Comments inside the copied text stay, the comments around it are formatted
    3071            1 :         let (out, _) = format("-- a\nselect from /* b */ from;\n-- c\nselect  2", FormattingMode::COMPACT, 120);
    3072            1 :         assert_eq!(out, "-- a\nselect from /* b */ from;\n\n-- c\nselect 2;");
    3073              :         // A script that is nothing but an error is copied
    3074            1 :         assert_eq!(format("select from where", FormattingMode::PRETTY, 120).0, "select from where");
    3075            1 :     }
    3076              : 
    3077              :     #[test]
    3078            1 :     fn keeps_comments() {
    3079            1 :         let (out, _) = format("-- head\nselect 1; -- tail\nselect 2", FormattingMode::COMPACT, 120);
    3080            1 :         assert_eq!(out, "-- head\nselect 1;\n-- tail\n\nselect 2;");
    3081            1 :     }
    3082              : 
    3083              :     #[test]
    3084            1 :     fn records_unformattable_nodes() {
    3085              :         // CREATE TABLE is only formatted as statement root, format_node_at does not mark the roots
    3086            1 :         let parsed = parse(Arc::new(scan("create table t (a int)", 0, 2)));
    3087            1 :         let root = parsed.statements[0].root as usize;
    3088            1 :         let mut formatter = Formatter::new(&parsed);
    3089            1 :         let mut config = FormattingConfigT::default();
    3090            1 :         config.mode = FormattingMode::INLINE;
    3091            1 :         assert_eq!(formatter.format(&config), "create table t (a integer);");
    3092            1 :         assert!(formatter.is_fully_formatted());
    3093            1 :         assert_eq!(formatter.format_node_at(root, &config), "'<OBJECT_SQL_CREATE>'");
    3094            1 :         assert_eq!(formatter.unformattable_nodes(), vec![root as u32]);
    3095            1 :         assert_eq!(formatter.format_node_at(parsed.nodes.len(), &config), "");
    3096            1 :     }
    3097              : 
    3098              :     #[test]
    3099            1 :     fn looks_up_attributes_like_cxx() {
    3100            3 :         let node = |key: AttributeKey| Node::new(&SymbolSpan::default(), NodeType::NAME, key, 3, 0, 0);
    3101            1 :         let nodes = vec![
    3102            1 :             node(K::SQL_ALIAS_NAME),
    3103            1 :             node(K::SQL_ALIAS_NAME),
    3104            1 :             node(K::SQL_ALIAS_COLUMN_NAMES),
    3105            1 :             Node::new(&SymbolSpan::default(), NodeType::OBJECT_SQL_ALIAS, K::NONE, u32::MAX, 0, 3),
    3106              :         ];
    3107            1 :         let mut parsed = parse(Arc::new(scan("", 0, 2)));
    3108            1 :         parsed.nodes = nodes;
    3109            1 :         parsed.statements.clear();
    3110            1 :         let formatter = Formatter::new(&parsed);
    3111            1 :         let object = &parsed.nodes[3];
    3112              :         // One key: the first match, several keys: the last match
    3113            1 :         let [first] = formatter.attrs(object, [K::SQL_ALIAS_NAME]);
    3114            1 :         assert_eq!(formatter.node_id(first.unwrap()), 0);
    3115            1 :         let [last, columns, missing] =
    3116            1 :             formatter.attrs(object, [K::SQL_ALIAS_NAME, K::SQL_ALIAS_COLUMN_NAMES, K::SQL_ALIAS_COLUMN_DEFS]);
    3117            1 :         assert_eq!(formatter.node_id(last.unwrap()), 1);
    3118            1 :         assert_eq!(formatter.node_id(columns.unwrap()), 2);
    3119            1 :         assert!(missing.is_none());
    3120            1 :     }
    3121              : }
        

Generated by: LCOV version 2.0-1