Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : #include "monetdb_config.h"
14 : #define LINESIZE 160
15 : #define TABSTOP 2
16 :
17 : #include "rel_dump.h"
18 : #include "rel_rel.h"
19 : #include "rel_basetable.h"
20 : #include "rel_exp.h"
21 : #include "rel_updates.h"
22 : #include "rel_select.h"
23 : #include "rel_remote.h"
24 : #include "rel_rewriter.h"
25 : #include "rel_optimizer.h"
26 : #include "sql_privileges.h"
27 :
28 : static void
29 3578 : print_indent(mvc *sql, stream *fout, int depth, int decorate)
30 : {
31 3578 : char buf[LINESIZE+1];
32 3578 : int i;
33 :
34 3578 : (void)sql;
35 3578 : if (!decorate) {
36 992 : mnstr_printf(fout, "\n");
37 992 : return ;
38 : }
39 2586 : depth *= TABSTOP;
40 2586 : if (depth > LINESIZE)
41 : depth = LINESIZE;
42 21364 : for (i = 0; i < depth; i++){
43 18778 : if ((i % TABSTOP) == 0)
44 9389 : buf[i] = '|';
45 : else
46 9389 : buf[i] = ' ';
47 : }
48 2586 : buf[i] = 0;
49 2586 : mnstr_printf(fout, "\n=%s", buf);
50 : }
51 :
52 : static void
53 605 : cmp_print(mvc *sql, stream *fout, int cmp)
54 : {
55 605 : char *r = NULL;
56 :
57 605 : (void)sql;
58 605 : switch(cmp) {
59 24 : case cmp_gt: r = ">"; break;
60 10 : case cmp_gte: r = ">="; break;
61 107 : case cmp_lte: r = "<="; break;
62 38 : case cmp_lt: r = "<"; break;
63 348 : case cmp_equal: r = "="; break;
64 6 : case cmp_notequal: r = "!="; break;
65 :
66 0 : case cmp_filter: r = "filter"; break;
67 39 : case cmp_or: r = "or"; break;
68 25 : case cmp_in: r = "in"; break;
69 8 : case cmp_notin: r = "notin"; break;
70 :
71 0 : case cmp_all:
72 : case cmp_project:
73 : case cmp_joined:
74 : case cmp_left_project:
75 0 : r = "inner"; break;
76 : }
77 605 : mnstr_printf(fout, " %s ", r);
78 605 : }
79 :
80 : static const char *
81 18004 : dump_escape_ident(sql_allocator *sa, const char *s)
82 : {
83 18004 : char *res = NULL;
84 18004 : if (s) {
85 18004 : size_t l = strlen(s);
86 18004 : char *r = SA_NEW_ARRAY(sa, char, (l * 2) + 1);
87 :
88 18004 : res = r;
89 95050 : while (*s) {
90 77046 : if (*s == '"' || *s == '\\')
91 12 : *r++ = '\\';
92 77046 : *r++ = *s++;
93 : }
94 18004 : *r = '\0';
95 : }
96 18004 : return res;
97 : }
98 :
99 : static char *
100 1179 : dump_sql_subtype(sql_allocator *sa, sql_subtype *t)
101 : {
102 1179 : char buf[BUFSIZ];
103 :
104 1179 : if (t->digits && t->scale)
105 32 : snprintf(buf, BUFSIZ, "%s(%u,%u)", t->type->base.name, t->digits, t->scale);
106 1147 : else if (t->digits)
107 1015 : snprintf(buf, BUFSIZ, "%s(%u)", t->type->base.name, t->digits);
108 : else
109 132 : snprintf(buf, BUFSIZ, "%s", t->type->base.name);
110 1179 : return sa_strdup(sa, buf);
111 : }
112 :
113 : static void exps_print(mvc *sql, stream *fout, list *exps, int depth, list *refs, int alias, int brackets, int decorate);
114 :
115 : static void rel_print_rel(mvc *sql, stream *fout, sql_rel *rel, int depth, list *refs, int decorate);
116 :
117 : void
118 8175 : exp_print(mvc *sql, stream *fout, sql_exp *e, int depth, list *refs, int comma, int alias, int decorate)
119 : {
120 8175 : (void)sql;
121 8175 : if (!e)
122 : return;
123 : /*mnstr_printf(fout, "%p ", e);*/
124 8175 : switch(e->type) {
125 0 : case e_psm: {
126 0 : if (e->flag & PSM_SET) {
127 0 : const char *rname = exp_relname(e);
128 0 : int level = GET_PSM_LEVEL(e->flag);
129 0 : if (rname)
130 0 : mnstr_printf(fout, "\"%s\".", dump_escape_ident(sql->ta, rname));
131 0 : mnstr_printf(fout, "\"%s\" = ", dump_escape_ident(sql->ta, exp_name(e)));
132 0 : exp_print(sql, fout, e->l, depth, refs, 0, 0, decorate);
133 0 : mnstr_printf(fout, " FRAME %d ", level);
134 0 : alias = 0;
135 0 : } else if (e->flag & PSM_VAR) {
136 : // todo output table def (from e->f)
137 0 : const char *rname = exp_relname(e);
138 0 : char *type_str = e->f ? NULL : dump_sql_subtype(sql->ta, exp_subtype(e));
139 0 : int level = GET_PSM_LEVEL(e->flag);
140 0 : mnstr_printf(fout, "declare ");
141 0 : if (rname)
142 0 : mnstr_printf(fout, "\"%s\".", dump_escape_ident(sql->ta, rname));
143 0 : mnstr_printf(fout, "\"%s\" %s FRAME %d ", dump_escape_ident(sql->ta, exp_name(e)), type_str ? type_str : "", level);
144 0 : alias = 0;
145 0 : } else if (e->flag & PSM_RETURN) {
146 0 : int level = GET_PSM_LEVEL(e->flag);
147 0 : mnstr_printf(fout, "return ");
148 0 : exp_print(sql, fout, e->l, depth, refs, 0, 0, decorate);
149 0 : mnstr_printf(fout, " FRAME %d ", level);
150 0 : alias = 0;
151 0 : } else if (e->flag & PSM_WHILE) {
152 0 : mnstr_printf(fout, "while ");
153 0 : exp_print(sql, fout, e->l, depth, refs, 0, 0, decorate);
154 0 : exps_print(sql, fout, e->r, depth, refs, 0, 0, decorate);
155 0 : alias = 0;
156 0 : } else if (e->flag & PSM_IF) {
157 0 : mnstr_printf(fout, "if ");
158 0 : exp_print(sql, fout, e->l, depth, refs, 0, 0, decorate);
159 0 : exps_print(sql, fout, e->r, depth, refs, 0, 0, decorate);
160 0 : if (e->f)
161 0 : exps_print(sql, fout, e->f, depth, refs, 0, 0, decorate);
162 : alias = 0;
163 0 : } else if (e->flag & PSM_REL) {
164 0 : rel_print_rel(sql, fout, e->l, depth+10, refs, 1);
165 0 : } else if (e->flag & PSM_EXCEPTION) {
166 0 : mnstr_printf(fout, "except ");
167 0 : exp_print(sql, fout, e->l, depth, refs, 0, 0, decorate);
168 0 : mnstr_printf(fout, " error %s", (const char *) e->r);
169 0 : alias = 0;
170 : }
171 : break;
172 : }
173 126 : case e_convert: {
174 126 : char *to_type = dump_sql_subtype(sql->ta, exp_subtype(e));
175 126 : mnstr_printf(fout, "%s[", to_type);
176 126 : exp_print(sql, fout, e->l, depth, refs, 0, 0, decorate);
177 126 : mnstr_printf(fout, "]");
178 126 : break;
179 : }
180 1097 : case e_atom: {
181 1097 : if (e->l) {
182 1055 : atom *a = e->l;
183 1055 : if (atom_type(a)->type->localtype == TYPE_ptr) {
184 2 : sql_table *t = a->data.val.pval;
185 2 : mnstr_printf(fout, "%s(\"%s\")",
186 2 : isMergeTable(t)?"merge table":
187 2 : isReplicaTable(t)?"replica table":"table",
188 2 : dump_escape_ident(sql->ta, t->base.name));
189 : } else {
190 1053 : char *t = dump_sql_subtype(sql->ta, atom_type(a));
191 1053 : if (a->isnull)
192 58 : mnstr_printf(fout, "%s NULL", t);
193 : else {
194 995 : char *s = ATOMformat(a->data.vtype, VALptr(&a->data));
195 995 : if (s && *s == '"')
196 131 : mnstr_printf(fout, "%s %s", t, s);
197 864 : else if (s)
198 864 : mnstr_printf(fout, "%s \"%s\"", t, s);
199 995 : GDKfree(s);
200 : }
201 : }
202 : } else { /* variables */
203 42 : if (e->r) { /* named parameters and declared variables */
204 22 : sql_var_name *vname = (sql_var_name*) e->r;
205 22 : if (vname->sname)
206 3 : mnstr_printf(fout, "\"%s\".", dump_escape_ident(sql->ta, vname->sname));
207 22 : mnstr_printf(fout, "\"%s\"", dump_escape_ident(sql->ta, vname->name));
208 20 : } else if (e->f) { /* values list */
209 20 : list *l = e->f;
210 20 : exps_print(sql, fout, l, depth, refs, 0, 0, decorate);
211 : } else { /* numbered arguments */
212 0 : mnstr_printf(fout, "A%u", e->flag);
213 : }
214 : }
215 : } break;
216 309 : case e_func: {
217 309 : sql_subfunc *f = e->f;
218 309 : mnstr_printf(fout, "\"%s\".\"%s\"",
219 309 : f->func->s?dump_escape_ident(sql->ta, f->func->s->base.name):"sys",
220 309 : dump_escape_ident(sql->ta, f->func->base.name));
221 309 : exps_print(sql, fout, e->l, depth, refs, 0, 1, decorate);
222 309 : if (e->r) { /* list of optional lists */
223 0 : list *l = e->r;
224 0 : for(node *n = l->h; n; n = n->next)
225 0 : exps_print(sql, fout, n->data, depth, refs, 0, 1, decorate);
226 : }
227 309 : if (e->flag && is_compare_func(f))
228 0 : mnstr_printf(fout, " %s", e->flag==1?"ANY":"ALL");
229 : } break;
230 86 : case e_aggr: {
231 86 : sql_subfunc *a = e->f;
232 86 : mnstr_printf(fout, "\"%s\".\"%s\"",
233 86 : a->func->s?dump_escape_ident(sql->ta, a->func->s->base.name):"sys",
234 86 : dump_escape_ident(sql->ta, a->func->base.name));
235 86 : if (need_distinct(e))
236 4 : mnstr_printf(fout, " unique ");
237 86 : if (need_no_nil(e))
238 35 : mnstr_printf(fout, " no nil ");
239 86 : if (zero_if_empty(e))
240 0 : mnstr_printf(fout, " zero if empty ");
241 86 : if (e->l)
242 39 : exps_print(sql, fout, e->l, depth, refs, 0, 1, decorate);
243 : else
244 47 : mnstr_printf(fout, "()");
245 : } break;
246 6003 : case e_column: {
247 6003 : if (is_freevar(e))
248 0 : mnstr_printf(fout, "!!!FREE!!! ");
249 6003 : if (e->l)
250 5905 : mnstr_printf(fout, "\"%s\".", dump_escape_ident(sql->ta, (char*)e->l));
251 6003 : mnstr_printf(fout, "\"%s\"", dump_escape_ident(sql->ta, (char*)e->r));
252 6003 : if (exp_relname(e) && exp_name(e) && e->l && e->r &&
253 5873 : strcmp(exp_relname(e), e->l) == 0 &&
254 4133 : strcmp(exp_name(e), e->r) == 0)
255 6003 : alias = 0;
256 6003 : if(!exp_relname(e) && exp_name(e) && !e->l && strcmp(exp_name(e), e->r)==0)
257 75 : alias = 0;
258 : } break;
259 554 : case e_cmp:
260 554 : if (e->flag == cmp_in || e->flag == cmp_notin) {
261 33 : mnstr_printf(fout, "(");
262 33 : exp_print(sql, fout, e->l, depth+1, refs, 0, 0, decorate);
263 33 : mnstr_printf(fout, ")");
264 33 : if (is_anti(e))
265 0 : mnstr_printf(fout, " !");
266 33 : cmp_print(sql, fout, e->flag);
267 33 : exps_print(sql, fout, e->r, depth, refs, 0, 1, decorate);
268 521 : } else if (e->flag == cmp_or) {
269 39 : exps_print(sql, fout, e->l, depth, refs, 0, 1, decorate);
270 39 : if (is_anti(e))
271 0 : mnstr_printf(fout, " !");
272 39 : cmp_print(sql, fout, e->flag);
273 39 : exps_print(sql, fout, e->r, depth, refs, 0, 1, decorate);
274 482 : } else if (e->flag == cmp_filter) {
275 14 : sql_subfunc *f = e->f;
276 :
277 14 : exps_print(sql, fout, e->l, depth, refs, 0, 1, decorate);
278 14 : if (is_anti(e))
279 2 : mnstr_printf(fout, " !");
280 14 : mnstr_printf(fout, " FILTER \"%s\".\"%s\"",
281 14 : f->func->s?dump_escape_ident(sql->ta, f->func->s->base.name):"sys",
282 14 : dump_escape_ident(sql->ta, f->func->base.name));
283 14 : exps_print(sql, fout, e->r, depth, refs, 0, 1, decorate);
284 468 : } else if (e->f) {
285 65 : mnstr_printf(fout, "(");
286 65 : exp_print(sql, fout, e->r, depth+1, refs, 0, 0, decorate);
287 65 : mnstr_printf(fout, ")");
288 65 : if (is_anti(e))
289 6 : mnstr_printf(fout, " !");
290 65 : cmp_print(sql, fout, swap_compare(range2lcompare(e->flag)));
291 65 : mnstr_printf(fout, "(");
292 65 : exp_print(sql, fout, e->l, depth+1, refs, 0, 0, decorate);
293 65 : mnstr_printf(fout, ")");
294 65 : if (is_anti(e))
295 6 : mnstr_printf(fout, " !");
296 65 : cmp_print(sql, fout, range2rcompare(e->flag));
297 65 : mnstr_printf(fout, "(");
298 65 : exp_print(sql, fout, e->f, depth+1, refs, 0, 0, decorate);
299 65 : mnstr_printf(fout, ")");
300 65 : if (is_symmetric(e))
301 1 : mnstr_printf(fout, " SYM");
302 : } else {
303 403 : mnstr_printf(fout, "(");
304 403 : exp_print(sql, fout, e->l, depth+1, refs, 0, 0, decorate);
305 403 : mnstr_printf(fout, ")");
306 403 : if (is_anti(e))
307 12 : mnstr_printf(fout, " !");
308 403 : if (is_semantics(e))
309 30 : mnstr_printf(fout, " *");
310 403 : if (is_any(e))
311 2 : mnstr_printf(fout, " +");
312 403 : cmp_print(sql, fout, e->flag);
313 :
314 403 : mnstr_printf(fout, "(");
315 403 : exp_print(sql, fout, e->r, depth+1, refs, 0, 0, decorate);
316 403 : mnstr_printf(fout, ")");
317 : }
318 : break;
319 8175 : default:
320 8175 : ;
321 : }
322 8175 : if (e->type != e_atom && e->type != e_cmp && is_ascending(e))
323 90 : mnstr_printf(fout, " ASC");
324 8175 : if (e->type != e_atom && e->type != e_cmp && nulls_last(e))
325 24 : mnstr_printf(fout, " NULLS LAST");
326 8175 : if (e->type != e_atom && e->type != e_cmp && !has_nil(e))
327 2021 : mnstr_printf(fout, " NOT NULL");
328 8175 : if (e->type != e_atom && e->type != e_cmp && is_unique(e))
329 1320 : mnstr_printf(fout, " UNIQUE");
330 : /* don't show properties on value lists */
331 8175 : if (decorate && e->p && e->type != e_atom && !exp_is_atom(e)) {
332 8646 : for (prop *p = e->p; p; p = p->p) {
333 : /* Don't show min/max/unique est on atoms, or when running tests with forcemito */
334 6263 : if ((ATOMIC_GET(&GDKdebug) & FORCEMITOMASK) == 0 ||
335 6263 : (p->kind != PROP_MIN && p->kind != PROP_MAX && p->kind != PROP_NUNIQUES)) {
336 482 : char *pv = propvalue2string(sql->ta, p);
337 482 : mnstr_printf(fout, " %s %s", propkind2string(p), pv);
338 : }
339 : }
340 : }
341 8175 : if (exp_name(e) && alias) {
342 2158 : mnstr_printf(fout, " as ");
343 2158 : if (exp_relname(e))
344 2081 : mnstr_printf(fout, "\"%s\".", dump_escape_ident(sql->ta, exp_relname(e)));
345 2158 : mnstr_printf(fout, "\"%s\"", dump_escape_ident(sql->ta, exp_name(e)));
346 : }
347 8175 : if (comma)
348 4236 : mnstr_printf(fout, ", ");
349 : }
350 :
351 : static void
352 2879 : exps_print(mvc *sql, stream *fout, list *exps, int depth, list *refs, int alias, int brackets, int decorate)
353 : {
354 2879 : node *en;
355 :
356 2879 : if (brackets)
357 487 : mnstr_printf(fout, "(");
358 : else
359 2392 : mnstr_printf(fout, " [ ");
360 2879 : if (exps)
361 9786 : for (en = exps->h; en; en = en->next)
362 7007 : exp_print(sql, fout, en->data, depth+1, refs, (en->next!=NULL), alias, decorate);
363 2879 : if (brackets)
364 487 : mnstr_printf(fout, ")");
365 : else
366 2392 : mnstr_printf(fout, " ]");
367 2879 : }
368 :
369 : static int
370 10 : find_ref( list *refs, sql_rel *rel )
371 : {
372 10 : node *n;
373 10 : int nr = 1;
374 :
375 14 : for(n=refs->h; n; n = n->next, nr++){
376 12 : if (n->data == rel)
377 : return nr;
378 : }
379 : return 0;
380 : }
381 :
382 : static void
383 2170 : rel_print_rel(mvc *sql, stream *fout, sql_rel *rel, int depth, list *refs, int decorate)
384 : {
385 2170 : char *r = NULL;
386 :
387 2170 : if (!rel)
388 : return;
389 :
390 2170 : if (rel_is_ref(rel)) {
391 2 : int nr = list_length(refs) + 1;
392 2 : int cnt = rel->ref.refcnt;
393 2 : mnstr_printf(fout, "\n%cREF %d (%d)", decorate?'=':' ', nr, cnt);
394 : }
395 :
396 2170 : print_indent(sql, fout, depth, decorate);
397 :
398 2170 : if (is_single(rel))
399 7 : mnstr_printf(fout, "single ");
400 :
401 2170 : switch (rel->op) {
402 701 : case op_basetable: {
403 701 : sql_table *t = rel->l;
404 701 : const char *sname = t->s ? t->s->base.name : NULL; /* All tables, but declared ones on the stack have schema */
405 701 : const char *tname = t->base.name;
406 :
407 701 : if (isRemote(t)) {
408 215 : const char *uri = t->query;
409 :
410 215 : sname = mapiuri_schema( uri, sql->sa, sname);
411 215 : tname = mapiuri_table( uri, sql->sa, tname);
412 : }
413 701 : if (sname)
414 1402 : mnstr_printf(fout, "%s(\"%s\".\"%s\")",
415 701 : isRemote(t)&&decorate?"REMOTE":
416 682 : isReplicaTable(t)?"REPLICA":"table",
417 : dump_escape_ident(sql->ta, sname), dump_escape_ident(sql->ta, tname));
418 : else
419 0 : mnstr_printf(fout, "%s(\"%s\")",
420 0 : isRemote(t)&&decorate?"REMOTE":
421 0 : isReplicaTable(t)?"REPLICA":"table",
422 : dump_escape_ident(sql->ta, tname));
423 701 : if (rel->exps)
424 701 : exps_print(sql, fout, rel->exps, depth, refs, 1, 0, decorate);
425 : else
426 0 : rel_base_dump_exps(fout, rel);
427 : } break;
428 20 : case op_table:
429 20 : mnstr_printf(fout, "table (");
430 :
431 20 : if (rel->r)
432 8 : exp_print(sql, fout, rel->r, depth, refs, 1, 0, decorate);
433 20 : if (rel->l) {
434 17 : if (rel->flag == TRIGGER_WRAPPER)
435 0 : mnstr_printf(fout, "rel_dump not yet implemented for trigger input");
436 : else
437 17 : rel_print_rel(sql, fout, rel->l, depth+1, refs, decorate);
438 : }
439 20 : print_indent(sql, fout, depth, decorate);
440 20 : mnstr_printf(fout, ")");
441 20 : if (rel->exps)
442 20 : exps_print(sql, fout, rel->exps, depth, refs, 1, 0, decorate);
443 : break;
444 2 : case op_ddl:
445 2 : mnstr_printf(fout, "ddl");
446 2 : if (rel->l)
447 0 : rel_print_rel(sql, fout, rel->l, depth+1, refs, decorate);
448 2 : if (rel->r)
449 0 : rel_print_rel(sql, fout, rel->r, depth+1, refs, decorate);
450 2 : if (rel->exps && (rel->flag == ddl_psm || rel->flag == ddl_exception || rel->flag == ddl_list))
451 0 : exps_print(sql, fout, rel->exps, depth, refs, 1, 0, decorate);
452 : break;
453 290 : case op_join:
454 : case op_left:
455 : case op_right:
456 : case op_full:
457 : case op_semi:
458 : case op_anti:
459 : case op_union:
460 : case op_inter:
461 : case op_except:
462 290 : r = "join";
463 290 : if (rel->op == op_left)
464 43 : r = rel->attr?"left outer group join":"left outer join";
465 : else if (rel->op == op_right)
466 : r = "right outer join";
467 : else if (rel->op == op_full)
468 : r = "full outer join";
469 : else if (rel->op == op_semi)
470 : r = "semijoin";
471 : else if (rel->op == op_anti)
472 : r = "antijoin";
473 : else if (rel->op == op_union)
474 : r = "union";
475 : else if (rel->op == op_inter)
476 : r = "intersect";
477 : else if (rel->op == op_except)
478 : r = "except";
479 175 : else if (rel->op == op_join) {
480 175 : if (list_empty(rel->exps))
481 26 : r = rel->attr?"group crossproduct":"crossproduct";
482 : else
483 149 : r = rel->attr?"group join":"join";
484 : }
485 :
486 290 : if (is_dependent(rel))
487 0 : mnstr_printf(fout, "dependent ");
488 290 : if (need_distinct(rel))
489 13 : mnstr_printf(fout, "distinct ");
490 290 : mnstr_printf(fout, "%s (", r);
491 290 : if (rel->l) {
492 290 : if (rel_is_ref(rel->l)) {
493 2 : int nr = find_ref(refs, rel->l);
494 2 : print_indent(sql, fout, depth+1, decorate);
495 2 : mnstr_printf(fout, "& REF %d ", nr);
496 : } else
497 288 : rel_print_rel(sql, fout, rel->l, depth+1, refs, decorate);
498 : }
499 290 : mnstr_printf(fout, ",");
500 290 : if (rel->r) {
501 290 : if (rel_is_ref(rel->r)) {
502 0 : int nr = find_ref(refs, rel->r);
503 0 : print_indent(sql, fout, depth+1, decorate);
504 0 : mnstr_printf(fout, "& REF %d ", nr);
505 : } else
506 290 : rel_print_rel(sql, fout, rel->r, depth+1, refs, decorate);
507 : }
508 290 : print_indent(sql, fout, depth, decorate);
509 290 : mnstr_printf(fout, ")");
510 290 : exps_print(sql, fout, rel->exps, depth, refs, 1, 0, decorate);
511 290 : if (is_join(rel->op) && rel->attr) /* group joins */
512 2 : exps_print(sql, fout, rel->attr, depth, refs, 1, 0, decorate);
513 : break;
514 1150 : case op_project:
515 : case op_select:
516 : case op_groupby:
517 : case op_topn:
518 : case op_sample:
519 1150 : r = "project";
520 1150 : if (rel->op == op_select)
521 228 : r = "select";
522 1150 : if (rel->op == op_groupby)
523 116 : r = "group by";
524 1150 : if (rel->op == op_topn)
525 12 : r = "top N";
526 1150 : if (rel->op == op_sample)
527 0 : r = "sample";
528 :
529 1150 : if (rel->l) {
530 1087 : if (need_distinct(rel))
531 0 : mnstr_printf(fout, "distinct ");
532 1087 : mnstr_printf(fout, "%s (", r);
533 1087 : if (rel_is_ref(rel->l)) {
534 2 : int nr = find_ref(refs, rel->l);
535 2 : print_indent(sql, fout, depth+1, decorate);
536 2 : mnstr_printf(fout, "& REF %d ", nr);
537 : } else
538 1085 : rel_print_rel(sql, fout, rel->l, depth+1, refs, decorate);
539 1087 : print_indent(sql, fout, depth, decorate);
540 1087 : mnstr_printf(fout, ")");
541 : }
542 1150 : if (rel->op == op_groupby) /* group by columns */
543 116 : exps_print(sql, fout, rel->r, depth, refs, 1, 0, decorate);
544 1150 : exps_print(sql, fout, rel->exps, depth, refs, 1, 0, decorate);
545 1150 : if (rel->r && rel->op == op_project) /* order by columns */
546 92 : exps_print(sql, fout, rel->r, depth, refs, 1, 0, decorate);
547 : break;
548 7 : case op_insert:
549 : case op_update:
550 : case op_delete:
551 : case op_truncate:
552 : case op_merge: {
553 :
554 7 : if (rel->op == op_insert)
555 1 : mnstr_printf(fout, "insert(");
556 6 : else if (rel->op == op_update)
557 1 : mnstr_printf(fout, "update(");
558 5 : else if (rel->op == op_delete)
559 0 : mnstr_printf(fout, "delete(");
560 5 : else if (rel->op == op_merge)
561 0 : mnstr_printf(fout, "merge(");
562 5 : else if (rel->op == op_truncate) {
563 5 : assert(list_length(rel->exps) == 2);
564 5 : sql_exp *first = (sql_exp*) rel->exps->h->data, *second = (sql_exp*) rel->exps->h->next->data;
565 5 : int restart_sequences = ((atom*)first->l)->data.val.ival,
566 5 : drop_action = ((atom*)second->l)->data.val.ival;
567 13 : mnstr_printf(fout, "truncate %s identity, %s(", restart_sequences ? "restart" : "continue",
568 : drop_action ? "cascade" : "restrict");
569 : }
570 :
571 7 : if (rel->l) {
572 7 : if (rel_is_ref(rel->l)) {
573 0 : int nr = find_ref(refs, rel->l);
574 0 : print_indent(sql, fout, depth+1, decorate);
575 0 : mnstr_printf(fout, "& REF %d ", nr);
576 : } else
577 7 : rel_print_rel(sql, fout, rel->l, depth+1, refs, decorate);
578 : }
579 7 : if (rel->r) {
580 2 : if (rel_is_ref(rel->r)) {
581 0 : int nr = find_ref(refs, rel->r);
582 0 : print_indent(sql, fout, depth+1, decorate);
583 0 : mnstr_printf(fout, "& REF %d ", nr);
584 : } else
585 2 : rel_print_rel(sql, fout, rel->r, depth+1, refs, decorate);
586 : }
587 7 : print_indent(sql, fout, depth, decorate);
588 7 : mnstr_printf(fout, ")");
589 7 : if (rel->op != op_truncate && rel->op != op_merge && rel->exps)
590 1 : exps_print(sql, fout, rel->exps, depth, refs, 1, 0, decorate);
591 : } break;
592 : default:
593 0 : assert(0);
594 : }
595 2170 : if (decorate && rel->p) {
596 2936 : for (prop *p = rel->p; p; p = p->p) {
597 1468 : if (p->kind != PROP_COUNT || (ATOMIC_GET(&GDKdebug) & FORCEMITOMASK) == 0) {
598 12 : char *pv = propvalue2string(sql->ta, p);
599 12 : mnstr_printf(fout, " %s %s", propkind2string(p), pv);
600 : }
601 : }
602 : }
603 : }
604 :
605 : void
606 2148 : rel_print_refs(mvc *sql, stream* fout, sql_rel *rel, int depth, list *refs, int decorate)
607 : {
608 2148 : if (!rel)
609 : return;
610 2148 : switch (rel->op) {
611 : case op_basetable:
612 : case op_table:
613 : break;
614 2 : case op_ddl:
615 2 : if (rel->flag == ddl_list || rel->flag == ddl_exception) {
616 0 : if (rel->l) {
617 0 : rel_print_refs(sql, fout, rel->l, depth, refs, decorate);
618 0 : if (rel_is_ref(rel->l) && !find_ref(refs, rel->l)) {
619 0 : rel_print_rel(sql, fout, rel->l, depth, refs, decorate);
620 0 : list_append(refs, rel->l);
621 : }
622 : }
623 0 : if (rel->r) {
624 0 : rel_print_refs(sql, fout, rel->r, depth, refs, decorate);
625 0 : if (rel_is_ref(rel->r) && !find_ref(refs, rel->r)) {
626 0 : rel_print_rel(sql, fout, rel->r, depth, refs, decorate);
627 0 : list_append(refs, rel->r);
628 : }
629 : }
630 : }
631 : break;
632 289 : case op_join:
633 : case op_left:
634 : case op_right:
635 : case op_full:
636 : case op_semi:
637 : case op_anti:
638 : case op_union:
639 : case op_inter:
640 : case op_except:
641 289 : if (rel->l)
642 289 : rel_print_refs(sql, fout, rel->l, depth, refs, decorate);
643 289 : if (rel->r)
644 289 : rel_print_refs(sql, fout, rel->r, depth, refs, decorate);
645 292 : if (rel->l && rel_is_ref(rel->l) && !find_ref(refs, rel->l)) {
646 0 : rel_print_rel(sql, fout, rel->l, depth, refs, decorate);
647 0 : list_append(refs, rel->l);
648 : }
649 289 : if (rel->r && rel_is_ref(rel->r) && !find_ref(refs, rel->r)) {
650 0 : rel_print_rel(sql, fout, rel->r, depth, refs, decorate);
651 0 : list_append(refs, rel->r);
652 : }
653 : break;
654 1145 : case op_project:
655 : case op_select:
656 : case op_groupby:
657 : case op_topn:
658 : case op_sample:
659 1145 : if (rel->l)
660 1082 : rel_print_refs(sql, fout, rel->l, depth, refs, decorate);
661 1148 : if (rel->l && rel_is_ref(rel->l) && !find_ref(refs, rel->l)) {
662 2 : rel_print_rel(sql, fout, rel->l, depth, refs, decorate);
663 2 : list_append(refs, rel->l);
664 : }
665 : break;
666 7 : case op_insert:
667 : case op_update:
668 : case op_delete:
669 : case op_truncate:
670 : case op_merge:
671 7 : if (rel->l)
672 7 : rel_print_refs(sql, fout, rel->l, depth, refs, decorate);
673 7 : if (rel->l && rel_is_ref(rel->l) && !find_ref(refs, rel->l)) {
674 0 : rel_print_rel(sql, fout, rel->l, depth, refs, decorate);
675 0 : list_append(refs, rel->l);
676 : }
677 7 : if (rel->r)
678 2 : rel_print_refs(sql, fout, rel->r, depth, refs, decorate);
679 7 : if (rel->r && rel_is_ref(rel->r) && !find_ref(refs, rel->r)) {
680 0 : rel_print_rel(sql, fout, rel->r, depth, refs, decorate);
681 0 : list_append(refs, rel->r);
682 : }
683 : break;
684 : }
685 : }
686 :
687 : void
688 479 : rel_print_(mvc *sql, stream *fout, sql_rel *rel, int depth, list *refs, int decorate)
689 : {
690 479 : rel_print_rel(sql, fout, rel, depth, refs, decorate);
691 479 : if (sql->runs) {
692 0 : for (int i = 0 ; i < NSQLREWRITERS ; i++) {
693 0 : sql_optimizer_run *run = &(sql->runs[i]);
694 :
695 0 : if (run->name) { /* if name is set, then the optimizer did run */
696 0 : print_indent(sql, fout, depth, decorate);
697 0 : mnstr_printf(fout, "# %-36s %3d actions " LLFMT " usec",
698 : run->name, run->nchanges, run->time);
699 : }
700 : }
701 : }
702 479 : }
703 :
704 : static void
705 24549 : skipWS( char *r, int *pos)
706 : {
707 38275 : while(r[*pos] && (isspace((unsigned char) r[*pos]) || r[*pos] == '|'))
708 13726 : (*pos)++;
709 24549 : }
710 :
711 : static void
712 0 : skipUntilWS( char *r, int *pos)
713 : {
714 0 : while(r[*pos] && (!isspace((unsigned char) r[*pos]) || r[*pos] == '|'))
715 0 : (*pos)++;
716 0 : }
717 :
718 : static void
719 10477 : skipIdent( char *r, int *pos)
720 : {
721 10477 : if (r[*pos] == '"') {
722 9882 : (*pos)++;
723 56244 : while (r[*pos] && r[*pos] != '"') {
724 : /* We send escaped '"' and '\' characters */
725 46362 : if (r[*pos] == '\\' && (r[*pos + 1] == '"' || r[*pos + 1] == '\\'))
726 12 : (*pos)+=2;
727 : else
728 46350 : (*pos)++;
729 : }
730 : } else {
731 3010 : while(r[*pos] && (isalnum((unsigned char) r[*pos]) || r[*pos] == '_' || r[*pos] == '%'))
732 2415 : (*pos)++;
733 : }
734 10477 : }
735 :
736 : static void
737 10484 : convertIdent(char *r)
738 : {
739 10484 : int i = 0, j = 0;
740 59762 : while (r[i] && r[i] != '"') {
741 : /* We send escaped '"' and '\' characters */
742 49278 : if (r[i] == '\\' && (r[i + 1] == '"' || r[i + 1] == '\\')) {
743 12 : r[j++] = r[i + 1];
744 12 : i+=2;
745 : } else {
746 49266 : r[j++] = r[i++];
747 : }
748 : }
749 10484 : r[j] = '\0';
750 10484 : }
751 :
752 : static void
753 3190 : skipIdentOrSymbol( char *r, int *pos)
754 : {
755 3190 : if (r[*pos] == '"') {
756 3190 : skipIdent(r, pos);
757 : } else {
758 0 : while(r[*pos] && (isalnum((unsigned char) r[*pos]) ||
759 : r[*pos] == '=' ||
760 : r[*pos] == '_' || r[*pos] == '%' ||
761 : r[*pos] == '<' || r[*pos] == '>' ||
762 : r[*pos] == '/' || r[*pos] == '*' ||
763 : r[*pos] == '-' || r[*pos] == '+' ||
764 : r[*pos] == '~' || r[*pos] == '^' ))
765 0 : (*pos)++;
766 : }
767 3191 : }
768 :
769 : static int
770 415 : readInt( char *r, int *pos)
771 : {
772 415 : int res = 0;
773 :
774 1034 : while (isdigit((unsigned char) r[*pos])) {
775 619 : res *= 10;
776 619 : res += r[*pos]-'0';
777 619 : (*pos)++;
778 : }
779 415 : return res;
780 : }
781 :
782 : static void *
783 303 : readAtomString(int localtype, char *r, int *pos)
784 : {
785 303 : void *res = NULL;
786 303 : size_t nbytes = 0;
787 303 : int firstpos = 0, rtype = ATOMstorage(localtype) == TYPE_str ? TYPE_str : localtype;
788 :
789 : /* TODO I had issues with the 'external' flag on the JSONfromString function, maybe something is missing there? */
790 303 : assert(r[*pos] == '"'); /* skip first '"' */
791 303 : (*pos)++;
792 :
793 303 : firstpos = *pos;
794 303 : if (rtype == TYPE_str) /* string reads require double quotes at the beginning */
795 51 : firstpos--;
796 1217 : while (r[*pos] && r[*pos] != '"') { /* compute end of atom string */
797 914 : if (r[*pos] == '\\')
798 9 : (*pos)+=2;
799 : else
800 905 : (*pos)++;
801 : }
802 303 : if (!r[*pos])
803 : return NULL;
804 :
805 303 : assert(r[*pos] == '"'); /* skip second '"' */
806 303 : if (rtype != TYPE_str) /* string reads require double quotes at the end */
807 252 : r[*pos] = '\0';
808 303 : (*pos)++;
809 :
810 303 : if (ATOMfromstr(rtype, &res, &nbytes, r + firstpos, true) < 0) {
811 0 : GDKfree(res);
812 0 : return NULL;
813 : }
814 303 : return res;
815 : }
816 :
817 : static sql_exp* exp_read(mvc *sql, sql_rel *lrel, sql_rel *rrel, list *top_exps, char *r, int *pos, int grp);
818 :
819 : static sql_exp*
820 7408 : read_prop(mvc *sql, sql_exp *exp, char *r, int *pos, bool *found)
821 : {
822 : /* PROPs */
823 7408 : if (strncmp(r+*pos, "JOINIDX", strlen("JOINIDX")) == 0) {
824 0 : char *sname, *tname, *iname;
825 0 : sql_schema *s = NULL;
826 0 : prop *p;
827 :
828 0 : (*pos)+= (int) strlen("JOINIDX");
829 0 : skipWS(r, pos);
830 : /* schema.table.index */
831 0 : sname = r+*pos + 1;
832 0 : skipIdent(r,pos);
833 0 : convertIdent(sname);
834 0 : (*pos)++;
835 0 : if (r[*pos] != '.')
836 0 : return sql_error(sql, -1, SQLSTATE(42000) "JOINIDX: missing '.'\n");
837 0 : (*pos)++;
838 0 : tname = r+*pos + 1;
839 0 : skipIdent(r,pos);
840 0 : convertIdent(tname);
841 0 : (*pos)++;
842 0 : if (r[*pos] != '.')
843 0 : return sql_error(sql, -1, SQLSTATE(42000) "JOINIDX: missing '.'\n");
844 0 : (*pos)++;
845 0 : iname = r+*pos + 1;
846 0 : skipIdent(r,pos);
847 0 : convertIdent(iname);
848 0 : (*pos)++;
849 :
850 0 : (void) tname;
851 0 : s = mvc_bind_schema(sql, sname);
852 0 : if (sname && !s)
853 0 : return sql_error(sql, -1, SQLSTATE(42000) "Schema %s missing\n", sname);
854 0 : if (!find_prop(exp->p, PROP_JOINIDX)) {
855 0 : p = exp->p = prop_create(sql->sa, PROP_JOINIDX, exp->p);
856 0 : if (!(p->value.pval = mvc_bind_idx(sql, s, iname)))
857 0 : return sql_error(sql, -1, SQLSTATE(42000) "Index %s missing\n", iname);
858 : }
859 0 : skipWS(r,pos);
860 0 : if (found)
861 0 : *found = true;
862 : }
863 : return exp;
864 : }
865 :
866 : static list*
867 1019 : read_exps(mvc *sql, sql_rel *lrel, sql_rel *rrel, list *top_exps, char *r, int *pos, char bracket, int grp, int top)
868 : {
869 1019 : list *exps = new_exp_list(sql->sa);
870 1018 : sql_exp *e;
871 1018 : char ebracket = (bracket == '[')?']':')';
872 :
873 1018 : if (r[*pos] == bracket) {
874 1018 : skipWS( r, pos);
875 :
876 1018 : (*pos)++;
877 1018 : skipWS( r, pos);
878 1363 : e = exp_read(sql, lrel, rrel, top ? exps : top_exps, r, pos, grp);
879 1018 : if (!e && r[*pos] != ebracket) {
880 1 : return sql_error(sql, -1, SQLSTATE(42000) "Missing closing %c\n", ebracket);
881 85 : } else if (!e) {
882 85 : (*pos)++;
883 85 : skipWS(r, pos);
884 85 : return sql->errstr[0] ? NULL : exps; /* A function call might not have any input expressions, so return empty exps on that case */
885 : }
886 932 : append(exps, e);
887 932 : skipWS( r, pos);
888 932 : if (!read_prop(sql, e, r, pos, NULL))
889 : return NULL;
890 3650 : while (r[*pos] == ',') {
891 :
892 2718 : (*pos)++;
893 2718 : skipWS( r, pos);
894 2718 : e = exp_read(sql, lrel, rrel, top ? exps : top_exps, r, pos, grp);
895 2718 : if (!e)
896 : return NULL;
897 2718 : append(exps, e);
898 2718 : skipWS( r, pos);
899 2718 : if (!read_prop(sql, e, r, pos, NULL))
900 : return NULL;
901 : }
902 932 : if (r[*pos] != ebracket)
903 0 : return sql_error(sql, -1, SQLSTATE(42000) "Missing closing %c\n", ebracket);
904 932 : (*pos)++;
905 932 : skipWS( r, pos);
906 : }
907 : return exps;
908 : }
909 :
910 : static sql_exp*
911 0 : exp_read_min_or_max(mvc *sql, sql_exp *exp, char *r, int *pos, const char *prop_str, rel_prop kind)
912 : {
913 0 : atom *a;
914 0 : sql_subtype *tpe = exp_subtype(exp);
915 :
916 0 : (*pos)+= (int) strlen(prop_str);
917 0 : skipWS(r, pos);
918 :
919 0 : if (strncmp(r+*pos, "NULL", strlen("NULL")) == 0) {
920 0 : (*pos)+= (int) strlen("NULL");
921 0 : a = atom_general(sql->sa, tpe, NULL);
922 : } else {
923 0 : void *ptr = readAtomString(tpe->type->localtype, r, pos);
924 0 : if (!ptr)
925 0 : return sql_error(sql, -1, SQLSTATE(42000) "Invalid atom string\n");
926 0 : a = atom_general_ptr(sql->sa, tpe, ptr);
927 0 : GDKfree(ptr);
928 : }
929 0 : if (!find_prop(exp->p, kind)) {
930 0 : prop *p = exp->p = prop_create(sql->sa, kind, exp->p);
931 0 : p->value.pval = a;
932 : }
933 0 : skipWS(r, pos);
934 0 : return exp;
935 : }
936 :
937 : static sql_exp*
938 0 : exp_read_nuniques(mvc *sql, sql_exp *exp, char *r, int *pos)
939 : {
940 0 : void *ptr = NULL;
941 0 : size_t nbytes = 0;
942 0 : ssize_t res = 0;
943 0 : sql_subtype *tpe = sql_bind_localtype("dbl");
944 :
945 0 : (*pos)+= (int) strlen("NUNIQUES");
946 0 : skipWS(r, pos);
947 :
948 0 : if ((res = ATOMfromstr(tpe->type->localtype, &ptr, &nbytes, r + *pos, true)) < 0) {
949 0 : GDKfree(ptr);
950 0 : return sql_error(sql, -1, SQLSTATE(42000) "Invalid atom string\n");
951 : }
952 :
953 0 : if (!find_prop(exp->p, PROP_NUNIQUES)) {
954 0 : prop *p = exp->p = prop_create(sql->sa, PROP_NUNIQUES, exp->p);
955 0 : p->value.dval = *(dbl*)ptr;
956 : }
957 0 : (*pos) += (int) res; /* it should always fit */
958 0 : GDKfree(ptr);
959 0 : skipWS(r, pos);
960 0 : return exp;
961 : }
962 :
963 : static sql_exp*
964 3758 : read_exp_properties(mvc *sql, sql_exp *exp, char *r, int *pos)
965 : {
966 3758 : bool found = true;
967 7516 : while (found) {
968 3758 : found = false;
969 :
970 3758 : if (strncmp(r+*pos, "COUNT", strlen("COUNT")) == 0) {
971 0 : (*pos)+= (int) strlen("COUNT");
972 0 : if (!find_prop(exp->p, PROP_COUNT))
973 0 : exp->p = prop_create(sql->sa, PROP_COUNT, exp->p);
974 0 : skipWS(r,pos);
975 0 : found = true;
976 3758 : } else if (strncmp(r+*pos, "HASHIDX", strlen("HASHIDX")) == 0) {
977 0 : (*pos)+= (int) strlen("HASHIDX");
978 0 : if (!find_prop(exp->p, PROP_HASHIDX))
979 0 : exp->p = prop_create(sql->sa, PROP_HASHIDX, exp->p);
980 0 : skipWS(r,pos);
981 0 : found = true;
982 3758 : } else if (strncmp(r+*pos, "HASHCOL", strlen("HASHCOL")) == 0) {
983 0 : (*pos)+= (int) strlen("HASHCOL");
984 0 : if (!find_prop(exp->p, PROP_HASHCOL))
985 0 : exp->p = prop_create(sql->sa, PROP_HASHCOL, exp->p);
986 0 : skipWS(r,pos);
987 0 : found = true;
988 3758 : } else if (strncmp(r+*pos, "MIN", strlen("MIN")) == 0) {
989 0 : if (!exp_read_min_or_max(sql, exp, r, pos, "MIN", PROP_MIN))
990 : return NULL;
991 0 : found = true;
992 3758 : } else if (strncmp(r+*pos, "MAX", strlen("MAX")) == 0) {
993 0 : if (!exp_read_min_or_max(sql, exp, r, pos, "MAX", PROP_MAX))
994 : return NULL;
995 0 : found = true;
996 3758 : } else if (strncmp(r+*pos, "NUNIQUES", strlen("NUNIQUES")) == 0) {
997 0 : if (!exp_read_nuniques(sql, exp, r, pos))
998 : return NULL;
999 0 : found = true;
1000 : }
1001 3758 : if (!read_prop(sql, exp, r, pos, &found))
1002 : return NULL;
1003 : }
1004 : return exp;
1005 : }
1006 :
1007 : static sql_exp*
1008 327 : parse_atom(mvc *sql, char *r, int *pos, sql_subtype *tpe)
1009 : {
1010 327 : if (strncmp(r+*pos, "NULL", strlen("NULL")) == 0) {
1011 24 : (*pos)+= (int) strlen("NULL");
1012 24 : return exp_atom(sql->sa, atom_general(sql->sa, tpe, NULL));
1013 : } else {
1014 303 : void *ptr = readAtomString(tpe->type->localtype, r, pos);
1015 303 : if (!ptr)
1016 0 : return sql_error(sql, -1, SQLSTATE(42000) "Invalid atom string\n");
1017 303 : sql_exp *res = exp_atom(sql->sa, atom_general_ptr(sql->sa, tpe, ptr));
1018 303 : GDKfree(ptr);
1019 303 : return res;
1020 : }
1021 : }
1022 :
1023 : static sql_exp*
1024 1 : function_error_string(mvc *sql, const char *schema, const char *fname, list *exps, bool found, sql_ftype type)
1025 : {
1026 1 : char *arg_list = NULL, *F = NULL, *fn = NULL;
1027 :
1028 1 : FUNC_TYPE_STR(type, F, fn)
1029 :
1030 1 : (void) F;
1031 1 : if (!list_empty(exps)) {
1032 2 : for (node *n = exps->h; n ; n = n->next) {
1033 1 : sql_subtype *t = exp_subtype(n->data);
1034 1 : char *tpe = t ? sql_subtype_string(sql->ta, t) : "?";
1035 :
1036 1 : if (arg_list) {
1037 0 : arg_list = sa_message(sql->ta, "%s, %s", arg_list, tpe);
1038 : } else {
1039 : arg_list = tpe;
1040 : }
1041 : }
1042 : }
1043 2 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42000) "%s %s %s%s%s'%s'(%s)",
1044 : found ? "Insufficient privileges for" : "No such", fn, schema ? "'":"", schema ? schema : "",
1045 : schema ? "'.":"", fname, arg_list ? arg_list : "");
1046 : }
1047 :
1048 : static unsigned int /* keep updating the label count */
1049 3060 : try_update_label_count(mvc *sql, const char *label)
1050 : {
1051 3060 : if (label && label[0] == '%' && isdigit((unsigned char) label[1])) {
1052 392 : char *eptr = NULL;
1053 392 : unsigned int value = (unsigned int) strtol(label + 1, &eptr, 10);
1054 392 : if (eptr && eptr[0] == '\0') {
1055 392 : sql->label = MAX(sql->label, value);
1056 392 : return value;
1057 : }
1058 : }
1059 : return 0;
1060 : }
1061 :
1062 : static sql_exp*
1063 3840 : exp_read(mvc *sql, sql_rel *lrel, sql_rel *rrel, list *top_exps, char *r, int *pos, int grp)
1064 : {
1065 3840 : int old, d=0, s=0, unique = 0, no_nils = 0, quote = 0, zero_if_empty = 0;
1066 3840 : char *tname = NULL, *cname = NULL, *var_cname = NULL, *e, *b = r + *pos;
1067 3840 : sql_exp *exp = NULL;
1068 3840 : list *exps = NULL;
1069 3840 : sql_type *t = NULL;
1070 3840 : sql_subtype tpe;
1071 :
1072 3840 : quote = (r[*pos] == '"');
1073 3840 : b += quote;
1074 3840 : skipIdent(r, pos);
1075 3840 : e = r+*pos;
1076 3840 : (*pos) += quote;
1077 3840 : skipWS(r, pos);
1078 3842 : switch(r[*pos]) {
1079 3191 : case '.':
1080 3191 : *e = 0;
1081 3191 : (*pos)++;
1082 3191 : tname = b;
1083 3191 : convertIdent(tname);
1084 3190 : cname = r + *pos + quote;
1085 3190 : skipIdentOrSymbol(r, pos);
1086 3192 : e = r+*pos;
1087 3192 : if (quote) {
1088 3192 : old = ' ';
1089 3192 : convertIdent(cname);
1090 : } else {
1091 0 : old = *e;
1092 : }
1093 3191 : *e = 0;
1094 :
1095 3191 : tname = sa_strdup(sql->sa, tname);
1096 3192 : cname = sa_strdup(sql->sa, cname);
1097 3190 : *e = old;
1098 3190 : skipWS(r, pos);
1099 3190 : if (r[*pos] != '(') { /* if there's a function/aggregate call next don't attempt to bind columns */
1100 3025 : if (top_exps) {
1101 3025 : exp = exps_bind_column2(top_exps, tname, cname, NULL);
1102 3026 : if (exp)
1103 51 : exp = exp_alias_or_copy(sql, tname, cname, lrel, exp);
1104 : }
1105 3026 : if (!exp && lrel) {
1106 2975 : exp = rel_bind_column2(sql, lrel, tname, cname, 0);
1107 2975 : if (!exp && rrel)
1108 13 : exp = rel_bind_column2(sql, rrel, tname, cname, 0);
1109 51 : } else if (!exp) {
1110 0 : exp = exp_column(sql->sa, tname, cname, NULL, CARD_ATOM, 1, 0, cname[0] == '%');
1111 : }
1112 : }
1113 : break;
1114 : /* atom */
1115 463 : case '(':
1116 463 : if (b == (r+*pos)) { /* comparison expression */
1117 80 : int anti = 0, sym = 0, semantics = 0, any = 0;
1118 80 : comp_type ctype = cmp_all, ctype2 = cmp_all;
1119 80 : list *lexps = NULL, *rexps = NULL, *fexps = NULL;
1120 80 : char *sname = NULL, *fname = NULL;
1121 :
1122 80 : if (!(lexps = read_exps(sql, lrel, rrel, top_exps, r, pos, '(', 0, 0)))
1123 : return NULL;
1124 80 : skipWS(r, pos);
1125 80 : if (r[*pos] == '!') {
1126 5 : anti = 1;
1127 5 : (*pos)++;
1128 5 : skipWS(r, pos);
1129 : }
1130 80 : if (r[*pos] == '*') {
1131 5 : semantics = 1;
1132 5 : (*pos)++;
1133 5 : skipWS(r, pos);
1134 : }
1135 80 : if (r[*pos] == '+') {
1136 1 : any = 1;
1137 1 : (*pos)++;
1138 1 : skipWS(r, pos);
1139 : }
1140 :
1141 80 : switch(r[*pos]) {
1142 1 : case 'n':
1143 1 : if (strncmp(r+*pos, "notin", strlen("notin")) == 0) {
1144 1 : (*pos)+= (int) strlen("notin");
1145 1 : ctype = cmp_notin;
1146 : }
1147 : break;
1148 2 : case 'F':
1149 2 : if (strncmp(r+*pos, "FILTER", strlen("FILTER")) == 0) {
1150 2 : (*pos)+= (int) strlen("FILTER");
1151 2 : ctype = cmp_filter;
1152 2 : skipWS(r, pos);
1153 2 : sname = r+*pos + 1;
1154 2 : skipIdent(r, pos);
1155 2 : convertIdent(sname);
1156 2 : (*pos)+=2;
1157 2 : fname = r+*pos + 1;
1158 2 : skipIdent(r, pos);
1159 2 : convertIdent(fname);
1160 2 : (*pos)++;
1161 : }
1162 : break;
1163 1 : case 'i':
1164 1 : if (strncmp(r+*pos, "in", strlen("in")) == 0) {
1165 1 : (*pos)+= (int) strlen("in");
1166 1 : ctype = cmp_in;
1167 : }
1168 : break;
1169 4 : case 'o':
1170 4 : if (strncmp(r+*pos, "or", strlen("or")) == 0) {
1171 4 : (*pos)+= (int) strlen("or");
1172 4 : ctype = cmp_or;
1173 : }
1174 : break;
1175 0 : case '!':
1176 0 : ctype = cmp_notequal;
1177 0 : (*pos)++;
1178 0 : if (r[(*pos)] == '=')
1179 0 : (*pos)++;
1180 : break;
1181 45 : case '=':
1182 45 : ctype = cmp_equal;
1183 45 : (*pos)++;
1184 45 : break;
1185 22 : case '<':
1186 22 : ctype = cmp_lt;
1187 22 : (*pos)++;
1188 22 : if (r[(*pos)] == '=') {
1189 15 : ctype = cmp_lte;
1190 15 : (*pos)++;
1191 : }
1192 : break;
1193 5 : case '>':
1194 5 : ctype = cmp_gt;
1195 5 : (*pos)++;
1196 5 : if (r[(*pos)] == '=') {
1197 3 : ctype = cmp_gte;
1198 3 : (*pos)++;
1199 : }
1200 : break;
1201 0 : default:
1202 0 : return sql_error(sql, -1, SQLSTATE(42000) "Type: missing comparison type\n");
1203 : }
1204 :
1205 80 : skipWS(r, pos);
1206 80 : if (!(rexps = read_exps(sql, lrel, rrel, top_exps, r, pos, '(', 0, 0)))
1207 : return NULL;
1208 80 : skipWS(r, pos);
1209 :
1210 80 : switch (ctype) {
1211 72 : case cmp_gt:
1212 : case cmp_gte:
1213 : case cmp_lte:
1214 : case cmp_lt:
1215 : case cmp_equal:
1216 : case cmp_notequal:
1217 72 : if (r[*pos] == '!' || r[*pos] == '<' || r[*pos] == '>') { /* BETWEEN case */
1218 17 : if (r[*pos] == '!') { /* ignore next anti */
1219 2 : (*pos)++;
1220 2 : skipWS(r, pos);
1221 : }
1222 17 : switch(r[*pos]) {
1223 17 : case '<':
1224 17 : ctype2 = cmp_lt;
1225 17 : (*pos)++;
1226 17 : if (r[(*pos)] == '=') {
1227 14 : ctype2 = cmp_lte;
1228 14 : (*pos)++;
1229 : }
1230 : break;
1231 0 : case '>':
1232 0 : ctype2 = cmp_gt;
1233 0 : (*pos)++;
1234 0 : if (r[(*pos)] == '=') {
1235 0 : ctype2 = cmp_gte;
1236 0 : (*pos)++;
1237 : }
1238 : break;
1239 0 : default:
1240 0 : return sql_error(sql, -1, SQLSTATE(42000) "Type: missing comparison type\n");
1241 : }
1242 17 : skipWS(r, pos);
1243 17 : if (!(fexps = read_exps(sql, lrel, rrel, top_exps, r, pos, '(', 0, 0)))
1244 : return NULL;
1245 17 : skipWS(r, pos);
1246 17 : if (strncmp(r+*pos, "SYM", strlen("SYM")) == 0) {
1247 1 : (*pos)+= (int) strlen("SYM");
1248 1 : skipWS(r, pos);
1249 1 : sym = 1;
1250 : }
1251 17 : exp = exp_compare2(sql->sa, rexps->h->data, lexps->h->data, fexps->h->data, compare2range(swap_compare(ctype), ctype2), sym);
1252 : } else {
1253 55 : exp = exp_compare(sql->sa, lexps->h->data, rexps->h->data, ctype);
1254 55 : if (semantics)
1255 5 : set_semantics(exp);
1256 55 : if (any)
1257 1 : set_any(exp);
1258 : }
1259 72 : if (anti)
1260 5 : set_anti(exp);
1261 72 : assert(list_length(lexps) == 1 && list_length(rexps) == 1 && (!fexps || list_length(fexps) == 1));
1262 : break;
1263 2 : case cmp_in:
1264 : case cmp_notin:
1265 2 : assert(list_length(lexps) == 1);
1266 2 : exp = exp_in(sql->sa, lexps->h->data, rexps, ctype);
1267 2 : if (anti)
1268 0 : set_anti(exp);
1269 : break;
1270 2 : case cmp_filter: {
1271 2 : sql_subfunc *f = NULL;
1272 2 : list *tl = sa_list(sql->sa);
1273 :
1274 2 : if (!list_empty(lexps)) {
1275 4 : for (node *n = lexps->h; n; n = n->next){
1276 2 : sql_exp *e = n->data;
1277 :
1278 2 : list_append(tl, exp_subtype(e));
1279 : }
1280 : }
1281 2 : if (!list_empty(rexps)) {
1282 8 : for (node *n = rexps->h; n; n = n->next){
1283 6 : sql_exp *e = n->data;
1284 :
1285 6 : list_append(tl, exp_subtype(e));
1286 : }
1287 : }
1288 :
1289 2 : if (sname && !mvc_bind_schema(sql, sname))
1290 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(3F000) "No such schema '%s'\n", sname);
1291 2 : if (!(f = sql_bind_func_(sql, sname, fname, tl, F_FILT, true)))
1292 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42000) "Filter: missing function '%s'.'%s'\n", sname, fname);
1293 2 : if (!execute_priv(sql, f->func))
1294 0 : return sql_error(sql, -1, SQLSTATE(42000) "Filter: no privilege to call filter function '%s'.'%s'\n", sname, fname);
1295 2 : exp = exp_filter(sql->sa, lexps, rexps, f, anti);
1296 2 : } break;
1297 4 : case cmp_or:
1298 4 : exp = exp_or(sql->sa, lexps, rexps, anti);
1299 4 : break;
1300 0 : default:
1301 0 : return sql_error(sql, -1, SQLSTATE(42000) "Type: missing comparison type\n");
1302 : }
1303 : break;
1304 : }
1305 : /* fall through */
1306 : case '[':
1307 388 : tname = b;
1308 388 : if (tname && *tname == '[') { /* list of values */
1309 0 : if (!(exps = read_exps(sql, lrel, rrel, top_exps, r, pos, '[', 0, 0)))
1310 : return NULL;
1311 0 : exp = exp_values(sql->sa, exps);
1312 : } else {
1313 388 : old = *e;
1314 388 : *e = 0;
1315 388 : if (old != '[') {
1316 383 : (*pos)++;
1317 383 : d = readInt(r,pos);
1318 383 : if (r[*pos] != ')' && r[*pos] != ',')
1319 0 : return sql_error(sql, -1, SQLSTATE(42000) "Type: missing ')' or ','\n");
1320 383 : if (r[*pos] == ',') {
1321 32 : (*pos)++;
1322 32 : s = readInt(r,pos);
1323 : }
1324 383 : if (r[*pos] != ')')
1325 0 : return sql_error(sql, -1, SQLSTATE(42000) "Type: missing ')'\n");
1326 383 : (*pos)++;
1327 : }
1328 388 : convertIdent(tname);
1329 388 : if (!sql_find_subtype(&tpe, tname, d, s)) {
1330 0 : if (!(t = mvc_bind_type(sql, tname))) /* try an external type */
1331 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42000) "SQL type %s(%d, %d) not found\n", tname, d, s);
1332 0 : sql_init_subtype(&tpe, t, d, s);
1333 : }
1334 388 : skipWS(r, pos);
1335 388 : *e = old;
1336 388 : if (r[*pos] == '[') { /* convert */
1337 107 : (*pos)++;
1338 107 : skipWS(r, pos);
1339 107 : if (!(exp = exp_read(sql, lrel, rrel, top_exps, r, pos, 0)))
1340 : return NULL;
1341 107 : if (r[*pos] != ']')
1342 0 : return sql_error(sql, -1, SQLSTATE(42000) "Convert: missing ']'\n");
1343 107 : (*pos)++;
1344 107 : skipWS(r, pos);
1345 107 : exp = exp_convert(sql->sa, exp, exp_subtype(exp), &tpe);
1346 : } else {
1347 281 : if (!(exp = parse_atom(sql, r, pos, &tpe)))
1348 : return NULL;
1349 281 : skipWS(r, pos);
1350 : }
1351 : }
1352 : break;
1353 54 : case '\"':
1354 : case 'N': /* for NULL values, but 'NOT NULL' and 'NULLS LAST' cannot match here */
1355 54 : if (r[*pos] == '\"' || (strncmp(r+*pos, "NULL", strlen("NULL")) == 0 && r[*pos+4] != 'S')) {
1356 46 : *e = 0;
1357 46 : tname = b;
1358 46 : convertIdent(tname);
1359 46 : if (!sql_find_subtype(&tpe, tname, 0, 0)) {
1360 18 : if (!(t = mvc_bind_type(sql, tname))) /* try an external type */
1361 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42000) "SQL type %s not found\n", tname);
1362 18 : sql_init_subtype(&tpe, t, 0, 0);
1363 : }
1364 46 : if (!(exp = parse_atom(sql, r, pos, &tpe)))
1365 : return NULL;
1366 46 : skipWS(r, pos);
1367 : }
1368 : break;
1369 3842 : default:
1370 3842 : (void)sql;
1371 : }
1372 :
1373 : /* func or aggr */
1374 3842 : if (grp) {
1375 56 : skipWS(r, pos);
1376 56 : if (r[*pos] == 'u') {
1377 0 : unique = 1;
1378 0 : (*pos)+= (int) strlen("unique");
1379 0 : skipWS(r, pos);
1380 : }
1381 56 : if (r[*pos] == 'n') {
1382 3 : no_nils = 1;
1383 3 : (*pos)+= (int) strlen("no nil");
1384 3 : skipWS(r, pos);
1385 : }
1386 56 : if (r[*pos] == 'z') {
1387 0 : zero_if_empty = 1;
1388 0 : (*pos)+= (int) strlen("zero if empty");
1389 0 : skipWS(r, pos);
1390 : }
1391 : }
1392 3842 : if (r[*pos] == '(') {
1393 169 : sql_subfunc *f = NULL;
1394 :
1395 169 : if (!(exps = read_exps(sql, lrel, rrel, top_exps, r, pos, '(', 0, 0)))
1396 : return NULL;
1397 169 : tname = b;
1398 169 : *e = 0;
1399 169 : convertIdent(tname);
1400 169 : if (tname && !mvc_bind_schema(sql, tname))
1401 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(3F000) "No such schema '%s'\n", tname);
1402 169 : if (grp) {
1403 55 : if (exps && exps->h) {
1404 11 : list *ops = sa_list(sql->sa);
1405 23 : for( node *n = exps->h; n; n = n->next)
1406 12 : append(ops, exp_subtype(n->data));
1407 11 : f = sql_bind_func_(sql, tname, cname, ops, F_AGGR, true);
1408 : } else {
1409 33 : f = sql_bind_func(sql, tname, cname, sql_bind_localtype("void"), NULL, F_AGGR, true); /* count(*) */
1410 : }
1411 44 : if (!f)
1412 0 : return function_error_string(sql, tname, cname, exps, false, F_AGGR);
1413 44 : if (!execute_priv(sql, f->func))
1414 0 : return function_error_string(sql, tname, cname, exps, true, F_AGGR);
1415 44 : exp = exp_aggr(sql->sa, exps, f, unique, no_nils, CARD_ATOM, 1);
1416 44 : if (zero_if_empty)
1417 0 : set_zero_if_empty(exp);
1418 : } else {
1419 125 : int nops = list_length(exps);
1420 125 : if (!strcmp(tname, "sys") && (!strcmp(cname, "case") || !strcmp(cname, "casewhen") || !strcmp(cname, "coalesce") || !strcmp(cname, "nullif"))) {
1421 : /* these functions are bound on a different way */
1422 24 : if ((f = sql_find_func(sql, NULL, cname, 2, F_FUNC, true, NULL))) {
1423 24 : if (!execute_priv(sql, f->func))
1424 0 : return function_error_string(sql, tname, cname, exps, true, F_FUNC);
1425 24 : sql_exp *res = exps->t->data;
1426 24 : sql_subtype *restype = exp_subtype(res);
1427 24 : f->res->h->data = sql_create_subtype(sql->sa, restype->type, restype->digits, restype->scale);
1428 : }
1429 : } else {
1430 101 : list *ops = sa_list(sql->sa);
1431 320 : for( node *n = exps->h; n; n = n->next)
1432 219 : append(ops, exp_subtype(n->data));
1433 :
1434 101 : f = sql_bind_func_(sql, tname, cname, ops, F_FUNC, true);
1435 101 : if (!f) {
1436 11 : sql->session->status = 0; /* if the function was not found clean the error */
1437 11 : sql->errstr[0] = '\0';
1438 11 : f = sql_bind_func_(sql, tname, cname, ops, F_ANALYTIC, true);
1439 : }
1440 101 : if (!f && nops > 1) { /* window functions without frames get 2 extra arguments */
1441 6 : sql->session->status = 0; /* if the function was not found clean the error */
1442 6 : sql->errstr[0] = '\0';
1443 6 : list_remove_node(ops, NULL, ops->t);
1444 6 : list_remove_node(ops, NULL, ops->t);
1445 6 : f = sql_bind_func_(sql, tname, cname, ops, F_ANALYTIC, true);
1446 : }
1447 101 : if (!f && nops > 4) { /* window functions with frames get 5 extra arguments */
1448 4 : sql->session->status = 0; /* if the function was not found clean the error */
1449 4 : sql->errstr[0] = '\0';
1450 16 : for (int i = 0 ; i < 3 ; i++)
1451 12 : list_remove_node(ops, NULL, ops->t);
1452 4 : f = sql_bind_func_(sql, tname, cname, ops, F_ANALYTIC, true);
1453 : }
1454 :
1455 101 : if (f && !execute_priv(sql, f->func))
1456 0 : return function_error_string(sql, tname, cname, exps, true, F_FUNC);
1457 : /* apply scale fixes if needed */
1458 100 : if (f && f->func->type != F_ANALYTIC) {
1459 90 : if (list_length(exps) == 2) {
1460 74 : sql_exp *l = exps->h->data;
1461 74 : sql_exp *r = exps->h->next->data;
1462 :
1463 : /* Find converted value type for division and update function output type */
1464 74 : if (f->func->fix_scale == SCALE_DIV) {
1465 2 : sql_subtype *lt = exp_subtype(l);
1466 2 : sql_subtype *rt = exp_subtype(r);
1467 :
1468 2 : if (lt->type->scale == SCALE_FIX && rt->scale && strcmp(sql_func_imp(f->func), "/") == 0) {
1469 2 : sql_subtype *res = f->res->h->data;
1470 2 : unsigned int scale = lt->scale - rt->scale;
1471 2 : unsigned int digits = (lt->digits > rt->digits) ? lt->digits : rt->digits;
1472 :
1473 : #ifdef HAVE_HGE
1474 2 : if (res->type->radix == 10 && digits > 38)
1475 2 : digits = 38;
1476 2 : if (res->type->radix == 2 && digits > 128)
1477 2 : digits = 128;
1478 : #else
1479 : if (res->type->radix == 10 && digits > 18)
1480 : digits = 18;
1481 : if (res->type->radix == 2 && digits > 64)
1482 : digits = 64;
1483 : #endif
1484 :
1485 2 : sql_find_subtype(res, lt->type->base.name, digits, scale);
1486 : }
1487 72 : } else if (f->func->fix_scale == SCALE_MUL) {
1488 4 : exp_sum_scales(f, l, r);
1489 68 : } else if (f->func->fix_scale == DIGITS_ADD) {
1490 1 : sql_subtype *t1 = exp_subtype(l);
1491 1 : sql_subtype *t2 = exp_subtype(r);
1492 1 : sql_subtype *res = f->res->h->data;
1493 :
1494 1 : if (t1->digits && t2->digits) {
1495 1 : res->digits = t1->digits + t2->digits;
1496 1 : if (res->digits < t1->digits || res->digits < t2->digits || res->digits >= (unsigned int) INT32_MAX)
1497 0 : return sql_error(sql, -1, SQLSTATE(42000) "Output number of digits for %s%s%s is too large\n", tname ? tname : "", tname ? "." : "", cname);
1498 : } else {
1499 0 : res->digits = 0;
1500 : }
1501 : }
1502 16 : } else if (list_length(exps) > 2) {
1503 3 : if (!f->func->vararg && !(exps = check_arguments_and_find_largest_any_type(sql, lrel, exps, f, 0)))
1504 : return NULL;
1505 : }
1506 : }
1507 : }
1508 48 : if (f) {
1509 126 : exp = exp_op(sql->sa, list_empty(exps) ? NULL : exps, f);
1510 124 : if (is_compare_func(f)) { /* has to parse any/all */
1511 14 : skipWS(r,pos);
1512 : /* [ ANY|ALL ] */
1513 14 : if (strncmp(r+*pos, "ANY", strlen("ANY")) == 0) {
1514 0 : (*pos)+= (int) strlen("ANY");
1515 0 : skipWS(r, pos);
1516 0 : exp->flag = 1;
1517 : }
1518 14 : if (strncmp(r+*pos, "ALL", strlen("ALL")) == 0) {
1519 0 : (*pos)+= (int) strlen("ALL");
1520 0 : skipWS(r, pos);
1521 0 : exp->flag = 2;
1522 : }
1523 : }
1524 : } else {
1525 1 : return function_error_string(sql, tname, cname, exps, false, F_FUNC);
1526 : }
1527 : }
1528 : }
1529 :
1530 3841 : if (!exp && lrel && b != e) { /* simple ident */
1531 57 : int amb = 0, mul = 0;
1532 :
1533 57 : old = *e;
1534 57 : *e = 0;
1535 57 : convertIdent(b);
1536 57 : var_cname = sa_strdup(sql->sa, b);
1537 57 : if (top_exps) {
1538 57 : exp = exps_bind_column(top_exps, var_cname, &amb, &mul, 1);
1539 57 : if (exp)
1540 0 : exp = exp_alias_or_copy(sql, exp_relname(exp), var_cname, lrel, exp);
1541 : }
1542 57 : (void)amb;
1543 57 : (void)mul;
1544 57 : assert(amb == 0 && mul == 0);
1545 57 : if (!exp && lrel)
1546 57 : exp = rel_bind_column(sql, lrel, var_cname, 0, 1);
1547 57 : if (!exp && rrel)
1548 1 : exp = rel_bind_column(sql, rrel, var_cname, 0, 1);
1549 57 : *e = old;
1550 57 : skipWS(r,pos);
1551 : }
1552 :
1553 3841 : if (!exp && (cname || var_cname)) { /* Try a variable */
1554 29 : sql_var *var = NULL;
1555 29 : sql_subtype *tpe = NULL;
1556 29 : int level = 0;
1557 29 : sql_arg *a = NULL;
1558 29 : bool has_tname = cname && tname && strcmp(tname, cname) != 0;
1559 :
1560 54 : if (find_variable_on_scope(sql, has_tname ? tname : NULL, cname ? cname : var_cname, &var, &a, &tpe, &level, "SELECT")) {
1561 28 : if (var) /* if variable is known from the stack or a global var */
1562 31 : exp = exp_param_or_declared(sql->sa, var->sname ? sa_strdup(sql->sa, var->sname) : NULL, sa_strdup(sql->sa, var->name), &(var->var.tpe), level);
1563 28 : if (a) /* if variable is a parameter */
1564 0 : exp = exp_param_or_declared(sql->sa, NULL, sa_strdup(sql->sa, cname), &(a->type), level);
1565 : }
1566 : }
1567 :
1568 113 : if (!exp) {
1569 85 : if (cname) {
1570 1 : bool has_tname = tname && strcmp(tname, cname) != 0;
1571 1 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42000) "Identifier %s%s%s doesn't exist\n", has_tname ? tname : "", has_tname ? "." : "", cname);
1572 84 : } else if (var_cname) {
1573 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42000) "Identifier %s doesn't exist\n", var_cname);
1574 : }
1575 : return NULL;
1576 : }
1577 :
1578 : /* [ ASC ] */
1579 3756 : if (strncmp(r+*pos, "ASC", strlen("ASC")) == 0) {
1580 12 : (*pos)+= (int) strlen("ASC");
1581 12 : skipWS(r, pos);
1582 12 : set_ascending(exp);
1583 : }
1584 : /* [ NULLS LAST ] */
1585 3756 : if (strncmp(r+*pos, "NULLS LAST", strlen("NULLS LAST")) == 0) {
1586 9 : (*pos)+= (int) strlen("NULLS LAST");
1587 9 : skipWS(r, pos);
1588 9 : set_nulls_last(exp);
1589 : }
1590 : /* [ NOT NULL ] */
1591 3756 : if (strncmp(r+*pos, "NOT NULL", strlen("NOT NULL")) == 0) {
1592 339 : (*pos)+= (int) strlen("NOT NULL");
1593 339 : skipWS(r, pos);
1594 338 : set_has_no_nil(exp);
1595 : }
1596 : /* [ UNIQUE ] */
1597 3755 : if (strncmp(r+*pos, "UNIQUE", strlen("UNIQUE")) == 0) {
1598 219 : (*pos)+= (int) strlen("UNIQUE");
1599 219 : skipWS(r, pos);
1600 219 : set_unique(exp);
1601 : }
1602 :
1603 3755 : if (!(exp = read_exp_properties(sql, exp, r, pos)))
1604 : return NULL;
1605 :
1606 : /* as alias */
1607 3758 : if (strncmp(r+*pos, "as", 2) == 0) {
1608 1509 : unsigned int rlabel = 0, nlabel = 0;
1609 1509 : (*pos)+=2;
1610 1509 : skipWS(r, pos);
1611 :
1612 1509 : tname = r+*pos+1;
1613 1509 : skipIdent(r, pos);
1614 1509 : convertIdent(tname);
1615 1509 : (*pos)++;
1616 1509 : if (r[*pos] != '.') {
1617 20 : cname = tname;
1618 20 : tname = NULL;
1619 20 : exp_setname(sql->sa, exp, NULL, cname);
1620 20 : skipWS(r, pos);
1621 : } else {
1622 1489 : (*pos)++;
1623 1489 : cname = r+*pos+1;
1624 1489 : skipIdent(r, pos);
1625 1489 : convertIdent(cname);
1626 1489 : (*pos)++;
1627 1489 : skipWS(r, pos);
1628 1489 : exp_setname(sql->sa, exp, tname, cname);
1629 : }
1630 1508 : rlabel = try_update_label_count(sql, tname);
1631 1508 : nlabel = try_update_label_count(sql, cname);
1632 1508 : if (rlabel && rlabel == nlabel)
1633 166 : exp->alias.label = rlabel;
1634 : }
1635 : return exp;
1636 : }
1637 :
1638 : static int
1639 2 : rel_set_types(mvc *sql, sql_rel *rel)
1640 : {
1641 2 : list *iexps = rel_projections( sql, rel->l, NULL, 0, 1);
1642 2 : node *n, *m;
1643 :
1644 2 : if (!iexps || list_length(iexps) > list_length(rel->exps))
1645 0 : return -1;
1646 7 : for(n=iexps->h, m=rel->exps->h; n && m; n = n->next, m = m->next) {
1647 5 : sql_exp *e = m->data;
1648 :
1649 5 : if (!e->tpe.type)
1650 0 : e->tpe = *exp_subtype( n->data );
1651 : }
1652 : return 0;
1653 : }
1654 :
1655 : static sql_rel*
1656 0 : rel_read_count(mvc *sql, sql_rel *rel, char *r, int *pos)
1657 : {
1658 0 : void *ptr = NULL;
1659 0 : size_t nbytes = 0;
1660 0 : ssize_t res = 0;
1661 0 : sql_subtype *tpe = sql_bind_localtype("oid");
1662 :
1663 0 : (*pos)+= (int) strlen("COUNT");
1664 0 : skipWS(r, pos);
1665 :
1666 0 : if ((res = ATOMfromstr(tpe->type->localtype, &ptr, &nbytes, r + *pos, true)) < 0) {
1667 0 : GDKfree(ptr);
1668 0 : return sql_error(sql, -1, SQLSTATE(42000) "Invalid atom string\n");
1669 : }
1670 :
1671 0 : set_count_prop(sql->sa, rel, *(BUN*)ptr);
1672 0 : (*pos) += (int) res; /* it should always fit */
1673 0 : GDKfree(ptr);
1674 0 : skipWS(r, pos);
1675 0 : return rel;
1676 : }
1677 :
1678 : static sql_rel*
1679 597 : read_rel_properties(mvc *sql, sql_rel *rel, char *r, int *pos)
1680 : {
1681 597 : bool found = true;
1682 597 : while (found) {
1683 595 : found = false;
1684 :
1685 595 : if (strncmp(r+*pos, "COUNT", strlen("COUNT")) == 0) {
1686 0 : if (!rel_read_count(sql, rel, r, pos))
1687 : return NULL;
1688 : found = true;
1689 595 : } else if (strncmp(r+*pos, "REMOTE", strlen("REMOTE")) == 0) { /* Remote tables under remote tables not supported, so remove REMOTE property */
1690 0 : (*pos)+= (int) strlen("REMOTE");
1691 0 : skipWS(r, pos);
1692 0 : skipUntilWS(r, pos);
1693 0 : skipWS(r, pos);
1694 0 : found = true;
1695 595 : } else if (strncmp(r+*pos, "USED", strlen("USED")) == 0) {
1696 0 : (*pos)+= (int) strlen("USED");
1697 0 : if (!find_prop(rel->p, PROP_USED))
1698 0 : rel->p = prop_create(sql->sa, PROP_USED, rel->p);
1699 0 : skipWS(r, pos);
1700 0 : found = true;
1701 595 : } else if (strncmp(r+*pos, "GROUPINGS", strlen("GROUPINGS")) == 0) {
1702 0 : (*pos)+= (int) strlen("GROUPINGS");
1703 0 : if (!find_prop(rel->p, PROP_GROUPINGS))
1704 0 : rel->p = prop_create(sql->sa, PROP_GROUPINGS, rel->p);
1705 0 : skipWS(r, pos);
1706 0 : found = true;
1707 : }
1708 : }
1709 : return rel;
1710 : }
1711 :
1712 : sql_rel*
1713 605 : rel_read(mvc *sql, char *r, int *pos, list *refs)
1714 : {
1715 605 : sql_rel *rel = NULL, *nrel, *lrel, *rrel;
1716 605 : list *exps, *gexps;
1717 605 : int distinct = 0, dependent = 0, single = 0;
1718 605 : operator_type j = op_basetable;
1719 605 : bool groupjoin = false;
1720 :
1721 605 : skipWS(r,pos);
1722 605 : if (r[*pos] == 'R') {
1723 0 : *pos += (int) strlen("REF");
1724 :
1725 0 : skipWS(r, pos);
1726 0 : (void)readInt(r,pos);
1727 0 : skipWS(r, pos);
1728 0 : (*pos)++; /* ( */
1729 0 : (void)readInt(r,pos); /* skip nr refs */
1730 0 : (*pos)++; /* ) */
1731 0 : if (!(rel = rel_read(sql, r, pos, refs)))
1732 : return NULL;
1733 0 : append(refs, rel);
1734 0 : skipWS(r,pos);
1735 : }
1736 605 : if (r[*pos] == '&') {
1737 0 : int nr;
1738 0 : (*pos)++;
1739 0 : skipWS(r, pos);
1740 0 : *pos += (int) strlen("REF");
1741 0 : skipWS(r, pos);
1742 0 : nr = readInt(r,pos); /* skip nr refs */
1743 0 : return rel_dup(list_fetch(refs, nr-1));
1744 : }
1745 :
1746 605 : if (r[*pos] == 'i' && r[*pos+1] == 'n' && r[*pos+2] == 's') {
1747 0 : sql_table *t;
1748 :
1749 0 : *pos += (int) strlen("insert");
1750 0 : skipWS(r, pos);
1751 0 : (*pos)++; /* ( */
1752 0 : if (!(lrel = rel_read(sql, r, pos, refs))) /* to be inserted relation */
1753 : return NULL;
1754 0 : skipWS(r,pos);
1755 0 : if (!(rrel = rel_read(sql, r, pos, refs))) /* the inserts relation */
1756 : return NULL;
1757 0 : skipWS(r,pos);
1758 0 : (*pos)++; /* ) */
1759 :
1760 0 : t = get_table(lrel);
1761 0 : if (!insert_allowed(sql, t, t->base.name, "INSERT", "insert"))
1762 : return NULL;
1763 :
1764 0 : if (!(rel = rel_insert(sql, lrel, rrel)) || !(rel = read_rel_properties(sql, rel, r, pos)))
1765 0 : return NULL;
1766 : }
1767 :
1768 605 : if (r[*pos] == 'd' && r[*pos+1] == 'e' && r[*pos+2] == 'l') {
1769 0 : sql_table *t;
1770 :
1771 0 : *pos += (int) strlen("delete");
1772 0 : skipWS(r, pos);
1773 0 : (*pos)++; /* ( */
1774 0 : if (!(lrel = rel_read(sql, r, pos, refs))) /* to be deleted relation */
1775 : return NULL;
1776 0 : skipWS(r,pos);
1777 0 : if (!(rrel = rel_read(sql, r, pos, refs))) /* the deletes relation */
1778 : return NULL;
1779 0 : skipWS(r,pos);
1780 0 : (*pos)++; /* ) */
1781 :
1782 0 : t = get_table(lrel);
1783 0 : if (!update_allowed(sql, t, t->base.name, "DELETE", "delete", 1))
1784 : return NULL;
1785 :
1786 0 : if (!(rel = rel_delete(sql->sa, lrel, rrel)) || !(rel = read_rel_properties(sql, rel, r, pos)))
1787 0 : return NULL;
1788 : }
1789 :
1790 605 : if (r[*pos] == 't' && r[*pos+1] == 'r' && r[*pos+2] == 'u') {
1791 0 : sql_table *t;
1792 0 : int restart_sequences = 0, drop_action = 0;
1793 :
1794 0 : *pos += (int) strlen("truncate ");
1795 0 : if (r[*pos] == 'r') {
1796 0 : restart_sequences = 1;
1797 0 : *pos += (int) strlen("restart identity, ");
1798 : } else {
1799 0 : *pos += (int) strlen("continue identity, ");
1800 : }
1801 0 : if (r[*pos] == 'c') {
1802 0 : drop_action = 1;
1803 0 : *pos += (int) strlen("cascade");
1804 : } else {
1805 0 : *pos += (int) strlen("restrict");
1806 : }
1807 0 : skipWS(r, pos);
1808 0 : (*pos)++; /* ( */
1809 0 : if (!(lrel = rel_read(sql, r, pos, refs))) /* to be truncated relation */
1810 : return NULL;
1811 0 : skipWS(r,pos);
1812 0 : (*pos)++; /* ) */
1813 :
1814 0 : t = get_table(lrel);
1815 0 : if (!update_allowed(sql, t, t->base.name, "TRUNCATE", "truncate", 2))
1816 : return NULL;
1817 :
1818 0 : if (!(rel = rel_truncate(sql->sa, lrel, restart_sequences, drop_action)) || !(rel = read_rel_properties(sql, rel, r, pos)))
1819 0 : return NULL;
1820 : }
1821 :
1822 605 : if (r[*pos] == 'u' && r[*pos+1] == 'p' && r[*pos+2] == 'd') {
1823 0 : sql_table *t;
1824 0 : list *nexps = new_exp_list(sql->sa);
1825 :
1826 0 : *pos += (int) strlen("update");
1827 0 : skipWS(r, pos);
1828 0 : (*pos)++; /* ( */
1829 0 : if (!(lrel = rel_read(sql, r, pos, refs))) /* to be updated relation */
1830 : return NULL;
1831 0 : skipWS(r,pos);
1832 0 : if (!(rrel = rel_read(sql, r, pos, refs))) /* the updates relation */
1833 : return NULL;
1834 0 : skipWS(r,pos);
1835 0 : (*pos)++; /* ) */
1836 :
1837 0 : t = get_table(lrel);
1838 0 : if (!update_allowed(sql, t, t->base.name, "UPDATE", "update", 0) )
1839 : return NULL;
1840 :
1841 0 : if (!(exps = read_exps(sql, lrel, rrel, NULL, r, pos, '[', 0, 1))) /* columns to be updated */
1842 : return NULL;
1843 :
1844 0 : for (node *n = rel->exps->h ; n ; n = n->next) {
1845 0 : sql_exp *e = (sql_exp *) n->data;
1846 0 : const char *cname = exp_name(e);
1847 :
1848 0 : if (cname[0] != '%') { /* Skip TID column */
1849 0 : sql_column *c = mvc_bind_column(sql, t, cname);
1850 :
1851 0 : if (!c)
1852 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "UPDATE: no such column '%s.%s'\n", t->base.name, cname);
1853 0 : if (!(e = update_check_column(sql, t, c, e, rrel, c->base.name, "UPDATE")))
1854 : return NULL;
1855 : }
1856 0 : list_append(nexps, e);
1857 : }
1858 :
1859 0 : if (!(rel = rel_update(sql, lrel, rrel, NULL, nexps)) || !(rel = read_rel_properties(sql, rel, r, pos)))
1860 0 : return NULL;
1861 : }
1862 :
1863 605 : if (r[*pos] == 'm' && r[*pos+1] == 'e' && r[*pos+2] == 'r')
1864 0 : return sql_error(sql, -1, SQLSTATE(42000) "Merge statements not supported in remote plans\n");
1865 :
1866 605 : if (r[*pos] == 'd' && r[*pos+1] == 'i') {
1867 0 : *pos += (int) strlen("distinct");
1868 0 : skipWS(r, pos);
1869 0 : distinct = 1;
1870 : }
1871 605 : if (r[*pos] == 's' && r[*pos+1] == 'i') {
1872 0 : *pos += (int) strlen("single");
1873 0 : skipWS(r, pos);
1874 0 : single = 1;
1875 : }
1876 605 : if (r[*pos] == 'd' && r[*pos+1] == 'e') {
1877 0 : *pos += (int) strlen("dependent");
1878 0 : skipWS(r, pos);
1879 0 : dependent = 1;
1880 : }
1881 :
1882 605 : switch(r[*pos]) {
1883 203 : case 't':
1884 203 : if (r[*pos+1] == 'a') {
1885 200 : sql_schema *s = NULL;
1886 200 : sql_table *t = NULL;
1887 200 : char *sname, *tname;
1888 200 : *pos += (int) strlen("table");
1889 200 : skipWS(r, pos);
1890 200 : if (r[*pos] != '(')
1891 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table: missing '('\n");
1892 200 : (*pos)++;
1893 200 : skipWS(r, pos);
1894 200 : sname = r+*pos + 1;
1895 200 : skipIdent(r, pos);
1896 199 : convertIdent(sname);
1897 200 : (*pos)++;
1898 200 : if (r[*pos] != '.')
1899 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table: missing '.' in table name\n");
1900 200 : (*pos)++;
1901 200 : tname = r+*pos + 1;
1902 200 : skipIdent(r, pos);
1903 200 : convertIdent(tname);
1904 200 : (*pos)++;
1905 200 : skipWS(r, pos);
1906 200 : if (r[*pos] == '(') { /* table returning function */
1907 : node *m;
1908 : sql_exp *tudf, *next;
1909 : list *inputs, *outputs;
1910 : sql_subfunc *sf;
1911 : int x = *pos, y; /* save current position, after parsing the input relation we have to parse the input parameters */
1912 : bool inside_identifier = false;
1913 :
1914 471 : while (r[*pos] && (inside_identifier || r[*pos] != '\n')) { /* the input parameters must be parsed after the input relation, skip them for now */
1915 208 : if (inside_identifier && r[*pos] == '\\' && (r[*pos + 1] == '"' || r[*pos + 1] == '\\')) {
1916 1 : (*pos)+=2;
1917 465 : } else if (r[*pos] == '"') {
1918 102 : inside_identifier = !inside_identifier;
1919 102 : (*pos)++;
1920 : } else {
1921 363 : (*pos)++;
1922 : }
1923 : }
1924 5 : if (r[*pos] != '\n')
1925 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table returning function: missing ']' for output parameters\n");
1926 :
1927 5 : skipWS(r, pos); /* now parse the input relation */
1928 5 : if (!(lrel = rel_read(sql, r, pos, refs)))
1929 : return NULL;
1930 5 : y = *pos; /* later we have to return here to parse the output identifiers */
1931 5 : *pos = x;
1932 5 : if (!(inputs = read_exps(sql, lrel, NULL, NULL, r, pos, '(', 0, 1)))
1933 : return NULL;
1934 :
1935 5 : if (!mvc_bind_schema(sql, sname))
1936 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(3F000) "No such schema '%s'\n", sname);
1937 5 : if (!(tudf = find_table_function(sql, sname, tname, list_empty(inputs) ? NULL : inputs, list_empty(inputs) ? NULL : exp_types(sql->sa, inputs), F_UNION)))
1938 : return NULL;
1939 5 : sf = tudf->f;
1940 5 : if (tudf->type != e_func || sf->func->type != F_UNION)
1941 0 : return sql_error(sql, 02, SQLSTATE(42000) "'%s' does not return a table\n", exp_func_name(tudf));
1942 :
1943 5 : *pos = y; /* now at the end of the input relation */
1944 5 : skipWS(r, pos);
1945 5 : if (r[*pos] != ')')
1946 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table returning function: missing ')' at the end of the input relation\n");
1947 5 : (*pos)++;
1948 5 : skipWS(r, pos);
1949 :
1950 : /* Parse identifiers manually, we cannot use read_exps because the labels may not match */
1951 5 : if (r[*pos] != '[')
1952 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table returning function: missing '[' for output parameters\n");
1953 5 : (*pos)++;
1954 5 : skipWS(r, pos);
1955 5 : m = sf->func->res->h;
1956 5 : outputs = new_exp_list(sql->sa);
1957 27 : while (r[*pos] && r[*pos] != ']' && m) {
1958 22 : sql_arg *a = m->data;
1959 22 : unsigned int rlabel, nlabel;
1960 22 : char *nrname, *ncname;
1961 :
1962 22 : if (r[*pos] != '"')
1963 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table returning function: missing identifier for output parameters\n");
1964 22 : nrname = r+*pos + 1;
1965 22 : skipIdent(r, pos);
1966 22 : if (r[*pos] != '"')
1967 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table returning function: missing identifier for output parameters\n");
1968 22 : convertIdent(nrname);
1969 22 : (*pos)++;
1970 22 : if (r[*pos] != '.')
1971 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table returning function: missing '.' for output parameters\n");
1972 22 : (*pos)++; /* skip '.' */
1973 22 : if (r[*pos] != '"')
1974 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table returning function: missing identifier for output parameters\n");
1975 22 : ncname = r+*pos + 1;
1976 22 : skipIdent(r, pos);
1977 22 : if (r[*pos] != '"')
1978 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table returning function: missing identifier for output parameters\n");
1979 22 : convertIdent(ncname);
1980 22 : (*pos)++;
1981 22 : if (r[*pos] == ',')
1982 17 : (*pos)++;
1983 :
1984 22 : next = exp_column(sql->sa, nrname, ncname, &a->type, CARD_MULTI, 1, 0, 0);
1985 22 : rlabel = try_update_label_count(sql, nrname);
1986 22 : nlabel = try_update_label_count(sql, ncname);
1987 22 : if (rlabel && rlabel == nlabel)
1988 0 : next->alias.label = rlabel;
1989 22 : set_basecol(next);
1990 22 : append(outputs, next);
1991 22 : m = m->next;
1992 22 : skipWS(r, pos);
1993 : }
1994 5 : if (r[*pos] != ']')
1995 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table returning function: missing ']' for output parameters\n");
1996 5 : (*pos)++;
1997 5 : skipWS(r, pos);
1998 5 : if (list_length(outputs) != list_length(sf->func->res))
1999 0 : return sql_error(sql, -1, SQLSTATE(42000) "Table returning function: the number of output parameters don't match the table ones relation outputs: %d != function outputs: %d\n",
2000 0 : list_length(outputs), list_length(sf->func->res));
2001 5 : rel = rel_table_func(sql->sa, lrel, tudf, outputs, TABLE_FROM_RELATION);
2002 5 : set_processed(rel);
2003 : } else {
2004 195 : if (r[*pos] != ')')
2005 0 : sql_error(sql, -1, SQLSTATE(42000) "Table: missing ')'\n");
2006 195 : (*pos)++;
2007 195 : skipWS(r, pos);
2008 195 : if (!(s = mvc_bind_schema(sql, sname)))
2009 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(3F000) "No such schema '%s'\n", sname);
2010 195 : if (!(t = mvc_bind_table(sql, s, tname)))
2011 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S02) "Table missing '%s.%s'\n", sname, tname);
2012 195 : if (isMergeTable(t))
2013 1 : return sql_error(sql, -1, SQLSTATE(42000) "Merge tables not supported under remote connections\n");
2014 194 : if (isRemote(t))
2015 1 : return sql_error(sql, -1, SQLSTATE(42000) "Remote tables not supported under remote connections\n");
2016 193 : if (isReplicaTable(t))
2017 0 : return sql_error(sql, -1, SQLSTATE(42000) "Replica tables not supported under remote connections\n");
2018 193 : rel = rel_basetable(sql, t, tname);
2019 193 : if (!table_privs(sql, t, PRIV_SELECT)) {
2020 0 : rel_base_disallow(rel);
2021 0 : if (rel_base_has_column_privileges(sql, rel) == 0)
2022 0 : return sql_error(sql, -1, SQLSTATE(42000) "Access denied for %s to table '%s.%s'\n",
2023 : get_string_global_var(sql, "current_user"), s->base.name, tname);
2024 : }
2025 193 : rel_base_use_all(sql, rel);
2026 192 : rel = rewrite_basetable(sql, rel);
2027 :
2028 192 : if (!r[*pos])
2029 : return rel;
2030 :
2031 : /* scan aliases */
2032 192 : if (!(exps = read_exps(sql, rel, NULL, NULL, r, pos, '[', 0, 1)))
2033 : return NULL;
2034 191 : rel->exps = exps;
2035 : }
2036 : } else { /* top N */
2037 3 : *pos += (int) strlen("top N");
2038 3 : skipWS(r, pos);
2039 3 : if (r[*pos] != '(')
2040 0 : return sql_error(sql, -1, SQLSTATE(42000) "Top N: missing '('\n");
2041 3 : (*pos)++;
2042 3 : skipWS(r, pos);
2043 3 : if (!(nrel = rel_read(sql, r, pos, refs)))
2044 : return NULL;
2045 3 : if (r[*pos] != ')')
2046 0 : return sql_error(sql, -1, SQLSTATE(42000) "Top N: missing ')'\n");
2047 3 : (*pos)++;
2048 3 : skipWS(r, pos);
2049 3 : if (!(exps = read_exps(sql, nrel, NULL, NULL, r, pos, '[', 0, 1)))
2050 : return NULL;
2051 3 : rel = rel_topn(sql->sa, nrel, exps);
2052 3 : set_processed(rel);
2053 : }
2054 : break;
2055 277 : case 'p':
2056 277 : *pos += (int) strlen("project");
2057 277 : skipWS(r, pos);
2058 :
2059 277 : if (r[*pos] != '(')
2060 0 : return sql_error(sql, -1, SQLSTATE(42000) "Project: missing '('\n");
2061 277 : (*pos)++;
2062 277 : skipWS(r, pos);
2063 277 : if (!(nrel = rel_read(sql, r, pos, refs)))
2064 : return NULL;
2065 273 : skipWS(r, pos);
2066 273 : if (r[*pos] != ')')
2067 0 : return sql_error(sql, -1, SQLSTATE(42000) "Project: missing ')'\n");
2068 273 : (*pos)++;
2069 273 : skipWS(r, pos);
2070 :
2071 273 : if (!(exps = read_exps(sql, nrel, NULL, NULL, r, pos, '[', 0, 1)))
2072 : return NULL;
2073 272 : rel = rel_project(sql->sa, nrel, exps);
2074 272 : set_processed(rel);
2075 : /* order by ? */
2076 : /* first projected expressions, then left relation projections */
2077 272 : if (r[*pos] == '[' && !(rel->r = read_exps(sql, rel, nrel, NULL, r, pos, '[', 0, 1)))
2078 : return NULL;
2079 : break;
2080 60 : case 's':
2081 : case 'a':
2082 60 : if (r[*pos+1] == 'a') {
2083 0 : *pos += (int) strlen("sample");
2084 0 : skipWS(r, pos);
2085 0 : if (r[*pos] != '(')
2086 0 : return sql_error(sql, -1, SQLSTATE(42000) "Sample: missing '('\n");
2087 0 : (*pos)++;
2088 0 : skipWS(r, pos);
2089 0 : if (!(nrel = rel_read(sql, r, pos, refs)))
2090 : return NULL;
2091 0 : if (r[*pos] != ')')
2092 0 : return sql_error(sql, -1, SQLSTATE(42000) "Sample: missing ')'\n");
2093 0 : (*pos)++;
2094 0 : skipWS(r, pos);
2095 0 : if (!(exps = read_exps(sql, nrel, NULL, NULL, r, pos, '[', 0, 1)))
2096 : return NULL;
2097 0 : rel = rel_sample(sql->sa, nrel, exps);
2098 0 : set_processed(rel);
2099 60 : } else if (r[*pos+2] == 'l') {
2100 60 : *pos += (int) strlen("select");
2101 60 : skipWS(r, pos);
2102 60 : if (r[*pos] != '(')
2103 0 : return sql_error(sql, -1, SQLSTATE(42000) "Select: missing '('\n");
2104 60 : (*pos)++;
2105 60 : skipWS(r, pos);
2106 60 : if (!(nrel = rel_read(sql, r, pos, refs)))
2107 : return NULL;
2108 60 : skipWS(r, pos);
2109 60 : if (r[*pos] != ')')
2110 0 : return sql_error(sql, -1, SQLSTATE(42000) "Select: missing ')'\n");
2111 60 : (*pos)++;
2112 60 : skipWS(r, pos);
2113 :
2114 60 : if (!(exps = read_exps(sql, nrel, NULL, NULL, r, pos, '[', 0, 1)))
2115 : return NULL;
2116 60 : rel = rel_select_copy(sql->sa, nrel, exps);
2117 60 : set_processed(rel);
2118 : /* semijoin or antijoin */
2119 0 : } else if (r[*pos+1] == 'e' || r[*pos+1] == 'n') {
2120 0 : if (r[*pos+1] == 'n') {
2121 0 : j = op_anti;
2122 0 : *pos += (int) strlen("antijoin");
2123 : } else {
2124 0 : j = op_semi;
2125 0 : *pos += (int) strlen("semijoin");
2126 : }
2127 :
2128 0 : skipWS(r, pos);
2129 0 : if (r[*pos] != '(')
2130 0 : return sql_error(sql, -1, SQLSTATE(42000) "%s: missing '('\n", (j == op_semi)?"Semijoin":"Antijoin");
2131 0 : (*pos)++;
2132 0 : skipWS(r, pos);
2133 0 : if (!(lrel = rel_read(sql, r, pos, refs)))
2134 : return NULL;
2135 0 : skipWS(r, pos);
2136 :
2137 0 : if (r[*pos] != ',')
2138 0 : return sql_error(sql, -1, SQLSTATE(42000) "%s: missing ','\n", (j == op_semi)?"Semijoin":"Antijoin");
2139 0 : (*pos)++;
2140 0 : skipWS(r, pos);
2141 0 : if (!(rrel = rel_read(sql, r, pos, refs)))
2142 : return NULL;
2143 :
2144 0 : skipWS(r, pos);
2145 0 : if (r[*pos] != ')')
2146 0 : return sql_error(sql, -1, SQLSTATE(42000) "%s: missing ')'\n", (j == op_semi)?"Semijoin":"Antijoin");
2147 0 : (*pos)++;
2148 0 : skipWS(r, pos);
2149 :
2150 0 : if (!(exps = read_exps(sql, lrel, rrel, NULL, r, pos, '[', 0, 1)))
2151 : return NULL;
2152 0 : rel = rel_crossproduct(sql->sa, lrel, rrel, j);
2153 0 : rel->exps = exps;
2154 0 : set_processed(rel);
2155 : }
2156 : break;
2157 54 : case 'g':
2158 54 : *pos += (int) strlen("group");
2159 54 : skipWS(r, pos);
2160 :
2161 54 : if (r[*pos] == 'b') {
2162 54 : *pos += (int) strlen("by");
2163 54 : skipWS(r, pos);
2164 :
2165 54 : if (r[*pos] != '(')
2166 0 : return sql_error(sql, -1, SQLSTATE(42000) "Group by: missing '('\n");
2167 54 : (*pos)++;
2168 54 : skipWS(r, pos);
2169 54 : if (!(nrel = rel_read(sql, r, pos, refs)))
2170 : return NULL;
2171 53 : skipWS(r, pos);
2172 54 : if (r[*pos] != ')')
2173 0 : return sql_error(sql, -1, SQLSTATE(42000) "Group by: missing ')'\n");
2174 54 : (*pos)++;
2175 54 : skipWS(r, pos);
2176 :
2177 54 : if (!(gexps = read_exps(sql, nrel, NULL, NULL, r, pos, '[', 0, 1)))
2178 : return NULL;
2179 54 : skipWS(r, pos);
2180 54 : rel = rel_groupby(sql, nrel, gexps);
2181 54 : rel->exps = new_exp_list(sql->sa); /* empty projection list for now */
2182 54 : set_processed(rel); /* don't search beyond the group by */
2183 : /* first group projected expressions, then group by columns, then left relation projections */
2184 54 : if (!(exps = read_exps(sql, rel, nrel, NULL, r, pos, '[', 1, 1)))
2185 : return NULL;
2186 54 : rel->exps = exps;
2187 54 : rel->nrcols = list_length(exps);
2188 54 : break;
2189 : } else {
2190 : groupjoin = true;
2191 : }
2192 : /* fall through */
2193 1 : case 'l':
2194 1 : if (strncmp(r+*pos, "left outer join", strlen("left outer join")) == 0) {
2195 0 : *pos += (int) strlen("left outer join");
2196 : } else {
2197 1 : groupjoin = true;
2198 1 : *pos += (int) strlen("left outer group join");
2199 : }
2200 : j = op_left;
2201 : /* fall through */
2202 : case 'r':
2203 0 : if (j == op_basetable) {
2204 0 : *pos += (int) strlen("right outer join");
2205 0 : j = op_right;
2206 : }
2207 : /* fall through */
2208 : case 'f':
2209 0 : if (j == op_basetable) {
2210 0 : *pos += (int) strlen("full outer join");
2211 0 : j = op_full;
2212 : }
2213 : /* fall through */
2214 : case 'c':
2215 0 : if (j == op_basetable) {
2216 7 : *pos += (int) strlen("crossproduct");
2217 7 : j = op_join;
2218 : }
2219 : /* fall through */
2220 : case 'j':
2221 7 : if (j == op_basetable) {
2222 1 : *pos += (int) strlen("join");
2223 1 : j = op_join;
2224 : }
2225 9 : skipWS(r, pos);
2226 :
2227 9 : if (r[*pos] != '(')
2228 0 : return sql_error(sql, -1, SQLSTATE(42000) "Join: missing '('\n");
2229 9 : (*pos)++;
2230 9 : skipWS(r, pos);
2231 9 : if (!(lrel = rel_read(sql, r, pos, refs)))
2232 : return NULL;
2233 9 : skipWS(r, pos);
2234 :
2235 9 : if (r[*pos] != ',')
2236 0 : return sql_error(sql, -1, SQLSTATE(42000) "Join: missing ','\n");
2237 9 : (*pos)++;
2238 9 : skipWS(r, pos);
2239 9 : if (!(rrel = rel_read(sql, r, pos, refs)))
2240 : return NULL;
2241 :
2242 9 : skipWS(r, pos);
2243 9 : if (r[*pos] != ')')
2244 0 : return sql_error(sql, -1, SQLSTATE(42000) "Join: missing ')'\n");
2245 9 : (*pos)++;
2246 9 : skipWS(r, pos);
2247 :
2248 9 : if (!(exps = read_exps(sql, lrel, rrel, NULL, r, pos, '[', 0, 1)))
2249 : return NULL;
2250 9 : rel = rel_crossproduct(sql->sa, lrel, rrel, j);
2251 9 : rel->exps = exps;
2252 9 : if (groupjoin) {
2253 1 : list *attr = NULL;
2254 1 : if (!(attr = read_exps(sql, lrel, rrel, NULL, r, pos, '[', 0, 1)))
2255 : return NULL;
2256 1 : rel->attr = attr;
2257 : }
2258 9 : set_processed(rel);
2259 9 : break;
2260 : case 'u':
2261 0 : if (j == op_basetable) {
2262 0 : *pos += (int) strlen("union");
2263 0 : j = op_union;
2264 : }
2265 : /* fall through */
2266 : case 'i':
2267 1 : if (j == op_basetable) {
2268 1 : *pos += (int) strlen("intersect");
2269 1 : j = op_inter;
2270 : }
2271 : /* fall through */
2272 : case 'e':
2273 1 : if (j == op_basetable) {
2274 1 : *pos += (int) strlen("except");
2275 1 : j = op_except;
2276 : }
2277 2 : skipWS(r, pos);
2278 :
2279 2 : if (r[*pos] != '(')
2280 0 : return sql_error(sql, -1, SQLSTATE(42000) "Setop: missing '('\n");
2281 2 : (*pos)++;
2282 2 : skipWS(r, pos);
2283 2 : if (!(lrel = rel_read(sql, r, pos, refs)))
2284 : return NULL;
2285 2 : skipWS(r, pos);
2286 :
2287 2 : if (r[*pos] != ',')
2288 0 : return sql_error(sql, -1, SQLSTATE(42000) "Setop: missing ','\n");
2289 2 : (*pos)++;
2290 2 : skipWS(r, pos);
2291 2 : if (!(rrel = rel_read(sql, r, pos, refs)))
2292 : return NULL;
2293 :
2294 2 : skipWS(r, pos);
2295 2 : if (r[*pos] != ')')
2296 0 : return sql_error(sql, -1, SQLSTATE(42000) "Setop: missing ')'\n");
2297 2 : (*pos)++;
2298 2 : skipWS(r, pos);
2299 :
2300 2 : if (!(exps = read_exps(sql, lrel, rrel, NULL, r, pos, '[', 0, 1)))
2301 : return NULL;
2302 2 : rel = rel_setop(sql->sa, lrel, rrel, j);
2303 2 : rel_setop_set_exps(sql, rel, exps, false);
2304 2 : if (rel_set_types(sql, rel) < 0)
2305 0 : return sql_error(sql, -1, SQLSTATE(42000) "Setop: number of expressions don't match\n");
2306 2 : set_processed(rel);
2307 2 : break;
2308 0 : case '[': /* projection of list of values */
2309 0 : if (!(exps = read_exps(sql, NULL, NULL, NULL, r, pos, '[', 0, 1)))
2310 : return NULL;
2311 0 : rel = rel_project(sql->sa, NULL, exps);
2312 : /* order by ? */
2313 0 : if (r[*pos] == '[' && !(rel->r = read_exps(sql, NULL, rel, NULL, r, pos, '[', 0, 1)))
2314 : return NULL;
2315 0 : set_processed(rel);
2316 0 : break;
2317 0 : case 'd':
2318 : /* 'ddl' not supported */
2319 : default:
2320 0 : return sql_error(sql, -1, SQLSTATE(42000) "Could not determine the input relation\n");
2321 : }
2322 :
2323 324 : if (!rel)
2324 0 : return sql_error(sql, -1, SQLSTATE(42000) "Could not determine the input relation\n");
2325 596 : if (distinct)
2326 0 : set_distinct(rel);
2327 596 : if (single)
2328 0 : set_single(rel);
2329 596 : if (dependent)
2330 0 : set_dependent(rel);
2331 :
2332 : /* sometimes, properties are sent */
2333 596 : if (!(rel = read_rel_properties(sql, rel, r, pos)))
2334 : return NULL;
2335 : return rel;
2336 : }
|