Line data Source code
1 : //! SELECT statements.
2 :
3 : use dashql_parser::attrs;
4 : use super::{FmtReg, Formatter, FormattingJoinPolicy, K};
5 : use dashql_buffers::formatting::FormattingMode;
6 : use dashql_buffers::parser::{CombineModifier, CombineOperation, Node, NodeType};
7 :
8 : /// The binding strength of a set operation, INTERSECT binds tighter than UNION and EXCEPT
9 390 : fn combine_precedence(operation: CombineOperation) -> u8 {
10 390 : if operation == CombineOperation::INTERSECT {
11 51 : 2
12 : } else {
13 339 : 1
14 : }
15 390 : }
16 :
17 : impl<'a> Formatter<'a> {
18 : /// Does an operand of a set operation need parentheses to keep its meaning?
19 : ///
20 : /// That is the case if it has clauses that would otherwise apply to the whole combination, or if it is a
21 : /// set operation that binds weaker than the parent or that is the right operand of an equally strong parent.
22 1062 : fn combine_input_needs_parentheses(&self, input: &'a Node, parent: CombineOperation, index: usize) -> bool {
23 1062 : if input.node_type() != NodeType::OBJECT_SQL_SELECT {
24 0 : return false;
25 1062 : }
26 : #[rustfmt::skip]
27 1062 : let [order, limit, limit_all, offset, locking, ctes, operation] = attrs!(self.children(input), [
28 : K::SQL_SELECT_ORDER,
29 : K::SQL_SELECT_LIMIT,
30 : K::SQL_SELECT_LIMIT_ALL,
31 : K::SQL_SELECT_OFFSET,
32 : K::SQL_SELECT_ROW_LOCKING,
33 : K::SQL_SELECT_WITH_CTES,
34 : K::SQL_COMBINE_OPERATION,
35 : ]);
36 1062 : if [order, limit, limit_all, offset, locking, ctes].iter().any(Option::is_some) {
37 3 : return true;
38 1059 : }
39 1059 : let Some(operation) = operation else { return false };
40 195 : let (child, parent) =
41 195 : (combine_precedence(CombineOperation(super::value_u8(operation))), combine_precedence(parent));
42 195 : child < parent || (child == parent && index > 0)
43 1062 : }
44 :
45 8962 : pub(super) fn format_select(&self, node_id: usize) -> FmtReg {
46 8962 : let f = &self.fmt;
47 8962 : let node: &'a Node = &self.ast[node_id];
48 : #[rustfmt::skip]
49 : let [
50 8962 : select_all, select_distinct, select_targets, select_into, select_from, select_where, select_groups,
51 8962 : select_having, select_windows, select_order, select_row_locking, select_with_ctes, select_with_recursive,
52 8962 : select_offset, select_limit, select_limit_all, select_sample, select_values, select_table,
53 8962 : combine_operation, combine_modifier, combine_input, select_statement,
54 8962 : ] = attrs!(self.children(node), [
55 : K::SQL_SELECT_ALL,
56 : K::SQL_SELECT_DISTINCT,
57 : K::SQL_SELECT_TARGETS,
58 : K::SQL_SELECT_INTO,
59 : K::SQL_SELECT_FROM,
60 : K::SQL_SELECT_WHERE,
61 : K::SQL_SELECT_GROUPS,
62 : K::SQL_SELECT_HAVING,
63 : K::SQL_SELECT_WINDOWS,
64 : K::SQL_SELECT_ORDER,
65 : K::SQL_SELECT_ROW_LOCKING,
66 : K::SQL_SELECT_WITH_CTES,
67 : K::SQL_SELECT_WITH_RECURSIVE,
68 : K::SQL_SELECT_OFFSET,
69 : K::SQL_SELECT_LIMIT,
70 : K::SQL_SELECT_LIMIT_ALL,
71 : K::SQL_SELECT_SAMPLE,
72 : K::SQL_SELECT_VALUES,
73 : K::SQL_SELECT_TABLE,
74 : K::SQL_COMBINE_OPERATION,
75 : K::SQL_COMBINE_MODIFIER,
76 : K::SQL_COMBINE_INPUT,
77 : K::SQL_SELECT_EXPRESSION_STATEMENT,
78 : ],
79 : );
80 :
81 8962 : let mut query = 0;
82 8962 : if let Some(select_statement) = select_statement {
83 0 : query = self.reg(select_statement);
84 0 : if query == 0 {
85 0 : return self.format_unimplemented(node);
86 0 : }
87 8962 : }
88 8962 : if let (Some(combine_operation), Some(combine_input)) = (combine_operation, combine_input) {
89 531 : let op_text = match CombineOperation(super::value_u8(combine_operation)) {
90 429 : CombineOperation::UNION => "union",
91 69 : CombineOperation::INTERSECT => "intersect",
92 33 : CombineOperation::EXCEPT => "except",
93 0 : _ => return self.format_unimplemented(node),
94 : };
95 531 : let mod_text = match combine_modifier.map(|m| CombineModifier(super::value_u8(m))) {
96 345 : Some(CombineModifier::ALL) => " all",
97 12 : Some(CombineModifier::DISTINCT) => " distinct",
98 174 : _ => "",
99 : };
100 531 : let op_reg =
101 531 : if mod_text.is_empty() { f.text(op_text) } else { f.concat(&[f.text(op_text), f.text(mod_text)]) };
102 531 : let separator = f.concat(&[f.text(" "), op_reg, f.text(" ")]);
103 531 : let break_separator = f.concat(&[f.break_(), op_reg, f.break_()]);
104 531 : let mut inputs = self.array_regs(combine_input);
105 1062 : if inputs.iter().any(|&i| i == 0) {
106 0 : return self.format_unimplemented(node);
107 531 : }
108 : // The AST does not keep the parentheses of the inputs, add those that the operands need
109 531 : let operation = CombineOperation(super::value_u8(combine_operation));
110 1062 : for (i, input) in self.children(combine_input).iter().enumerate() {
111 1062 : if self.combine_input_needs_parentheses(input, operation, i) {
112 9 : inputs[i] = f.parenthesized(inputs[i]);
113 1053 : }
114 : }
115 531 : query = f.join(&inputs, separator, break_separator, Some(FormattingJoinPolicy::BreakAllOrNone), false);
116 :
117 : // ORDER BY, LIMIT, OFFSET and locking apply to the whole combination
118 531 : let mut tail = Vec::with_capacity(4);
119 531 : if let Some(select_order) = select_order {
120 6 : tail.push(f.concat(&[f.text("order by "), self.reg(select_order)]));
121 525 : }
122 531 : if select_limit_all.is_some() {
123 3 : tail.push(f.text("limit all"));
124 528 : } else if let Some(select_limit) = select_limit {
125 3 : let mut body = self.reg(select_limit);
126 3 : if select_limit.node_type() == NodeType::BOOL && select_limit.children_begin_or_value() != 0 {
127 0 : body = f.text("1");
128 3 : }
129 3 : tail.push(f.concat(&[f.text("limit "), body]));
130 525 : }
131 531 : if let Some(select_offset) = select_offset {
132 6 : tail.push(f.concat(&[f.text("offset "), self.reg(select_offset)]));
133 525 : }
134 531 : if let Some(select_row_locking) = select_row_locking {
135 3 : let body = self.reg(select_row_locking);
136 3 : if body == 0 {
137 0 : return self.format_unimplemented(node);
138 3 : }
139 3 : tail.push(body);
140 528 : }
141 531 : if !tail.is_empty() {
142 9 : tail.insert(0, query);
143 9 : query = self.space_join(&tail, self.pretty_policy(FormattingJoinPolicy::BreakAllOrNone), false);
144 522 : }
145 8431 : }
146 :
147 8962 : if query == 0 {
148 8431 : let mut clauses = Vec::with_capacity(12);
149 8431 : if let Some(select_values) = select_values {
150 75 : let values_reg = self.reg(select_values);
151 75 : if values_reg == 0 {
152 0 : return self.format_unimplemented(node);
153 75 : }
154 75 : if self.config.mode == FormattingMode::PRETTY {
155 25 : clauses.push(f.concat(&[f.text("values"), f.indented(f.concat(&[f.break_(), values_reg]))]));
156 50 : } else {
157 50 : clauses.push(f.concat(&[f.text("values "), values_reg]));
158 50 : }
159 8356 : }
160 8431 : if let Some(select_table) = select_table {
161 18 : let table_reg = self.reg(select_table);
162 18 : if table_reg == 0 {
163 0 : return self.format_unimplemented(select_table);
164 18 : }
165 18 : clauses.push(f.concat(&[f.text("table "), table_reg]));
166 8413 : }
167 : // A select without targets is valid SQL, `select from t`
168 8431 : let has_source = select_values.is_some() || select_table.is_some();
169 8431 : if select_targets.is_none_or(|t| t.children_count() == 0) && !has_source {
170 24 : clauses.push(f.text(if select_distinct.is_some() {
171 0 : "select distinct"
172 24 : } else if select_all.is_some() {
173 12 : "select all"
174 : } else {
175 12 : "select"
176 : }));
177 8407 : } else if let Some(select_targets) = select_targets {
178 8314 : let body = self.reg(select_targets);
179 8314 : match select_distinct.filter(|d| d.node_type() == NodeType::ARRAY) {
180 138 : Some(select_distinct) if select_distinct.children_count() > 0 => {
181 18 : let on_cols = self.reg(select_distinct);
182 18 : clauses.push(f.concat(&[
183 18 : f.text("select distinct on "),
184 18 : f.parenthesized(on_cols),
185 18 : f.text(" "),
186 18 : body,
187 18 : ]));
188 18 : }
189 120 : Some(_) => clauses.push(f.concat(&[f.text("select distinct "), body])),
190 8176 : None if select_all.is_some() => clauses.push(f.concat(&[f.text("select all "), body])),
191 8173 : None => clauses.push(f.concat(&[f.text("select "), body])),
192 : }
193 93 : }
194 8431 : if let Some(select_into) = select_into {
195 51 : let body = self.reg(select_into);
196 51 : if body == 0 {
197 0 : return self.format_unimplemented(node);
198 51 : }
199 51 : clauses.push(body);
200 8380 : }
201 8431 : if let Some(select_from) = select_from {
202 5986 : clauses.push(f.concat(&[f.text("from "), self.reg(select_from)]));
203 6333 : }
204 8431 : if let Some(select_where) = select_where {
205 3317 : clauses.push(f.concat(&[f.text("where "), self.reg(select_where)]));
206 5114 : }
207 8431 : if let Some(select_groups) = select_groups {
208 1530 : clauses.push(f.concat(&[f.text("group by "), self.reg(select_groups)]));
209 6901 : }
210 8431 : if let Some(select_having) = select_having {
211 117 : clauses.push(f.concat(&[f.text("having "), self.reg(select_having)]));
212 8314 : }
213 8431 : if let Some(select_windows) = select_windows {
214 63 : let body = self.reg(select_windows);
215 63 : if body == 0 {
216 0 : return self.format_unimplemented(node);
217 63 : }
218 63 : clauses.push(f.concat(&[f.text("window "), body]));
219 8368 : }
220 8431 : if let Some(select_sample) = select_sample {
221 48 : let body = self.reg(select_sample);
222 48 : if body == 0 {
223 0 : return self.format_unimplemented(node);
224 48 : }
225 48 : clauses.push(body);
226 8383 : }
227 8431 : if let Some(select_order) = select_order {
228 1161 : clauses.push(f.concat(&[f.text("order by "), self.reg(select_order)]));
229 7270 : }
230 8431 : if select_limit_all.is_some() {
231 21 : clauses.push(f.text("limit all"));
232 8410 : } else if let Some(select_limit) = select_limit {
233 876 : let mut body = self.reg(select_limit);
234 876 : if select_limit.node_type() == NodeType::BOOL && select_limit.children_begin_or_value() != 0 {
235 3 : body = f.text("1");
236 873 : }
237 876 : clauses.push(f.concat(&[f.text("limit "), body]));
238 7534 : }
239 8431 : if let Some(select_offset) = select_offset {
240 27 : clauses.push(f.concat(&[f.text("offset "), self.reg(select_offset)]));
241 8404 : }
242 8431 : if let Some(select_row_locking) = select_row_locking {
243 78 : let body = self.reg(select_row_locking);
244 78 : if body == 0 {
245 0 : return self.format_unimplemented(node);
246 78 : }
247 78 : clauses.push(body);
248 8353 : }
249 :
250 8431 : if clauses.is_empty() {
251 0 : return self.format_unimplemented(node);
252 8431 : }
253 8431 : let clause_policy = self.pretty_policy(FormattingJoinPolicy::BreakAllOrNone);
254 8431 : query = self.space_join(&clauses, clause_policy, false);
255 531 : }
256 :
257 8962 : if let Some(select_with_ctes) = select_with_ctes {
258 462 : let cte_children = self.array_regs(select_with_ctes);
259 462 : let mut cte_regs = Vec::with_capacity(cte_children.len() * 2);
260 813 : for (i, &cte) in cte_children.iter().enumerate() {
261 813 : if i > 0 {
262 351 : cte_regs.push(f.text(", "));
263 462 : }
264 813 : cte_regs.push(cte);
265 : }
266 462 : let ctes = f.concat(&cte_regs);
267 462 : let keyword = if select_with_recursive.is_some() { "with recursive " } else { "with " };
268 462 : let with_clause = f.concat(&[f.text(keyword), ctes]);
269 462 : let with_policy = self.pretty_policy(FormattingJoinPolicy::BreakAllOrNone);
270 462 : query = self.space_join(&[with_clause, query], with_policy, false);
271 8500 : }
272 8962 : query
273 8962 : }
274 : }
|