LCOV - code coverage report
Current view: top level - sql/server - rel_dump.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 975 1395 69.9 %
Date: 2021-10-13 02:24:04 Functions: 22 24 91.7 %

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

Generated by: LCOV version 1.14