Line data Source code
1 : //! CREATE, DROP, ATTACH and SET statements.
2 :
3 : use dashql_parser::attrs;
4 : use super::{FmtReg, Formatter, FormattingJoinPolicy, K};
5 : use dashql_buffers::parser::{Node, NodeType, OnCommitOption, TempType};
6 :
7 : impl<'a> Formatter<'a> {
8 105 : pub(super) fn format_temp_type(&self, node: &'a Node) -> FmtReg {
9 105 : let f = &self.fmt;
10 105 : match TempType(super::value_u8(node)) {
11 51 : TempType::DEFAULT | TempType::LOCAL => f.text("temporary"),
12 3 : TempType::GLOBAL => f.text("global temporary"),
13 3 : TempType::UNLOGGED => f.text("unlogged"),
14 48 : TempType::NONE => f.empty(),
15 0 : _ => self.format_unimplemented(node),
16 : }
17 105 : }
18 :
19 33 : pub(super) fn format_on_commit_option(&self, node: &'a Node) -> FmtReg {
20 33 : let f = &self.fmt;
21 33 : match OnCommitOption(super::value_u8(node)) {
22 15 : OnCommitOption::DROP => f.text("on commit drop"),
23 9 : OnCommitOption::DELETE_ROWS => f.text("on commit delete rows"),
24 9 : OnCommitOption::PRESERVE_ROWS => f.text("on commit preserve rows"),
25 0 : OnCommitOption::NOOP => f.empty(),
26 0 : _ => self.format_unimplemented(node),
27 : }
28 33 : }
29 :
30 335 : pub(super) fn format_create(&self, node_id: usize) -> FmtReg {
31 335 : let f = &self.fmt;
32 335 : let node: &'a Node = &self.ast[node_id];
33 335 : if !self.node_states[node_id].is_statement_root {
34 1 : return self.format_unimplemented(node);
35 334 : }
36 334 : let [name, elements, if_not_exists, temp, on_commit] = attrs!(self.children(node), [
37 : K::SQL_CREATE_TABLE_NAME,
38 : K::SQL_CREATE_TABLE_ELEMENTS,
39 : K::SQL_CREATE_TABLE_IF_NOT_EXISTS,
40 : K::SQL_CREATE_TABLE_TEMP,
41 : K::SQL_CREATE_TABLE_ON_COMMIT,
42 : ],
43 : );
44 334 : let (Some(name), Some(elements)) = (name, elements) else { return self.format_unimplemented(node) };
45 :
46 334 : let mut header_parts = vec![f.text("create ")];
47 334 : if let Some(temp) = temp {
48 33 : header_parts.push(self.reg(temp));
49 33 : header_parts.push(f.text(" "));
50 301 : }
51 334 : header_parts.push(f.text("table "));
52 334 : if if_not_exists.is_some() {
53 15 : header_parts.push(f.text("if not exists "));
54 319 : }
55 334 : header_parts.push(self.reg(name));
56 334 : let header = f.concat(&header_parts);
57 :
58 334 : let mut table_elements = f.empty();
59 334 : if elements.children_count() > 0 {
60 334 : let mut parts = Vec::with_capacity(elements.children_count() as usize);
61 1387 : for element in self.children(elements) {
62 1387 : let reg = self.reg(element);
63 1387 : if reg == 0 {
64 0 : return self.format_unimplemented(node);
65 1387 : }
66 1387 : parts.push(reg);
67 : }
68 334 : let (inline_separator, break_separator) = self.comma_separators();
69 334 : table_elements = f.join(&parts, inline_separator, break_separator, None, false);
70 0 : }
71 :
72 334 : let element_block = if elements.children_count() > 0 { f.parenthesized(table_elements) } else { f.text("()") };
73 334 : let mut statement = f.concat(&[header, f.text(" "), element_block]);
74 334 : if let Some(on_commit) = on_commit {
75 24 : statement = f.concat(&[statement, f.text(" "), self.reg(on_commit)]);
76 310 : }
77 334 : statement
78 335 : }
79 :
80 39 : pub(super) fn format_create_as(&self, node: &'a Node) -> FmtReg {
81 39 : let f = &self.fmt;
82 39 : let [name, columns, if_not_exists, temp, statement, with_data, on_commit] = attrs!(self.children(node), [
83 : K::SQL_CREATE_AS_NAME,
84 : K::SQL_CREATE_AS_COLUMNS,
85 : K::SQL_CREATE_AS_IF_NOT_EXISTS,
86 : K::SQL_CREATE_AS_TEMP,
87 : K::SQL_CREATE_AS_STATEMENT,
88 : K::SQL_CREATE_AS_WITH_DATA,
89 : K::SQL_CREATE_AS_ON_COMMIT,
90 : ],
91 : );
92 39 : let (Some(name), Some(statement)) = (name, statement) else { return self.format_unimplemented(node) };
93 :
94 39 : let mut parts = vec![f.text("create ")];
95 39 : if let Some(temp) = temp {
96 15 : parts.push(self.reg(temp));
97 15 : parts.push(f.text(" "));
98 24 : }
99 39 : parts.push(f.text("table "));
100 39 : if if_not_exists.is_some() {
101 15 : parts.push(f.text("if not exists "));
102 33 : }
103 39 : parts.push(self.reg(name));
104 39 : if let Some(columns) = columns.filter(|c| c.children_count() > 0) {
105 6 : parts.push(f.parenthesized(self.reg(columns)));
106 33 : }
107 39 : if let Some(on_commit) = on_commit {
108 9 : parts.push(f.text(" "));
109 9 : parts.push(self.reg(on_commit));
110 30 : }
111 39 : parts.push(f.text(" as"));
112 : // The query follows on the same line only if the whole statement fits, like the query of a view
113 39 : let header = f.concat(&parts);
114 39 : let body = self.space_join(&[header, self.reg(statement)], FormattingJoinPolicy::BreakAllOrNone, false);
115 39 : match with_data {
116 9 : Some(with_data) => {
117 9 : let include_data = with_data.node_type() == NodeType::BOOL && with_data.children_begin_or_value() != 0;
118 9 : f.concat(&[body, f.text(if include_data { " with data" } else { " with no data" })])
119 : }
120 30 : None => body,
121 : }
122 39 : }
123 :
124 24 : pub(super) fn format_view(&self, node: &'a Node) -> FmtReg {
125 24 : let f = &self.fmt;
126 24 : let [name, columns, or_replace, temp, statement] = attrs!(self.children(node), [K::SQL_VIEW_NAME, K::SQL_VIEW_COLUMNS, K::SQL_VIEW_OR_REPLACE, K::SQL_VIEW_TEMP, K::SQL_VIEW_STATEMENT],
127 : );
128 24 : let (Some(name), Some(statement)) = (name, statement) else { return self.format_unimplemented(node) };
129 :
130 24 : let mut parts = vec![f.text("create ")];
131 24 : if or_replace.is_some() {
132 6 : parts.push(f.text("or replace "));
133 18 : }
134 24 : if let Some(temp) = temp {
135 6 : parts.push(self.reg(temp));
136 6 : parts.push(f.text(" "));
137 18 : }
138 24 : parts.push(f.text("view "));
139 24 : parts.push(self.reg(name));
140 24 : if let Some(columns) = columns.filter(|c| c.children_count() > 0) {
141 3 : parts.push(f.parenthesized(self.reg(columns)));
142 21 : }
143 24 : parts.push(f.text(" as"));
144 24 : let header = f.concat(&parts);
145 24 : self.space_join(&[header, self.reg(statement)], FormattingJoinPolicy::BreakAllOrNone, false)
146 24 : }
147 :
148 57 : pub(super) fn format_function_param(&self, node: &'a Node) -> FmtReg {
149 57 : let f = &self.fmt;
150 57 : let [name, type_node] = attrs!(self.children(node), [K::SQL_FUNCTION_PARAM_NAME, K::SQL_FUNCTION_PARAM_TYPE]);
151 57 : let (Some(name), Some(type_node)) = (name, type_node) else { return self.format_unimplemented(node) };
152 57 : f.concat(&[self.reg(name), f.text(" "), self.reg(type_node)])
153 57 : }
154 :
155 45 : pub(super) fn format_create_function(&self, node: &'a Node) -> FmtReg {
156 45 : let f = &self.fmt;
157 45 : let [name, params, returns, aggregate] = attrs!(self.children(node), [
158 : K::SQL_CREATE_FUNCTION_NAME,
159 : K::SQL_CREATE_FUNCTION_PARAMS,
160 : K::SQL_CREATE_FUNCTION_RETURNS,
161 : K::SQL_CREATE_FUNCTION_IS_AGGREGATE,
162 : ],
163 : );
164 45 : let (Some(name), Some(returns)) = (name, returns) else { return self.format_unimplemented(node) };
165 45 : let kind = if aggregate.is_some() { "create aggregate " } else { "create function " };
166 45 : let params_reg = params.map(|p| self.reg(p)).unwrap_or(0);
167 45 : let params_reg = if params_reg == 0 { f.text("()") } else { f.parenthesized(params_reg) };
168 45 : f.concat(&[f.text(kind), self.reg(name), params_reg, f.text(" returns "), self.reg(returns)])
169 45 : }
170 :
171 42 : pub(super) fn format_drop(&self, node: &'a Node, table: bool) -> FmtReg {
172 42 : let f = &self.fmt;
173 42 : let [name, if_exists] = attrs!(self.children(node), [K::SQL_DROP_NAME, K::SQL_DROP_IF_EXISTS]);
174 42 : let Some(name) = name else { return self.format_unimplemented(node) };
175 42 : let object = if table { "table " } else { "view " };
176 42 : let if_exists_reg = if if_exists.is_some() { f.text("if exists ") } else { f.empty() };
177 42 : f.concat(&[f.text("drop "), f.text(object), if_exists_reg, self.reg(name)])
178 42 : }
179 :
180 18 : pub(super) fn format_attach_database_option(&self, node: &'a Node) -> FmtReg {
181 18 : let f = &self.fmt;
182 18 : let [key, value] = attrs!(self.children(node), [K::SQL_GENERIC_OPTION_KEY, K::SQL_GENERIC_OPTION_VALUE]);
183 18 : let (Some(key), Some(value)) = (key, value) else { return self.format_unimplemented(node) };
184 18 : f.concat(&[self.reg(key), f.text(" = "), self.reg(value)])
185 18 : }
186 :
187 18 : pub(super) fn format_attach_database(&self, node: &'a Node) -> FmtReg {
188 18 : let f = &self.fmt;
189 18 : let [path, alias, local, options] = attrs!(self.children(node), [
190 : K::SQL_ATTACH_DATABASE_PATH,
191 : K::SQL_ATTACH_DATABASE_ALIAS,
192 : K::SQL_ATTACH_DATABASE_LOCAL,
193 : K::SQL_ATTACH_DATABASE_OPTIONS,
194 : ],
195 : );
196 18 : let (Some(path), Some(alias)) = (path, alias) else { return self.format_unimplemented(node) };
197 18 : let mut parts = vec![
198 18 : f.text(if local.is_some() { "attach local database " } else { "attach database " }),
199 18 : self.reg(path),
200 18 : f.text(" as "),
201 18 : self.reg(alias),
202 : ];
203 18 : if let Some(options) = options {
204 9 : parts.push(f.text(" with "));
205 9 : parts.push(f.parenthesized(self.reg(options)));
206 9 : }
207 18 : f.concat(&parts)
208 18 : }
209 :
210 78 : pub(super) fn format_vararg_field(&self, node: &'a Node) -> FmtReg {
211 78 : let f = &self.fmt;
212 78 : let [key, value] = attrs!(self.children(node), [K::EXT_VARARG_FIELD_KEY, K::EXT_VARARG_FIELD_VALUE]);
213 78 : let (Some(key), Some(value)) = (key, value) else { return self.format_unimplemented(node) };
214 78 : f.concat(&[self.reg(key), f.text(" = "), self.reg(value)])
215 78 : }
216 :
217 9 : pub(super) fn format_vararg_array(&self, node: &'a Node) -> FmtReg {
218 9 : let f = &self.fmt;
219 9 : let [values] = attrs!(self.children(node), [K::EXT_VARARG_ARRAY_VALUES]);
220 9 : let Some(values) = values.filter(|v| v.node_type() == NodeType::ARRAY) else {
221 0 : return self.format_unimplemented(node);
222 : };
223 9 : if values.children_count() == 0 {
224 0 : return f.text("[]");
225 9 : }
226 18 : let items: Vec<FmtReg> = self.children(values).iter().map(|v| self.reg(v)).filter(|&r| r != 0).collect();
227 9 : if items.is_empty() {
228 0 : return f.text("[]");
229 9 : }
230 9 : let (inline_separator, break_separator) = self.comma_separators();
231 9 : let list =
232 9 : f.join(&items, inline_separator, break_separator, Some(FormattingJoinPolicy::BreakOnOverflow), false);
233 9 : f.concat(&[f.text("["), list, f.text("]")])
234 9 : }
235 :
236 24 : pub(super) fn format_set(&self, node: &'a Node) -> FmtReg {
237 24 : let f = &self.fmt;
238 24 : let [varargs] = attrs!(self.children(node), [K::EXT_SET_VARARGS]);
239 24 : let Some(varargs) = varargs else { return self.format_unimplemented(node) };
240 24 : f.concat(&[f.text("set "), self.reg(varargs)])
241 24 : }
242 : }
|