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