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