Branch data Line data Source code
1 : : #include "parse/Sema.hpp"
2 : :
3 : : #include <cstdint>
4 : : #include <mutable/catalog/Catalog.hpp>
5 : : #include <mutable/io/Reader.hpp>
6 : : #include <mutable/Options.hpp>
7 : : #include <sstream>
8 : : #include <unordered_map>
9 : :
10 : :
11 : : using namespace m;
12 : : using namespace m::ast;
13 : :
14 : :
15 : 0 : std::unique_ptr<DatabaseCommand> Sema::analyze(std::unique_ptr<ast::Command> ast)
16 : : {
17 : 0 : (*this)(*ast); // perform semantic analysis
18 [ # # ]: 0 : if (command_)
19 [ # # ]: 0 : command_->ast(std::move(ast)); // move AST into DatabaseCommand instance
20 : 0 : return std::move(command_);
21 : 0 : }
22 : :
23 : 1365 : bool Sema::is_nested() const
24 : : {
25 : 1365 : return contexts_.size() > 1;
26 : : }
27 : :
28 : : /*----------------------------------------------------------------------------------------------------------------------
29 : : * Sema Designator Helpers
30 : : *--------------------------------------------------------------------------------------------------------------------*/
31 : :
32 : 30 : std::unique_ptr<Designator> Sema::create_designator(ThreadSafePooledString name, Token tok, const Expr &target)
33 : : {
34 [ + - ]: 60 : auto new_designator = std::make_unique<Designator>(tok, Token::CreateArtificial(),
35 [ + - + - ]: 30 : Token(tok.pos, std::move(name), TK_IDENTIFIER));
36 [ + - ]: 30 : new_designator->type_ = target.type();
37 : 30 : new_designator->target_ = ⌖
38 : 30 : return new_designator;
39 [ + - ]: 30 : }
40 : :
41 : 0 : std::unique_ptr<Designator> Sema::create_designator(const Expr &name, const Expr &target, bool drop_table_name)
42 : : {
43 : 0 : auto &C = Catalog::Get();
44 : :
45 : 0 : std::unique_ptr<Designator> new_designator;
46 [ # # # # ]: 0 : if (auto d = cast<const Designator>(&name)) {
47 [ # # # # : 0 : Token table_name = drop_table_name ? Token::CreateArtificial() : d->table_name; // possibly drop table name
# # ]
48 [ # # ]: 0 : new_designator = std::make_unique<Designator>(d->tok, std::move(table_name), d->attr_name); // copy of `name`
49 : 0 : } else {
50 [ # # # # ]: 0 : oss.str("");
51 [ # # ]: 0 : oss << name; // stringify `name`
52 [ # # # # : 0 : Token tok(target.tok.pos, C.pool(oss.str().c_str()), TK_DEC_INT); // fresh identifier
# # ]
53 [ # # ]: 0 : new_designator = std::make_unique<Designator>(std::move(tok));
54 : 0 : }
55 : :
56 [ # # ]: 0 : new_designator->type_ = target.type();
57 : 0 : new_designator->target_ = ⌖
58 : 0 : return new_designator;
59 [ # # ]: 0 : }
60 : :
61 : 0 : void Sema::replace_by_fresh_designator_to(std::unique_ptr<Expr> &to_replace, const Expr &target)
62 : : {
63 : 0 : auto new_designator = create_designator(*to_replace, target);
64 : 0 : to_replace = std::move(new_designator);
65 : 0 : }
66 : :
67 : 0 :
68 : : /*----------------------------------------------------------------------------------------------------------------------
69 : : * Other Sema Helpers
70 : : *--------------------------------------------------------------------------------------------------------------------*/
71 : :
72 : 2252 : ThreadSafePooledOptionalString Sema::make_unique_id_from_binding_path(context_stack_t::reverse_iterator current_ctx,
73 : : context_stack_t::reverse_iterator binding_ctx)
74 : 1 : {
75 [ + + ]: 2252 : if (current_ctx == binding_ctx) return {};
76 : :
77 [ + - + - ]: 28 : oss.str("");
78 [ + + ]: 56 : for (auto it = current_ctx; it != binding_ctx; ++it) {
79 [ + - ]: 28 : if (it != current_ctx) oss << '.';
80 : 28 : M_insist((*it)->alias.has_value(), "nested queries must have an alias");
81 : 28 : oss << (*it)->alias;
82 : 28 : }
83 : :
84 : 28 : auto &C = Catalog::Get();
85 [ + - - + ]: 28 : return C.pool(oss.str().c_str());
86 : 2252 : }
87 : :
88 : 0 : bool Sema::is_composable_of(const ast::Expr &expr,
89 : : const std::vector<std::reference_wrapper<ast::Expr>> components)
90 : : {
91 : 0 : auto recurse = overloaded {
92 : 0 : [&](const ast::Designator &d) -> bool {
93 [ # # ]: 0 : return d.contains_free_variables() or d.is_identifier(); // identifiers are implicitly composable, as they never refer into a table XXX do we have to check the target?
94 : : },
95 : 0 : [&](const ast::FnApplicationExpr &e) -> bool {
96 [ # # # # ]: 0 : if (not is_composable_of(*e.fn, components)) return false;
97 [ # # ]: 0 : for (auto &arg : e.args) {
98 [ # # # # ]: 0 : if (not is_composable_of(*arg, components))
99 : 0 : return false;
100 : : }
101 : 0 : return true;
102 : 0 : },
103 [ # # ]: 0 : [&](const ast::UnaryExpr &e) -> bool { return is_composable_of(*e.expr, components); },
104 : 0 : [&](const ast::BinaryExpr &e) -> bool {
105 [ # # # # : 0 : return is_composable_of(*e.lhs, components) and is_composable_of(*e.rhs, components);
# # # # #
# # # ]
106 : 0 : },
107 : 0 : [](auto&) -> bool { return true; },
108 : : };
109 : :
110 [ # # ]: 0 : for (auto c : components)
111 [ # # ]: 0 : if (expr == c.get()) return true; // syntactically equivalent to a component
112 : 0 : return visit(recurse, expr, m::tag<m::ast::ConstASTExprVisitor>()); // attempt to recursively compose expr
113 : 0 : }
114 : :
115 : 0 : void Sema::compose_of(std::unique_ptr<ast::Expr> &ptr, const std::vector<std::reference_wrapper<ast::Expr>> components)
116 : : {
117 : 0 : auto recurse = overloaded {
118 : 0 : [&](const ast::Designator &d) -> bool {
119 [ # # ]: 0 : return d.contains_free_variables() or d.is_identifier(); // identifiers are implicitly composable, as they never refer into a table XXX do we have to check the target?
120 : : },
121 : 0 : [&](const ast::FnApplicationExpr &e) -> bool {
122 [ # # # # ]: 0 : if (not is_composable_of(*e.fn, components)) return false;
123 [ # # ]: 0 : for (auto &arg : e.args) {
124 [ # # # # ]: 0 : if (not is_composable_of(*arg, components))
125 : 0 : return false;
126 : : }
127 : 0 : return true;
128 : 0 : },
129 [ # # ]: 0 : [&](const ast::UnaryExpr &e) -> bool { return is_composable_of(*e.expr, components); },
130 : 0 : [&](const ast::BinaryExpr &e) -> bool {
131 [ # # # # : 0 : return is_composable_of(*e.lhs, components) and is_composable_of(*e.rhs, components);
# # # # #
# # # ]
132 : 0 : },
133 : 0 : [](auto&) -> bool { return true; },
134 : : };
135 : :
136 [ # # ]: 0 : for (auto c : components) {
137 [ # # ]: 0 : if (*ptr == c.get())
138 : 0 : replace_by_fresh_designator_to(/* to_replace= */ ptr, /* target= */ c.get());
139 : : }
140 : 0 : visit(recurse, *ptr, m::tag<m::ast::ConstASTExprVisitor>()); // attempt to recursively compose expr
141 : 0 : }
142 : :
143 : : /*===== Expr =========================================================================================================*/
144 : :
145 : 0 : void Sema::operator()(ErrorExpr &e)
146 : : {
147 [ # # ]: 0 : e.type_ = Type::Get_Error();
148 : 0 : }
149 : :
150 : 2376 : void Sema::operator()(Designator &e)
151 : : {
152 : 2376 : Catalog &C = Catalog::Get();
153 : 2376 : SemaContext *current_ctx = &get_context();
154 : 2376 : auto attr_name = e.attr_name.text.assert_not_none();
155 : :
156 [ + - + - ]: 2376 : oss.str("");
157 [ + - ]: 2376 : oss << e;
158 [ + - + - ]: 2376 : auto pooled_name = C.pool(oss.str().c_str());
159 : :
160 : : /*----- In a stage after SELECT, check whether the `Designator` refers to a value produced by SELECT. -----*/
161 [ + + ]: 2376 : if (current_ctx->stage > SemaContext::S_Select) {
162 [ + - ]: 127 : auto [begin, end] = current_ctx->results.equal_range(pooled_name);
163 [ + - + - : 82 : if (std::distance(begin, end) > 1) {
+ + ]
164 [ + - + - : 7 : diag.e(e.tok.pos) << "Designator " << e << " is ambiguous, multiple occurrences in SELECT clause.\n";
+ - + - ]
165 [ + - + - ]: 7 : e.type_ = Type::Get_Error();
166 : 7 : return;
167 [ + - + - : 68 : } else if (std::distance(begin, end) == 1) {
+ + ]
168 : 18 : SemaContext::result_t &result = begin->second;
169 [ + - + - : 18 : if (auto d = cast<Designator>(&result.expr()); d and not result.alias.has_value()) // target is a designator
+ - + - +
+ ]
170 [ + - + - ]: 3 : e.table_name.text = d->table_name.text; // w/o explicit alias
171 [ + - + - ]: 18 : e.type_ = result.expr().type();
172 [ + - ]: 18 : e.target_ = &result.expr();
173 : 18 : return;
174 : : }
175 : 16 : }
176 : :
177 : : /*----- In a stage after GROUP BY, check whether the entire expression refers to a grouping key. -----*/
178 [ + + + + ]: 2351 : if (current_ctx->stage > SemaContext::S_GroupBy and not current_ctx->grouping_keys.empty()) {
179 [ + - ]: 339 : auto [begin, end] = current_ctx->grouping_keys.equal_range(pooled_name);
180 [ + - + - : 180 : if (std::distance(begin, end) > 1) {
- + ]
181 [ # # # # : 0 : diag.e(e.tok.pos) << "Designator " << e << " is ambiguous, multiple occurrences in GROUP BY clause.\n";
# # # # ]
182 [ # # # # ]: 0 : e.type_ = Type::Get_Error();
183 : 0 : return;
184 [ + - + - : 180 : } else if (std::distance(begin, end) == 1) {
+ + ]
185 : 69 : auto &referenced_expr = begin->second.get();
186 [ + - ]: 69 : e.type_ = referenced_expr.type();
187 [ + - + - : 69 : if (auto pt = cast<const PrimitiveType>(e.type()))
+ - ]
188 [ + - ]: 69 : e.type_ = pt->as_scalar();
189 : : else
190 [ # # # # : 0 : M_insist(e.type()->is_error(), "grouping expression must be of primitive type");
# # ]
191 : 69 : e.target_ = &referenced_expr;
192 : 69 : return;
193 : : }
194 : 21 : }
195 : :
196 : : /*----- Designator was neither a reference to a SELECT or GROUP BY expression. -----*/
197 : 2282 : decltype(contexts_)::reverse_iterator found_ctx; // the context where the designator is found
198 : 2282 : bool is_result = false;
199 : :
200 : : /* If the designator references an attribute of a table, search for it. */
201 [ + - + + ]: 2282 : if (e.table_name) {
202 : : /* Find the source table first and then locate the target inside this table. */
203 : 1974 : SemaContext::source_type src;
204 : :
205 : : /* Search all contexts, starting with the innermost and advancing outwards. */
206 : 1974 : auto it = contexts_.rbegin();
207 [ + + + - ]: 2013 : for (auto end = contexts_.rend(); it != end; ++it) {
208 : : try {
209 [ + - + - : 2005 : src = (*it)->sources.at(e.table_name.text.assert_not_none()).first;
+ + + - ]
210 : 1966 : break;
211 [ - + ]: 39 : } catch (std::out_of_range) {
212 : : /* The source is not found in this context so iterate over the entire stack. */
213 [ + - ]: 39 : }
214 : 39 : }
215 : :
216 [ + + + + ]: 1966 : if (it == contexts_.rend()) {
217 [ + - + - : 8 : diag.e(e.table_name.pos) << "Source table " << e.table_name.text
+ - ]
218 [ + - ]: 8 : << " not found. Maybe you forgot to specify it in the FROM clause?\n";
219 [ + - + - ]: 8 : e.type_ = Type::Get_Error();
220 : 8 : return;
221 : : }
222 : 1966 : found_ctx = it;
223 : :
224 : : /* Find the target inside the source table. */
225 : 1966 : Designator::target_type target;
226 [ + + ]: 1966 : if (auto ref = std::get_if<std::reference_wrapper<const Table>>(&src)) {
227 : 1946 : const Table &tbl = ref->get();
228 : : /* Find the attribute inside the table. */
229 : : try {
230 [ + + ]: 1946 : target = &tbl.at(attr_name); // we found an attribute of that name in the source tables
231 [ - + ]: 1946 : } catch (std::out_of_range) {
232 [ + - + - : 2 : diag.e(e.attr_name.pos) << "Table " << e.table_name.text << " has no attribute " << attr_name << ".\n";
+ - + - +
- + - ]
233 [ + - + - ]: 2 : e.type_ = Type::Get_Error();
234 : : return;
235 [ + - # # ]: 2 : }
236 [ + - ]: 1964 : } else if (auto T = std::get_if<SemaContext::named_expr_table>(&src)) {
237 : 20 : const SemaContext::named_expr_table &tbl = *T;
238 : : /* Find expression inside named expression table. */
239 [ + - ]: 32 : auto [begin, end] = tbl.equal_range(attr_name);
240 [ + + ]: 20 : if (begin == end) {
241 [ + - + - : 1 : diag.e(e.attr_name.pos) << "Source " << e.table_name.text << " has no attribute " << attr_name << ".\n";
+ - + - +
- + - ]
242 [ + - + - ]: 1 : e.type_ = Type::Get_Error();
243 : 1 : return;
244 [ + - + - : 38 : } else if (std::distance(begin, end) > 1) {
+ + ]
245 [ + - + - : 7 : diag.e(e.attr_name.pos) << "Source " << e.table_name.text << " has multiple attributes " << attr_name
+ - + - +
- ]
246 [ + - ]: 7 : << ".\n";
247 [ + - + - ]: 7 : e.type_ = Type::Get_Error();
248 : 7 : return;
249 : : } else {
250 : 12 : target = &begin->second.first.get();
251 : : }
252 : 12 : } else {
253 [ # # ]: 0 : M_unreachable("invalid variant");
254 : : }
255 : 1956 : e.target_ = target;
256 [ + - + - ]: 1956 : e.set_binding_depth(std::distance(contexts_.rbegin(), found_ctx));
257 [ + - - + ]: 1956 : e.unique_id_ = make_unique_id_from_binding_path(contexts_.rbegin(), found_ctx);
258 [ + + ]: 1974 : } else {
259 : : /* No table name was specified. The designator references either a result or a named expression. Search the
260 : : * named expressions first, because they overrule attribute names. */
261 [ + - - + ]: 308 : if (auto [begin, end] = current_ctx->results.equal_range(attr_name);
262 [ + + + - : 308 : current_ctx->stage > SemaContext::S_Select and std::distance(begin, end) >= 1)
+ - ]
263 : : {
264 : : /* Found a named expression. */
265 [ # # # # : 0 : if (std::distance(begin, end) > 1) {
# # ]
266 [ # # # # : 0 : diag.e(e.attr_name.pos) << "Attribute specifier " << attr_name << " is ambiguous.\n";
# # # # ]
267 [ # # # # ]: 0 : e.type_ = Type::Get_Error();
268 : 0 : return;
269 : : } else {
270 [ # # # # : 0 : M_insist(std::distance(begin, end) == 1);
# # ]
271 : 0 : SemaContext::result_t &result = begin->second;
272 [ # # ]: 0 : e.target_ = &result.expr();
273 [ # # # # : 0 : if (auto d = cast<Designator>(&result.expr()); d and d->attr_name.text == attr_name)
# # # # #
# # # # #
# # ]
274 [ # # # # ]: 0 : e.table_name.text = d->table_name.text;
275 [ # # ]: 0 : e.set_binding_depth(0); // bound by the current (innermost) context ⇒ bound variable
276 : 0 : is_result = true;
277 : 0 : found_ctx = contexts_.rbegin(); // iterator to the current context
278 : : }
279 : 0 : } else {
280 : : /* Since no table was explicitly specified, we must search *all* sources for the attribute. */
281 : 308 : Designator::target_type target;
282 : 308 : ThreadSafePooledOptionalString alias;
283 : :
284 : : /* Search all contexts, starting with the innermost and advancing outwards. */
285 [ + - + + : 318 : for (auto it = contexts_.rbegin(), end = contexts_.rend(); it != end; ++it) {
+ - ]
286 [ + - + + ]: 621 : for (auto &src : (*it)->sources) {
287 [ + + ]: 315 : if (auto ref = std::get_if<std::reference_wrapper<const Table>>(&src.second.first)) {
288 : 306 : const Table &tbl = ref->get();
289 : : try {
290 [ + + ]: 306 : const Attribute &A = tbl.at(attr_name);
291 [ + + ]: 296 : if (not std::holds_alternative<std::monostate>(target)) {
292 : : /* ambiguous attribute name */
293 [ + - + - : 3 : diag.e(e.attr_name.pos) << "Attribute specifier " << attr_name << " is ambiguous.\n";
+ - + - ]
294 : : // TODO print names of conflicting tables
295 [ + - + - ]: 3 : e.type_ = Type::Get_Error();
296 : 3 : return;
297 : : } else {
298 : 293 : target = &A; // we found an attribute of that name in the source tables
299 [ + - + - ]: 293 : alias = src.first;
300 : 293 : found_ctx = it;
301 : : }
302 [ - + ]: 303 : } catch (std::out_of_range) {
303 : : /* This source table has no attribute of that name. OK, continue. */
304 [ + - ]: 10 : }
305 [ - + ]: 312 : } else if (auto T = std::get_if<SemaContext::named_expr_table>(&src.second.first)) {
306 : 9 : const SemaContext::named_expr_table &tbl = *T;
307 [ + - ]: 32 : auto [begin, end] = tbl.equal_range(attr_name);
308 [ - + ]: 9 : if (begin == end) {
309 : : /* This source table has no attribute of that name. OK, continue. */
310 [ + - + - : 18 : } else if (std::distance(begin, end) > 1) {
+ + ]
311 [ + - + - : 1 : diag.e(e.attr_name.pos) << "Attribute specifier " << attr_name << " is ambiguous.\n";
+ - + - ]
312 [ + - + - ]: 1 : e.type_ = Type::Get_Error();
313 : 1 : return;
314 : : } else {
315 [ + - + - : 16 : M_insist(std::distance(begin, end) == 1);
+ - ]
316 [ + + ]: 8 : if (not std::holds_alternative<std::monostate>(target)) {
317 : : /* ambiguous attribute name */
318 [ + - + - : 1 : diag.e(e.attr_name.pos) << "Attribute specifier " << attr_name << " is ambiguous.\n";
+ - + - ]
319 : : // TODO print names of conflicting tables
320 [ + - + - ]: 1 : e.type_ = Type::Get_Error();
321 : 1 : return;
322 : : } else {
323 : 7 : target = &begin->second.first.get(); // we found an attribute of that name in the source tables
324 [ + - + - ]: 7 : alias = src.first;
325 : 7 : found_ctx = it;
326 : : }
327 : : }
328 : 7 : } else {
329 [ # # ]: 0 : M_unreachable("invalid variant");
330 : : }
331 : : }
332 : : /* If we found target of the designator, abort searching contexts further outside. */
333 [ + + ]: 306 : if (not std::holds_alternative<std::monostate>(target))
334 : 296 : break;
335 : 10 : }
336 : :
337 : : /* If this designator could not be resolved, emit an error and abort further semantic analysis. */
338 [ + + ]: 303 : if (std::holds_alternative<std::monostate>(target)) {
339 [ + - + - : 7 : diag.e(e.attr_name.pos) << "Attribute " << attr_name << " not found.\n";
+ - + - ]
340 [ + - + - ]: 7 : e.type_ = Type::Get_Error();
341 : 7 : return;
342 : : }
343 : :
344 : 296 : e.target_ = target;
345 [ + - + - ]: 296 : e.table_name.text = alias; // set the deduced table name of this designator
346 [ + - + - ]: 296 : e.set_binding_depth(std::distance(contexts_.rbegin(), found_ctx));
347 [ + - + - ]: 296 : e.unique_id_ = make_unique_id_from_binding_path(contexts_.rbegin(), found_ctx);
348 [ + + ]: 308 : }
349 : : }
350 : :
351 : : /* Compute the type of this designator based on the referenced source. */
352 [ + - ]: 2252 : M_insist(e.target_.index() != 0);
353 : : struct get_type {
354 : 0 : const Type * operator()(std::monostate&) const { M_unreachable("target not set"); }
355 : 2234 : const Type * operator()(const Attribute *attr) const { return attr->type; }
356 : 18 : const Type * operator()(const Expr *expr) const { return expr->type_; }
357 : : };
358 [ + - + - ]: 2252 : const PrimitiveType *pt = cast<const PrimitiveType>(std::visit(get_type(), e.target_));
359 : 2252 : e.type_ = pt;
360 : :
361 [ + - ]: 2252 : if (not is_result)
362 [ + - ]: 2252 : e.type_ = pt->as_vectorial();
363 : :
364 : : /* Check if any context between current context and found context is in stage `S_FROM`. */
365 [ + - + + : 2280 : for (auto it = contexts_.rbegin(); it != found_ctx; ++it) {
+ - ]
366 [ + - - + ]: 28 : if ((*it)->stage == SemaContext::S_From) {
367 : : /* The designator is correlated and occurs in a nested query in the FROM. Emit an error. */
368 [ # # # # ]: 0 : diag.e(e.attr_name.pos) << "Correlated attributes are not allowed in the FROM clause.\n";
369 [ # # # # ]: 0 : e.type_ = Type::Get_Error();
370 : 0 : return;
371 : : }
372 : 28 : }
373 : :
374 [ + - - + : 2252 : switch ((*found_ctx)->stage) {
+ ]
375 : : default:
376 [ # # ]: 0 : M_unreachable("designator not allowed in this stage");
377 : :
378 : : case SemaContext::S_From:
379 : : /* The designator is correlated and occurs in a nested query in the FROM. Emit an error. */
380 [ + - + - ]: 1 : diag.e(e.attr_name.pos) << "Correlated attributes are not allowed in the FROM clause.\n";
381 [ + - + - ]: 1 : e.type_ = Type::Get_Error();
382 : 1 : return;
383 : :
384 : : case SemaContext::S_Where:
385 : : case SemaContext::S_GroupBy:
386 : : case SemaContext::S_Having:
387 : : case SemaContext::S_Select:
388 : : case SemaContext::S_OrderBy:
389 : : /* The type of the attribute remains unchanged. Nothing to be done. */
390 : 2251 : break;
391 : : }
392 [ - + ]: 2443 : }
393 : :
394 : 3671 : void Sema::operator()(Constant &e)
395 : : {
396 : 3671 : int base = 8; // for integers
397 [ + + + + : 3671 : switch (e.tok.type) {
+ + + + +
- ]
398 : : default:
399 : 0 : M_unreachable("a constant must be one of the types below");
400 : :
401 : : case TK_Null:
402 [ + - ]: 40 : e.type_ = Type::Get_None();
403 : 40 : break;
404 : :
405 : : case TK_STRING_LITERAL:
406 [ + - + - : 95 : e.type_ = Type::Get_Char(Type::TY_Scalar, interpret(*e.tok.text).length());
+ - + - ]
407 : 95 : break;
408 : :
409 : : case TK_DATE: {
410 : : int year, month, day;
411 : 20 : sscanf(*e.tok.text, "d'%d-%d-%d'", &year, &month, &day);
412 [ + + ]: 20 : if (year == 0) {
413 : 1 : diag.e(e.tok.pos) << e << " has invalid year (after year -1 (1 BC) follows year 1 (1 AD)).\n";
414 [ + - ]: 1 : e.type_ = Type::Get_Error();
415 : 1 : return;
416 : : }
417 [ + + + + ]: 19 : if (month < 1 or month > 12) {
418 : 4 : diag.e(e.tok.pos) << e << " has invalid month.\n";
419 [ + - ]: 4 : e.type_ = Type::Get_Error();
420 : 2 : return;
421 : : }
422 [ + + + + ]: 34 : if (day < 1 or (month == 2 and day > 29)
423 [ + + + - : 16 : or ((month == 4 or month == 6 or month == 9 or month == 11) and day > 30)
+ - ]
424 [ + + + + : 16 : or ((month == 1 or month == 3 or month == 5 or month == 7 or month == 8 or month == 10 or month == 12)
+ + + - +
- + - +
- ]
425 : 13 : and day > 31)) {
426 : 14 : diag.e(e.tok.pos) << e << " has invalid day.\n";
427 [ + - ]: 14 : e.type_ = Type::Get_Error();
428 : 4 : return;
429 : : }
430 [ + - ]: 13 : e.type_ = Type::Get_Date(Type::TY_Scalar);
431 : 13 : break;
432 : : }
433 : :
434 : : case TK_DATE_TIME: {
435 : : int year, month, day, hour, minute, second;
436 : 21 : sscanf(*e.tok.text, "d'%d-%d-%d %d:%d:%d'", &year, &month, &day, &hour, &minute, &second);
437 [ + + ]: 21 : if (year == 0) {
438 : 1 : diag.e(e.tok.pos) << e << " has invalid year (after year -1 (1 BC) follows year 1 (1 AD)).\n";
439 [ + - ]: 1 : e.type_ = Type::Get_Error();
440 : 1 : return;
441 : : }
442 [ + + + + ]: 20 : if (month < 1 or month > 12) {
443 : 2 : diag.e(e.tok.pos) << e << " has invalid month.\n";
444 [ + - ]: 2 : e.type_ = Type::Get_Error();
445 : 2 : return;
446 : : }
447 [ + + + + ]: 32 : if (day < 1 or (month == 2 and day > 29)
448 [ + + + - : 17 : or ((month == 4 or month == 6 or month == 9 or month == 11) and day > 30)
+ - ]
449 [ + + + + : 16 : or ((month == 1 or month == 3 or month == 5 or month == 7 or month == 8 or month == 10 or month == 12)
+ + + - +
- + - +
- ]
450 : 14 : and day > 31)) {
451 : 4 : diag.e(e.tok.pos) << e << " has invalid day.\n";
452 [ + - ]: 4 : e.type_ = Type::Get_Error();
453 : 4 : return;
454 : : }
455 : 14 : M_insist(hour >= 0);
456 [ + + ]: 14 : if (hour > 23) {
457 : 1 : diag.e(e.tok.pos) << e << " has invalid hour.\n";
458 [ + - ]: 1 : e.type_ = Type::Get_Error();
459 : 1 : return;
460 : : }
461 : 13 : M_insist(minute >= 0);
462 [ + + ]: 13 : if (minute > 59) {
463 : 1 : diag.e(e.tok.pos) << e << " has invalid minute.\n";
464 [ + - ]: 1 : e.type_ = Type::Get_Error();
465 : 1 : return;
466 : : }
467 : 12 : M_insist(second >= 0);
468 [ + + ]: 12 : if (second > 59) {
469 : 1 : diag.e(e.tok.pos) << e << " has invalid second.\n";
470 [ - + ]: 1 : e.type_ = Type::Get_Error();
471 : 1 : return;
472 : : }
473 [ - + ]: 11 : e.type_ = Type::Get_Datetime(Type::TY_Scalar);
474 : 11 : break;
475 : : }
476 : :
477 : : case TK_True:
478 : : case TK_False:
479 [ + - ]: 222 : e.type_ = Type::Get_Boolean(Type::TY_Scalar);
480 : 222 : break;
481 : :
482 : : case TK_HEX_INT:
483 : 20 : base += 6;
484 : : case TK_DEC_INT:
485 : 3122 : base += 2;
486 : : case TK_OCT_INT: {
487 : 3196 : int64_t value = strtol(*e.tok.text, nullptr, base);
488 [ + + ]: 3196 : if (value == int32_t(value))
489 [ + - ]: 3177 : e.type_ = Type::Get_Integer(Type::TY_Scalar, 4);
490 : : else
491 [ + - ]: 19 : e.type_ = Type::Get_Integer(Type::TY_Scalar, 8);
492 : 3196 : break;
493 : : }
494 : :
495 : : case TK_DEC_FLOAT:
496 : : case TK_HEX_FLOAT:
497 [ + - ]: 77 : e.type_ = Type::Get_Double(Type::TY_Scalar); // TODO: 32-bit floating-point constants
498 : 77 : break;
499 : : }
500 : 3671 : }
501 : :
502 : 78 : void Sema::operator()(FnApplicationExpr &e)
503 : : {
504 : 78 : SemaContext &Ctx = get_context();
505 : 78 : Catalog &C = Catalog::Get();
506 : :
507 : : /* Analyze function name. */
508 : 78 : auto d = cast<Designator>(e.fn.get());
509 [ + - - + ]: 78 : if (not d or not d->is_identifier()) {
510 : 0 : diag.e(d->attr_name.pos) << *d << " is not a valid function.\n";
511 [ # # ]: 0 : d->type_ = e.type_ = Type::Get_Error();
512 : 0 : return;
513 : : }
514 : 78 : M_insist(bool(d));
515 : 78 : M_insist(not d->type_, "This identifier has already been analyzed.");
516 : :
517 : : /* Analyze arguments. */
518 [ + + ]: 156 : for (auto &arg : e.args)
519 : 78 : (*this)(*arg);
520 : :
521 : : /* Lookup the function. */
522 [ + - ]: 78 : if (C.has_database_in_use()) {
523 : 78 : const auto &DB = C.get_database_in_use();
524 : : try {
525 [ + - + + ]: 78 : e.func_ = DB.get_function(d->attr_name.text.assert_not_none());
526 [ - + ]: 78 : } catch (std::out_of_range) {
527 [ + - + - : 1 : diag.e(d->attr_name.pos) << "Function " << d->attr_name.text << " is not defined in database " << DB.name
+ - + - +
- ]
528 [ + - ]: 1 : << ".\n";
529 [ + - + - ]: 1 : e.type_ = Type::Get_Error();
530 : : return;
531 [ # # ]: 1 : }
532 : 77 : } else {
533 : : try {
534 [ # # # # ]: 0 : e.func_ = C.get_function(d->attr_name.text.assert_not_none());
535 [ # # ]: 0 : } catch (std::out_of_range) {
536 [ # # # # : 0 : diag.e(d->attr_name.pos) << "Function " << d->attr_name.text << " is not defined.\n";
# # # # ]
537 [ # # # # ]: 0 : e.type_ = Type::Get_Error();
538 : : return;
539 [ # # ]: 0 : }
540 : : }
541 : 77 : M_insist(e.func_);
542 : :
543 : : /* Infer the type of the function. Functions are defined in an abstract way, where the type of the parameters is
544 : : * not specified. We must infer the parameter types and the return type of the function. */
545 [ - + - + : 77 : switch (e.func_->fnid) {
+ ]
546 : : default:
547 : 0 : M_unreachable("Function not implemented");
548 : :
549 : : case Function::FN_UDF:
550 : 0 : diag.e(d->attr_name.pos) << "User-defined functions are not yet supported.\n";
551 [ # # ]: 0 : d->type_ = e.type_ = Type::Get_Error();
552 : 0 : return;
553 : :
554 : : case Function::FN_MIN:
555 : : case Function::FN_MAX:
556 : : case Function::FN_SUM:
557 : : case Function::FN_AVG: {
558 [ + + ]: 67 : if (e.args.size() == 0) {
559 : 1 : diag.e(d->attr_name.pos) << "Missing argument for aggregate " << *d << ".\n";
560 [ + - ]: 1 : d->type_ = e.type_ = Type::Get_Error();
561 : 1 : return;
562 : : }
563 [ + + ]: 66 : if (e.args.size() > 1) {
564 : 1 : diag.e(d->attr_name.pos) << "Too many arguments for aggregate " << *d << ".\n";
565 [ + - ]: 1 : d->type_ = e.type_ = Type::Get_Error();
566 : 1 : return;
567 : : }
568 : 65 : M_insist(e.args.size() == 1);
569 : 65 : auto &arg = *e.args[0];
570 [ + + ]: 65 : if (arg.type()->is_error()) {
571 : : /* skip argument of error type */
572 [ + - ]: 1 : d->type_ = e.type_ = Type::Get_Error();
573 : 1 : return;
574 : : }
575 [ + + ]: 64 : if (not arg.type()->is_numeric()) {
576 : : /* invalid argument type */
577 : 1 : diag.e(d->attr_name.pos) << "Argument of aggregate function must be of numeric type.\n";
578 [ + - ]: 1 : d->type_ = e.type_ = Type::Get_Error();
579 : 1 : return;
580 : : }
581 : 63 : M_insist(arg.type()->is_numeric());
582 : 63 : const Numeric *arg_type = cast<const Numeric>(arg.type());
583 [ + + ]: 63 : if (not arg_type->is_vectorial()) {
584 : 3 : diag.w(d->attr_name.pos) << "Argument of aggregate is not of vectorial type. "
585 : : "(Aggregates over scalars are discouraged.)\n";
586 : 3 : }
587 : :
588 [ - + + + ]: 63 : switch (e.func_->fnid) {
589 : : default:
590 : 0 : M_unreachable("Invalid function");
591 : :
592 : : case Function::FN_MIN:
593 : : case Function::FN_MAX: {
594 : : /* MIN/MAX maintain type */
595 : 50 : e.type_ = arg_type->as_scalar();
596 [ + - + - : 50 : d->type_ = Type::Get_Function(e.type_, { arg.type() });
+ - ]
597 : 50 : break;
598 : : }
599 : :
600 : : case Function::FN_AVG: {
601 : : /* AVG always uses double precision floating-point */
602 [ + - ]: 6 : e.type_ = Type::Get_Double(Type::TY_Scalar);
603 [ + - + - : 6 : d->type_ = Type::Get_Function(e.type_, { arg.type() });
+ - ]
604 : 6 : break;
605 : : }
606 : :
607 : : case Function::FN_SUM: {
608 : : /* SUM can overflow. Always assume type of highest precision. */
609 [ - + + + ]: 7 : switch (arg_type->kind) {
610 : : case Numeric::N_Int:
611 [ + - ]: 5 : e.type_ = Type::Get_Integer(Type::TY_Scalar, 8);
612 : 5 : break;
613 : :
614 : : case Numeric::N_Float:
615 [ + - ]: 1 : e.type_ = Type::Get_Double(Type::TY_Scalar);
616 : 1 : break;
617 : :
618 : : case Numeric::N_Decimal:
619 [ + - ]: 1 : e.type_ = Type::Get_Decimal(Type::TY_Scalar, Numeric::MAX_DECIMAL_PRECISION,
620 : 1 : arg_type->scale);
621 : 1 : break;
622 : : }
623 [ + - + - : 7 : d->type_ = Type::Get_Function(e.type(), { e.type() });
+ - ]
624 : 7 : break;
625 : : }
626 : : }
627 : 63 : break;
628 : : }
629 : :
630 : : case Function::FN_COUNT: {
631 [ + + ]: 2 : if (e.args.size() > 1) {
632 : 1 : diag.e(d->attr_name.pos) << "Too many arguments for aggregate " << *d << ".\n";
633 [ + - ]: 1 : e.type_ = Type::Get_Error();
634 : 1 : return;
635 : : }
636 : :
637 : : /* TODO If argument is given, check whether it can be NULL. If not, COUNT(arg) == COUNT(*) */
638 : :
639 [ + - ]: 1 : e.type_ = Type::Get_Integer(Type::TY_Scalar, 8);
640 [ + - + - ]: 1 : d->type_ = Type::Get_Function(e.type_, {});
641 : 1 : break;
642 : : }
643 : :
644 : : case Function::FN_ISNULL: {
645 [ + + ]: 8 : if (e.args.size() == 0) {
646 : 1 : diag.e(d->attr_name.pos) << "Missing argument for aggregate " << *d << ".\n";
647 [ + - ]: 1 : e.type_ = Type::Get_Error();
648 : 1 : return;
649 : : }
650 [ + + ]: 7 : if (e.args.size() > 1) {
651 : 1 : diag.e(d->attr_name.pos) << "Too many arguments for aggregate " << *d << ".\n";
652 [ + - ]: 1 : e.type_ = Type::Get_Error();
653 : 1 : return;
654 : : }
655 : 6 : M_insist(e.args.size() == 1);
656 : 6 : auto &arg = *e.args[0];
657 : :
658 [ + + ]: 6 : if (arg.type()->is_error()) {
659 [ + - ]: 1 : e.type_ = Type::Get_Error();
660 : 1 : return;
661 : : }
662 : 5 : const PrimitiveType *arg_type = cast<const PrimitiveType>(arg.type());
663 [ + + ]: 5 : if (not arg_type) {
664 : 1 : diag.e(d->attr_name.pos) << "Function ISNULL can only be applied to expressions of primitive type.\n";
665 [ + - ]: 1 : e.type_ = Type::Get_Error();
666 : 1 : return;
667 : : }
668 : :
669 [ + - + - : 4 : d->type_ = Type::Get_Function(Type::Get_Boolean(arg_type->category), { arg.type() });
+ - + - +
- ]
670 [ + - ]: 4 : e.type_= Type::Get_Boolean(arg_type->category);
671 : 4 : break;
672 : : }
673 : : }
674 : :
675 : 68 : M_insist(d->type_);
676 [ - + ]: 68 : M_insist(d->type()->is_error() or cast<const FnType>(d->type()));
677 : 68 : M_insist(e.type_);
678 : 68 : M_insist(not e.type()->is_error());
679 : 68 : M_insist(e.type()->is_primitive());
680 : :
681 [ - + + + : 68 : switch (Ctx.stage) {
- + + - ]
682 : : case SemaContext::S_From:
683 : 0 : M_unreachable("Function application in FROM clause is impossible");
684 : :
685 : : case SemaContext::S_Where:
686 [ + + ]: 3 : if (e.func_->is_aggregate()) {
687 : 1 : diag.e(d->attr_name.pos) << "Aggregate functions are not allowed in WHERE clause.\n";
688 : 1 : return;
689 : : }
690 : 2 : break;
691 : :
692 : : case SemaContext::S_GroupBy:
693 [ + + ]: 3 : if (e.func_->is_aggregate()) {
694 : 2 : diag.e(d->attr_name.pos) << "Aggregate functions are not allowed in GROUP BY clause.\n";
695 : 2 : return;
696 : : }
697 : 1 : break;
698 : :
699 : : case SemaContext::S_Having:
700 : : /* nothing to be done */
701 : 11 : break;
702 : :
703 : : case SemaContext::S_OrderBy:
704 : : /* TODO */
705 : 3 : break;
706 : :
707 : : case SemaContext::S_Select:
708 : : /* TODO */
709 : 48 : break;
710 : :
711 : : case SemaContext::S_Limit:
712 : : /* TODO */
713 : 0 : break;
714 : : }
715 : 79 : }
716 : :
717 : 88 : void Sema::operator()(UnaryExpr &e)
718 : : {
719 : : /* Analyze sub-expression. */
720 : 88 : (*this)(*e.expr);
721 : :
722 : : /* If the sub-expression is erroneous, so is this expression. */
723 [ + + ]: 88 : if (e.expr->type()->is_error()) {
724 [ + - ]: 1 : e.type_ = Type::Get_Error();
725 : 1 : return;
726 : : }
727 : :
728 [ + + - ]: 87 : switch (e.op().type) {
729 : : default:
730 : 0 : M_unreachable("invalid unary expression");
731 : :
732 : : case TK_Not:
733 [ + + ]: 17 : if (not e.expr->type()->is_boolean()) {
734 [ + - + - : 1 : diag.e(e.op().pos) << "Invalid expression " << e << " must be boolean.\n";
+ - + - ]
735 [ - + ]: 1 : e.type_ = Type::Get_Error();
736 : 1 : return;
737 : : }
738 : 16 : break;
739 : :
740 : : case TK_PLUS:
741 : : case TK_MINUS:
742 : : case TK_TILDE:
743 [ + + ]: 70 : if (not e.expr->type()->is_numeric()) {
744 [ + - + - : 6 : diag.e(e.op().pos) << "Invalid expression " << e << " must be numeric.\n";
+ - + - ]
745 [ - + ]: 6 : e.type_ = Type::Get_Error();
746 : 6 : return;
747 : : }
748 : 64 : break;
749 : : }
750 : :
751 : 80 : e.type_ = e.expr->type();
752 : 88 : }
753 : :
754 : 812 : void Sema::operator()(BinaryExpr &e)
755 : : {
756 : : /* Analyze sub-expressions. */
757 : 812 : (*this)(*e.lhs);
758 : 812 : (*this)(*e.rhs);
759 : :
760 : : /* If at least one of the sub-expressions is erroneous, so is this expression. */
761 [ + + + + ]: 812 : if (e.lhs->type()->is_error() or e.rhs->type()->is_error()) {
762 [ + - ]: 21 : e.type_ = Type::Get_Error();
763 : 21 : return;
764 : : }
765 : :
766 : : /* Validate that lhs and rhs are compatible with binary operator. */
767 [ + + + + : 791 : switch (e.op().type) {
+ + - ]
768 : : default:
769 : 0 : M_unreachable("Invalid binary operator.");
770 : :
771 : : /* Arithmetic operations are only valid for numeric types. Compute the type of the binary expression that is
772 : : * precise enough. */
773 : : case TK_PLUS:
774 : : case TK_MINUS:
775 : : case TK_ASTERISK:
776 : : case TK_SLASH:
777 : : case TK_PERCENT: {
778 : : /* Verify that both operands are of numeric type. */
779 : 85 : const Numeric *ty_lhs = cast<const Numeric>(e.lhs->type());
780 : 85 : const Numeric *ty_rhs = cast<const Numeric>(e.rhs->type());
781 [ + + + + ]: 85 : if (not ty_lhs or not ty_rhs) {
782 [ + - + - : 21 : diag.e(e.op().pos) << "Invalid expression " << e << ", operands must be of numeric type.\n";
+ - + - ]
783 [ + - ]: 21 : e.type_ = Type::Get_Error();
784 : 21 : return;
785 : : }
786 : 64 : M_insist(ty_lhs);
787 : 64 : M_insist(ty_rhs);
788 : :
789 : : /* Compute type of the binary expression. */
790 : 64 : e.type_ = e.common_operand_type = arithmetic_join(ty_lhs, ty_rhs);
791 : 64 : break;
792 : : }
793 : :
794 : : case TK_DOTDOT: {
795 : : /* Concatenation of two strings. */
796 : 14 : auto ty_lhs = cast<const CharacterSequence>(e.lhs->type());
797 : 14 : auto ty_rhs = cast<const CharacterSequence>(e.rhs->type());
798 [ + + + + ]: 14 : if (not ty_lhs or not ty_rhs) {
799 [ + - + - : 11 : diag.e(e.op().pos) << "Invalid expression " << e << ", concatenation requires string operands.\n";
+ - + - ]
800 [ + - ]: 11 : e.type_ = Type::Get_Error();
801 : 11 : return;
802 : : }
803 : 3 : M_insist(ty_lhs);
804 : 3 : M_insist(ty_rhs);
805 : :
806 : : /* Scalar and scalar yield a scalar. Otherwise, expression yields a vectorial. */
807 : 3 : Type::category_t c = std::max(ty_lhs->category, ty_rhs->category);
808 : :
809 [ + - ]: 3 : e.type_ = Type::Get_Char(c, ty_lhs->length + ty_rhs->length);
810 : 3 : break;
811 : : }
812 : :
813 : : case TK_LESS:
814 : : case TK_LESS_EQUAL:
815 : : case TK_GREATER:
816 : : case TK_GREATER_EQUAL: {
817 [ + + ]: 74 : if (auto ty_lhs = cast<const Numeric>(e.lhs->type())) {
818 : : /* Verify that both operands are of numeric type. */
819 : 59 : auto ty_rhs = cast<const Numeric>(e.rhs->type());
820 [ + - + + ]: 59 : if (not ty_lhs or not ty_rhs) {
821 [ + - + - : 6 : diag.e(e.op().pos) << "Invalid expression " << e << ", both operands must be of numeric type.\n";
+ - + - ]
822 [ + - ]: 6 : e.type_ = Type::Get_Error();
823 : 6 : return;
824 : : }
825 : 53 : M_insist(ty_lhs);
826 : 53 : M_insist(ty_rhs);
827 : :
828 : : /* Scalar and scalar yield a scalar. Otherwise, expression yields a vectorial. */
829 : 53 : Type::category_t c = std::max(ty_lhs->category, ty_rhs->category);
830 : :
831 : : /* Comparisons always have boolean type. */
832 [ + - ]: 53 : e.type_ = Type::Get_Boolean(c);
833 : 53 : e.common_operand_type = arithmetic_join(ty_lhs, ty_rhs);
834 [ + + ]: 68 : } else if (auto ty_lhs = cast<const CharacterSequence>(e.lhs->type())) {
835 : : /* Verify that both operands are character sequences. */
836 : 6 : auto ty_rhs = cast<const CharacterSequence>(e.rhs->type());
837 [ + - + + ]: 6 : if (not ty_lhs or not ty_rhs) {
838 [ + - + - : 2 : diag.e(e.op().pos) << "Invalid expression " << e << ", both operands must be strings.\n";
+ - + - ]
839 [ + - ]: 2 : e.type_ = Type::Get_Error();
840 : 2 : return;
841 : : }
842 : 4 : M_insist(ty_lhs);
843 : 4 : M_insist(ty_rhs);
844 : :
845 : : /* Scalar and scalar yield a scalar. Otherwise, expression yields a vectorial. */
846 : 4 : Type::category_t c = std::max(ty_lhs->category, ty_rhs->category);
847 : :
848 : : /* Comparisons always have boolean type. */
849 [ + - ]: 4 : e.type_ = Type::Get_Boolean(c);
850 [ + + ]: 13 : } else if (auto ty_lhs = cast<const Date>(e.lhs->type())) {
851 : : /* Verify that both operands are dates. */
852 : 2 : auto ty_rhs = cast<const Date>(e.rhs->type());
853 [ + - + + ]: 2 : if (not ty_lhs or not ty_rhs) {
854 [ + - + - : 1 : diag.e(e.op().pos) << "Invalid expression " << e << ", both operands must be dates.\n";
+ - + - ]
855 [ + - ]: 1 : e.type_ = Type::Get_Error();
856 : 1 : return;
857 : : }
858 : 1 : M_insist(ty_lhs);
859 : 1 : M_insist(ty_rhs);
860 : :
861 : : /* Scalar and scalar yield a scalar. Otherwise, expression yields a vectorial. */
862 : 1 : Type::category_t c = std::max(ty_lhs->category, ty_rhs->category);
863 : :
864 : : /* Comparisons always have boolean type. */
865 [ + - ]: 1 : e.type_ = Type::Get_Boolean(c);
866 [ - + ]: 8 : } else if (auto ty_lhs = cast<const DateTime>(e.lhs->type())) {
867 : : /* Verify that both operands are datetimes. */
868 : 0 : auto ty_rhs = cast<const DateTime>(e.rhs->type());
869 [ # # # # ]: 0 : if (not ty_lhs or not ty_rhs) {
870 [ # # # # : 0 : diag.e(e.op().pos) << "Invalid expression " << e << ", both operands must be datetimes.\n";
# # # # ]
871 [ # # ]: 0 : e.type_ = Type::Get_Error();
872 : 0 : return;
873 : : }
874 : 0 : M_insist(ty_lhs);
875 : 0 : M_insist(ty_rhs);
876 : :
877 : : /* Scalar and scalar yield a scalar. Otherwise, expression yields a vectorial. */
878 : 0 : Type::category_t c = std::max(ty_lhs->category, ty_rhs->category);
879 : :
880 : : /* Comparisons always have boolean type. */
881 [ # # ]: 0 : e.type_ = Type::Get_Boolean(c);
882 : 0 : } else {
883 [ + - + - : 7 : diag.e(e.op().pos) << "Invalid expression " << e << ", operator not supported for given operands.\n";
+ - + - ]
884 [ + - ]: 7 : e.type_ = Type::Get_Error();
885 : 7 : return;
886 : : }
887 : 58 : break;
888 : : }
889 : :
890 : : case TK_EQUAL:
891 : : case TK_BANG_EQUAL: {
892 [ + + ]: 386 : if (not is_comparable(e.lhs->type(), e.rhs->type())) {
893 [ + - + - : 11 : diag.e(e.op().pos) << "Invalid expression " << e << ", operands are incomparable.\n";
+ - + - ]
894 [ + - ]: 11 : e.type_ = Type::Get_Error();
895 : 11 : return;
896 : : }
897 : 375 : const PrimitiveType *ty_lhs = as<const PrimitiveType>(e.lhs->type());
898 : 375 : const PrimitiveType *ty_rhs = as<const PrimitiveType>(e.rhs->type());
899 : :
900 : : /* Scalar and scalar yield a scalar. Otherwise, expression yields a vectorial. */
901 : 375 : Type::category_t c = std::max(ty_lhs->category, ty_rhs->category);
902 : :
903 : : /* Comparisons always have boolean type. */
904 [ + - ]: 375 : e.type_ = Type::Get_Boolean(c);
905 [ + + ]: 375 : if (auto ty_lhs = cast<const Numeric>(e.lhs->type()))
906 : 366 : e.common_operand_type = arithmetic_join(ty_lhs, as<const Numeric>(e.rhs->type()));
907 : 375 : break;
908 : : }
909 : :
910 : : case TK_Like: {
911 : 14 : auto ty_lhs = cast<const CharacterSequence>(e.lhs->type());
912 : 14 : auto ty_rhs = cast<const CharacterSequence>(e.rhs->type());
913 [ + + + + ]: 14 : if (not ty_lhs or not ty_rhs) {
914 [ + - + - : 9 : diag.e(e.op().pos) << "Invalid expression " << e << ", operands must be character sequences.\n";
+ - + - ]
915 [ + - ]: 9 : e.type_ = Type::Get_Error();
916 : 9 : return;
917 : : }
918 : 5 : M_insist(ty_lhs);
919 : 5 : M_insist(ty_rhs);
920 : :
921 : : /* Scalar and scalar yield a scalar. Otherwise, expression yields a vectorial. */
922 : 5 : Type::category_t c = std::max(ty_lhs->category, ty_rhs->category);
923 : :
924 : : /* Comparisons always have boolean type. */
925 [ + - ]: 5 : e.type_ = Type::Get_Boolean(c);
926 : 5 : break;
927 : : }
928 : :
929 : : case TK_And:
930 : : case TK_Or: {
931 : 218 : const Boolean *ty_lhs = cast<const Boolean>(e.lhs->type());
932 : 218 : const Boolean *ty_rhs = cast<const Boolean>(e.rhs->type());
933 : :
934 : : /* Both operands must be of boolean type. */
935 [ + + + + ]: 218 : if (not ty_lhs or not ty_rhs) {
936 [ + - + - : 10 : diag.e(e.op().pos) << "Invalid expression " << e << ", operands must be of boolean type.\n";
+ - + - ]
937 [ + - ]: 10 : e.type_ = Type::Get_Error();
938 : 10 : return;
939 : : }
940 : :
941 : : /* Scalar and scalar yield a scalar. Otherwise, expression yields a vectorial. */
942 : 208 : Type::category_t c = std::max(ty_lhs->category, ty_rhs->category);
943 : :
944 : : /* Logical operators always have boolean type. */
945 [ + - ]: 208 : e.type_ = Type::Get_Boolean(c);
946 : 208 : break;
947 : : }
948 : : }
949 : 812 : }
950 : :
951 : 97 : void Sema::operator()(QueryExpr &e)
952 : : {
953 : 97 : M_insist(is<SelectStmt>(*e.query), "nested statements are always select statements");
954 : :
955 : 97 : SemaContext &Ctx = get_context();
956 : :
957 : : /* Evaluate the nested statement in a fresh sema context. */
958 [ + - ]: 97 : push_context(*e.query, e.alias());
959 : 97 : (*this)(*e.query);
960 : 97 : M_insist(not contexts_.empty());
961 : 97 : SemaContext inner_ctx = pop_context();
962 : :
963 : : /* TODO an EXISTS operator allows multiple results */
964 [ + + ]: 97 : if (1 != inner_ctx.results.size()) {
965 [ + + + - : 53 : diag.e(e.tok.pos) << "Invalid expression:\n" << e << ",\nnested statement must return a single column.\n";
+ - + - ]
966 [ + - + - ]: 3 : e.type_ = Type::Get_Error();
967 : 3 : return;
968 : : }
969 [ + - ]: 44 : M_insist(1 == inner_ctx.results.size());
970 [ + - ]: 44 : Expr &res = inner_ctx.results.begin()->second.expr();
971 : :
972 [ + - + - : 44 : if (not res.type()->is_primitive()) {
- + ]
973 [ # # # # : 0 : diag.e(e.tok.pos) << "Invalid expression:\n" << e << ",\nnested statement must return a primitive value.\n";
# # # # ]
974 [ # # # # ]: 0 : e.type_ = Type::Get_Error();
975 : 0 : return;
976 : : }
977 [ + - ]: 44 : auto *pt = as<const PrimitiveType>(res.type_);
978 : 44 : e.type_ = pt;
979 : :
980 [ + + ]: 44 : switch (Ctx.stage) {
981 : : default: {
982 [ + - + - ]: 2 : diag.e(e.tok.pos) << "Nested statements are not allowed in this stage.\n";
983 [ + - + - ]: 2 : e.type_ = Type::Get_Error();
984 : 2 : return;
985 : : }
986 : : case SemaContext::S_Where:
987 : : case SemaContext::S_Having:
988 : : /* TODO The result must not be a single scalar value in general. */
989 : :
990 : : case SemaContext::S_Select: {
991 : : /* The result of the nested query must be a single scalar value. */
992 : :
993 [ + - + + ]: 42 : if (not pt->is_scalar()) {
994 [ + - + - : 6 : diag.e(e.tok.pos) << "Invalid expression:\n" << e
+ - ]
995 [ + - ]: 6 : << ",\nnested statement must return a scalar value.\n";
996 [ + - + - ]: 6 : e.type_ = Type::Get_Error();
997 : 6 : return;
998 : : }
999 : :
1000 [ + - ]: 36 : auto is_fn = is<FnApplicationExpr>(res);
1001 [ + - ]: 36 : auto is_const = res.is_constant();
1002 [ + - ]: 36 : auto &q = as<const SelectStmt>(*e.query);
1003 : : /* The result is a single value iff it is a constant and there is no from clause or
1004 : : * iff it is an aggregate and there is no group_by clause. */
1005 [ + + + + : 36 : if (not(is_const and not q.from) and not(is_fn and not q.group_by)) {
+ + ]
1006 [ + + + - : 57 : diag.e(e.tok.pos) << "Invalid expression:\n" << e
+ - ]
1007 [ + - ]: 7 : << ",\nnested statement must return a single value.\n";
1008 [ + - + - ]: 7 : e.type_ = Type::Get_Error();
1009 : 7 : return;
1010 : : }
1011 : 29 : break;
1012 : : }
1013 : : }
1014 [ - + ]: 147 : }
1015 : :
1016 : : /*===== Clause =======================================================================================================*/
1017 : :
1018 : 0 : void Sema::operator()(ErrorClause&)
1019 : : {
1020 : : /* nothing to be done */
1021 : 0 : }
1022 : :
1023 : 574 : void Sema::operator()(SelectClause &c)
1024 : : {
1025 : 574 : SemaContext &Ctx = get_context();
1026 : 574 : Ctx.stage = SemaContext::S_Select;
1027 : 574 : Catalog &C = Catalog::Get();
1028 : :
1029 : 574 : bool has_vectorial = false;
1030 : 574 : bool has_scalar = false;
1031 : 574 : uint64_t const_counter = 0;
1032 : 574 : M_insist(Ctx.results.empty());
1033 : 574 : unsigned result_counter = 0;
1034 : :
1035 [ + + ]: 574 : if (c.select_all) {
1036 : : /* Expand the `SELECT *` by creating dummy expressions for all accessible values of all sources. */
1037 : 265 : auto &stmt = as<const SelectStmt>(Ctx.stmt);
1038 : :
1039 [ + + ]: 265 : if (stmt.group_by) {
1040 : : /* If the statement contains a GROUP BY clause, we must include all grouping keys in the result. */
1041 : 30 : auto &group_by = as<const GroupByClause>(*stmt.group_by);
1042 [ - + ]: 30 : has_scalar = has_scalar or not group_by.group_by.empty();
1043 [ + + ]: 130 : for (auto &[expr, alias] : group_by.group_by) {
1044 : 30 : std::unique_ptr<Designator> d;
1045 [ + - + + ]: 30 : if (alias) { // alias was given
1046 [ + - + - : 7 : d = create_designator(alias.text.assert_not_none(), expr->tok, *expr);
+ - ]
1047 [ + - + + ]: 30 : } else if (auto D = cast<const ast::Designator>(expr.get())) { // no alias, but designator -> keep name
1048 [ + - + - : 18 : d = create_designator(D->attr_name.text.assert_not_none(), D->tok, *D);
+ - ]
1049 : 18 : } else { // no designator, no alias -> derive name
1050 [ + - ]: 5 : std::ostringstream oss;
1051 [ + - ]: 5 : oss << *expr;
1052 [ + - + - : 5 : d = create_designator(C.pool(oss.str().c_str()), expr->tok, *expr);
+ - + - ]
1053 : 5 : }
1054 [ + - + - : 30 : if (auto ty = cast<const PrimitiveType>(d->type()))
+ + ]
1055 [ + - ]: 29 : d->type_ = ty->as_scalar();
1056 : : else
1057 [ + - + - : 1 : M_insist(d->type()->is_error(), "grouping key must be of primitive type");
+ - ]
1058 [ + - ]: 30 : auto attr_name = d->attr_name.text.assert_not_none();
1059 [ + - ]: 30 : auto &ref = c.expanded_select_all.emplace_back(std::move(d));
1060 [ + - ]: 30 : (*this)(*ref);
1061 [ + - + - : 60 : Ctx.results.emplace(std::move(attr_name), SemaContext::result_t(*ref, result_counter++, alias.text));
+ - + - ]
1062 : 30 : }
1063 [ + + ]: 265 : } else if (stmt.having) {
1064 : : /* A statement with a HAVING clause but without a GROUP BY clause may only have literals in its SELECT
1065 : : * clause. Therefore, '*' has no meaning and we should emit a warning. */
1066 : 4 : diag.w(c.select_all.pos) << "The '*' has no meaning in this query. Did you forget the GROUP BY clause?.\n";
1067 : 4 : } else {
1068 : : /* The '*' in the SELECT clause selects all attributes of all sources. */
1069 [ + + ]: 1862 : for (auto &[src_name, src] : Ctx.sources) {
1070 [ + + ]: 459 : if (auto ref = std::get_if<std::reference_wrapper<const Table>>(&src.first)) {
1071 : : /* The source is a database table. */
1072 : 452 : auto &tbl = ref->get();
1073 [ + + ]: 1614 : for (auto &attr : tbl) {
1074 [ + - ]: 1162 : auto d = create_designator(
1075 : 1162 : /* pos= */ c.select_all.pos,
1076 : 1162 : /* table_name= */ src_name,
1077 [ + - ]: 1162 : /* attr_name= */ attr.name,
1078 : 1162 : /* target= */ &attr,
1079 : 1162 : /* type= */ attr.type
1080 : : );
1081 [ + - ]: 1162 : auto &ref = c.expanded_select_all.emplace_back(std::move(d));
1082 [ + - ]: 1162 : (*this)(*ref);
1083 [ + - + - ]: 1162 : Ctx.results.emplace(attr.name, SemaContext::result_t(*ref, result_counter++));
1084 : 1162 : }
1085 : 452 : has_vectorial = true;
1086 : 452 : } else {
1087 : : /* The source is a nested query. */
1088 : 7 : auto &named_exprs = std::get<SemaContext::named_expr_table>(src.first);
1089 [ + - ]: 7 : std::vector<std::unique_ptr<Expr>> expanded_select_all(named_exprs.size());
1090 [ + + ]: 27 : for (auto &[name, expr_w_pos] : named_exprs) {
1091 : 50 : auto &[expr, pos] = expr_w_pos;
1092 [ + - ]: 10 : auto d = create_designator(
1093 : 10 : /* pos= */ c.select_all.pos,
1094 [ + - ]: 10 : /* table_name= */ src_name,
1095 [ + - ]: 10 : /* attr_name= */ name,
1096 : 10 : /* target= */ &expr.get(),
1097 [ + - ]: 10 : /* type= */ expr.get().type()
1098 : : );
1099 : 10 : auto &ref = (expanded_select_all[pos] = std::move(d));
1100 [ + - ]: 10 : (*this)(*ref);
1101 [ + - + - : 10 : if (auto pt = cast<const PrimitiveType>(ref->type())) {
+ + ]
1102 [ + - + - ]: 6 : has_scalar = has_scalar or pt->is_scalar();
1103 [ + + + - ]: 6 : has_vectorial = has_vectorial or pt->is_vectorial();
1104 : 6 : } else {
1105 [ + - + - : 4 : M_insist(ref->type()->is_error(), "result of nested query must be of primitive type");
+ - ]
1106 : : }
1107 [ + - + - : 30 : Ctx.results.emplace(name, SemaContext::result_t(*ref, result_counter + pos));
+ - + - ]
1108 : 10 : }
1109 : 7 : result_counter += named_exprs.size();
1110 [ + + + - ]: 17 : for (auto &e : expanded_select_all) c.expanded_select_all.emplace_back(std::move(e));
1111 : 7 : }
1112 : : }
1113 : : }
1114 : 265 : }
1115 : :
1116 [ + + ]: 937 : for (auto it = c.select.begin(), end = c.select.end(); it != end; ++it) {
1117 : 363 : auto &select_expr = *it->first;
1118 : 363 : auto alias = it->second;
1119 : :
1120 [ + - ]: 363 : (*this)(select_expr); // recursively analyze select expression
1121 [ + - + + : 363 : if (select_expr.contains_free_variables() and not is<QueryExpr>(select_expr))
+ - + - ]
1122 [ + - + - : 6 : diag.e(select_expr.tok.pos) << select_expr << " contains free variables (not yet supported).\n";
+ - ]
1123 : :
1124 [ + - + - : 363 : if (select_expr.type()->is_error()) continue;
+ + ]
1125 : :
1126 : : /* Expressions *must* be scalar when we have grouping. */
1127 [ + - + - : 342 : if (auto pt = cast<const PrimitiveType>(select_expr.type()); Ctx.needs_grouping and pt and pt->is_vectorial()) {
+ + + - +
- + + ]
1128 [ + - + - : 2 : diag.e(select_expr.tok.pos) << select_expr << " is not scalar.\n";
+ - ]
1129 : 2 : continue;
1130 : : }
1131 : :
1132 : : /* Constants and scalar values of nested queries can be broadcast from scalar to vectorial. We collect the
1133 : : * scalar/vector-ness information of each expression in the SELECT clause. */
1134 [ + - + + : 340 : if (not select_expr.is_constant() and not is<QueryExpr>(select_expr)) {
+ - + + ]
1135 [ + - + - ]: 286 : auto pt = as<const PrimitiveType>(select_expr.type());
1136 [ + + + - ]: 286 : has_vectorial = has_vectorial or pt->is_vectorial();
1137 [ + + + - ]: 286 : has_scalar = has_scalar or pt->is_scalar();
1138 : 286 : }
1139 : :
1140 [ + - + + ]: 340 : if (alias) { // SELECT expression has alias?
1141 : : /* Expression with alias. */
1142 [ + - + - : 51 : Ctx.results.emplace(alias.text, SemaContext::result_t(select_expr, result_counter++, alias.text));
+ - ]
1143 : 80 : auto pred = [&](const std::pair<std::unique_ptr<Expr>, Token> &sel) {
1144 [ + - ]: 29 : return sel.second.text == alias.text;
1145 : 0 : };
1146 [ + - + + ]: 51 : if (auto num = std::count_if(c.select.begin(), it, pred)) {
1147 : : /* Found ambiguous alias which is only allowed without accessing it. This is checked via the `Ctx`
1148 : : * in which the ambiguous alias is contained. However, make alias unique for later accessing steps. */
1149 [ - + + - ]: 8 : oss.str("");
1150 [ + - + - : 8 : oss << alias.text << "$" << num;
+ - ]
1151 [ + - - + : 8 : alias.text = C.pool(oss.str().c_str());
- + - + ]
1152 : 8 : }
1153 [ + - + + ]: 340 : } else if (auto d = cast<Designator>(&select_expr)) {
1154 : : /* Expression is a designator. Simply reuse the name without table prefix. */
1155 [ + - - + ]: 76 : Ctx.results.emplace(d->attr_name.text, SemaContext::result_t(*d, result_counter++));
1156 : 76 : } else {
1157 [ + - + - ]: 213 : M_insist(not is<Designator>(select_expr));
1158 : : /* Expression without alias. Print expression as string to get a name. Use '$const' as prefix for
1159 : : * constants. */
1160 [ + - + - ]: 213 : oss.str("");
1161 [ + - + + ]: 213 : if (select_expr.is_constant())
1162 [ + - + - ]: 46 : oss << "$const" << const_counter++;
1163 : : else
1164 [ + - ]: 167 : oss << select_expr;
1165 [ + - + - : 213 : Ctx.results.emplace(C.pool(oss.str().c_str()), SemaContext::result_t(select_expr, result_counter++));
+ - + - ]
1166 : : }
1167 [ - + + ]: 363 : }
1168 : :
1169 [ + + + - ]: 574 : if (has_vectorial and has_scalar)
1170 : 0 : diag.e(c.tok.pos) << "SELECT clause with mixed scalar and vectorial values is forbidden.\n";
1171 : 574 : }
1172 : :
1173 : 546 : void Sema::operator()(FromClause &c)
1174 : : {
1175 : 546 : SemaContext &Ctx = get_context();
1176 : 546 : Ctx.stage = SemaContext::S_From;
1177 : :
1178 : 546 : Catalog &C = Catalog::Get();
1179 : 546 : const auto &DB = C.get_database_in_use();
1180 : :
1181 : 546 : M_insist(Ctx.sources.empty());
1182 : 546 : unsigned source_counter = 0;
1183 : :
1184 : : /* Check whether the source tables in the FROM clause exist in the database. Add the source tables to the current
1185 : : * context, using their alias if provided (e.g. FROM src AS alias). */
1186 [ + + ]: 1342 : for (auto &src: c.from) {
1187 [ + + ]: 2372 : if (auto name = std::get_if<Token>(&src.source)) {
1188 : : try {
1189 [ + + + + ]: 2314 : const Table &T = DB.get_table(name->text.assert_not_none());
1190 [ + - + + : 777 : Token table_name = src.alias ? src.alias : *name; // FROM name AS alias ?
+ + ]
1191 [ + + + - ]: 2311 : auto res = Ctx.sources.emplace(table_name.text, std::make_pair(std::ref(T), source_counter++));
1192 : : /* Check if the table name is already in use in other contexts. */
1193 : 777 : bool unique = true;
1194 : 836 : for (std::size_t i = 0; i < contexts_.size() - 1; ++i) {
1195 [ + + ]: 836 : if (contexts_[i]->stage == SemaContext::S_From) continue;
1196 [ + + - + : 805 : if (contexts_[i]->sources.contains(table_name.text.assert_not_none())) {
+ + ]
1197 : 8 : unique = false;
1198 : 8 : break;
1199 : : }
1200 : 28 : }
1201 [ + + + + ]: 8 : if (not res.second or not unique)
1202 [ + + + - : 775 : diag.e(table_name.pos) << "Table name " << table_name.text << " already in use.\n";
+ - + - ]
1203 : 777 : src.table_ = &T;
1204 [ - + ]: 780 : } catch (std::out_of_range) {
1205 [ + - + - : 3 : diag.e(name->pos) << "No table " << name->text << " in database " << DB.name << ".\n";
+ - + - +
- + - ]
1206 : : return;
1207 [ # # ]: 3 : }
1208 [ - + ]: 835 : } else if (auto stmt = std::get_if<Stmt*>(&src.source)) {
1209 : 58 : M_insist(is<SelectStmt>(*stmt), "nested statements are always select statements");
1210 : :
1211 : : /* Evaluate the nested statement in a fresh sema context. */
1212 [ - + ]: 58 : push_context(**stmt, src.alias.text);
1213 : 58 : (*this)(**stmt);
1214 : 58 : M_insist(not contexts_.empty());
1215 : 58 : SemaContext inner_ctx = pop_context();
1216 : :
1217 : 58 : SemaContext::named_expr_table results;
1218 [ + + ]: 90 : for (auto &[name, res] : inner_ctx.results)
1219 [ + + + - : 70 : results.emplace(name, std::make_pair(std::ref(res.expr()), res.order));
+ - + - ]
1220 : :
1221 : : /* Add the results of the nested statement to the list of sources. */
1222 [ + - + - ]: 20 : auto res = Ctx.sources.emplace(src.alias.text, std::make_pair(std::move(results), source_counter++));
1223 : : /* Convert scalar results to vectorials. */
1224 [ + + ]: 52 : for (auto &[_, result] : inner_ctx.results)
1225 [ + - + - : 32 : result.expr().type_ = as<const PrimitiveType>(result.expr().type())->as_vectorial();
+ - + - +
- ]
1226 : : /* Check if the table name is already in use in other contexts. */
1227 : 20 : bool unique = true;
1228 : 20 : for (std::size_t i = 0; i < contexts_.size() - 1; ++i) {
1229 [ + - ]: 20 : if (contexts_[i]->stage == SemaContext::S_From) continue;
1230 [ - + # # : 20 : if (contexts_[i]->sources.contains(src.alias.text.assert_not_none())) {
# # ]
1231 : 0 : unique = false;
1232 : 0 : break;
1233 : : }
1234 : 0 : }
1235 [ + + - + ]: 0 : if (not res.second or not unique) {
1236 [ + + + - : 19 : diag.e(src.alias.pos) << "Table name " << src.alias.text << " already in use.\n";
+ - + - ]
1237 : 1 : return;
1238 : : }
1239 [ - + + ]: 20 : } else {
1240 : 0 : M_unreachable("invalid variant");
1241 : : }
1242 : : }
1243 : 7249 : }
1244 : :
1245 : 197 : void Sema::operator()(WhereClause &c)
1246 : : {
1247 : 197 : SemaContext &Ctx = get_context();
1248 : 197 : Ctx.stage = SemaContext::S_Where;
1249 : :
1250 : : /* Analyze expression. */
1251 : 197 : (*this)(*c.where);
1252 : :
1253 [ + + ]: 197 : if (c.where->type()->is_error())
1254 : 16 : return; /* nothing to be done */
1255 : :
1256 : 181 : const Boolean *ty = cast<const Boolean>(c.where->type());
1257 : :
1258 : : /* WHERE condition must be of boolean type. */
1259 [ + + ]: 181 : if (not ty) {
1260 : 1 : diag.e(c.tok.pos) << "The expression in the WHERE clause must be of boolean type.\n";
1261 : 1 : return;
1262 : : }
1263 : 197 : }
1264 : :
1265 : 58 : void Sema::operator()(GroupByClause &c)
1266 : : {
1267 : 58 : Catalog &C = Catalog::Get();
1268 : 58 : SemaContext &Ctx = get_context();
1269 : 58 : Ctx.stage = SemaContext::S_GroupBy;
1270 : :
1271 : 58 : Ctx.needs_grouping = true;
1272 [ + + ]: 162 : for (auto &[expr, alias] : c.group_by) {
1273 : 58 : (*this)(*expr);
1274 : :
1275 : : /* Skip errors. */
1276 [ + + ]: 58 : if (expr->type()->is_error())
1277 : 2 : continue;
1278 : :
1279 [ + + ]: 56 : if (expr->contains_free_variables())
1280 : 9 : diag.e(expr->tok.pos) << *expr << " contains free variable(s) (not yet supported).\n";
1281 : :
1282 : 56 : const PrimitiveType *pt = cast<const PrimitiveType>(expr->type());
1283 : :
1284 : : /* Can only group by expressions of primitive type. */
1285 [ + - ]: 56 : if (not pt) {
1286 : 0 : diag.e(c.tok.pos) << "Cannot group by " << *expr << ", has invalid type.\n";
1287 : 0 : continue;
1288 : : }
1289 : :
1290 : : /* Can only group by vectorials. The expression in the GROUP BY clause must be evaluated per tuple. */
1291 [ + + ]: 56 : if (not pt->is_vectorial()) {
1292 : 6 : diag.e(c.tok.pos) << "Cannot group by " << *expr << ". Expressions in the GROUP BY clause must be "
1293 : : "vectorial, i.e. they must depend on each row separately.\n";
1294 : 3 : continue;
1295 : : }
1296 : :
1297 : : /* Add expression to list of grouping keys. */
1298 [ + + ]: 53 : if (alias) {
1299 : 24 : Ctx.grouping_keys.emplace(alias.text, *expr);
1300 [ + + ]: 53 : } else if (auto d = cast<Designator>(expr.get())) {
1301 : 88 : Ctx.grouping_keys.emplace(d->attr_name.text, *expr);
1302 : 44 : } else {
1303 [ - + - + ]: 1 : oss.str("");
1304 : 2 : oss << *expr;
1305 [ - + - + ]: 1 : Ctx.grouping_keys.emplace(C.pool(oss.str().c_str()), *expr);
1306 : : }
1307 : : }
1308 : 58 : }
1309 : :
1310 : 40 : void Sema::operator()(HavingClause &c)
1311 : : {
1312 : 40 : SemaContext &Ctx = get_context();
1313 : 40 : Ctx.stage = SemaContext::S_Having;
1314 : 40 : Ctx.needs_grouping = true;
1315 : :
1316 : 40 : (*this)(*c.having);
1317 : :
1318 : : /* Skip errors. */
1319 [ + + ]: 40 : if (c.having->type()->is_error())
1320 : 12 : return;
1321 : :
1322 : 28 : const Boolean *ty = cast<const Boolean>(c.having->type());
1323 : :
1324 : : /* HAVING condition must be of boolean type. */
1325 [ + + ]: 28 : if (not ty) {
1326 : 1 : diag.e(c.tok.pos) << "The expression in the HAVING clause must be of boolean type.\n";
1327 : 1 : return;
1328 : : }
1329 : :
1330 [ + + ]: 27 : if (not ty->is_scalar()) {
1331 : 1 : diag.e(c.tok.pos) << "The expression in the HAVING clause must be scalar.\n";
1332 : 1 : return;
1333 : : }
1334 : :
1335 : : /* TODO The HAVING clause must be a conjunction or disjunction of aggregates or comparisons of grouping keys. */
1336 : 40 : }
1337 : :
1338 : 33 : void Sema::operator()(OrderByClause &c)
1339 : : {
1340 : 33 : SemaContext &Ctx = get_context();
1341 : 33 : Ctx.stage = SemaContext::S_OrderBy;
1342 : :
1343 : : /* Analyze all ordering expressions. */
1344 [ + + ]: 76 : for (auto &o : c.order_by) {
1345 : 43 : auto &e = o.first;
1346 : 43 : (*this)(*e);
1347 : :
1348 [ + + ]: 43 : if (e->type()->is_error()) continue;
1349 [ + + ]: 33 : if (e->contains_free_variables())
1350 : 3 : diag.e(e->tok.pos) << *e << " contains free variable(s) (not yet supported).\n";
1351 : :
1352 : 33 : auto pt = as<const PrimitiveType>(e->type());
1353 : :
1354 [ + + ]: 33 : if (Ctx.needs_grouping) { // w/ grouping
1355 : : /* If we grouped, the grouping keys now have scalar type. */
1356 [ + + ]: 7 : if (pt->is_vectorial())
1357 : 2 : diag.e(c.tok.pos) << "Cannot order by " << *e << ", expression must be scalar.\n";
1358 : 7 : } else { // w/o grouping
1359 : : /* If we did not group, the ordering expressions must be vectorial. */
1360 [ + + ]: 26 : if (pt->is_scalar())
1361 : 1 : diag.e(c.tok.pos) << "Cannot order by " << *e << ", expression must be vectorial.\n";
1362 : : }
1363 : : }
1364 : 33 : }
1365 : :
1366 : 4 : void Sema::operator()(LimitClause &c)
1367 : : {
1368 : 4 : SemaContext &Ctx = get_context();
1369 : 4 : Ctx.stage = SemaContext::S_Limit;
1370 : :
1371 : : /* TODO limit only makes sense when SELECT is vectorial and not scalar */
1372 : :
1373 : 4 : errno = 0;
1374 : 4 : strtoull(*c.limit.text, nullptr, 0);
1375 [ - + ]: 4 : if (errno == EINVAL)
1376 : 0 : diag.e(c.limit.pos) << "Invalid value for LIMIT.\n";
1377 [ - + ]: 4 : else if (errno == ERANGE)
1378 : 0 : diag.e(c.limit.pos) << "Value of LIMIT out of range.\n";
1379 [ - + ]: 4 : else if (errno != 0)
1380 : 0 : diag.e(c.limit.pos) << "Invalid LIMIT.\n";
1381 : :
1382 [ + + ]: 4 : if (c.offset) {
1383 : 2 : errno = 0;
1384 : 2 : strtoull(*c.offset.text, nullptr, 0);
1385 [ - + ]: 2 : if (errno == EINVAL)
1386 : 0 : diag.e(c.offset.pos) << "Invalid value for OFFSET.\n";
1387 [ - + ]: 2 : else if (errno == ERANGE)
1388 : 0 : diag.e(c.offset.pos) << "Value of OFFSET out of range.\n";
1389 [ - + ]: 2 : else if (errno != 0)
1390 : 0 : diag.e(c.offset.pos) << "Invalid OFFSET.\n";
1391 : 2 : }
1392 : 4 : }
1393 : :
1394 : :
1395 : : /*===== Instruction ==================================================================================================*/
1396 : :
1397 : 0 : void Sema::operator()(Instruction &I) {
1398 : 0 : Catalog &C = Catalog::Get();
1399 : : try {
1400 [ # # ]: 0 : command_ = C.create_instruction(I.name, I.args);
1401 [ # # ]: 0 : } catch (std::invalid_argument) {
1402 [ # # # # : 0 : diag.e(I.tok.pos) << "Instruction " << I.name << " unknown\n";
# # # # ]
1403 [ # # ]: 0 : }
1404 : 0 : }
1405 : :
1406 : :
1407 : : /*===== Stmt =========================================================================================================*/
1408 : :
1409 : 0 : void Sema::operator()(ErrorStmt&)
1410 : : {
1411 : : /* nothing to be done */
1412 : 0 : }
1413 : :
1414 : 0 : void Sema::operator()(EmptyStmt&)
1415 : : {
1416 : 0 : command_ = std::make_unique<EmptyCommand>();
1417 : 0 : }
1418 : :
1419 : 2 : void Sema::operator()(CreateDatabaseStmt &s)
1420 : : {
1421 : 2 : RequireContext RCtx(this, s);
1422 [ + - ]: 2 : Catalog &C = Catalog::Get();
1423 [ + - ]: 2 : auto db_name = s.database_name.text.assert_not_none();
1424 : :
1425 [ + - + + ]: 2 : if (not C.has_database(db_name))
1426 [ + - ]: 1 : command_ = std::make_unique<CreateDatabase>(std::move(db_name));
1427 : : else
1428 [ + - + - : 1 : diag.e(s.database_name.pos) << "Database " << db_name << " already exists.\n";
+ - + - ]
1429 : 2 : }
1430 : :
1431 : 3 : void Sema::operator()(DropDatabaseStmt &s)
1432 : : {
1433 : 3 : RequireContext RCtx(this, s);
1434 [ + - ]: 3 : Catalog &C = Catalog::Get();
1435 [ + - ]: 3 : auto db_name = s.database_name.text.assert_not_none();
1436 : :
1437 [ + - - + ]: 3 : if (C.has_database_in_use()) {
1438 [ # # # # : 0 : if (C.get_database_in_use().name == db_name) {
# # # # ]
1439 [ # # # # : 0 : diag.e(s.database_name.pos) << "Database " << db_name << " is in use.\n";
# # # # ]
1440 : 0 : return;
1441 : : }
1442 : 0 : }
1443 : :
1444 [ + - + + ]: 3 : if (C.has_database(db_name))
1445 [ + - ]: 1 : command_ = std::make_unique<DropDatabase>(std::move(db_name));
1446 : : else {
1447 [ + + ]: 2 : if (s.has_if_exists)
1448 [ + - ]: 1 : command_ = std::make_unique<EmptyCommand>();
1449 : : else
1450 [ + - + - : 1 : diag.e(s.database_name.pos) << "Database " << db_name << " does not exist.\n";
+ - + - ]
1451 : : }
1452 [ - + ]: 3 : }
1453 : :
1454 : 3 : void Sema::operator()(UseDatabaseStmt &s)
1455 : : {
1456 : 3 : RequireContext RCtx(this, s);
1457 [ + - ]: 3 : Catalog &C = Catalog::Get();
1458 [ + - ]: 3 : auto db_name = s.database_name.text.assert_not_none();
1459 : :
1460 [ + - + + ]: 3 : if (C.has_database(db_name))
1461 [ + - ]: 1 : command_ = std::make_unique<UseDatabase>(std::move(db_name));
1462 : : else
1463 [ + - + - : 2 : diag.e(s.database_name.pos) << "Database " << db_name << " does not exist.\n";
+ - + - ]
1464 : 3 : }
1465 : :
1466 : 26 : void Sema::operator()(CreateTableStmt &s)
1467 : : {
1468 : 26 : RequireContext RCtx(this, s);
1469 [ + - ]: 26 : Catalog &C = Catalog::Get();
1470 : :
1471 [ + - + + ]: 26 : if (not C.has_database_in_use()) {
1472 [ + - + - ]: 1 : diag.err() << "No database selected.\n";
1473 : 1 : return;
1474 : : }
1475 [ + - ]: 25 : auto &DB = C.get_database_in_use();
1476 [ + - ]: 25 : auto table_name = s.table_name.text.assert_not_none();
1477 [ + - + - : 25 : std::unique_ptr<Table> T = C.table_factory().make(table_name);
+ - ]
1478 : :
1479 : : /* Add the newly declared table to the list of sources of the sema context. We need to add the table to the sema
1480 : : * context so that semantic analysis of `CHECK` expressions can resolve references to attributes of the same table.
1481 : : * */
1482 [ + - + - : 25 : get_context().sources.emplace(table_name, std::make_pair(SemaContext::source_type(*T), 0U));
+ - ]
1483 : :
1484 : : /* Verify table does not yet exist. */
1485 : : try {
1486 [ + + ]: 25 : DB.get_table(table_name);
1487 [ + - + - : 1 : diag.e(s.table_name.pos) << "Table " << table_name << " already exists in database " << DB.name << ".\n";
+ - + - +
- + - ]
1488 [ + - ]: 25 : } catch (std::out_of_range) {
1489 : : /* nothing to be done */
1490 [ + - ]: 24 : }
1491 : :
1492 : : /* Analyze attributes and add them to the new table. */
1493 : 25 : bool has_primary_key = false;
1494 [ + + ]: 93 : for (auto &attr : s.attributes) {
1495 [ + - ]: 68 : auto attribute_name = attr->name.text.assert_not_none();
1496 [ + - ]: 68 : const PrimitiveType *ty = cast<const PrimitiveType>(attr->type);
1497 [ - + ]: 68 : if (not ty) {
1498 [ # # # # : 0 : diag.e(attr->name.pos) << "Attribute " << attr->name.text << " cannot be defined with type " << *attr->type
# # # # #
# ]
1499 [ # # ]: 0 : << ".\n";
1500 : 0 : return;
1501 : : }
1502 [ + - ]: 68 : attr->type = ty->as_vectorial(); // convert potentially scalar type to vectorial
1503 : :
1504 : : /* Before we check the constraints, we must add this newly declared attribute to its table, and hence to the
1505 : : * sema context. */
1506 : : try {
1507 [ + - + - : 68 : T->push_back(attribute_name, ty->as_vectorial());
+ + ]
1508 [ + - ]: 68 : } catch (std::invalid_argument) {
1509 : : /* attribute name is a duplicate */
1510 [ + - + - : 1 : diag.e(attr->name.pos) << "Attribute " << attr->name.text << " occurs multiple times in defintion of table "
+ - + - ]
1511 [ + - + - ]: 1 : << table_name << ".\n";
1512 [ + - # # ]: 1 : }
1513 : :
1514 : : /* Check constraint definitions. */
1515 : 68 : bool has_reference = false; ///< at most one reference allowed per attribute
1516 : 68 : bool is_unique = false, is_not_null = false;
1517 [ + - ]: 68 : get_context().stage = SemaContext::S_Where;
1518 [ + + ]: 100 : for (auto &c : attr->constraints) {
1519 [ + - + + ]: 32 : if (is<PrimaryKeyConstraint>(c)) {
1520 [ + + ]: 16 : if (has_primary_key)
1521 [ + - + - : 2 : diag.e(attr->name.pos) << "Duplicate definition of primary key as attribute " << attr->name.text
+ - ]
1522 [ + - ]: 1 : << ".\n";
1523 : 16 : has_primary_key = true;
1524 [ + - ]: 16 : T->add_primary_key(attribute_name);
1525 : 16 : }
1526 : :
1527 [ + - + + ]: 32 : if (is<UniqueConstraint>(c)) {
1528 [ + + ]: 4 : if (is_unique)
1529 [ + - + - : 1 : diag.w(c->tok.pos) << "Duplicate definition of attribute " << attr->name.text << " as UNIQUE.\n";
+ - + - ]
1530 : 4 : is_unique = true;
1531 [ + - ]: 4 : T->at(attribute_name).unique = true;
1532 : 4 : }
1533 : :
1534 [ + - + + ]: 32 : if (is<NotNullConstraint>(c)) {
1535 [ + + ]: 4 : if (is_not_null)
1536 [ + - + - : 1 : diag.w(c->tok.pos) << "Duplicate definition of attribute " << attr->name.text << " as NOT NULL.\n";
+ - + - ]
1537 : 4 : is_not_null = true;
1538 [ + - ]: 4 : T->at(attribute_name).not_nullable = true;
1539 : 4 : }
1540 : :
1541 [ + - + + ]: 35 : if (auto check = cast<CheckConditionConstraint>(c)) {
1542 : : /* Verify that the type of the condition is boolean. */
1543 : : /* TODO if the condition uses already mentioned attributes, we must add them to the sema context before
1544 : : * invoking semantic analysis of the condition! */
1545 [ + - ]: 3 : (*this)(*check->cond);
1546 [ + - ]: 3 : auto ty = check->cond->type();
1547 [ + - + + ]: 3 : if (not ty->is_boolean())
1548 [ + - + - : 1 : diag.e(check->tok.pos) << "Condition " << *check->cond << " is an invalid CHECK constraint.\n";
+ - + - ]
1549 : 3 : }
1550 : :
1551 [ + - + + ]: 37 : if (auto ref = cast<ReferenceConstraint>(c)) {
1552 [ + + ]: 5 : if (has_reference)
1553 [ + - + - : 1 : diag.e(ref->tok.pos) << "Attribute " << attr->name.text << " must not have multiple references.\n";
+ - + - ]
1554 : 5 : has_reference = true;
1555 : :
1556 : : /* Check that the referenced attribute exists. */
1557 : : try {
1558 [ + - + + ]: 5 : auto &ref_table = DB.get_table(ref->table_name.text.assert_not_none());
1559 : : try {
1560 [ + - + + ]: 4 : auto &ref_attr = ref_table.at(ref->attr_name.text.assert_not_none());
1561 [ + + ]: 3 : if (attr->type != ref_attr.type)
1562 [ + - + - ]: 1 : diag.e(ref->attr_name.pos) << "Referenced attribute has different type.\n";
1563 [ + - + - ]: 3 : T->at(attr->name.text.assert_not_none()).reference = &ref_attr;
1564 [ + - ]: 4 : } catch (std::out_of_range) {
1565 [ + - + - : 1 : diag.e(ref->attr_name.pos) << "Invalid reference, attribute " << ref->attr_name.text
+ - ]
1566 [ + - + - : 1 : << " not found in table " << ref->table_name.text << ".\n";
+ - ]
1567 [ + - # # ]: 1 : }
1568 [ - + ]: 5 : } catch (std::out_of_range) {
1569 [ + - + - : 1 : diag.e(ref->table_name.pos) << "Invalid reference, table " << ref->table_name.text
+ - ]
1570 [ + - ]: 1 : << " not found.\n";
1571 [ + - # # ]: 1 : }
1572 : 5 : }
1573 : : }
1574 [ - + ]: 68 : }
1575 : :
1576 [ + - + - : 25 : if (not is_nested() and not diag.num_errors())
+ + ]
1577 [ + - ]: 17 : command_ = std::make_unique<CreateTable>(std::move(T));
1578 [ - + ]: 53 : }
1579 : :
1580 : 4 : void Sema::operator()(DropTableStmt &s)
1581 : : {
1582 : 4 : RequireContext RCtx(this, s);
1583 [ + - ]: 4 : Catalog &C = Catalog::Get();
1584 : :
1585 [ + - - + ]: 4 : if (not C.has_database_in_use()) {
1586 [ # # # # ]: 0 : diag.err() << "No database selected.\n";
1587 : 0 : return;
1588 : : }
1589 [ + - ]: 4 : auto &DB = C.get_database_in_use();
1590 : :
1591 : 4 : bool ok = true;
1592 : 4 : std::vector<ThreadSafePooledString> table_names;
1593 [ + + ]: 9 : for (auto &tok : s.table_names) {
1594 [ + - ]: 5 : auto table_name = tok->text.assert_not_none();
1595 [ + - + + ]: 5 : if (DB.has_table(table_name))
1596 [ + - ]: 2 : table_names.emplace_back(std::move(table_name));
1597 : : else {
1598 [ + + ]: 3 : if (not s.has_if_exists) {
1599 [ + - + - : 1 : diag.e(tok->pos) << "Table " << table_name << " does not exist in database " << DB.name << ".\n";
+ - + - +
- + - ]
1600 : 1 : ok = false;
1601 : 1 : } else {
1602 [ + - + - : 2 : diag.n(tok->pos) << "Table " << table_name << " does not exist in database " << DB.name << ". "
+ - + - +
- + - ]
1603 [ + - ]: 2 : << "Skipping.\n";
1604 : : }
1605 : : }
1606 : 5 : }
1607 [ + + ]: 4 : if (ok)
1608 [ + - ]: 3 : command_ = std::make_unique<DropTable>(std::move(table_names));
1609 [ - + ]: 4 : }
1610 : :
1611 : 7 : void Sema::operator()(CreateIndexStmt &s)
1612 : : {
1613 : 7 : RequireContext RCtx(this, s);
1614 [ + - ]: 7 : Catalog &C = Catalog::Get();
1615 : :
1616 [ + - - + ]: 7 : if (not C.has_database_in_use()) {
1617 [ # # # # ]: 0 : diag.err() << "No database selected.\n";
1618 : 0 : return;
1619 : : }
1620 [ + - ]: 7 : auto &DB = C.get_database_in_use();
1621 : :
1622 : : /* Check if `UNIQUE` was present in statement. */
1623 [ + - - + ]: 7 : if (s.has_unique) {
1624 [ # # # # ]: 0 : diag.e(s.has_unique.pos) << "Keyword UNIQUE not supported.\n";
1625 : 0 : return;
1626 : : }
1627 : :
1628 : : /* Check that an index name is set. */
1629 [ + - + + ]: 7 : if (not s.index_name) {
1630 [ + - + - ]: 4 : diag.err() << "Indexes without name not supported.\n";
1631 : 4 : return;
1632 : : }
1633 : :
1634 : : /* Check that the index name does not yet exist. */
1635 [ + - ]: 3 : auto index_name = s.index_name.text.assert_not_none();
1636 [ + - + + ]: 3 : if (DB.has_index(index_name)) {
1637 [ - + ]: 1 : if (s.has_if_not_exists) {
1638 [ # # # # : 0 : diag.w(s.index_name.pos) << "Index " << index_name << " already exists in database " << DB.name
# # # # #
# ]
1639 [ # # ]: 0 : << ". Skipping.\n";
1640 [ # # ]: 0 : command_ = std::make_unique<EmptyCommand>();
1641 : 0 : return;
1642 : : } else {
1643 [ + - + - : 1 : diag.e(s.index_name.pos) << "Index " << index_name << " already exists in database " << DB.name << ".\n";
+ - + - +
- + - ]
1644 : 1 : return;
1645 : : }
1646 : : }
1647 : :
1648 : : /* Check that the table exists. */
1649 [ + - ]: 2 : auto table_name = s.table_name.text.assert_not_none();
1650 [ + - - + ]: 2 : if (not DB.has_table(table_name)) {
1651 [ # # # # : 0 : diag.e(s.table_name.pos) << "Table " << table_name << " does not exist in database " << DB.name << "\n.";
# # # # #
# # # ]
1652 : 0 : return;
1653 : : }
1654 [ + - ]: 2 : auto &table = DB.get_table(table_name);
1655 : :
1656 : : /* Check that the index method exists. */
1657 [ + - + - ]: 2 : if (not s.method) { // if method is not set, set to default
1658 [ + - - + ]: 2 : s.method = Token::CreateArtificial(TK_Default);
1659 : 2 : s.method.pos = s.table_name.pos;
1660 : 2 : }
1661 [ - - + ]: 2 : switch(s.method.type) {
1662 : : case TK_Default: // ok
1663 : 2 : break;
1664 : :
1665 : : case TK_IDENTIFIER:
1666 [ # # # # : 0 : if (s.method.text.assert_not_none() == C.pool("array")) // ok
# # # # ]
1667 : 0 : break;
1668 [ # # # # : 0 : else if (s.method.text == C.pool("rmi")) // ok
# # ]
1669 : 0 : break;
1670 : : else { // unknown method, not ok
1671 [ # # # # : 0 : diag.e(s.method.pos) << "Index method " << s.method.text << " not supported.\n";
# # # # ]
1672 : 0 : return;
1673 : : }
1674 : :
1675 : : default: // unknown token type, not ok
1676 [ # # # # : 0 : diag.e(s.method.pos) << "Index method " << s.method.text << " not supported.\n";
# # # # ]
1677 : 0 : return;
1678 : : }
1679 : :
1680 : : /* Check that at most one key field is set. */
1681 [ - + ]: 2 : if (s.key_fields.size() > 1) {
1682 [ # # # # ]: 0 : diag.err() << "More than one key field for indexes not supported.\n";
1683 : 0 : return;
1684 : : }
1685 : :
1686 : : /* Compute attribute from key field. */
1687 [ + + ]: 4 : for (auto it = s.key_fields.cbegin(), end = s.key_fields.cend(); it != end; ++it) {
1688 : 2 : auto field = it->get();
1689 [ + - + - ]: 2 : if (auto d = cast<Designator>(field)) {
1690 [ + - - + : 2 : if (not table.has_attribute(d->attr_name.text.assert_not_none())) {
- + ]
1691 [ # # # # : 0 : diag.e(d->tok.pos) << "Attribute " << d->attr_name.text << " does not exists in table "
# # # # ]
1692 [ # # # # ]: 0 : << table_name << ".\n";
1693 : 0 : return;
1694 : : }
1695 : 2 : } else {
1696 [ # # # # ]: 0 : diag.e(field->tok.pos) << "Non-attribute key fields for indexes not supported.\n";
1697 : 0 : return;
1698 : : }
1699 : 2 : }
1700 [ + - - + ]: 2 : auto attribute_name = cast<Designator>(s.key_fields.front())->attr_name.text.assert_not_none();
1701 [ + - ]: 2 : auto &attribute = table.at(attribute_name);
1702 : :
1703 : : /* Build index based on selected method and key type. */
1704 : 2 : std::unique_ptr<idx::IndexBase> index;
1705 : 4 : auto make_index = [&]<template<typename> typename Index, typename Key>() {
1706 : : if constexpr(requires { typename Index<Key>; }) {
1707 : 2 : return std::make_unique<Index<Key>>();
1708 : : } else {
1709 : 0 : diag(s.method.pos) << "Index method not available for given key type.\n";
1710 : 0 : return nullptr;
1711 : : }
1712 : : };
1713 : 4 : auto set_index = [&]<template<typename> typename Index>() {
1714 : 10 : visit(overloaded {
1715 : 4 : [&](const Boolean&) { index = make_index.operator()<Index, bool>(); },
1716 : 2 : [&](const Numeric &n) {
1717 [ # # # # : 0 : switch (n.kind) {
# # ]
1718 : : case Numeric::N_Int:
1719 : : case Numeric::N_Decimal:
1720 [ # # # # : 0 : switch (n.size()) {
# # # # #
# ]
1721 : 0 : default: M_unreachable("invalid size");
1722 : 0 : case 8: index = make_index.operator()<Index, int8_t>(); break;
1723 : 0 : case 16: index = make_index.operator()<Index, int16_t>(); break;
1724 : 0 : case 32: index = make_index.operator()<Index, int32_t>(); break;
1725 : 0 : case 64: index = make_index.operator()<Index, int64_t>(); break;
1726 : : }
1727 : 0 : break;
1728 : : case Numeric::N_Float:
1729 [ # # # # : 0 : switch (n.size()) {
# # ]
1730 : 0 : default: M_unreachable("invalid size");
1731 : 0 : case 32: index = make_index.operator()<Index, float>(); break;
1732 : 0 : case 64: index = make_index.operator()<Index, double>(); break;
1733 : : }
1734 : 0 : }
1735 : 0 : },
1736 : 2 : [&](const CharacterSequence&) { index = make_index.operator()<Index, const char*>(); },
1737 : 2 : [&](const Date&) { index = std::make_unique<Index<int32_t>>(); },
1738 : 2 : [&](const DateTime&) { index = std::make_unique<Index<int64_t>>(); },
1739 : 0 : [](auto&&) { M_unreachable("invalid type"); },
1740 : 2 : }, *attribute.type);
1741 : 2 : };
1742 [ - - + ]: 2 : switch(s.method.type) {
1743 [ + - ]: 2 : case TK_Default: set_index.operator()<idx::ArrayIndex>(); break;
1744 : : case TK_IDENTIFIER:
1745 [ # # # # : 0 : if (s.method.text.assert_not_none() == C.pool("array"))
# # # # ]
1746 [ # # ]: 0 : set_index.operator()<idx::ArrayIndex>();
1747 [ # # # # : 0 : else if (s.method.text == C.pool("rmi"))
# # ]
1748 [ # # ]: 0 : set_index.operator()<idx::RecursiveModelIndex>();
1749 : 0 : break;
1750 : : default:
1751 [ # # ]: 0 : M_unreachable("invalid token type");
1752 : : }
1753 [ - + ]: 2 : if (not index) // No index was set
1754 : 0 : return;
1755 : :
1756 [ + - ]: 2 : command_ = std::make_unique<CreateIndex>(std::move(index), std::move(table_name), std::move(attribute_name),
1757 : : std::move(index_name));
1758 [ - + ]: 7 : }
1759 : :
1760 : 4 : void Sema::operator()(DropIndexStmt &s)
1761 : : {
1762 : 4 : RequireContext RCtx(this, s);
1763 [ + - ]: 4 : Catalog &C = Catalog::Get();
1764 : :
1765 [ + - - + ]: 4 : if (not C.has_database_in_use()) {
1766 [ # # # # ]: 0 : diag.err() << "No database selected.\n";
1767 : 0 : return;
1768 : : }
1769 [ + - ]: 4 : auto &DB = C.get_database_in_use();
1770 : :
1771 : 4 : bool ok = true;
1772 : 4 : std::vector<ThreadSafePooledString> index_names;
1773 [ + + ]: 9 : for (auto &tok : s.index_names) {
1774 [ + - ]: 5 : auto index_name = tok->text.assert_not_none();
1775 [ + - + + ]: 5 : if (DB.has_index(index_name))
1776 [ + - ]: 2 : index_names.emplace_back(index_name);
1777 : : else {
1778 [ + + ]: 3 : if (not s.has_if_exists) {
1779 [ + - + - : 1 : diag.e(tok->pos) << "Index " << index_name << " does not exist in database " << DB.name << ".\n";
+ - + - +
- + - ]
1780 : 1 : ok = false;
1781 : 1 : } else {
1782 [ + - + - : 2 : diag.w(tok->pos) << "Index " << index_name << " does not exist in database " << DB.name << ". "
+ - + - +
- + - ]
1783 [ + - ]: 2 : << "Skipping.\n";
1784 : : }
1785 : : }
1786 : 5 : }
1787 [ + + ]: 4 : if (ok)
1788 [ + - ]: 3 : command_ = std::make_unique<DropIndex>(std::move(index_names));
1789 [ - + ]: 4 : }
1790 : :
1791 : 575 : void Sema::operator()(SelectStmt &s)
1792 : : {
1793 : 575 : RequireContext RCtx(this, s);
1794 [ + - ]: 575 : Catalog &C = Catalog::Get();
1795 : :
1796 [ + + ]: 575 : if (s.from) {
1797 [ + - + + ]: 547 : if (not C.has_database_in_use()) {
1798 [ + - + - ]: 1 : diag.err() << "No database selected.\n";
1799 : 1 : return;
1800 : : }
1801 [ + - ]: 546 : (*this)(*s.from);
1802 : 546 : }
1803 [ + + + - ]: 574 : if (s.where) (*this)(*s.where);
1804 [ + + + - ]: 574 : if (s.group_by) (*this)(*s.group_by);
1805 [ + + + - ]: 574 : if (s.having) (*this)(*s.having);
1806 [ + - ]: 574 : (*this)(*s.select);
1807 [ + + + - ]: 574 : if (s.order_by) (*this)(*s.order_by);
1808 [ + + + - ]: 574 : if (s.limit) (*this)(*s.limit);
1809 : :
1810 : :
1811 [ + + + - : 574 : if (not is_nested() and not diag.num_errors())
+ + ]
1812 [ + - ]: 421 : command_ = std::make_unique<QueryDatabase>();
1813 [ - + ]: 575 : }
1814 : :
1815 : 768 : void Sema::operator()(InsertStmt &s)
1816 : : {
1817 : 768 : RequireContext RCtx(this, s);
1818 [ + - ]: 768 : Catalog &C = Catalog::Get();
1819 : :
1820 [ + - + + ]: 768 : if (not C.has_database_in_use()) {
1821 [ + - + - ]: 1 : diag.e(s.table_name.pos) << "No database in use.\n";
1822 : 1 : return;
1823 : : }
1824 [ + - ]: 767 : auto &DB = C.get_database_in_use();
1825 : :
1826 : : const Table *tbl;
1827 : : try {
1828 [ + - + + ]: 767 : tbl = &DB.get_table(s.table_name.text.assert_not_none());
1829 [ - + ]: 767 : } catch (std::out_of_range) {
1830 [ + - + - : 1 : diag.e(s.table_name.pos) << "Table " << s.table_name.text << " does not exist in database " << DB.name << ".\n";
+ - + - +
- + - ]
1831 : : return;
1832 [ + - # # ]: 1 : }
1833 : :
1834 : : /* Analyze values. */
1835 [ + + ]: 1610 : for (std::size_t i = 0; i != s.tuples.size(); ++i) {
1836 : 844 : auto &t = s.tuples[i];
1837 [ - + ]: 844 : if (t.empty())
1838 : 0 : continue; // syntax error, already reported
1839 [ + - + + ]: 844 : if (t.size() != tbl->num_attrs()) {
1840 [ + - + - : 2 : diag.e(s.table_name.pos) << "Tuple " << (i + 1) << " has not enough values.\n";
+ - + - ]
1841 : 2 : continue;
1842 : : }
1843 [ + - + - : 4238 : for (auto [it, j] = std::tuple{tbl->begin(), 0}; it != tbl->end(); ++it, ++j) {
+ - + + +
- ]
1844 : 6792 : auto &v = t[j];
1845 [ + - ]: 3396 : auto &attr = *it;
1846 [ + + + ]: 3396 : switch (v.first) {
1847 : : case InsertStmt::I_Expr: {
1848 [ + - ]: 3210 : (*this)(*v.second);
1849 [ + - + - : 3210 : if (v.second->type()->is_error()) continue;
- + ]
1850 [ + - + - ]: 3210 : auto ty = as<const PrimitiveType>(v.second->type());
1851 [ + - + + : 3210 : if (ty->is_boolean() and attr.type->is_boolean())
+ - + + ]
1852 : 127 : break;
1853 [ + - + + : 3083 : if (ty->is_character_sequence() and attr.type->is_character_sequence())
+ - + - ]
1854 : 45 : break;
1855 [ + - - + : 3038 : if (ty->is_date() and attr.type->is_date())
# # # # ]
1856 : 0 : break;
1857 [ + - - + : 3038 : if (ty->is_date_time() and attr.type->is_date_time())
# # # # ]
1858 : 0 : break;
1859 [ + - + + : 3038 : if (ty->is_numeric() and attr.type->is_numeric())
+ - + + ]
1860 : 3034 : break;
1861 [ + - + - : 4 : diag.e(s.table_name.pos) << "Value " << *v.second << " is not valid for attribute "
+ - + - ]
1862 [ + - + - ]: 4 : << attr.name << ".\n";
1863 : 4 : break;
1864 : : }
1865 : :
1866 : : case InsertStmt::I_Null: {
1867 [ - + ]: 183 : if (attr.not_nullable)
1868 [ # # # # : 0 : diag.e(s.table_name.pos) << "Value NULL is not valid for attribute " << attr.name
# # ]
1869 [ # # ]: 0 : << " declared as NOT NULL.\n";
1870 : 183 : break;
1871 : : }
1872 : :
1873 : : case InsertStmt::I_Default:
1874 : : /* TODO has default? */
1875 : 3 : break;
1876 : : }
1877 : 3396 : }
1878 : 842 : }
1879 : :
1880 [ + - + - : 766 : if (not is_nested() and not diag.num_errors())
+ + ]
1881 [ + - ]: 761 : command_ = std::make_unique<InsertRecords>();
1882 [ - + ]: 769 : }
1883 : :
1884 : 0 : void Sema::operator()(UpdateStmt &s)
1885 : : {
1886 : 0 : RequireContext RCtx(this, s);
1887 : : /* TODO */
1888 : 0 : (void) s;
1889 [ # # ]: 0 : M_unreachable("Not implemented.");
1890 : 0 : }
1891 : :
1892 : 0 : void Sema::operator()(DeleteStmt &s)
1893 : : {
1894 : 0 : RequireContext RCtx(this, s);
1895 : : /* TODO */
1896 : 0 : (void) s;
1897 [ # # ]: 0 : M_unreachable("Not implemented.");
1898 : 0 : }
1899 : :
1900 : 9 : void Sema::operator()(DSVImportStmt &s)
1901 : : {
1902 : 9 : RequireContext RCtx(this, s);
1903 [ + - ]: 9 : auto &C = Catalog::Get();
1904 : :
1905 [ + - + + ]: 9 : if (not C.has_database_in_use()) {
1906 [ + - + - ]: 1 : diag.e(s.table_name.pos) << "No database selected\n";
1907 : 1 : return;
1908 : : }
1909 [ + - ]: 8 : auto &DB = C.get_database_in_use();
1910 : :
1911 : 8 : const Table *table = nullptr;
1912 : : try {
1913 [ + - + + ]: 8 : table = &DB.get_table(s.table_name.text.assert_not_none());
1914 [ - + ]: 8 : } catch (std::out_of_range) {
1915 [ + - + - : 1 : diag.e(s.table_name.pos) << "Table " << s.table_name.text << " does not exist in database " << DB.name << ".\n";
+ - + - +
- + - ]
1916 [ + - # # ]: 1 : }
1917 : :
1918 : 8 : DSVReader::Config cfg;
1919 : 8 : cfg.has_header = s.has_header;
1920 : 8 : cfg.skip_header = s.skip_header;
1921 [ + - + + ]: 8 : if (s.rows)
1922 [ + - ]: 1 : cfg.num_rows = atoi(*s.rows.text);
1923 : :
1924 : : /* If character was provided by user, check that length is equal to 1. */
1925 : : #define SET_CHAR(NAME) \
1926 : : if (s.NAME) { \
1927 : : std::string NAME = interpret(*s.NAME.text); \
1928 : : if (NAME.length() == 1) \
1929 : : cfg.NAME = NAME[0]; \
1930 : : else \
1931 : : diag.e(s.NAME.pos) << "Invalid " #NAME " character " << s.NAME.text << ". Must have length 1.\n"; \
1932 : : }
1933 [ + - + + : 9 : SET_CHAR(delimiter);
+ - + - +
- + + + -
+ - + - +
- + - ]
1934 [ + - + + : 9 : SET_CHAR(quote);
+ - + - +
- + + + -
+ - + - +
- + - ]
1935 [ + - + + : 9 : SET_CHAR(escape);
+ - + - +
- + + + -
+ - + - +
- + - ]
1936 : : #undef SET_CHAR
1937 : :
1938 : : /* Delimiter and quote character must be distinct. */
1939 [ + + ]: 8 : if (cfg.delimiter == cfg.quote) {
1940 [ + - + - ]: 1 : auto pos = s.delimiter ? s.delimiter.pos : s.quote.pos;
1941 [ + - + - : 1 : diag.e(pos) << "The delimiter (" << cfg.delimiter << ") must differ from the quote character (" << cfg.quote
+ - + - +
- ]
1942 [ + - ]: 1 : << ").\n";
1943 : 1 : }
1944 : :
1945 : : /* Sanity check for skip header. */
1946 [ + + + + ]: 8 : if (cfg.skip_header and not cfg.has_header) {
1947 [ + - - + ]: 1 : if (not Options::Get().quiet)
1948 [ # # # # ]: 0 : diag.n(s.path.pos) << "I will assume the existence of a header so I can skip it.\n";
1949 : 1 : }
1950 : :
1951 : : /* Get filesystem path from path token by removing surrounding quotation marks. */
1952 [ + - + - : 8 : std::filesystem::path path(std::string(*s.path.text, 1, strlen(*s.path.text) - 2));
+ - + - ]
1953 : :
1954 [ + - + + ]: 8 : if (not diag.num_errors())
1955 [ + - ]: 3 : command_ = std::make_unique<ImportDSV>(*table, path, std::move(cfg));
1956 [ - + ]: 10 : }
|