1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9#include "monetdb_config.h"
10#define LINESIZE 160
11#define TABSTOP 2
12
13#include "rel_dump.h"
14#include "rel_rel.h"
15#include "rel_exp.h"
16#include "rel_prop.h"
17#include "rel_updates.h"
18#include "rel_remote.h"
19#include "mal_errors.h" /* for SQLSTATE() */
20
21static void
22print_indent(mvc *sql, stream *fout, int depth, int decorate)
23{
24 char buf[LINESIZE+1];
25 int i;
26
27 (void)sql;
28 if (!decorate) {
29 mnstr_printf(fout, "\n");
30 return ;
31 }
32 depth *= TABSTOP;
33 if (depth > LINESIZE)
34 depth = LINESIZE;
35 for (i = 0; i < depth; i++){
36 if ((i % TABSTOP) == 0)
37 buf[i] = '|';
38 else
39 buf[i] = ' ';
40 }
41 buf[i] = 0;
42 mnstr_printf(fout, "\n=%s", buf);
43}
44
45static void
46cmp_print(mvc *sql, stream *fout, int cmp)
47{
48 char *r = NULL;
49
50 (void)sql;
51 switch(cmp) {
52 case cmp_gt: r = ">"; break;
53 case cmp_gte: r = ">="; break;
54 case cmp_lte: r = "<="; break;
55 case cmp_lt: r = "<"; break;
56 case cmp_equal: r = "="; break;
57 case cmp_notequal: r = "!="; break;
58
59 case cmp_filter: r = "filter"; break;
60 case cmp_or: r = "or"; break;
61 case cmp_in: r = "in"; break;
62 case cmp_notin: r = "notin"; break;
63 case cmp_equal_nil: r = "=*"; break;
64
65 case mark_in: r = "any ="; break;
66 case mark_notin: r = "all <>"; break;
67 case mark_exists: r = "exists"; break;
68 case mark_notexists: r = "!exists"; break;
69
70 case cmp_all:
71 case cmp_project:
72 case cmp_joined:
73 case cmp_left:
74 case cmp_left_project:
75 r = "inner"; break;
76 }
77 mnstr_printf(fout, " %s ", r);
78}
79
80static void exps_print(mvc *sql, stream *fout, list *exps, int depth, list *refs, int alias, int brackets);
81
82static void
83exp_print(mvc *sql, stream *fout, sql_exp *e, int depth, list *refs, int comma, int alias)
84{
85 (void)sql;
86 if (!e)
87 return;
88 /*mnstr_printf(fout, "%p ", e);*/
89 switch(e->type) {
90 case e_psm: {
91 if (e->flag & PSM_SET) {
92 mnstr_printf(fout, "%s = ", exp_name(e));
93 exp_print(sql, fout, e->l, depth, refs, 0, 0);
94 } else if (e->flag & PSM_VAR) {
95 // todo output table def (from e->f)
96 // or type if e-f == NULL
97 mnstr_printf(fout, "declare %s ", exp_name(e));
98 } else if (e->flag & PSM_RETURN) {
99 mnstr_printf(fout, "return ");
100 exp_print(sql, fout, e->l, depth, refs, 0, 0);
101 } else if (e->flag & PSM_WHILE) {
102 mnstr_printf(fout, "while ");
103 exp_print(sql, fout, e->l, depth, refs, 0, 0);
104 exps_print(sql, fout, e->r, depth, refs, alias, 0);
105 } else if (e->flag & PSM_IF) {
106 mnstr_printf(fout, "if ");
107 exp_print(sql, fout, e->l, depth, refs, 0, 0);
108 exps_print(sql, fout, e->r, depth, refs, alias, 0);
109 if (e->f)
110 exps_print(sql, fout, e->f, depth, refs, alias, 0);
111 } else if (e->flag & PSM_REL) {
112 rel_print_(sql, fout, e->l, depth+10, refs, 1);
113 } else if (e->flag & PSM_EXCEPTION) {
114 mnstr_printf(fout, "except ");
115 exp_print(sql, fout, e->l, depth, refs, 0, 0);
116 mnstr_printf(fout, " error %s", (const char *) e->r);
117 }
118 break;
119 }
120 case e_convert: {
121 char *to_type = sql_subtype_string(&e->tpe);
122 mnstr_printf(fout, "%s[", to_type);
123 exp_print(sql, fout, e->l, depth, refs, 0, 0);
124 mnstr_printf(fout, "]");
125 _DELETE(to_type);
126 break;
127 }
128 case e_atom: {
129 if (e->l) {
130 atom *a = e->l;
131 if (atom_type(a)->type->localtype == TYPE_ptr) {
132 sql_table *t = a->data.val.pval;
133 mnstr_printf(fout, "%s(%s)",
134 isStream(t)?"stream":
135 isMergeTable(t)?"merge table":
136 isReplicaTable(t)?"replica table":"table",
137 t->base.name);
138 } else {
139 char *t = sql_subtype_string(atom_type(a));
140 if (a->isnull)
141 mnstr_printf(fout, "%s \"NULL\"", t);
142 else {
143 char *s = ATOMformat(a->data.vtype, VALptr(&a->data));
144 if (s && *s == '"')
145 mnstr_printf(fout, "%s %s", t, s);
146 else if (s)
147 mnstr_printf(fout, "%s \"%s\"", t, s);
148 GDKfree(s);
149 }
150 _DELETE(t);
151 }
152 } else { /* variables */
153 if (e->r) { /* named parameters */
154 char *name = e->r;
155 mnstr_printf(fout, "%s", name);
156 } else if (e->f) { /* values list */
157 list *l = e->f;
158 exps_print(sql, fout, l, depth, refs, 0, 0);
159 } else { /* numbered arguments */
160 mnstr_printf(fout, "A%d", e->flag);
161 }
162 }
163 } break;
164 case e_func: {
165 sql_subfunc *f = e->f;
166 mnstr_printf(fout, "%s.%s",
167 f->func->s?f->func->s->base.name:"sys",
168 f->func->base.name);
169 exps_print(sql, fout, e->l, depth, refs, alias, 1);
170 if (e->r) { /* list of optional lists */
171 list *l = e->r;
172 for(node *n = l->h; n; n = n->next)
173 exps_print(sql, fout, n->data, depth, refs, alias, 1);
174 }
175 if (e->flag && is_compare_func(f))
176 mnstr_printf(fout, " %s", e->flag==1?"ANY":"ALL");
177 } break;
178 case e_aggr: {
179 sql_subaggr *a = e->f;
180 mnstr_printf(fout, "%s.%s",
181 a->aggr->s?a->aggr->s->base.name:"sys",
182 a->aggr->base.name);
183 if (need_distinct(e))
184 mnstr_printf(fout, " unique ");
185 if (need_no_nil(e))
186 mnstr_printf(fout, " no nil ");
187 if (zero_if_empty(e))
188 mnstr_printf(fout, " zero if empty ");
189 if (e->l)
190 exps_print(sql, fout, e->l, depth, refs, alias, 1);
191 else
192 mnstr_printf(fout, "()");
193 } break;
194 case e_column:
195 if (is_freevar(e))
196 mnstr_printf(fout, "!!!FREE!!! ");
197 if (e->l)
198 mnstr_printf(fout, "\"%s\".", (char*)e->l);
199 mnstr_printf(fout, "\"%s\"", (char*)e->r);
200 if (exp_relname(e) && exp_name(e) && e->l && e->r &&
201 strcmp(exp_relname(e), e->l) == 0 &&
202 strcmp(exp_name(e), e->r) == 0)
203 alias = 0;
204 if (!exp_relname(e) && exp_name(e) && strcmp(exp_name(e), e->r)==0)
205 alias = 0;
206 break;
207 case e_cmp:
208 if (e->flag == cmp_in || e->flag == cmp_notin) {
209 exp_print(sql, fout, e->l, depth, refs, 0, alias);
210 if (is_anti(e))
211 mnstr_printf(fout, " !");
212 cmp_print(sql, fout, get_cmp(e));
213 exps_print(sql, fout, e->r, depth, refs, alias, 1);
214 } else if (get_cmp(e) == cmp_or) {
215 exps_print(sql, fout, e->l, depth, refs, alias, 1);
216 if (is_anti(e))
217 mnstr_printf(fout, " !");
218 cmp_print(sql, fout, get_cmp(e));
219 exps_print(sql, fout, e->r, depth, refs, alias, 1);
220 } else if (get_cmp(e) == cmp_filter) {
221 sql_subfunc *f = e->f;
222
223 exps_print(sql, fout, e->l, depth, refs, alias, 1);
224 if (is_anti(e))
225 mnstr_printf(fout, " !");
226 mnstr_printf(fout, " FILTER %s ", f->func->base.name);
227 exps_print(sql, fout, e->r, depth, refs, alias, 1);
228 } else if (e->f) {
229 exp_print(sql, fout, e->r, depth+1, refs, 0, 0);
230 if (is_anti(e))
231 mnstr_printf(fout, " !");
232 cmp_print(sql, fout, swap_compare(range2lcompare(e->flag)) );
233 exp_print(sql, fout, e->l, depth+1, refs, 0, 0);
234 if (is_anti(e))
235 mnstr_printf(fout, " !");
236 cmp_print(sql, fout, range2rcompare(e->flag) );
237 exp_print(sql, fout, e->f, depth+1, refs, 0, 0);
238 if (e->flag & CMP_BETWEEN)
239 mnstr_printf(fout, " BETWEEN ");
240 if (e->flag & CMP_SYMMETRIC)
241 mnstr_printf(fout, " SYM ");
242 } else {
243 exp_print(sql, fout, e->l, depth+1, refs, 0, 0);
244 if (is_anti(e))
245 mnstr_printf(fout, " !");
246 cmp_print(sql, fout, get_cmp(e));
247
248 exp_print(sql, fout, e->r, depth+1, refs, 0, 0);
249 }
250 break;
251 default:
252 ;
253 }
254 if (e->type != e_atom && e->type != e_cmp && is_ascending(e))
255 mnstr_printf(fout, " ASC");
256 if (e->type != e_atom && e->type != e_cmp && !has_nil(e))
257 mnstr_printf(fout, " NOT NULL");
258 /*
259 if (is_basecol(e))
260 mnstr_printf(fout, " BASECOL");
261 */
262 if (e->p) {
263 prop *p = e->p;
264 char *pv;
265
266 for (; p; p = p->p) {
267 pv = propvalue2string(p);
268 mnstr_printf(fout, " %s %s", propkind2string(p), pv);
269 GDKfree(pv);
270 }
271 }
272 if (exp_name(e) && alias) {
273 mnstr_printf(fout, " as ");
274 if (exp_relname(e))
275 mnstr_printf(fout, "\"%s\".", exp_relname(e));
276 mnstr_printf(fout, "\"%s\"", exp_name(e));
277 }
278 if (comma)
279 mnstr_printf(fout, ", ");
280}
281
282static void
283exps_print(mvc *sql, stream *fout, list *exps, int depth, list *refs, int alias, int brackets)
284{
285 node *en;
286
287 if (brackets)
288 mnstr_printf(fout, "(");
289 else
290 mnstr_printf(fout, " [ ");
291 if (exps)
292 for (en = exps->h; en; en = en->next)
293 exp_print(sql, fout, en->data, depth+1, refs, (en->next!=NULL), alias);
294 if (brackets)
295 mnstr_printf(fout, ")");
296 else
297 mnstr_printf(fout, " ]");
298}
299
300const char *
301op2string(operator_type op)
302{
303 switch (op) {
304 case op_basetable:
305 return "basetable";
306 case op_table:
307 return "table";
308 case op_ddl:
309 return "ddl";
310 case op_project:
311 return "project";
312 case op_select:
313 return "select";
314 case op_join:
315 case op_left:
316 case op_right:
317 case op_full:
318 return "join";
319 case op_semi:
320 return "semi";
321 case op_anti:
322 return "anti";
323 case op_union:
324 case op_inter:
325 case op_except:
326 return "set op";
327 case op_groupby:
328 return "group by";
329 case op_topn:
330 return "topn";
331 case op_sample:
332 return "sample";
333 case op_insert:
334 case op_update:
335 case op_delete:
336 case op_truncate:
337 return "modify op";
338 default:
339 return "unknown";
340 }
341}
342
343static int
344find_ref( list *refs, sql_rel *rel )
345{
346 node *n;
347 int nr = 1;
348
349 for(n=refs->h; n; n = n->next, nr++){
350 if (n->data == rel)
351 return nr;
352 }
353 return 0;
354}
355
356void
357rel_print_(mvc *sql, stream *fout, sql_rel *rel, int depth, list *refs, int decorate)
358{
359 char *r = NULL;
360
361 if (!rel)
362 return;
363
364 if (rel_is_ref(rel)) {
365 int nr = list_length(refs) + 1;
366 int cnt = rel->ref.refcnt;
367 mnstr_printf(fout, "\n%cREF %d (%d)", decorate?'=':' ', nr, cnt);
368 }
369
370 switch (rel->op) {
371 case op_basetable: {
372 sql_table *t = rel->l;
373 sql_column *c = rel->r;
374 print_indent(sql, fout, depth, decorate);
375
376 if (!t && c) {
377 mnstr_printf(fout, "dict(%s.%s)", c->t->base.name, c->base.name);
378 } else {
379 const char *sname = t->s?t->s->base.name:NULL;
380 const char *tname = t->base.name;
381
382 if (isRemote(t)) {
383 const char *uri = t->query;
384
385 sname = mapiuri_schema( uri, sql->sa, sname);
386 tname = mapiuri_table( uri, sql->sa, tname);
387 }
388 if (sname)
389 mnstr_printf(fout, "%s(%s.%s)",
390 isStream(t)?"stream":
391 isRemote(t)&&decorate?"REMOTE":
392 isReplicaTable(t)?"REPLICA":"table",
393 sname, tname);
394 else
395 mnstr_printf(fout, "%s(%s)",
396 isStream(t)?"stream":
397 isRemote(t)&&decorate?"REMOTE":
398 isReplicaTable(t)?"REPLICA":"table",
399 tname);
400 }
401 if (rel->exps)
402 exps_print(sql, fout, rel->exps, depth, refs, 1, 0);
403 } break;
404 case op_table:
405 print_indent(sql, fout, depth, decorate);
406 mnstr_printf(fout, "table ");
407
408 if (rel->r)
409 exp_print(sql, fout, rel->r, depth, refs, 1, 0);
410 if (rel->l)
411 rel_print_(sql, fout, rel->l, depth+1, refs, decorate);
412 if (rel->exps)
413 exps_print(sql, fout, rel->exps, depth, refs, 1, 0);
414 break;
415 case op_ddl:
416 print_indent(sql, fout, depth, decorate);
417 mnstr_printf(fout, "ddl");
418 if (rel->l)
419 rel_print_(sql, fout, rel->l, depth+1, refs, decorate);
420 if (rel->r)
421 rel_print_(sql, fout, rel->r, depth+1, refs, decorate);
422 if (rel->exps && (rel->flag == ddl_psm || rel->flag == ddl_exception || rel->flag == ddl_list))
423 exps_print(sql, fout, rel->exps, depth, refs, 1, 0);
424 break;
425 case op_join:
426 case op_left:
427 case op_right:
428 case op_full:
429 case op_semi:
430 case op_anti:
431 case op_union:
432 case op_inter:
433 case op_except:
434 r = "join";
435 if (rel->op == op_left)
436 r = "left outer join";
437 else if (rel->op == op_right)
438 r = "right outer join";
439 else if (rel->op == op_full)
440 r = "full outer join";
441 else if (rel->op == op_semi)
442 r = "semijoin";
443 else if (rel->op == op_anti)
444 r = "antijoin";
445 else if (rel->op == op_union)
446 r = "union";
447 else if (rel->op == op_inter)
448 r = "intersect";
449 else if (rel->op == op_except)
450 r = "except";
451 else if (!rel->exps && rel->op == op_join)
452 r = "crossproduct";
453 print_indent(sql, fout, depth, decorate);
454 if (is_dependent(rel))
455 mnstr_printf(fout, "dependent ");
456 if (need_distinct(rel))
457 mnstr_printf(fout, "distinct ");
458 mnstr_printf(fout, "%s (", r);
459 if (rel->l) {
460 if (rel_is_ref(rel->l)) {
461 int nr = find_ref(refs, rel->l);
462 print_indent(sql, fout, depth+1, decorate);
463 mnstr_printf(fout, "& REF %d ", nr);
464 } else
465 rel_print_(sql, fout, rel->l, depth+1, refs, decorate);
466 }
467 mnstr_printf(fout, ",");
468 if (rel->r) {
469 if (rel_is_ref(rel->r)) {
470 int nr = find_ref(refs, rel->r);
471 print_indent(sql, fout, depth+1, decorate);
472 mnstr_printf(fout, "& REF %d ", nr);
473 } else
474 rel_print_(sql, fout, rel->r, depth+1, refs, decorate);
475 }
476 print_indent(sql, fout, depth, decorate);
477 mnstr_printf(fout, ")");
478 exps_print(sql, fout, rel->exps, depth, refs, 1, 0);
479 break;
480 case op_project:
481 case op_select:
482 case op_groupby:
483 case op_topn:
484 case op_sample:
485 r = "project";
486 if (rel->op == op_select)
487 r = "select";
488 if (rel->op == op_groupby)
489 r = "group by";
490 if (rel->op == op_topn)
491 r = "top N";
492 if (rel->op == op_sample)
493 r = "sample";
494 print_indent(sql, fout, depth, decorate);
495 if (rel->l) {
496 if (need_distinct(rel))
497 mnstr_printf(fout, "distinct ");
498 mnstr_printf(fout, "%s (", r);
499 if (rel_is_ref(rel->l)) {
500 int nr = find_ref(refs, rel->l);
501 print_indent(sql, fout, depth+1, decorate);
502 mnstr_printf(fout, "& REF %d ", nr);
503 } else
504 rel_print_(sql, fout, rel->l, depth+1, refs, decorate);
505 print_indent(sql, fout, depth, decorate);
506 mnstr_printf(fout, ")");
507 }
508 if (rel->op == op_groupby) /* group by columns */
509 exps_print(sql, fout, rel->r, depth, refs, 1, 0);
510 exps_print(sql, fout, rel->exps, depth, refs, 1, 0);
511 if (rel->r && rel->op == op_project) /* order by columns */
512 exps_print(sql, fout, rel->r, depth, refs, 1, 0);
513 break;
514 case op_insert:
515 case op_update:
516 case op_delete:
517 case op_truncate: {
518
519 print_indent(sql, fout, depth, decorate);
520 if (rel->op == op_insert)
521 mnstr_printf(fout, "insert(");
522 else if (rel->op == op_update)
523 mnstr_printf(fout, "update(");
524 else if (rel->op == op_delete)
525 mnstr_printf(fout, "delete(");
526 else if (rel->op == op_truncate) {
527 assert(list_length(rel->exps) == 2);
528 sql_exp *first = (sql_exp*) rel->exps->h->data, *second = (sql_exp*) rel->exps->h->next->data;
529 int restart_sequences = ((atom*)first->l)->data.val.ival,
530 drop_action = ((atom*)second->l)->data.val.ival;
531 mnstr_printf(fout, "truncate %s identity, %s(", restart_sequences ? "restart" : "continue",
532 drop_action ? "cascade" : "restrict");
533 }
534
535 if (rel->l) {
536 if (rel_is_ref(rel->l)) {
537 int nr = find_ref(refs, rel->l);
538 print_indent(sql, fout, depth+1, decorate);
539 mnstr_printf(fout, "& REF %d ", nr);
540 } else
541 rel_print_(sql, fout, rel->l, depth+1, refs, decorate);
542 }
543 if (rel->r) {
544 if (rel_is_ref(rel->r)) {
545 int nr = find_ref(refs, rel->r);
546 print_indent(sql, fout, depth+1, decorate);
547 mnstr_printf(fout, "& REF %d ", nr);
548 } else
549 rel_print_(sql, fout, rel->r, depth+1, refs, decorate);
550 }
551 print_indent(sql, fout, depth, decorate);
552 mnstr_printf(fout, ")");
553 if (rel->op != op_truncate && rel->exps)
554 exps_print(sql, fout, rel->exps, depth, refs, 1, 0);
555 } break;
556 default:
557 assert(0);
558 }
559 if (rel->single)
560 mnstr_printf(fout, " single ");
561 if (rel->p) {
562 prop *p = rel->p;
563 char *pv;
564
565 for (; p; p = p->p) {
566 pv = propvalue2string(p);
567 mnstr_printf(fout, " %s %s", propkind2string(p), pv);
568 GDKfree(pv);
569 }
570 }
571 //mnstr_printf(fout, " %p ", rel);
572}
573
574void
575rel_print_refs(mvc *sql, stream* fout, sql_rel *rel, int depth, list *refs, int decorate)
576{
577 if (!rel)
578 return;
579 switch (rel->op) {
580 case op_basetable:
581 case op_table:
582 break;
583 case op_ddl:
584 if (rel->flag == ddl_list || rel->flag == ddl_exception) {
585 if (rel->l) {
586 rel_print_refs(sql, fout, rel->l, depth, refs, decorate);
587 if (rel_is_ref(rel->l) && !find_ref(refs, rel->l)) {
588 rel_print_(sql, fout, rel->l, depth, refs, decorate);
589 list_append(refs, rel->l);
590 }
591 }
592 if (rel->r) {
593 rel_print_refs(sql, fout, rel->r, depth, refs, decorate);
594 if (rel_is_ref(rel->r) && !find_ref(refs, rel->r)) {
595 rel_print_(sql, fout, rel->r, depth, refs, decorate);
596 list_append(refs, rel->r);
597 }
598 }
599 }
600 break;
601 case op_join:
602 case op_left:
603 case op_right:
604 case op_full:
605 case op_semi:
606 case op_anti:
607 case op_union:
608 case op_inter:
609 case op_except:
610 if (rel->l)
611 rel_print_refs(sql, fout, rel->l, depth, refs, decorate);
612 if (rel->r)
613 rel_print_refs(sql, fout, rel->r, depth, refs, decorate);
614 if (rel->l && rel_is_ref(rel->l) && !find_ref(refs, rel->l)) {
615 rel_print_(sql, fout, rel->l, depth, refs, decorate);
616 list_append(refs, rel->l);
617 }
618 if (rel->r && rel_is_ref(rel->r) && !find_ref(refs, rel->r)) {
619 rel_print_(sql, fout, rel->r, depth, refs, decorate);
620 list_append(refs, rel->r);
621 }
622 break;
623 case op_project:
624 case op_select:
625 case op_groupby:
626 case op_topn:
627 case op_sample:
628 if (rel->l)
629 rel_print_refs(sql, fout, rel->l, depth, refs, decorate);
630 if (rel->l && rel_is_ref(rel->l) && !find_ref(refs, rel->l)) {
631 rel_print_(sql, fout, rel->l, depth, refs, decorate);
632 list_append(refs, rel->l);
633 }
634 break;
635 case op_insert:
636 case op_update:
637 case op_delete:
638 case op_truncate:
639 if (rel->l)
640 rel_print_refs(sql, fout, rel->l, depth, refs, decorate);
641 if (rel->l && rel_is_ref(rel->l) && !find_ref(refs, rel->l)) {
642 rel_print_(sql, fout, rel->l, depth, refs, decorate);
643 list_append(refs, rel->l);
644 }
645 if (rel->r)
646 rel_print_refs(sql, fout, rel->r, depth, refs, decorate);
647 if (rel->r && rel_is_ref(rel->r) && !find_ref(refs, rel->r)) {
648 rel_print_(sql, fout, rel->r, depth, refs, decorate);
649 list_append(refs, rel->r);
650 }
651 break;
652 }
653}
654
655static void
656skipWS( char *r, int *pos)
657{
658 while(r[*pos] && (isspace((unsigned char) r[*pos]) || r[*pos] == '|'))
659 (*pos)++;
660}
661
662static void
663skipUntilWS( char *r, int *pos)
664{
665 while(r[*pos] && (!isspace((unsigned char) r[*pos]) || r[*pos] == '|'))
666 (*pos)++;
667}
668
669static void
670skipIdent( char *r, int *pos)
671{
672 if (r[*pos] == '"') {
673 (*pos)++;
674 while(r[*pos] && r[*pos] != '"')
675 (*pos)++;
676 (*pos)++;
677 } else {
678 while(r[*pos] && (isalnum((unsigned char) r[*pos]) || r[*pos] == '_' || r[*pos] == '%'))
679 (*pos)++;
680 }
681}
682
683static void
684skipIdentOrSymbol( char *r, int *pos)
685{
686 if (r[*pos] == '"') {
687 skipIdent(r, pos);
688 } else {
689 while(r[*pos] && (isalnum((unsigned char) r[*pos]) ||
690 r[*pos] == '=' ||
691 r[*pos] == '_' || r[*pos] == '%' ||
692 r[*pos] == '<' || r[*pos] == '>' ||
693 r[*pos] == '/' || r[*pos] == '*' ||
694 r[*pos] == '-' || r[*pos] == '+' ||
695 r[*pos] == '~' || r[*pos] == '^' ))
696 (*pos)++;
697 }
698}
699
700static int
701readInt( char *r, int *pos)
702{
703 int res = 0;
704
705 while (isdigit((unsigned char) r[*pos])) {
706 res *= 10;
707 res += r[*pos]-'0';
708 (*pos)++;
709 }
710 return res;
711}
712
713static char *
714readString( char *r, int *pos)
715{
716 char *st = NULL;
717
718 if (r[*pos] == '"'){
719 (*pos)++;
720 st = r+*pos;
721 while (r[*pos] != '"')
722 (*pos)++;
723 r[*pos] = 0;
724 (*pos)++;
725 }
726 return st;
727}
728
729static sql_exp* exp_read(mvc *sql, sql_rel *lrel, sql_rel *rrel, list *pexps, char *r, int *pos, int grp) ;
730
731static void *
732read_prop( mvc *sql, sql_exp *exp, char *r, int *pos)
733{
734 /* PROPs */
735 if (strncmp(r+*pos, "JOINIDX", strlen("JOINIDX")) == 0) {
736 int old;
737 char *sname,*iname;
738 sql_schema *s = NULL;
739 prop *p;
740
741 (*pos)+= (int) strlen("JOINIDX");
742 skipWS(r, pos);
743 /* schema.table.index */
744 sname = r+*pos;
745 skipIdent(r,pos);
746 if (r[*pos] != '.')
747 return sql_error(sql, -1, SQLSTATE(42000) "JOINIDX: missing '.'\n");
748 r[*pos] = 0;
749 (*pos)++;
750 skipIdent(r,pos);
751 if (r[*pos] != '.')
752 return sql_error(sql, -1, SQLSTATE(42000) "JOINIDX: missing '.'\n");
753 r[*pos] = 0;
754 (*pos)++;
755 iname = r+*pos;
756 skipIdent(r,pos);
757 old = r[*pos];
758 r[*pos] = 0;
759
760 s = mvc_bind_schema(sql, sname);
761 if (!find_prop(exp->p, PROP_JOINIDX)) {
762 p = exp->p = prop_create(sql->sa, PROP_JOINIDX, exp->p);
763 p->value = mvc_bind_idx(sql, s, iname);
764 }
765 r[*pos] = old;
766 skipWS(r,pos);
767 }
768 return exp->p;
769}
770
771static list*
772read_exps(mvc *sql, sql_rel *lrel, sql_rel *rrel, list *pexps, char *r, int *pos, char bracket, int grp)
773{
774 list *exps = new_exp_list(sql->sa);
775 sql_exp *e;
776 char ebracket = (bracket == '[')?']':')';
777
778 if (r[*pos] == bracket) {
779 skipWS( r, pos);
780
781 (*pos)++;
782 skipWS( r, pos);
783 e = exp_read(sql, lrel, rrel, pexps, r, pos, grp);
784 if (!e && r[*pos] != ebracket) {
785 return sql_error(sql, -1, SQLSTATE(42000) "Missing closing %c\n", ebracket);
786 } else if (!e) {
787 (*pos)++;
788 skipWS( r, pos);
789 return exps;
790 }
791 append(exps, e);
792 skipWS( r, pos);
793 read_prop( sql, e, r, pos);
794 while (r[*pos] == ',') {
795 int op = 0;
796
797 (*pos)++;
798 skipWS( r, pos);
799 op = *pos;
800 e = exp_read(sql, lrel, rrel, exps, r, pos, grp);
801 if (!e && pexps) {
802 *pos = op;
803 e = exp_read(sql, lrel, rrel, pexps, r, pos, grp);
804 }
805 if (!e)
806 return NULL;
807 append(exps, e);
808 skipWS( r, pos);
809 read_prop( sql, e, r, pos);
810 }
811 if (r[*pos] != ebracket)
812 return sql_error(sql, -1, SQLSTATE(42000) "Missing closing %c\n", ebracket);
813 (*pos)++;
814 skipWS( r, pos);
815 }
816 return exps;
817}
818
819static sql_exp*
820exp_read(mvc *sql, sql_rel *lrel, sql_rel *rrel, list *pexps, char *r, int *pos, int grp)
821{
822 int f = -1, not = 1, old, d=0, s=0, unique = 0, no_nils = 0, quote = 0;
823 char *tname, *cname = NULL, *e, *b = r + *pos, *st;
824 sql_exp *exp = NULL;
825 list *exps = NULL;
826 sql_subtype *tpe;
827
828 quote = (r[*pos] == '"');
829 b += quote;
830 skipIdent(r, pos);
831 e = r+*pos-quote;
832 skipWS(r, pos);
833 switch(r[*pos]) {
834 case '.':
835 *e = 0;
836 (*pos)++;
837 tname = b;
838 cname = r + *pos + quote;
839 skipIdentOrSymbol(r, pos);
840 e = r+*pos - quote;
841 old = *e;
842 *e = 0;
843
844 tname = sa_strdup(sql->sa, tname);
845 cname = sa_strdup(sql->sa, cname);
846 *e = old;
847 skipWS(r, pos);
848 if (pexps) {
849 exp = exps_bind_column2(pexps, tname, cname);
850 if (exp)
851 exp = exp_alias_or_copy(sql, tname, cname, lrel, exp);
852 }
853 if (!exp && lrel) {
854 exp = rel_bind_column2(sql, lrel, tname, cname, 0);
855 if (!exp && rrel)
856 exp = rel_bind_column2(sql, rrel, tname, cname, 0);
857 } else if (!exp) {
858 exp = exp_column(sql->sa, tname, cname, NULL, CARD_ATOM, 1, (strchr(cname,'%') != NULL));
859 }
860 break;
861 /* atom */
862 case '(':
863 if (b == (r+*pos)) { /* or */
864 int filter = 0, anti = 0;
865 list *lexps,*rexps;
866 char *fname = NULL;
867
868 lexps = read_exps(sql, lrel, rrel, pexps, r, pos, '(', 0);
869 skipWS(r, pos);
870 if (r[*pos] == '!') {
871 anti = 1;
872 (*pos)++;
873 skipWS(r, pos);
874 }
875 if (strncmp(r+*pos, "or", strlen("or")) == 0) {
876 (*pos)+= (int) strlen("or");
877 } else if (strncmp(r+*pos, "FILTER", strlen("FILTER")) == 0) {
878 (*pos)+= (int) strlen("FILTER");
879 filter = 1;
880 } else {
881 return sql_error(sql, -1, SQLSTATE(42000) "Type: missing 'or'\n");
882 }
883 skipWS(r, pos);
884 if (filter) {
885 fname = r+*pos;
886
887 skipIdent(r,pos);
888 e = r+*pos;
889 *e = 0;
890 (*pos)++;
891 skipWS(r,pos);
892 }
893
894 rexps = read_exps(sql, lrel, rrel, pexps, r, pos, '(', 0);
895 if (filter) {
896 sql_subfunc *func = sql_find_func(sql->sa, mvc_bind_schema(sql, "sys"), fname, 1+list_length(exps), F_FILT, NULL);
897 if (!func)
898 return sql_error(sql, -1, SQLSTATE(42000) "Filter: missing function '%s'\n", fname);
899
900 return exp_filter(sql->sa, lexps, rexps, func, anti);
901 }
902 return exp_or(sql->sa, lexps, rexps, anti);
903 }
904 /* fall through */
905 case '[':
906 tname = b;
907 if (tname && *tname == '[') { /* list of values */
908 exps = read_exps(sql, lrel, rrel, pexps, r, pos, '[', 0);
909 if (!exps)
910 return NULL;
911 exp = exp_values(sql->sa, exps);
912 } else {
913 old = *e;
914 *e = 0;
915 if (old != '[') {
916 (*pos)++;
917 d = readInt(r,pos);
918 if (r[*pos] != ')' && r[*pos] != ',')
919 return sql_error(sql, -1, SQLSTATE(42000) "Type: missing ')' or ','\n");
920 if (r[*pos] == ',') {
921 (*pos)++;
922 s = readInt(r,pos);
923 }
924 if (r[*pos] != ')')
925 return sql_error(sql, -1, SQLSTATE(42000) "Type: missing ')'\n");
926 (*pos)++;
927 }
928 tpe = sql_bind_subtype(sql->sa, tname, d, s);
929 skipWS(r, pos);
930 *e = old;
931 if (r[*pos] == '[') { /* convert */
932 (*pos)++;
933 skipWS(r, pos);
934 exp = exp_read(sql, lrel, rrel, pexps, r, pos, 0);
935 if (!exp)
936 return NULL;
937 if (r[*pos] != ']')
938 return sql_error(sql, -1, SQLSTATE(42000) "Convert: missing ']'\n");
939 (*pos)++;
940 skipWS(r, pos);
941 exp = exp_convert(sql->sa, exp, exp_subtype(exp), tpe);
942 } else {
943 st = readString(r,pos);
944 if (st && strcmp(st, "NULL") == 0)
945 exp = exp_atom(sql->sa, atom_general(sql->sa, tpe, NULL));
946 else
947 exp = exp_atom(sql->sa, atom_general(sql->sa, tpe, st));
948 skipWS(r, pos);
949 }
950 }
951 break;
952 case '\"':
953 *e = 0;
954 tname = b;
955 tpe = sql_bind_subtype(sql->sa, tname, 0, 0);
956 st = readString(r,pos);
957 if (st && strcmp(st, "NULL") == 0)
958 exp = exp_atom(sql->sa, atom_general(sql->sa, tpe, NULL));
959 else
960 exp = exp_atom(sql->sa, atom_general(sql->sa, tpe, st));
961 skipWS(r, pos);
962 break;
963 default:
964 (void)sql;
965 }
966
967 /* func or aggr */
968 if (grp) {
969 skipWS(r, pos);
970 if (r[*pos] == 'u') {
971 unique = 1;
972 (*pos)+= (int) strlen("unique");
973 skipWS(r, pos);
974 }
975 if (r[*pos] == 'n') {
976 no_nils = 1;
977 (*pos)+= (int) strlen("no nil");
978 skipWS(r, pos);
979 }
980 }
981 if (r[*pos] == '(') {
982 sql_schema *s;
983 sql_subfunc *f = NULL;
984 sql_subaggr *a = NULL;
985 node *n;
986
987 exps = read_exps(sql, lrel, rrel, pexps, r, pos, '(', 0);
988 if (!exps)
989 return NULL;
990 tname = b;
991 *e = 0;
992 s = mvc_bind_schema(sql, tname);
993 if (grp) {
994 if (exps && exps->h)
995 a = sql_bind_aggr(sql->sa, s, cname, exp_subtype(exps->h->data));
996 else
997 a = sql_bind_aggr(sql->sa, s, cname, NULL);
998 exp = exp_aggr( sql->sa, exps, a, unique, no_nils, CARD_ATOM, 1);
999 } else {
1000 list *ops = sa_list(sql->sa);
1001 for( n = exps->h; n; n = n->next)
1002 append(ops, exp_subtype(n->data));
1003 f = sql_bind_func_(sql->sa, s, cname, ops, F_FUNC);
1004
1005 /* fix scale of mul function, other type casts are explicit */
1006 if (f && f->func->fix_scale == SCALE_MUL && list_length(exps) == 2) {
1007 sql_arg *ares = f->func->res->h->data;
1008
1009 if (strcmp(f->func->imp, "*") == 0 && ares->type.type->scale == SCALE_FIX) {
1010 sql_subtype *res = f->res->h->data;
1011 sql_subtype *lt = ops->h->data;
1012 sql_subtype *rt = ops->h->next->data;
1013
1014 res->digits = lt->digits;
1015 res->scale = lt->scale + rt->scale;
1016 }
1017 }
1018
1019 if (f)
1020 exp = exp_op( sql->sa, exps, f);
1021 else
1022 return sql_error(sql, -1, SQLSTATE(42000) "Function: missing '%s.%s %d'\n", tname, cname, list_length(ops));
1023 }
1024 }
1025
1026 if (!exp && b != e) { /* simple ident */
1027 if (b[0] == 'A' && isdigit((unsigned char) b[1])) {
1028 char *e2;
1029 int nr = strtol(b+1,&e2,10);
1030
1031 if (e == e2 && nr < sql->argc) {
1032 atom *a = sql->args[nr];
1033
1034 exp = exp_atom_ref(sql->sa, nr, &a->tpe);
1035 }
1036 assert(exp);
1037 }
1038 if (!exp) {
1039 old = *e;
1040 *e = 0;
1041 if (stack_find_var(sql, b)) {
1042 sql_subtype *tpe = stack_find_type(sql, b);
1043 int frame = stack_find_frame(sql, b);
1044 exp = exp_param(sql->sa, sa_strdup(sql->sa, b), tpe, frame);
1045 }
1046 *e = old;
1047 }
1048 if (!exp && lrel) {
1049 int amb = 0;
1050 char *cname;
1051
1052 old = *e;
1053 *e = 0;
1054 cname = sa_strdup(sql->sa, b);
1055 if (pexps) {
1056 exp = exps_bind_column(pexps, cname, &amb);
1057 if (exp)
1058 exp = exp_alias_or_copy(sql, exp_relname(exp), cname, lrel, exp);
1059 }
1060 (void)amb;
1061 assert(amb == 0);
1062 if (!exp && lrel)
1063 exp = rel_bind_column(sql, lrel, cname, 0);
1064 if (!exp && rrel)
1065 exp = rel_bind_column(sql, rrel, cname, 0);
1066 *e = old;
1067 skipWS(r,pos);
1068 }
1069 }
1070 if (!exp)
1071 return NULL;
1072
1073 if (r[*pos] == '!') {
1074 (*pos)++;
1075 skipWS(r, pos);
1076 set_anti(exp);
1077 }
1078 /* [ COUNT ] */
1079 if (strncmp(r+*pos, "COUNT", strlen("COUNT")) == 0) {
1080 (*pos)+= (int) strlen("COUNT");
1081 skipWS( r, pos);
1082 }
1083 /* [ ASC ] */
1084 if (strncmp(r+*pos, "ASC", strlen("ASC")) == 0) {
1085 (*pos)+= (int) strlen("ASC");
1086 skipWS(r, pos);
1087 set_direction(exp, 1);
1088 }
1089 /* [ ANY|ALL ] */
1090 if (strncmp(r+*pos, "ANY", strlen("ANY")) == 0) {
1091 (*pos)+= (int) strlen("ANY");
1092 skipWS(r, pos);
1093 exp->flag = 1;
1094 }
1095 if (strncmp(r+*pos, "ALL", strlen("ALL")) == 0) {
1096 (*pos)+= (int) strlen("ALL");
1097 skipWS(r, pos);
1098 exp->flag = 2;
1099 }
1100 /* [ NOT ] NULL */
1101 if (strncmp(r+*pos, "NOT", strlen("NOT")) == 0) {
1102 (*pos)+= (int) strlen("NOT");
1103 skipWS(r, pos);
1104 not = 1;
1105 }
1106 if (strncmp(r+*pos, "NULL", strlen("NULL")) == 0) {
1107 (*pos)+= (int) strlen("NULL");
1108 skipWS(r, pos);
1109 if (not)
1110 set_has_no_nil(exp);
1111 }
1112 if (strncmp(r+*pos, "HASHIDX", strlen("HASHIDX")) == 0) {
1113 (*pos)+= (int) strlen("HASHIDX");
1114 if (!find_prop(exp->p, PROP_HASHIDX))
1115 exp->p = prop_create(sql->sa, PROP_HASHIDX, exp->p);
1116 skipWS(r,pos);
1117 }
1118 if (strncmp(r+*pos, "HASHCOL", strlen("HASHCOL")) == 0) {
1119 (*pos)+= (int) strlen("HASHCOL");
1120 if (!find_prop(exp->p, PROP_HASHCOL))
1121 exp->p = prop_create(sql->sa, PROP_HASHCOL, exp->p);
1122 skipWS(r,pos);
1123 }
1124 if (strncmp(r+*pos, "FETCH", strlen("FETCH")) == 0) {
1125 (*pos)+= (int) strlen("FETCH");
1126 if (!find_prop(exp->p, PROP_FETCH))
1127 exp->p = prop_create(sql->sa, PROP_FETCH, exp->p);
1128 skipWS(r,pos);
1129 }
1130 read_prop( sql, exp, r, pos);
1131 skipWS(r,pos);
1132
1133 /* as alias */
1134 if (strncmp(r+*pos, "as", 2) == 0) {
1135 (*pos)+=2;
1136 skipWS(r, pos);
1137
1138 tname = r+*pos+1;
1139 skipIdent(r, pos);
1140 if (r[*pos] != '.') {
1141 r[*pos-1] = 0;
1142 cname = tname;
1143 exp_setname(sql->sa, exp, NULL, cname);
1144 skipWS(r, pos);
1145 } else {
1146 r[*pos-1] = 0;
1147 (*pos)++;
1148 cname = r+*pos+1;
1149 skipIdent(r, pos);
1150 e = r+*pos-1;
1151 skipWS(r, pos);
1152 *e = 0;
1153 exp_setname(sql->sa, exp, tname, cname);
1154 }
1155 }
1156 skipWS(r, pos);
1157 switch(r[*pos]) {
1158 case 'a':
1159 if (strncmp(r+*pos, "any =", strlen("any =")) == 0) {
1160 (*pos)+= (int) strlen("any =");
1161 f = mark_in;
1162 } else if (strncmp(r+*pos, "all <>", strlen("all <>")) == 0) {
1163 (*pos)+= (int) strlen("all <>");
1164 f = mark_notin;
1165 }
1166 break;
1167 case 'n':
1168 if (strncmp(r+*pos, "notin", strlen("notin")) == 0) {
1169 (*pos)+= (int) strlen("notin");
1170 f = cmp_notin;
1171 }
1172 break;
1173 case 'F':
1174 if (strncmp(r+*pos, "FILTER", strlen("FILTER")) == 0) {
1175 (*pos)+= (int) strlen("FILTER");
1176 f = cmp_filter;
1177 }
1178 break;
1179 case 'i':
1180 if (strncmp(r+*pos, "in", strlen("in")) == 0) {
1181 (*pos)+= (int) strlen("in");
1182 f = cmp_in;
1183 }
1184 break;
1185 case 'o':
1186 if (strncmp(r+*pos, "or", strlen("or")) == 0) {
1187 (*pos)+= (int) strlen("or");
1188 f = cmp_or;
1189 }
1190 break;
1191 case '!':
1192 f = cmp_notequal;
1193 (*pos)++;
1194 if (r[(*pos)] == '=') {
1195 f = cmp_notequal;
1196 (*pos)++;
1197 }
1198 break;
1199 case '=':
1200 f = cmp_equal;
1201 (*pos)++;
1202 if (r[(*pos)] == '*') {
1203 f = cmp_equal_nil;
1204 (*pos)++;
1205 }
1206 break;
1207 case '<':
1208 f = cmp_lt;
1209 (*pos)++;
1210 if (r[(*pos)] == '=') {
1211 f = cmp_lte;
1212 (*pos)++;
1213 }
1214 break;
1215 case '>':
1216 f = cmp_gt;
1217 (*pos)++;
1218 if (r[(*pos)] == '=') {
1219 f = cmp_gte;
1220 (*pos)++;
1221 }
1222 break;
1223 case ',':
1224 case ']':
1225 case ')':
1226 default:
1227 return exp;
1228 }
1229 if (f >= 0) {
1230 skipWS(r,pos);
1231 if (f == cmp_in || f == cmp_notin) {
1232 list *exps = read_exps(sql, lrel, rrel, pexps, r, pos, '(', 0);
1233 if (f == cmp_in || f == cmp_notin)
1234 return exp_in(sql->sa, exp, exps, f);
1235 } else {
1236 int sym = 0, between = 0;
1237 sql_exp *e = exp_read(sql, lrel, rrel, pexps, r, pos, 0);
1238
1239 if (strncmp(r+*pos, "BETWEEN", strlen("BETWEEN")) == 0) {
1240 (*pos)+= (int) strlen("BETWEEN");
1241 skipWS(r,pos);
1242 between = 1;
1243 }
1244 if (strncmp(r+*pos, "SYM", strlen("SYM")) == 0) {
1245 (*pos)+= (int) strlen("SYM");
1246 skipWS(r,pos);
1247 sym = 1;
1248 }
1249 if (e && e->type == e_cmp) {
1250 sql_exp *ne = exp_compare2(sql->sa, e->l, exp, e->r, compare2range(swap_compare((comp_type)f), e->flag));
1251 if (sym)
1252 ne->flag |= CMP_SYMMETRIC;
1253 if (between)
1254 ne->flag |= CMP_BETWEEN;
1255 if (is_anti(exp))
1256 set_anti(ne);
1257 return ne;
1258 } else if (e) {
1259 sql_exp *ne = exp_compare(sql->sa, exp, e, f);
1260 if (sym)
1261 ne->flag |= CMP_SYMMETRIC;
1262 if (between)
1263 ne->flag |= CMP_BETWEEN;
1264 if (is_anti(exp))
1265 set_anti(ne);
1266 return ne;
1267 }
1268 }
1269 }
1270 return exp;
1271}
1272
1273static int
1274rel_set_types(mvc *sql, sql_rel *rel)
1275{
1276 list *iexps = rel_projections( sql, rel->l, NULL, 0, 1);
1277 node *n, *m;
1278
1279 if (!iexps || list_length(iexps) > list_length(rel->exps))
1280 return -1;
1281 for(n=iexps->h, m=rel->exps->h; n && m; n = n->next, m = m->next) {
1282 sql_exp *e = m->data;
1283
1284 e->tpe = *exp_subtype( n->data );
1285 }
1286 return 0;
1287}
1288
1289sql_rel*
1290rel_read(mvc *sql, char *r, int *pos, list *refs)
1291{
1292 sql_rel *rel = NULL, *nrel, *lrel, *rrel;
1293 list *exps, *gexps;
1294 int distinct = 0;
1295 operator_type j = op_basetable;
1296
1297 skipWS(r,pos);
1298 if (r[*pos] == 'R') {
1299 *pos += (int) strlen("REF");
1300
1301 skipWS(r, pos);
1302 (void)readInt(r,pos);
1303 skipWS(r, pos);
1304 (*pos)++; /* ( */
1305 (void)readInt(r,pos); /* skip nr refs */
1306 (*pos)++; /* ) */
1307 rel = rel_read(sql, r, pos, refs);
1308 append(refs, rel);
1309 skipWS(r,pos);
1310 }
1311 if (r[*pos] == '&') {
1312 int nr;
1313 (*pos)++;
1314 skipWS(r, pos);
1315 *pos += (int) strlen("REF");
1316 skipWS(r, pos);
1317 nr = readInt(r,pos); /* skip nr refs */
1318 return rel_dup(list_fetch(refs, nr-1));
1319 }
1320
1321 if (r[*pos] == 'i' && r[*pos+1] == 'n' && r[*pos+2] == 's') {
1322 *pos += (int) strlen("insert");
1323 skipWS(r, pos);
1324 (*pos)++; /* ( */
1325 lrel = rel_read(sql, r, pos, refs); /* to be inserted relation */
1326 skipWS(r,pos);
1327 rrel = rel_read(sql, r, pos, refs); /* the inserts relation */
1328 skipWS(r,pos);
1329 (*pos)++; /* ) */
1330
1331 return rel_insert(sql, lrel, rrel);
1332 }
1333
1334 if (r[*pos] == 'd' && r[*pos+1] == 'e' && r[*pos+2] == 'l') {
1335 *pos += (int) strlen("delete");
1336 skipWS(r, pos);
1337 (*pos)++; /* ( */
1338 lrel = rel_read(sql, r, pos, refs); /* to be deleted relation */
1339 skipWS(r,pos);
1340 rrel = rel_read(sql, r, pos, refs); /* the deletes relation */
1341 skipWS(r,pos);
1342 (*pos)++; /* ) */
1343
1344 return rel_delete(sql->sa, lrel, rrel);
1345 }
1346
1347 if (r[*pos] == 't' && r[*pos+1] == 'r' && r[*pos+2] == 'u') {
1348 int restart_sequences = 0, drop_action = 0;
1349 *pos += (int) strlen("truncate ");
1350 if (r[*pos] == 'r') {
1351 restart_sequences = 1;
1352 *pos += (int) strlen("restart identity, ");
1353 } else {
1354 *pos += (int) strlen("continue identity, ");
1355 }
1356 if (r[*pos] == 'c') {
1357 drop_action = 1;
1358 *pos += (int) strlen("cascade");
1359 } else {
1360 *pos += (int) strlen("restrict");
1361 }
1362 skipWS(r, pos);
1363 (*pos)++; /* ( */
1364 lrel = rel_read(sql, r, pos, refs); /* to be truncated relation */
1365 skipWS(r,pos);
1366 (*pos)++; /* ) */
1367
1368 return rel_truncate(sql->sa, lrel, drop_action, restart_sequences);
1369 }
1370
1371 if (r[*pos] == 'u' && r[*pos+1] == 'p' && r[*pos+2] == 'd') {
1372 *pos += (int) strlen("update");
1373 skipWS(r, pos);
1374 (*pos)++; /* ( */
1375 lrel = rel_read(sql, r, pos, refs); /* to be updated relation */
1376 skipWS(r,pos);
1377 rrel = rel_read(sql, r, pos, refs); /* the updates relation */
1378 skipWS(r,pos);
1379 (*pos)++; /* ) */
1380
1381 exps = read_exps(sql, lrel, rrel, NULL, r, pos, '[', 0); /* columns to be updated */
1382 if (!exps)
1383 return NULL;
1384 return rel_update(sql, lrel, rrel, NULL, exps);
1385 }
1386
1387 if (r[*pos] == 'd') {
1388 *pos += (int) strlen("distinct");
1389 skipWS(r, pos);
1390 distinct = 1;
1391 }
1392 switch(r[*pos]) {
1393 case 't':
1394 if (r[*pos+1] == 'a') {
1395 sql_schema *s = NULL;
1396 sql_table *t = NULL;
1397 char *sname, *tname, *e;
1398 *pos += (int) strlen("table");
1399 skipWS(r, pos);
1400 if (r[*pos] != '(')
1401 return sql_error(sql, -1, SQLSTATE(42000) "Table: missing '('\n");
1402 (*pos)++;
1403 skipWS(r, pos);
1404 sname = r+*pos;
1405 skipIdent(r, pos);
1406 e = r+*pos;
1407 if (r[*pos] != '.')
1408 return sql_error(sql, -1, SQLSTATE(42000) "Table: missing '.' in table name\n");
1409 *e = 0;
1410 (*pos)++;
1411 tname = r+*pos;
1412 skipIdent(r, pos);
1413 e = r+*pos;
1414 skipWS(r, pos);
1415 if (r[*pos] != ')')
1416 sql_error(sql, -1, SQLSTATE(42000) "Table: missing ')'\n");
1417 *e = 0;
1418 (*pos)++;
1419 skipWS(r, pos);
1420 s = mvc_bind_schema(sql, sname);
1421 if (s)
1422 t = mvc_bind_table(sql, s, tname);
1423 if (!s || !t)
1424 return sql_error(sql, -1, SQLSTATE(42000) "Table: missing '%s.%s'\n", sname, tname);
1425 rel = rel_basetable(sql, t, tname);
1426
1427 if (!r[*pos])
1428 return rel;
1429
1430 /* scan aliases */
1431 exps = read_exps(sql, rel, NULL, NULL, r, pos, '[', 0);
1432 if (exps && list_length(exps))
1433 rel->exps = exps;
1434 if (strncmp(r+*pos, "COUNT", strlen("COUNT")) == 0) {
1435 (*pos)+= (int) strlen("COUNT");
1436 skipWS( r, pos);
1437 }
1438 } else { /* top N */
1439 *pos += (int) strlen("top N");
1440 skipWS(r, pos);
1441 if (r[*pos] != '(')
1442 return sql_error(sql, -1, SQLSTATE(42000) "Top N: missing '('\n");
1443 (*pos)++;
1444 skipWS(r, pos);
1445 nrel = rel_read(sql, r, pos, refs);
1446 if (r[*pos] != ')')
1447 return sql_error(sql, -1, SQLSTATE(42000) "Top N: missing ')'\n");
1448 (*pos)++;
1449 skipWS(r, pos);
1450 exps = read_exps(sql, nrel, NULL, NULL, r, pos, '[', 0);
1451 rel = rel_topn(sql->sa, nrel, exps);
1452 }
1453 break;
1454 case 'p':
1455 *pos += (int) strlen("project");
1456 skipWS(r, pos);
1457
1458 if (r[*pos] != '(')
1459 return sql_error(sql, -1, SQLSTATE(42000) "Project: missing '('\n");
1460 (*pos)++;
1461 skipWS(r, pos);
1462 nrel = rel_read(sql, r, pos, refs);
1463 skipWS(r, pos);
1464 if (r[*pos] != ')')
1465 return sql_error(sql, -1, SQLSTATE(42000) "Project: missing ')'\n");
1466 (*pos)++;
1467 skipWS(r, pos);
1468
1469 exps = read_exps(sql, nrel, NULL, NULL, r, pos, '[', 0);
1470 rel = rel_project(sql->sa, nrel, exps);
1471 /* order by ? */
1472 if (r[*pos] == '[')
1473 rel->r = read_exps(sql, nrel, rel, NULL, r, pos, '[', 0);
1474 if (distinct)
1475 set_distinct(rel);
1476 distinct = 0;
1477 break;
1478 case 'g':
1479 *pos += (int) strlen("group by");
1480 skipWS(r, pos);
1481
1482 if (r[*pos] != '(')
1483 return sql_error(sql, -1, SQLSTATE(42000) "Group by: missing '('\n");
1484 (*pos)++;
1485 skipWS(r, pos);
1486 nrel = rel_read(sql, r, pos, refs);
1487 skipWS(r, pos);
1488 if (r[*pos] != ')')
1489 return sql_error(sql, -1, SQLSTATE(42000) "Group by: missing ')'\n");
1490 (*pos)++;
1491 skipWS(r, pos);
1492
1493 gexps = read_exps(sql, nrel, NULL, NULL, r, pos, '[', 0);
1494 skipWS(r, pos);
1495 exps = read_exps(sql, nrel, NULL, gexps, r, pos, '[', 1);
1496 if (!exps)
1497 return NULL;
1498
1499 rel = rel_groupby(sql, nrel, gexps);
1500 rel->exps = exps;
1501 break;
1502 case 's':
1503 case 'a':
1504 if (r[*pos+1] == 'a') {
1505 *pos += (int) strlen("sample");
1506 skipWS(r, pos);
1507 if (r[*pos] != '(')
1508 return sql_error(sql, -1, SQLSTATE(42000) "Sample: missing '('\n");
1509 (*pos)++;
1510 skipWS(r, pos);
1511 nrel = rel_read(sql, r, pos, refs);
1512 if (r[*pos] != ')')
1513 return sql_error(sql, -1, SQLSTATE(42000) "Sample: missing ')'\n");
1514 (*pos)++;
1515 skipWS(r, pos);
1516 exps = read_exps(sql, nrel, NULL, NULL, r, pos, '[', 0);
1517 rel = rel_sample(sql->sa, nrel, exps);
1518 } else if (r[*pos+2] == 'l') {
1519 *pos += (int) strlen("select");
1520 skipWS(r, pos);
1521 if (r[*pos] != '(')
1522 return sql_error(sql, -1, SQLSTATE(42000) "Select: missing '('\n");
1523 (*pos)++;
1524 skipWS(r, pos);
1525 nrel = rel_read(sql, r, pos, refs);
1526 skipWS(r, pos);
1527 if (r[*pos] != ')')
1528 return sql_error(sql, -1, SQLSTATE(42000) "Select: missing ')'\n");
1529 (*pos)++;
1530 skipWS(r, pos);
1531
1532 exps = read_exps(sql, nrel, NULL, NULL, r, pos, '[', 0);
1533 rel = rel_select_copy(sql->sa, nrel, exps);
1534 /* semijoin or antijoin */
1535 } else if (r[*pos+1] == 'e' || r[*pos+1] == 'n') {
1536 j = op_semi;
1537
1538 if (r[*pos+1] == 'n')
1539 j = op_anti;
1540
1541 *pos += (int) strlen("semijoin");
1542 skipWS(r, pos);
1543 if (r[*pos] != '(')
1544 return sql_error(sql, -1, SQLSTATE(42000) "Semijoin: missing '('\n");
1545 (*pos)++;
1546 skipWS(r, pos);
1547 lrel = rel_read(sql, r, pos, refs);
1548 skipWS(r, pos);
1549
1550 if (r[*pos] != ',')
1551 return sql_error(sql, -1, SQLSTATE(42000) "Semijoin: missing ','\n");
1552 (*pos)++;
1553 skipWS(r, pos);
1554 rrel = rel_read(sql, r, pos, refs);
1555
1556 skipWS(r, pos);
1557 if (r[*pos] != ')')
1558 return sql_error(sql, -1, SQLSTATE(42000) "Semijoin: missing ')'\n");
1559 (*pos)++;
1560 skipWS(r, pos);
1561
1562 exps = read_exps(sql, lrel, rrel, NULL, r, pos, '[', 0);
1563 rel = rel_crossproduct(sql->sa, lrel, rrel, j);
1564 rel->exps = exps;
1565 }
1566 break;
1567 case 'l':
1568 *pos += (int) strlen("left outer join");
1569 j = op_left;
1570 /* fall through */
1571 case 'r':
1572 if (j == op_basetable) {
1573 *pos += (int) strlen("right outer join");
1574 j = op_right;
1575 }
1576 /* fall through */
1577 case 'f':
1578 if (j == op_basetable) {
1579 *pos += (int) strlen("full outer join");
1580 j = op_full;
1581 }
1582 /* fall through */
1583 case 'c':
1584 if (j == op_basetable) {
1585 *pos += (int) strlen("crossproduct");
1586 j = op_join;
1587 }
1588 /* fall through */
1589 case 'j':
1590 if (j == op_basetable) {
1591 *pos += (int) strlen("join");
1592 j = op_join;
1593 }
1594 skipWS(r, pos);
1595
1596 if (r[*pos] != '(')
1597 return sql_error(sql, -1, SQLSTATE(42000) "Join: missing '('\n");
1598 (*pos)++;
1599 skipWS(r, pos);
1600 lrel = rel_read(sql, r, pos, refs);
1601 skipWS(r, pos);
1602
1603 if (r[*pos] != ',')
1604 return sql_error(sql, -1, SQLSTATE(42000) "Join: missing ','\n");
1605 (*pos)++;
1606 skipWS(r, pos);
1607 rrel = rel_read(sql, r, pos, refs);
1608
1609 skipWS(r, pos);
1610 if (r[*pos] != ')')
1611 return sql_error(sql, -1, SQLSTATE(42000) "Join: missing ')'\n");
1612 (*pos)++;
1613 skipWS(r, pos);
1614
1615 exps = read_exps(sql, lrel, rrel, NULL, r, pos, '[', 0);
1616 rel = rel_crossproduct(sql->sa, lrel, rrel, j);
1617 rel->exps = exps;
1618 break;
1619 case 'u':
1620 if (j == op_basetable) {
1621 *pos += (int) strlen("union");
1622 j = op_union;
1623 }
1624 /* fall through */
1625 case 'i':
1626 if (j == op_basetable) {
1627 *pos += (int) strlen("intersect");
1628 j = op_inter;
1629 }
1630 /* fall through */
1631 case 'e':
1632 if (j == op_basetable) {
1633 *pos += (int) strlen("except");
1634 j = op_except;
1635 }
1636 skipWS(r, pos);
1637
1638 if (r[*pos] != '(')
1639 return sql_error(sql, -1, SQLSTATE(42000) "Setop: missing '('\n");
1640 (*pos)++;
1641 skipWS(r, pos);
1642 lrel = rel_read(sql, r, pos, refs);
1643 skipWS(r, pos);
1644
1645 if (r[*pos] != ',')
1646 return sql_error(sql, -1, SQLSTATE(42000) "Setop: missing ','\n");
1647 (*pos)++;
1648 skipWS(r, pos);
1649 rrel = rel_read(sql, r, pos, refs);
1650
1651 skipWS(r, pos);
1652 if (r[*pos] != ')')
1653 return sql_error(sql, -1, SQLSTATE(42000) "Setop: missing ')'\n");
1654 (*pos)++;
1655 skipWS(r, pos);
1656
1657 exps = read_exps(sql, NULL, NULL, NULL, r, pos, '[', 0);
1658 rel = rel_setop(sql->sa, lrel, rrel, j);
1659 if (!exps)
1660 return NULL;
1661 rel->exps = exps;
1662 if (rel_set_types(sql, rel) < 0)
1663 return NULL;
1664 set_processed(rel);
1665 break;
1666 case '[': /* projection of list of values */
1667 exps = read_exps(sql, NULL, NULL, NULL, r, pos, '[', 0);
1668 if (!exps)
1669 return NULL;
1670 rel = rel_project(sql->sa, NULL, exps);
1671 /* order by ? */
1672 if (r[*pos] == '[')
1673 rel->r = read_exps(sql, NULL, rel, NULL, r, pos, '[', 0);
1674 if (distinct)
1675 set_distinct(rel);
1676 distinct = 0;
1677 break;
1678 case 'd':
1679 /* 'ddl' not supported */
1680 default:
1681 return NULL;
1682 }
1683 /* sometimes the properties are send */
1684 while (strncmp(r+*pos, "REMOTE", strlen("REMOTE")) == 0) {
1685 (*pos)+= (int) strlen("REMOTE");
1686 skipWS(r, pos);
1687 skipUntilWS(r, pos);
1688 skipWS(r, pos);
1689 }
1690 while (strncmp(r+*pos, "USED", strlen("USED")) == 0) {
1691 (*pos)+= (int) strlen("USED");
1692 skipWS(r, pos);
1693 }
1694 while (strncmp(r+*pos, "DISTRIBUTE", strlen("DISTRIBUTE")) == 0) {
1695 (*pos)+= (int) strlen("DISTRIBUTE");
1696 skipWS(r, pos);
1697 }
1698 return rel;
1699}
1700