LCOV - code coverage report
Current view: top level - sql/server - rel_rel.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1190 1374 86.6 %
Date: 2024-04-25 20:03:45 Functions: 82 87 94.3 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "rel_rel.h"
      15             : #include "rel_basetable.h"
      16             : #include "rel_exp.h"
      17             : #include "rel_prop.h"
      18             : #include "rel_unnest.h"
      19             : #include "sql_semantic.h"
      20             : #include "sql_mvc.h"
      21             : #include "rel_rewriter.h"
      22             : 
      23             : void
      24         193 : rel_set_exps(sql_rel *rel, list *exps)
      25             : {
      26         193 :         rel->exps = exps;
      27         193 :         rel->nrcols = list_length(exps);
      28         193 : }
      29             : 
      30             : /* some projections results are order dependend (row_number etc) */
      31             : int
      32     1612615 : project_unsafe(sql_rel *rel, int allow_identity)
      33             : {
      34     1612615 :         sql_rel *sub = rel->l;
      35             : 
      36     1612615 :         if (need_distinct(rel) || rel->r /* order by */)
      37             :                 return 1;
      38     1459935 :         if (list_empty(rel->exps))
      39             :                 return 0;
      40             :         /* projects without sub and projects around ddl's cannot be changed */
      41     1459929 :         if (!sub || sub->op == op_ddl)
      42             :                 return 1;
      43     9930470 :         for(node *n = rel->exps->h; n; n = n->next) {
      44     8896656 :                 sql_exp *e = n->data, *ne;
      45             : 
      46             :                 /* aggr func in project ! */
      47     8896656 :                 if (exp_unsafe(e, allow_identity))
      48             :                         return 1;
      49     8795628 :                 if ((ne = rel_find_exp(rel, e)) && ne != e)
      50             :                         return 1; /* no self referencing */
      51             :         }
      52             :         return 0;
      53             : }
      54             : 
      55             : /* we don't name relations directly, but sometimes we need the relation
      56             :    name. So we look it up in the first expression
      57             : 
      58             :    we should clean up (remove) this function.
      59             :  */
      60             : const char *
      61      127023 : rel_name( sql_rel *r )
      62             : {
      63      130810 :         if (is_basetable(r->op))
      64      126900 :                 return rel_base_name(r);
      65        3910 :         if (!is_project(r->op) && !is_base(r->op) && r->l)
      66             :                 return rel_name(r->l);
      67         123 :         if (r->exps && list_length(r->exps)) {
      68         123 :                 sql_exp *e = r->exps->h->data;
      69         123 :                 if (exp_relname(e))
      70         123 :                         return exp_relname(e);
      71           0 :                 if (e->type == e_column)
      72           0 :                         return e->l;
      73             :         }
      74             :         return NULL;
      75             : }
      76             : 
      77             : sql_rel *
      78        9101 : rel_distinct(sql_rel *l)
      79             : {
      80        9101 :         set_distinct(l);
      81        9101 :         return l;
      82             : }
      83             : 
      84             : sql_rel *
      85      579363 : rel_dup(sql_rel *r)
      86             : {
      87      579363 :         sql_ref_inc(&r->ref);
      88      579363 :         return r;
      89             : }
      90             : 
      91             : static void
      92      658197 : rel_destroy_(sql_rel *rel)
      93             : {
      94      658197 :         if (!rel)
      95             :                 return;
      96      658197 :         switch(rel->op){
      97             :         case op_basetable:
      98             :                 break;
      99        4873 :         case op_table:
     100        4873 :                 if ((IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION) && rel->l)
     101          11 :                         rel_destroy(rel->l);
     102             :                 break;
     103      333147 :         case op_join:
     104             :         case op_left:
     105             :         case op_right:
     106             :         case op_full:
     107             :         case op_semi:
     108             :         case op_anti:
     109             :         case op_union:
     110             :         case op_inter:
     111             :         case op_except:
     112             :         case op_insert:
     113             :         case op_update:
     114             :         case op_delete:
     115             :         case op_merge:
     116      333147 :                 if (rel->l)
     117       53451 :                         rel_destroy(rel->l);
     118      333147 :                 if (rel->r)
     119       57697 :                         rel_destroy(rel->r);
     120             :                 break;
     121      310124 :         case op_project:
     122             :         case op_groupby:
     123             :         case op_select:
     124             :         case op_topn:
     125             :         case op_sample:
     126             :         case op_truncate:
     127      310124 :                 if (rel->l)
     128       86329 :                         rel_destroy(rel->l);
     129             :                 break;
     130           0 :         case op_ddl:
     131           0 :                 if (rel->flag == ddl_output || rel->flag == ddl_create_seq || rel->flag == ddl_alter_seq || rel->flag == ddl_alter_table || rel->flag == ddl_create_table || rel->flag == ddl_create_view) {
     132           0 :                         if (rel->l)
     133           0 :                                 rel_destroy(rel->l);
     134             :                 } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
     135           0 :                         if (rel->l)
     136           0 :                                 rel_destroy(rel->l);
     137           0 :                         if (rel->r)
     138           0 :                                 rel_destroy(rel->r);
     139             :                 }
     140             :                 break;
     141             :         }
     142             : }
     143             : 
     144             : void
     145     1176550 : rel_destroy(sql_rel *rel)
     146             : {
     147     1176550 :         if (!rel)
     148             :                 return;
     149     1176546 :         if (sql_ref_dec(&rel->ref) > 0)
     150             :                 return;
     151      621171 :         rel_destroy_(rel);
     152             : }
     153             : 
     154             : sql_rel*
     155     3197495 : rel_create(sql_allocator *sa)
     156             : {
     157     3197495 :         sql_rel *r = SA_NEW(sa, sql_rel);
     158     3197487 :         if(!r)
     159             :                 return NULL;
     160             : 
     161     3197487 :         *r = (sql_rel) {
     162             :                 .card = CARD_ATOM,
     163             :         };
     164     3197487 :         sql_ref_init(&r->ref);
     165     3197487 :         return r;
     166             : }
     167             : 
     168             : sql_rel *
     169         188 : rel_copy(mvc *sql, sql_rel *i, int deep)
     170             : {
     171         188 :         sql_rel *rel;
     172             : 
     173         188 :         if (mvc_highwater(sql))
     174           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     175             : 
     176         188 :         rel = rel_create(sql->sa);
     177         188 :         if (!rel)
     178             :                 return NULL;
     179             : 
     180         188 :         rel->op = i->op;
     181         188 :         switch(i->op) {
     182          60 :         case op_basetable:
     183          60 :                 rel_base_copy(sql, i, rel);
     184          60 :                 break;
     185           0 :         case op_table:
     186           0 :                 if ((IS_TABLE_PROD_FUNC(i->flag) || i->flag == TABLE_FROM_RELATION) && i->l)
     187           0 :                         rel->l = rel_copy(sql, i->l, deep);
     188           0 :                 rel->r = i->r;
     189           0 :                 break;
     190          80 :         case op_project:
     191             :         case op_groupby:
     192          80 :                 if (i->l)
     193          68 :                         rel->l = rel_copy(sql, i->l, deep);
     194          80 :                 if (i->r) {
     195           7 :                         if (!deep) {
     196           0 :                                 rel->r = list_dup(i->r, (fdup) NULL);
     197             :                         } else {
     198           7 :                                 rel->r = exps_copy(sql, i->r);
     199             :                         }
     200             :                 }
     201             :                 break;
     202           0 :         case op_ddl:
     203           0 :                 if (i->flag == ddl_output || i->flag == ddl_create_seq || i->flag == ddl_alter_seq || i->flag == ddl_alter_table || i->flag == ddl_create_table || i->flag == ddl_create_view) {
     204           0 :                         if (i->l)
     205           0 :                                 rel->l = rel_copy(sql, i->l, deep);
     206           0 :                 } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
     207           0 :                         if (i->l)
     208           0 :                                 rel->l = rel_copy(sql, i->l, deep);
     209           0 :                         if (i->r)
     210           0 :                                 rel->r = rel_copy(sql, i->r, deep);
     211             :                 }
     212             :                 break;
     213          23 :         case op_select:
     214             :         case op_topn:
     215             :         case op_sample:
     216             :         case op_truncate:
     217          23 :                 if (i->l)
     218          23 :                         rel->l = rel_copy(sql, i->l, deep);
     219             :                 break;
     220          25 :         case op_join:
     221             :         case op_left:
     222             :         case op_right:
     223             :         case op_full:
     224             :         case op_semi:
     225             :         case op_anti:
     226             : 
     227             :         case op_union:
     228             :         case op_inter:
     229             :         case op_except:
     230             : 
     231             :         case op_insert:
     232             :         case op_update:
     233             :         case op_delete:
     234             :         case op_merge:
     235          25 :                 if (i->l)
     236          25 :                         rel->l = rel_copy(sql, i->l, deep);
     237          25 :                 if (i->r)
     238          25 :                         rel->r = rel_copy(sql, i->r, deep);
     239             :                 break;
     240             :         }
     241             : 
     242         188 :         rel->card = i->card;
     243         188 :         rel->flag = i->flag;
     244         188 :         rel->nrcols = i->nrcols;
     245         188 :         rel->grouped = i->grouped;
     246         188 :         rel->used = i->used;
     247             : 
     248         188 :         if (is_processed(i))
     249         120 :                 set_processed(rel);
     250         188 :         if (is_dependent(i))
     251           0 :                 set_dependent(rel);
     252         188 :         if (is_outer(i))
     253           9 :                 set_outer(rel);
     254         188 :         if (is_single(i))
     255           4 :                 set_single(rel);
     256         188 :         if (need_distinct(i))
     257           4 :                 set_distinct(rel);
     258             : 
     259         188 :         rel->p = prop_copy(sql->sa, i->p);
     260         188 :         rel->exps = (!i->exps)?NULL:deep?exps_copy(sql, i->exps):list_dup(i->exps, (fdup)NULL);
     261         188 :         rel->attr = (!i->attr)?NULL:deep?exps_copy(sql, i->attr):list_dup(i->attr, (fdup)NULL);
     262         188 :         return rel;
     263             : }
     264             : 
     265             : sql_rel *
     266        4644 : rel_select_copy(sql_allocator *sa, sql_rel *l, list *exps)
     267             : {
     268        4644 :         sql_rel *rel = rel_create(sa);
     269        4644 :         if(!rel)
     270             :                 return NULL;
     271             : 
     272        4644 :         rel->l = l;
     273        4644 :         rel->r = NULL;
     274        4644 :         rel->op = op_select;
     275        4644 :         rel->exps = exps?list_dup(exps, (fdup)NULL):NULL;
     276        4644 :         rel->card = CARD_ATOM; /* no relation */
     277        4644 :         if (l) {
     278        4644 :                 rel->card = l->card;
     279        4644 :                 rel->nrcols = l->nrcols;
     280             :         }
     281             :         return rel;
     282             : }
     283             : 
     284             : sql_exp *
     285     7949811 : rel_bind_column( mvc *sql, sql_rel *rel, const char *cname, int f, int no_tname)
     286             : {
     287     7949811 :         int ambiguous = 0, multi = 0;
     288             : 
     289     7949811 :         if (!rel)
     290             :                 return NULL;
     291     7949811 :         if (mvc_highwater(sql))
     292           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     293             : 
     294     7949811 :         if ((is_project(rel->op) || is_base(rel->op))) {
     295     4217460 :                 sql_exp *e = NULL;
     296             : 
     297     4217460 :                 if (is_base(rel->op) && !rel->exps)
     298     4040396 :                         return rel_base_bind_column(sql, rel, cname, no_tname);
     299      177064 :                 if (!list_empty(rel->exps)) {
     300      177030 :                         e = exps_bind_column(rel->exps, cname, &ambiguous, &multi, no_tname);
     301      177030 :                         if (ambiguous || multi)
     302          10 :                                 return sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s' ambiguous", cname);
     303      177020 :                         if (!e && is_groupby(rel->op) && rel->r) {
     304         215 :                                 e = exps_bind_alias(rel->r, NULL, cname);
     305         215 :                                 if (e) {
     306           0 :                                         e = exps_bind_column(rel->r, cname, &ambiguous, &multi, no_tname);
     307           0 :                                         if (ambiguous || multi)
     308           0 :                                                 return sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s' ambiguous", cname);
     309             :                                         return e;
     310             :                                 }
     311             :                         }
     312             :                 }
     313       19177 :                 if (!e && (is_sql_sel(f) || is_sql_having(f) || !f) && is_groupby(rel->op) && rel->r) {
     314         215 :                         e = exps_bind_column(rel->r, cname, &ambiguous, &multi, no_tname);
     315         215 :                         if (ambiguous || multi)
     316           0 :                                 return sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s' ambiguous", cname);
     317         215 :                         if (e) {
     318           1 :                                 e = exp_ref(sql, e);
     319           1 :                                 e->card = rel->card;
     320           1 :                                 return e;
     321             :                         }
     322             :                 }
     323      157877 :                 if (e)
     324      157877 :                         return exp_alias_or_copy(sql, exp_relname(e), cname, rel, e);
     325             :         }
     326     3751527 :         if (is_simple_project(rel->op) && rel->l) {
     327        6921 :                 if (!is_processed(rel))
     328           0 :                         return rel_bind_column(sql, rel->l, cname, f, no_tname);
     329     3744606 :         } else if (is_set(rel->op)) {
     330          64 :                 assert(is_processed(rel));
     331             :                 return NULL;
     332             :         } else if (is_join(rel->op)) {
     333     3229081 :                 sql_exp *e1 = rel_bind_column(sql, rel->l, cname, f, no_tname), *e2 = NULL, *res;
     334             : 
     335     3229081 :                 if (e1 && (is_right(rel->op) || is_full(rel->op)))
     336           7 :                         set_has_nil(e1);
     337     1612962 :                 if (!e1 || !is_freevar(e1)) {
     338     3229081 :                         e2 = rel_bind_column(sql, rel->r, cname, f, no_tname);
     339     3229081 :                         if (e2 && (is_left(rel->op) || is_full(rel->op)))
     340          56 :                                 set_has_nil(e2);
     341     3229081 :                         if (e1 && e2 && !is_dependent(rel))
     342          35 :                                 return sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s' ambiguous", cname);
     343             :                 }
     344     3229046 :                 if (!e1 && !e2 && !list_empty(rel->attr)) {
     345           0 :                         e1 = exps_bind_column(rel->attr, cname, &ambiguous, &multi, no_tname);
     346           0 :                         if (ambiguous || multi)
     347           0 :                                 return sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s' ambiguous", cname);
     348             :                 }
     349     3229046 :                 res = e1 ? e1 : e2;
     350     1616119 :                 if (res)
     351     1701886 :                         set_not_unique(res);
     352     3229046 :                 return res;
     353             :         } else if (is_semi(rel->op) ||
     354             :                    is_select(rel->op) ||
     355             :                    is_topn(rel->op) ||
     356             :                    is_sample(rel->op)) {
     357      503270 :                 if (rel->l)
     358      503270 :                         return rel_bind_column(sql, rel->l, cname, f, no_tname);
     359             :         }
     360             :         return NULL;
     361             : }
     362             : 
     363             : sql_exp *
     364     4593581 : rel_bind_column2( mvc *sql, sql_rel *rel, const char *tname, const char *cname, int f)
     365             : {
     366     4593581 :         int ambiguous = 0, multi = 0;
     367             : 
     368     4593581 :         if (!rel)
     369             :                 return NULL;
     370     4593110 :         if (mvc_highwater(sql))
     371           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     372             : 
     373     4593111 :         if ((is_project(rel->op) || is_base(rel->op))) {
     374     2198029 :                 sql_exp *e = NULL;
     375             : 
     376     2198029 :                 if (is_basetable(rel->op) && !rel->exps)
     377     1284480 :                         return rel_base_bind_column2(sql, rel, tname, cname);
     378             :                 /* in case of orderby we should also lookup the column in group by list (and use existing references) */
     379      913549 :                 if (!list_empty(rel->exps)) {
     380      913469 :                         e = exps_bind_column2(rel->exps, tname, cname, &multi);
     381      913469 :                         if (multi)
     382           2 :                                 return sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s.%s' ambiguous",
     383             :                                                                  tname, cname);
     384      913467 :                         if (!e && is_groupby(rel->op) && rel->r) {
     385         118 :                                 e = exps_bind_alias(rel->r, tname, cname);
     386         118 :                                 if (e) {
     387           4 :                                         const char *rname = exp_relname(e), *nname = exp_name(e);
     388           4 :                                         if (rname)
     389           0 :                                                 e = exps_bind_column2(rel->exps, rname, nname, &multi);
     390             :                                         else
     391           4 :                                                 e = exps_bind_column(rel->exps, nname, &ambiguous, &multi, 0);
     392           4 :                                         if (ambiguous || multi)
     393           0 :                                                 return sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s%s%s' ambiguous",
     394             :                                                                                  rname ? rname : "", rname ? "." : "", nname);
     395           4 :                                         if (e)
     396             :                                                 return e;
     397             :                                 }
     398             :                         }
     399             :                 }
     400      357100 :                 if (!e && (is_sql_sel(f) || is_sql_having(f) || !f) && is_groupby(rel->op) && rel->r) {
     401         133 :                         e = exps_bind_column2(rel->r, tname, cname, &multi);
     402         133 :                         if (multi)
     403           0 :                                 return sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s.%s' ambiguous",
     404             :                                                                  tname, cname);
     405         133 :                         if (e) {
     406          10 :                                 e = exp_ref(sql, e);
     407          10 :                                 e->card = rel->card;
     408          10 :                                 return e;
     409             :                         }
     410             :                 }
     411      556443 :                 if (e)
     412      556443 :                         return exp_alias_or_copy(sql, tname, cname, rel, e);
     413             :         }
     414     2752172 :         if (is_simple_project(rel->op) && rel->l) {
     415      319285 :                 if (!is_processed(rel))
     416           0 :                         return rel_bind_column2(sql, rel->l, tname, cname, f);
     417     2432887 :         } else if (is_set(rel->op)) {
     418        4994 :                 assert(is_processed(rel));
     419             :                 return NULL;
     420             :         } else if (is_join(rel->op)) {
     421     1933391 :                 sql_exp *e = rel_bind_column2(sql, rel->l, tname, cname, f);
     422             : 
     423     1933391 :                 if (e && (is_right(rel->op) || is_full(rel->op)))
     424         253 :                         set_has_nil(e);
     425         253 :                 if (!e) {
     426      849101 :                         e = rel_bind_column2(sql, rel->r, tname, cname, f);
     427      849101 :                         if (e && (is_left(rel->op) || is_full(rel->op)))
     428       23155 :                                 set_has_nil(e);
     429             :                 }
     430      405621 :                 if (!e && !list_empty(rel->attr)) {
     431          14 :                         e = exps_bind_column2(rel->attr, tname, cname, &multi);
     432          14 :                         if (multi)
     433           0 :                                 return sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s.%s' ambiguous",
     434             :                                                                  tname, cname);
     435             :                 }
     436      382466 :                 if (e)
     437     1550929 :                         set_not_unique(e);
     438     1933391 :                 return e;
     439             :         } else if (is_semi(rel->op) ||
     440             :                    is_select(rel->op) ||
     441             :                    is_topn(rel->op) ||
     442             :                    is_sample(rel->op)) {
     443      461691 :                 if (rel->l)
     444      461691 :                         return rel_bind_column2(sql, rel->l, tname, cname, f);
     445             :         }
     446             :         return NULL;
     447             : }
     448             : 
     449             : sql_exp *
     450     1198239 : rel_bind_column3( mvc *sql, sql_rel *rel, const char *sname, const char *tname, const char *cname, int f)
     451             : {
     452     1198239 :         if (!sname)
     453     1198238 :                 return rel_bind_column2(sql, rel, tname, cname, f);
     454           1 :         if (is_basetable(rel->op) && !rel->exps) {
     455           0 :                 return rel_base_bind_column3(sql, rel, sname, tname, cname);
     456           1 :         } else if (is_set(rel->op)) {
     457             :                 return NULL;
     458           1 :         } else if (is_project(rel->op) && rel->l) {
     459           1 :                 if (!is_processed(rel))
     460             :                         return rel_bind_column3(sql, rel->l, sname, tname, cname, f);
     461             :                 else
     462           1 :                         return rel_bind_column2(sql, rel->l, tname, cname, f);
     463           0 :         } else if (is_join(rel->op)) {
     464           0 :                 sql_exp *e = rel_bind_column3(sql, rel->l, sname, tname, cname, f);
     465             : 
     466           0 :                 if (e && (is_right(rel->op) || is_full(rel->op)))
     467           0 :                         set_has_nil(e);
     468           0 :                 if (!e) {
     469           0 :                         e = rel_bind_column3(sql, rel->r, sname, tname, cname, f);
     470           0 :                         if (e && (is_left(rel->op) || is_full(rel->op)))
     471           0 :                                 set_has_nil(e);
     472             :                 }
     473           0 :                 if (!e)
     474           0 :                         return sql_error(sql, ERR_AMBIGUOUS, SQLSTATE(42000) "SELECT: identifier '%s.%s.%s' ambiguous", sname, tname, cname);
     475           0 :                 if (e)
     476           0 :                         set_not_unique(e);
     477           0 :                 return e;
     478           0 :         } else if (is_semi(rel->op) ||
     479           0 :                    is_select(rel->op) ||
     480           0 :                    is_topn(rel->op) ||
     481             :                    is_sample(rel->op)) {
     482           0 :                 if (rel->l)
     483             :                         return rel_bind_column3(sql, rel->l, sname, tname, cname, f);
     484             :         }
     485             :         return NULL;
     486             : }
     487             : 
     488             : sql_exp *
     489           0 : rel_first_column(mvc *sql, sql_rel *r)
     490             : {
     491           0 :         if (is_simple_project(r->op))
     492           0 :                 return r->exps->h->data;
     493             : 
     494           0 :         list *exps = rel_projections(sql, r, NULL, 1, 1);
     495             : 
     496           0 :         if (!list_empty(exps))
     497           0 :                 return exps->h->data;
     498             : 
     499             :         return NULL;
     500             : }
     501             : 
     502             : static void
     503       76166 : rel_inplace_reset_props(sql_rel *rel)
     504             : {
     505       76166 :         rel->flag = 0;
     506       76166 :         rel->attr = NULL;
     507       76166 :         reset_dependent(rel);
     508       76166 :         set_processed(rel);
     509             : }
     510             : 
     511             : sql_rel *
     512         102 : rel_inplace_basetable(sql_rel *rel, sql_rel *bt)
     513             : {
     514         102 :         assert(is_basetable(bt->op));
     515             : 
     516         102 :         rel_destroy_(rel);
     517         102 :         rel_inplace_reset_props(rel);
     518         102 :         rel->l = bt->l;
     519         102 :         rel->r = bt->r;
     520         102 :         rel->op = op_basetable;
     521         102 :         rel->exps = bt->exps;
     522         102 :         rel->card = CARD_MULTI;
     523         102 :         rel->nrcols = bt->nrcols;
     524         102 :         return rel;
     525             : }
     526             : 
     527             : sql_rel *
     528       36307 : rel_inplace_setop(mvc *sql, sql_rel *rel, sql_rel *l, sql_rel *r, operator_type setop, list *exps)
     529             : {
     530       36307 :         rel_destroy_(rel);
     531       36307 :         rel_inplace_reset_props(rel);
     532       36307 :         rel->l = l;
     533       36307 :         rel->r = r;
     534       36307 :         rel->op = setop;
     535       36307 :         rel->card = CARD_MULTI;
     536       36307 :         rel_setop_set_exps(sql, rel, exps, false);
     537       36307 :         return rel;
     538             : }
     539             : 
     540             : sql_rel *
     541       39190 : rel_inplace_project(sql_allocator *sa, sql_rel *rel, sql_rel *l, list *e)
     542             : {
     543       39190 :         if (!l) {
     544       39140 :                 l = rel_create(sa);
     545       39140 :                 if(!l)
     546             :                         return NULL;
     547             : 
     548       39140 :                 *l = *rel;
     549       39140 :                 l->ref.refcnt = 1;
     550             :         } else {
     551          50 :                 rel_destroy_(rel);
     552             :         }
     553       39190 :         rel_inplace_reset_props(rel);
     554       39190 :         rel->l = l;
     555       39190 :         rel->r = NULL;
     556       39190 :         rel->op = op_project;
     557       39190 :         rel->exps = e;
     558       39190 :         rel->card = CARD_MULTI;
     559       39190 :         if (l) {
     560       39190 :                 rel->nrcols = l->nrcols;
     561       39190 :                 assert (exps_card(rel->exps) <= rel->card);
     562             :         }
     563             :         return rel;
     564             : }
     565             : 
     566             : sql_rel *
     567          67 : rel_inplace_select(sql_rel *rel, sql_rel *l, list *exps)
     568             : {
     569          67 :         rel_destroy_(rel);
     570          67 :         rel_inplace_reset_props(rel);
     571          67 :         rel->l = l;
     572          67 :         rel->r = NULL;
     573          67 :         rel->op = op_select;
     574          67 :         rel->exps = exps;
     575          67 :         rel->card = CARD_ATOM; /* no relation */
     576          67 :         if (l) {
     577          67 :                 rel->card = l->card;
     578          67 :                 rel->nrcols = l->nrcols;
     579          67 :                 if (is_single(l))
     580           0 :                         set_single(rel);
     581             :         }
     582          67 :         return rel;
     583             : }
     584             : 
     585             : sql_rel *
     586         500 : rel_inplace_groupby(sql_rel *rel, sql_rel *l, list *groupbyexps, list *exps )
     587             : {
     588         500 :         rel_destroy_(rel);
     589         500 :         rel_inplace_reset_props(rel);
     590         500 :         rel->card = CARD_ATOM;
     591         500 :         if (groupbyexps)
     592         374 :                 rel->card = CARD_AGGR;
     593         500 :         rel->l = l;
     594         500 :         rel->r = groupbyexps;
     595         500 :         rel->exps = exps;
     596         500 :         rel->nrcols = l->nrcols;
     597         500 :         rel->op = op_groupby;
     598         500 :         return rel;
     599             : }
     600             : 
     601             : /* this function is to be used with the above rel_inplace_* functions */
     602             : sql_rel *
     603          27 : rel_dup_copy(sql_allocator *sa, sql_rel *rel)
     604             : {
     605          27 :         sql_rel *nrel = rel_create(sa);
     606             : 
     607          27 :         if (!nrel)
     608             :                 return NULL;
     609          27 :         *nrel = *rel;
     610          27 :         nrel->ref.refcnt = 1;
     611          27 :         switch(nrel->op){
     612             :         case op_basetable:
     613             :         case op_ddl:
     614             :                 break;
     615           0 :         case op_table:
     616           0 :                 if ((IS_TABLE_PROD_FUNC(nrel->flag) || nrel->flag == TABLE_FROM_RELATION) && nrel->l)
     617           0 :                         rel_dup(nrel->l);
     618             :                 break;
     619          18 :         case op_join:
     620             :         case op_left:
     621             :         case op_right:
     622             :         case op_full:
     623             :         case op_semi:
     624             :         case op_anti:
     625             :         case op_union:
     626             :         case op_inter:
     627             :         case op_except:
     628             :         case op_insert:
     629             :         case op_update:
     630             :         case op_delete:
     631             :         case op_merge:
     632          18 :                 if (nrel->l)
     633          18 :                         rel_dup(nrel->l);
     634          18 :                 if (nrel->r)
     635          18 :                         rel_dup(nrel->r);
     636             :                 break;
     637           9 :         case op_project:
     638             :         case op_groupby:
     639             :         case op_select:
     640             :         case op_topn:
     641             :         case op_sample:
     642             :         case op_truncate:
     643           9 :                 if (nrel->l)
     644           9 :                         rel_dup(nrel->l);
     645             :                 break;
     646             :         }
     647             :         return nrel;
     648             : }
     649             : 
     650             : sql_rel *
     651       62913 : rel_setop(sql_allocator *sa, sql_rel *l, sql_rel *r, operator_type setop)
     652             : {
     653       62913 :         sql_rel *rel = rel_create(sa);
     654       62913 :         if(!rel)
     655             :                 return NULL;
     656       62913 :         rel->l = l;
     657       62913 :         rel->r = r;
     658       62913 :         rel->op = setop;
     659       62913 :         rel->exps = NULL;
     660       62913 :         rel->card = CARD_MULTI;
     661       62913 :         assert(l->nrcols == r->nrcols);
     662       62913 :         rel->nrcols = l->nrcols;
     663       62913 :         return rel;
     664             : }
     665             : 
     666             : sql_rel *
     667       58256 : rel_setop_check_types(mvc *sql, sql_rel *l, sql_rel *r, list *ls, list *rs, operator_type op)
     668             : {
     669       58256 :         list *nls = new_exp_list(sql->sa);
     670       58256 :         list *nrs = new_exp_list(sql->sa);
     671       58256 :         node *n, *m;
     672             : 
     673       58256 :         if(!nls || !nrs)
     674             :                 return NULL;
     675             : 
     676      446684 :         for (n = ls->h, m = rs->h; n && m; n = n->next, m = m->next) {
     677      388433 :                 sql_exp *le = n->data;
     678      388433 :                 sql_exp *re = m->data;
     679             : 
     680      388433 :                 if (rel_convert_types(sql, l, r, &le, &re, 1, type_set) < 0)
     681           5 :                         return NULL;
     682      388428 :                 append(nls, le);
     683      388428 :                 append(nrs, re);
     684             :         }
     685       58251 :         l = rel_project(sql->sa, l, nls);
     686       58251 :         r = rel_project(sql->sa, r, nrs);
     687       58251 :         set_processed(l);
     688       58251 :         set_processed(r);
     689       58251 :         return rel_setop(sql->sa, l, r, op);
     690             : }
     691             : 
     692             : void
     693       97598 : rel_setop_set_exps(mvc *sql, sql_rel *rel, list *exps, bool keep_props)
     694             : {
     695       97598 :         sql_rel *l = rel->l, *r = rel->r;
     696       97598 :         list *lexps = l->exps, *rexps = r->exps;
     697             : 
     698       97598 :         if (!is_project(l->op))
     699        6338 :                 lexps = rel_projections(sql, l, NULL, 0, 1);
     700       97598 :         if (!is_project(r->op))
     701        6406 :                 rexps = rel_projections(sql, r, NULL, 0, 1);
     702             : 
     703       97598 :         assert(is_set(rel->op) /*&& list_length(lexps) == list_length(rexps) && list_length(exps) == list_length(lexps)*/);
     704             : 
     705      757365 :         for (node *n = exps->h, *m = lexps->h, *o = rexps->h ; m && n && o ; n = n->next, m = m->next,o = o->next) {
     706      659767 :                 sql_exp *e = n->data, *f = m->data, *g = o->data;
     707             : 
     708      659767 :                 if (is_union(rel->op)) { /* propagate set_has_no_nil only if it's applicable to both sides of the union*/
     709      656832 :                         if (has_nil(f) || has_nil(g))
     710      602877 :                                 set_has_nil(e);
     711             :                         else
     712       53955 :                                 set_has_no_nil(e);
     713      656832 :                         if (!keep_props) {
     714      656443 :                                 e->p = NULL; /* remove all the properties on unions on the general case */
     715      656443 :                                 set_not_unique(e);
     716             :                         }
     717             :                 }
     718      659767 :                 e->card = CARD_MULTI; /* multi cardinality */
     719             :         }
     720       97598 :         rel->nrcols = l->nrcols;
     721       97598 :         rel->exps = exps;
     722       97598 : }
     723             : 
     724             : sql_rel *
     725      514004 : rel_crossproduct(sql_allocator *sa, sql_rel *l, sql_rel *r, operator_type join)
     726             : {
     727      514004 :         sql_rel *rel = rel_create(sa);
     728      514004 :         if(!rel)
     729             :                 return NULL;
     730             : 
     731      514004 :         rel->l = l;
     732      514004 :         rel->r = r;
     733      514004 :         rel->op = join;
     734      514004 :         rel->exps = NULL;
     735      514004 :         rel->card = CARD_MULTI;
     736      514004 :         rel->nrcols = l->nrcols + r->nrcols;
     737      514004 :         return rel;
     738             : }
     739             : 
     740             : sql_exp *
     741           0 : rel_is_constant(sql_rel **R, sql_exp *e)
     742             : {
     743           0 :         sql_rel *rel = *R;
     744             : 
     745           0 :         if (rel && rel->op == op_project && list_length(rel->exps) == 1 &&
     746           0 :             !rel->l && !rel->r && !rel_is_ref(rel) && e->type == e_column) {
     747           0 :                 sql_exp *ne = rel_find_exp(rel, e);
     748           0 :                 if (ne) {
     749           0 :                         rel_destroy(rel);
     750           0 :                         *R = NULL;
     751           0 :                         return ne;
     752             :                 }
     753             :         }
     754             :         return e;
     755             : }
     756             : 
     757             : sql_rel *
     758       16980 : rel_topn(sql_allocator *sa, sql_rel *l, list *exps )
     759             : {
     760       16980 :         sql_rel *rel = rel_create(sa);
     761       16980 :         if(!rel)
     762             :                 return NULL;
     763             : 
     764       16980 :         rel->l = l;
     765       16980 :         rel->r = NULL;
     766       16980 :         rel->op = op_topn;
     767       16980 :         rel->exps = exps;
     768       16980 :         rel->card = l->card;
     769       16980 :         rel->nrcols = l->nrcols;
     770       16980 :         return rel;
     771             : }
     772             : 
     773             : sql_rel *
     774          23 : rel_sample(sql_allocator *sa, sql_rel *l, list *exps )
     775             : {
     776          23 :         sql_rel *rel = rel_create(sa);
     777          23 :         if(!rel)
     778             :                 return NULL;
     779             : 
     780          23 :         rel->l = l;
     781          23 :         rel->r = NULL;
     782          23 :         rel->op = op_sample;
     783          23 :         rel->exps = exps;
     784          23 :         rel->card = l->card;
     785          23 :         rel->nrcols = l->nrcols;
     786          23 :         return rel;
     787             : }
     788             : 
     789             : sql_rel *
     790       14072 : rel_label( mvc *sql, sql_rel *r, int all)
     791             : {
     792       14072 :         int nr = ++sql->label;
     793       14072 :         char tname[16], *tnme;
     794       14072 :         char cname[16], *cnme = NULL;
     795             : 
     796       14072 :         tnme = number2name(tname, sizeof(tname), nr);
     797       14072 :         if (!is_simple_project(r->op))
     798         603 :                 r = rel_project(sql->sa, r, rel_projections(sql, r, NULL, 1, 1));
     799       14072 :         if (!list_empty(r->exps)) {
     800       14072 :                 list_hash_clear(r->exps);
     801       55656 :                 for (node *ne = r->exps->h; ne; ne = ne->next) {
     802       41584 :                         sql_exp *e = ne->data;
     803             : 
     804       41584 :                         if (!is_freevar(e)) {
     805       41578 :                                 if (all) {
     806       41578 :                                         nr = ++sql->label;
     807       41578 :                                         cnme = number2name(cname, sizeof(cname), nr);
     808             :                                 }
     809       41578 :                                 exp_setname(sql->sa, e, tnme, cnme );
     810             :                         }
     811             :                 }
     812             :         }
     813             :         /* op_projects can have a order by list */
     814       14072 :         if (!list_empty(r->r)) {
     815           0 :                 for (node *ne = ((list*)r->r)->h; ne; ne = ne->next) {
     816           0 :                         if (all) {
     817           0 :                                 nr = ++sql->label;
     818           0 :                                 cnme = number2name(cname, sizeof(cname), nr);
     819             :                         }
     820           0 :                         exp_setname(sql->sa, ne->data, tnme, cnme );
     821             :                 }
     822             :         }
     823       14072 :         return r;
     824             : }
     825             : 
     826             : sql_exp *
     827       29778 : rel_project_add_exp( mvc *sql, sql_rel *rel, sql_exp *e)
     828             : {
     829       29778 :         assert(is_project(rel->op));
     830             : 
     831       29778 :         if (!exp_name(e))
     832          99 :                 exp_label(sql->sa, e, ++sql->label);
     833       29778 :         if (is_simple_project(rel->op)) {
     834       29774 :                 sql_rel *l = rel->l;
     835       29774 :                 if (!rel->exps)
     836          19 :                         rel->exps = new_exp_list(sql->sa);
     837       29774 :                 if (l && is_groupby(l->op) && exp_card(e) <= CARD_ATOM && list_empty(l->exps))
     838           4 :                         e = rel_project_add_exp(sql, l, e);
     839       29774 :                 if (e->card > rel->card)
     840           0 :                         rel->card = e->card;
     841       29774 :                 append(rel->exps, e);
     842       29774 :                 rel->nrcols++;
     843           4 :         } else if (is_groupby(rel->op)) {
     844           4 :                 return rel_groupby_add_aggr(sql, rel, e);
     845             :         }
     846       29774 :         e = exp_ref(sql, e);
     847       29774 :         return e;
     848             : }
     849             : 
     850             : sql_rel *
     851      276434 : rel_select_add_exp(sql_allocator *sa, sql_rel *l, sql_exp *e)
     852             : {
     853      276434 :         if ((l->op != op_select && !is_outerjoin(l->op)) || rel_is_ref(l))
     854        6871 :                 return rel_select(sa, l, e);
     855             : 
     856             : /*      allow during AST->relational for bool expresssions as well
     857             :         if (e->type != e_cmp && e->card > CARD_ATOM) {
     858             :                 sql_exp *t = exp_atom_bool(sa, 1);
     859             :                 e = exp_compare(sa, e, t, cmp_equal);
     860             :         }
     861             : */
     862      269563 :         if (!l->exps)
     863        4513 :                 l->exps = new_exp_list(sa);
     864      269563 :         append(l->exps, e);
     865      269563 :         return l;
     866             : }
     867             : 
     868             : void
     869      479200 : rel_join_add_exp( sql_allocator *sa, sql_rel *rel, sql_exp *e)
     870             : {
     871      479200 :         assert(is_join(rel->op) || is_semi(rel->op) || is_select(rel->op));
     872             : 
     873      479200 :         if (!rel->exps)
     874      435477 :                 rel->exps = new_exp_list(sa);
     875      479200 :         append(rel->exps, e);
     876      479200 :         if (e->card > rel->card)
     877           0 :                 rel->card = e->card;
     878      479200 : }
     879             : 
     880             : sql_exp *
     881       76182 : rel_groupby_add_aggr(mvc *sql, sql_rel *rel, sql_exp *e)
     882             : {
     883       76182 :         sql_exp *m = NULL, *ne;
     884             : 
     885       76182 :         if (list_empty(rel->r))
     886       26463 :                 rel->card = e->card = CARD_ATOM;
     887             : 
     888       76182 :         if ((m=exps_any_match(rel->exps, e)) == NULL) {
     889       44717 :                 if (!exp_name(e))
     890       44693 :                         exp_label(sql->sa, e, ++sql->label);
     891       44717 :                 append(rel->exps, e);
     892       44717 :                 rel->nrcols++;
     893       44717 :                 m = e;
     894             :         }
     895       76182 :         ne = exp_ref(sql, m);
     896       76182 :         return ne;
     897             : }
     898             : 
     899             : sql_rel *
     900      257951 : rel_select(sql_allocator *sa, sql_rel *l, sql_exp *e)
     901             : {
     902      257951 :         sql_rel *rel;
     903             : 
     904      257951 :         if (l && is_outerjoin(l->op) && !is_processed(l)) {
     905         204 :                 if (e) {
     906         188 :                         if (!l->exps)
     907         173 :                                 l->exps = new_exp_list(sa);
     908         188 :                         append(l->exps, e);
     909             :                 }
     910         204 :                 return l;
     911             :         }
     912             : 
     913      257747 :         if (l && is_select(l->op) && !rel_is_ref(l)) { /* refine old select */
     914       17541 :                 if (e)
     915        9488 :                         rel_select_add_exp(sa, l, e);
     916       17541 :                 return l;
     917             :         }
     918      240206 :         rel = rel_create(sa);
     919      240206 :         if(!rel)
     920             :                 return NULL;
     921             : 
     922      240206 :         rel->l = l;
     923      240206 :         rel->r = NULL;
     924      240206 :         rel->op = op_select;
     925      240206 :         rel->exps = new_exp_list(sa);
     926      240206 :         if (e)
     927      185174 :                 rel_select_add_exp(sa, rel, e);
     928      240206 :         rel->card = CARD_ATOM; /* no relation */
     929      240206 :         if (l) {
     930      240206 :                 rel->card = l->card;
     931      240206 :                 rel->nrcols = l->nrcols;
     932      240206 :                 if (is_single(l))
     933        1510 :                         set_single(rel);
     934             :         }
     935             :         return rel;
     936             : }
     937             : 
     938             : sql_rel *
     939       36764 : rel_groupby(mvc *sql, sql_rel *l, list *groupbyexps )
     940             : {
     941       36764 :         sql_rel *rel = rel_create(sql->sa);
     942       36764 :         list *aggrs = new_exp_list(sql->sa);
     943       36764 :         node *en;
     944       36764 :         if(!rel || !aggrs) {
     945           0 :                 rel_destroy(rel);
     946           0 :                 return NULL;
     947             :         }
     948             : 
     949       36764 :         rel->card = CARD_ATOM;
     950             :         /* reduce duplicates in groupbyexps */
     951       36764 :         if (groupbyexps && list_length(groupbyexps) > 1) {
     952        4977 :                 list *gexps = sa_list(sql->sa);
     953             : 
     954       24099 :                 for (en = groupbyexps->h; en; en = en->next) {
     955       19122 :                         sql_exp *e = en->data, *ne = exps_find_exp(gexps, e);
     956             : 
     957       19122 :                         if (!ne) {
     958       19019 :                                 list_append(gexps, e);
     959             :                         } else {
     960         103 :                                 const char *ername = exp_relname(e), *nername = exp_relname(ne), *ename = exp_name(e), *nename = exp_name(ne);
     961         103 :                                 if ((ername && !nername) || (!ername && nername) ||
     962          97 :                                         (ername && nername && strcmp(ername,nername) != 0) || strcmp(ename,nename) != 0)
     963          10 :                                         list_append(gexps, e);
     964             :                         }
     965             :                 }
     966             :                 groupbyexps = gexps;
     967             :         }
     968             : 
     969       10031 :         if (groupbyexps) {
     970       10031 :                 rel->card = CARD_AGGR;
     971       33971 :                 for (en = groupbyexps->h; en; en = en->next) {
     972       23940 :                         sql_exp *e = en->data, *ne;
     973             : 
     974             :                         /* after the group by the cardinality reduces */
     975       23940 :                         e->card = MIN(e->card, rel->card); /* if the column is an atom, the cardinality should not change */
     976       23940 :                         ne = exp_ref(sql, e);
     977       23940 :                         ne = exp_propagate(sql->sa, ne, e);
     978       23940 :                         append(aggrs, ne);
     979             :                 }
     980             :         }
     981       36764 :         rel->l = l;
     982       36764 :         rel->r = groupbyexps;
     983       36764 :         rel->exps = aggrs;
     984       36764 :         rel->nrcols = aggrs?list_length(aggrs):0;
     985       36764 :         rel->op = op_groupby;
     986       36764 :         rel->grouped = 1;
     987       36764 :         return rel;
     988             : }
     989             : 
     990             : sql_rel *
     991      955200 : rel_project(sql_allocator *sa, sql_rel *l, list *e)
     992             : {
     993      955200 :         sql_rel *rel = rel_create(sa);
     994      955195 :         if(!rel)
     995             :                 return NULL;
     996             : 
     997      955195 :         rel->l = l;
     998      955195 :         rel->r = NULL;
     999      955195 :         rel->op = op_project;
    1000      955195 :         rel->exps = e;
    1001      955195 :         rel->card = exps_card(e);
    1002      955197 :         if (l) {
    1003      770132 :                 rel->card = l->card;
    1004      770132 :                 if (e)
    1005      717191 :                         rel->nrcols = list_length(e);
    1006             :                 else
    1007       52941 :                         rel->nrcols = l->nrcols;
    1008      770128 :                 rel->single = is_single(l);
    1009             :         }
    1010      955193 :         if (e && !list_empty(e)) {
    1011      901848 :                 set_processed(rel);
    1012      901848 :                 rel->nrcols = list_length(e);
    1013             :         }
    1014             :         return rel;
    1015             : }
    1016             : 
    1017             : sql_rel *
    1018       72825 : rel_project_exp(mvc *sql, sql_exp *e)
    1019             : {
    1020       72825 :         if (!exp_name(e))
    1021       72825 :                 exp_label(sql->sa, e, ++sql->label);
    1022       72815 :         return rel_project(sql->sa, NULL, list_append(sa_list(sql->sa), e));
    1023             : }
    1024             : 
    1025             : sql_rel *
    1026      108342 : rel_list(sql_allocator *sa, sql_rel *l, sql_rel *r)
    1027             : {
    1028      108342 :         sql_rel *rel = rel_create(sa);
    1029      108342 :         if (!rel)
    1030             :                 return NULL;
    1031      108342 :         if (!l)
    1032             :                 return r;
    1033         547 :         rel->l = l;
    1034         547 :         rel->r = r;
    1035         547 :         rel->op = op_ddl;
    1036         547 :         rel->flag = ddl_list;
    1037         547 :         return rel;
    1038             : }
    1039             : 
    1040             : sql_rel *
    1041         149 : rel_exception(sql_allocator *sa, sql_rel *l, sql_rel *r, list *exps)
    1042             : {
    1043         149 :         sql_rel *rel = rel_create(sa);
    1044         149 :         if(!rel)
    1045             :                 return NULL;
    1046         149 :         rel->r = r;
    1047         149 :         rel->exps = exps;
    1048         149 :         rel->op = op_ddl;
    1049         149 :         rel->flag = ddl_exception;
    1050         149 :         if (l)
    1051         149 :                 return rel_list(sa, rel, l); /* keep base relation on the right ! */
    1052             :         return rel;
    1053             : }
    1054             : 
    1055             : sql_rel *
    1056         305 : rel_relational_func(sql_allocator *sa, sql_rel *l, list *exps)
    1057             : {
    1058         305 :         sql_rel *rel = rel_create(sa);
    1059         305 :         if(!rel)
    1060             :                 return NULL;
    1061             : 
    1062         305 :         rel->flag = TABLE_PROD_FUNC;
    1063         305 :         rel->l = l;
    1064         305 :         rel->op = op_table;
    1065         305 :         rel->exps = exps;
    1066         305 :         rel->card = CARD_MULTI;
    1067         305 :         rel->nrcols = list_length(exps);
    1068         305 :         return rel;
    1069             : }
    1070             : 
    1071             : sql_rel *
    1072       16293 : rel_table_func(sql_allocator *sa, sql_rel *l, sql_exp *f, list *exps, int kind)
    1073             : {
    1074       16293 :         sql_rel *rel = rel_create(sa);
    1075       16293 :         if(!rel)
    1076             :                 return NULL;
    1077             : 
    1078       16293 :         assert(kind > 0);
    1079       16293 :         rel->flag = kind;
    1080       16293 :         rel->l = l; /* relation before call */
    1081       16293 :         rel->r = f; /* expression (table func call) */
    1082       16293 :         rel->op = op_table;
    1083       16293 :         rel->exps = exps;
    1084       16293 :         rel->card = CARD_MULTI;
    1085       16293 :         rel->nrcols = list_length(exps);
    1086       16293 :         return rel;
    1087             : }
    1088             : 
    1089             : static void
    1090      295392 : exps_reset_props(list *exps, bool setnil)
    1091             : {
    1092      295392 :         if (!list_empty(exps)) {
    1093     2944170 :                 for (node *m = exps->h; m; m = m->next) {
    1094     2651711 :                         sql_exp *e = m->data;
    1095             : 
    1096     2651711 :                         if (setnil)
    1097      189792 :                                 set_has_nil(e);
    1098     2651711 :                         set_not_unique(e);
    1099             :                 }
    1100             :         }
    1101      295392 : }
    1102             : 
    1103             : list *
    1104     1085692 : _rel_projections(mvc *sql, sql_rel *rel, const char *tname, int settname, int intern, int basecol /* basecol only */ )
    1105             : {
    1106     1156206 :         list *lexps, *rexps = NULL, *exps;
    1107             : 
    1108     1156206 :         if (mvc_highwater(sql))
    1109           2 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    1110             : 
    1111     1156204 :         if (!rel)
    1112           0 :                 return new_exp_list(sql->sa);
    1113             : 
    1114     1156204 :         if (!tname && is_basetable(rel->op) && !is_processed(rel))
    1115      257106 :                 rel_base_use_all( sql, rel);
    1116             : 
    1117     1156204 :         switch(rel->op) {
    1118      147696 :         case op_join:
    1119             :         case op_left:
    1120             :         case op_right:
    1121             :         case op_full:
    1122      147696 :                 lexps = _rel_projections(sql, rel->l, tname, settname, intern, basecol);
    1123      147696 :                 exps_reset_props(lexps, is_right(rel->op) || is_full(rel->op));
    1124      147696 :                 if (!rel->attr)
    1125      144783 :                         rexps = _rel_projections(sql, rel->r, tname, settname, intern, basecol);
    1126      147696 :                 exps_reset_props(rexps, is_left(rel->op) || is_full(rel->op));
    1127      147696 :                 if (rexps)
    1128      144783 :                         lexps = list_merge(lexps, rexps, (fdup)NULL);
    1129      147696 :                 if (rel->attr)
    1130        2913 :                         append(lexps, exp_ref(sql, rel->attr->h->data));
    1131             :                 return lexps;
    1132        7017 :         case op_groupby:
    1133        7017 :                 if (list_empty(rel->exps) && rel->r) {
    1134           1 :                         list *r = rel->r;
    1135           1 :                         int label = 0;
    1136             : 
    1137           1 :                         if (!settname)
    1138           0 :                                 label = ++sql->label;
    1139           1 :                         exps = new_exp_list(sql->sa);
    1140           2 :                         for (node *en = r->h; en; en = en->next) {
    1141           1 :                                 sql_exp *e = en->data;
    1142             : 
    1143           1 :                                 if (basecol && !is_basecol(e))
    1144           0 :                                         continue;
    1145           1 :                                 if (intern || !is_intern(e)) {
    1146           1 :                                         e = exp_alias_or_copy(sql, tname, exp_name(e), rel, e);
    1147           1 :                                         if (!settname) /* noname use alias */
    1148           0 :                                                 exp_setrelname(sql->sa, e, label);
    1149           1 :                                         append(exps, e);
    1150             :                                 }
    1151             :                         }
    1152             :                         return exps;
    1153             :                 }
    1154             :                 /* fall through */
    1155             :         case op_project:
    1156             :         case op_basetable:
    1157             :         case op_table:
    1158             : 
    1159             :         case op_union:
    1160             :         case op_except:
    1161             :         case op_inter:
    1162      937993 :                 if (is_basetable(rel->op) && !rel->exps)
    1163       97556 :                         return rel_base_projection(sql, rel, intern);
    1164      840437 :                 if (rel->exps) {
    1165      782184 :                         int label = 0;
    1166             : 
    1167      782184 :                         if (!settname)
    1168      246470 :                                 label = ++sql->label;
    1169      782184 :                         exps = new_exp_list(sql->sa);
    1170     6259035 :                         for (node *en = rel->exps->h; en; en = en->next) {
    1171     5476852 :                                 sql_exp *e = en->data;
    1172             : 
    1173     5476852 :                                 if (basecol && !is_basecol(e))
    1174          44 :                                         continue;
    1175     5476808 :                                 if (intern || !is_intern(e)) {
    1176     5463425 :                                         e = exp_alias_or_copy(sql, tname, exp_name(e), rel, e);
    1177     5463426 :                                         if (!settname) /* noname use alias */
    1178     1642168 :                                                 exp_setrelname(sql->sa, e, label);
    1179     5463426 :                                         append(exps, e);
    1180             :                                 }
    1181             :                         }
    1182             :                         return exps;
    1183             :                 }
    1184             :                 /* I only expect set relations to hit here */
    1185       58253 :                 assert(is_set(rel->op));
    1186       58253 :                 lexps = _rel_projections(sql, rel->l, tname, settname, intern, basecol);
    1187       58253 :                 rexps = _rel_projections(sql, rel->r, tname, settname, intern, basecol);
    1188       58253 :                 if (lexps && rexps) {
    1189       58253 :                         int label = 0;
    1190             : 
    1191       58253 :                         if (!settname)
    1192       58253 :                                 label = ++sql->label;
    1193       58253 :                         assert(list_length(lexps) == list_length(rexps));
    1194      446685 :                         for (node *en = lexps->h; en; en = en->next) {
    1195      388432 :                                 sql_exp *e = en->data;
    1196             : 
    1197      388432 :                                 e->card = rel->card;
    1198      388432 :                                 if (!settname) /* noname use alias */
    1199      388432 :                                         exp_setrelname(sql->sa, e, label);
    1200             :                         }
    1201       58253 :                         if (!settname)
    1202       58253 :                                 list_hash_clear(lexps);
    1203             :                 }
    1204             :                 return lexps;
    1205       70514 :         case op_ddl:
    1206             :         case op_semi:
    1207             :         case op_anti:
    1208             : 
    1209             :         case op_select:
    1210             :         case op_topn:
    1211             :         case op_sample:
    1212       70514 :                 return _rel_projections(sql, rel->l, tname, settname, intern, basecol);
    1213             :         default:
    1214             :                 return NULL;
    1215             :         }
    1216             : }
    1217             : 
    1218             : list *
    1219      636860 : rel_projections(mvc *sql, sql_rel *rel, const char *tname, int settname, int intern)
    1220             : {
    1221      636860 :         assert(tname == NULL);
    1222      636860 :         return _rel_projections(sql, rel, tname, settname, intern, 0);
    1223             : }
    1224             : 
    1225             : /* find the path to the relation containing the base of the expression
    1226             :         (e_column), in most cases this means go down the join tree and
    1227             :         find the base column.
    1228             :  */
    1229             : static int
    1230     3963147 : rel_bind_path_(mvc *sql, sql_rel *rel, sql_exp *e, list *path )
    1231             : {
    1232     3963147 :         int found = 0;
    1233             : 
    1234     3963147 :         if (mvc_highwater(sql)) {
    1235           0 :                 sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    1236           0 :                 return 0;
    1237             :         }
    1238             : 
    1239     3963147 :         switch (rel->op) {
    1240     1841785 :         case op_join:
    1241             :         case op_left:
    1242             :         case op_right:
    1243             :         case op_full:
    1244             :                 /* first right (possible subquery) */
    1245     1841785 :                 found = rel_bind_path_(sql, rel->r, e, path);
    1246     1841785 :                 if (!found)
    1247     1553137 :                         found = rel_bind_path_(sql, rel->l, e, path);
    1248     1553137 :                 if (!found && !list_empty(rel->attr)) {
    1249           0 :                         if (e->l && exps_bind_column2(rel->attr, e->l, e->r, NULL))
    1250             :                                 found = 1;
    1251           0 :                         if (!found && !e->l && exps_bind_column(rel->attr, e->r, NULL, NULL, 1))
    1252             :                                 found = 1;
    1253             :                 }
    1254             :                 break;
    1255      112539 :         case op_semi:
    1256             :         case op_anti:
    1257             :         case op_select:
    1258             :         case op_topn:
    1259             :         case op_sample:
    1260      112539 :                 found = rel_bind_path_(sql, rel->l, e, path);
    1261      112539 :                 break;
    1262     2008823 :         case op_basetable:
    1263             :         case op_union:
    1264             :         case op_inter:
    1265             :         case op_except:
    1266             :         case op_groupby:
    1267             :         case op_project:
    1268             :         case op_table:
    1269     2008823 :                 if (is_basetable(rel->op) && !rel->exps) {
    1270     1822602 :                         if (e->l) {
    1271     1822602 :                                 if (rel_base_bind_column2_(rel, e->l, e->r))
    1272             :                                         found = 1;
    1273           0 :                         } else if (rel_base_bind_column_(rel, e->r))
    1274             :                                 found = 1;
    1275      186221 :                 } else if (rel->exps) {
    1276      186221 :                         if (!found && e->l && exps_bind_column2(rel->exps, e->l, e->r, NULL))
    1277             :                                 found = 1;
    1278       94237 :                         if (!found && !e->l && exps_bind_column(rel->exps, e->r, NULL, NULL, 1))
    1279             :                                 found = 1;
    1280             :                 }
    1281             :                 break;
    1282             :         case op_insert:
    1283             :         case op_update:
    1284             :         case op_delete:
    1285             :         case op_truncate:
    1286             :         case op_merge:
    1287             :         case op_ddl:
    1288             :                 break;
    1289             :         }
    1290      206782 :         if (found)
    1291     2366242 :                 list_prepend(path, rel);
    1292             :         return found;
    1293             : }
    1294             : 
    1295             : static list *
    1296      501608 : rel_bind_path(mvc *sql, sql_rel *rel, sql_exp *e, list *path)
    1297             : {
    1298      501608 :         if (!path)
    1299             :                 return NULL;
    1300             : 
    1301      501608 :         if (e->type == e_convert) {
    1302       40337 :                 if (!(path = rel_bind_path(sql, rel, e->l, path)))
    1303             :                         return NULL;
    1304      461271 :         } else if (e->type == e_column) {
    1305      455686 :                 if (rel) {
    1306      455686 :                         if (!rel_bind_path_(sql, rel, e, path)) {
    1307             :                                 /* something is wrong */
    1308             :                                 return NULL;
    1309             :                         }
    1310             :                 }
    1311      455686 :                 return path;
    1312             :         }
    1313             :         /* default the top relation */
    1314       45922 :         append(path, rel);
    1315       45922 :         return path;
    1316             : }
    1317             : 
    1318             : static sql_rel *
    1319       21165 : rel_select_push_exp_down(mvc *sql, sql_rel *rel, sql_exp *e)
    1320             : {
    1321       21165 :         sql_rel *r = rel->l, *jl = r->l, *jr = r->r;
    1322       21165 :         int left = r->op == op_join || r->op == op_left;
    1323       21165 :         int right = r->op == op_join || r->op == op_right;
    1324       21165 :         int done = 0;
    1325             : 
    1326       21165 :         assert(is_select(rel->op));
    1327       21165 :         if (!is_full(r->op) && !is_single(r)) {
    1328       21165 :                 if (left && rel_rebind_exp(sql, jl, e)) {
    1329           9 :                         done = 1;
    1330           9 :                         r->l = jl = rel_select_add_exp(sql->sa, jl, e);
    1331       21156 :                 } else if (right && rel_rebind_exp(sql, jr, e)) {
    1332           6 :                         done = 1;
    1333           6 :                         r->r = jr = rel_select_add_exp(sql->sa, jr, e);
    1334             :                 }
    1335             :         }
    1336          15 :         if (!done)
    1337       21150 :                 rel_select_add_exp(sql->sa, rel, e);
    1338       21165 :         return rel;
    1339             : }
    1340             : 
    1341             : /* ls is the left expression of the select, e is the select expression.  */
    1342             : sql_rel *
    1343      105951 : rel_push_select(mvc *sql, sql_rel *rel, sql_exp *ls, sql_exp *e, int f)
    1344             : {
    1345      105951 :         list *l = rel_bind_path(sql, rel, ls, sa_list(sql->sa));
    1346      105951 :         node *n;
    1347      105951 :         sql_rel *lrel = NULL, *p = NULL;
    1348             : 
    1349      105951 :         if (!l)
    1350             :                 return NULL;
    1351      105951 :         if (is_sql_or(f)) /* expression has no clear parent relation, so filter current with it */
    1352       21142 :                 return rel_select(sql->sa, rel, e);
    1353             : 
    1354      246006 :         for (n = l->h; n; n = n->next ) {
    1355      245294 :                 lrel = n->data;
    1356             : 
    1357      245294 :                 if (rel_is_ref(lrel))
    1358             :                         break;
    1359             : 
    1360             :                 /* push down as long as the operators allow this */
    1361      245282 :                 if (!is_select(lrel->op) &&
    1362      224741 :                     !(is_semi(lrel->op) && !rel_is_ref(lrel->l)) &&
    1363       84085 :                     lrel->op != op_join &&
    1364             :                     lrel->op != op_left)
    1365             :                         break;
    1366             :                 /* pushing through left head of a left join is allowed */
    1367      161201 :                 if (lrel->op == op_left && (!n->next || lrel->l != n->next->data))
    1368             :                         break;
    1369      161197 :                 p = lrel;
    1370             :         }
    1371       84809 :         if (!lrel)
    1372             :                 return NULL;
    1373       84809 :         if (p && is_select(p->op) && !rel_is_ref(p)) { /* refine old select */
    1374       18354 :                 p = rel_select_push_exp_down(sql, p, e);
    1375             :         } else {
    1376       66455 :                 sql_rel *n = rel_select(sql->sa, lrel, e);
    1377             : 
    1378       66455 :                 if (p && p != lrel) {
    1379       63458 :                         assert(p->op == op_join || p->op == op_left || is_semi(p->op));
    1380       63458 :                         if (p->l == lrel) {
    1381       23310 :                                 p->l = n;
    1382             :                         } else {
    1383       40148 :                                 p->r = n;
    1384             :                         }
    1385             :                 } else {
    1386        2997 :                         if (rel != lrel)
    1387           0 :                                 assert(0);
    1388             :                         rel = n;
    1389             :                 }
    1390             :         }
    1391             :         return rel;
    1392             : }
    1393             : 
    1394             : /* ls and rs are the left and right expression of the join, e is the
    1395             :    join expression.
    1396             :  */
    1397             : sql_rel *
    1398      177396 : rel_push_join(mvc *sql, sql_rel *rel, sql_exp *ls, sql_exp *rs, sql_exp *rs2, sql_exp *e, int f)
    1399             : {
    1400      177396 :         list *l = NULL, *r = NULL, *r2 = NULL;
    1401      177396 :         node *ln, *rn;
    1402      177396 :         sql_rel *lrel = NULL, *rrel = NULL, *rrel2 = NULL, *p = NULL;
    1403             : 
    1404      177396 :         if (!(l = rel_bind_path(sql, rel, ls, sa_list(sql->sa))) ||
    1405      177396 :                 !(r = rel_bind_path(sql, rel, rs, sa_list(sql->sa))) ||
    1406         528 :                 (rs2 && !(r2 = rel_bind_path(sql, rel, rs2, sa_list(sql->sa)))))
    1407           0 :                 return NULL;
    1408             : 
    1409      177396 :         if (is_sql_or(f))
    1410        2922 :                 return rel_push_select(sql, rel, ls, e, f);
    1411             : 
    1412      174474 :         p = rel;
    1413      174474 :         if (r2) {
    1414         520 :                 node *rn2;
    1415             : 
    1416        1047 :                 for (ln = l->h, rn = r->h, rn2 = r2->h; ln && rn && rn2; ln = ln->next, rn = rn->next, rn2 = rn2->next ) {
    1417         551 :                         lrel = ln->data;
    1418         551 :                         rrel = rn->data;
    1419         551 :                         rrel2 = rn2->data;
    1420             : 
    1421         551 :                         if (rel_is_ref(lrel) || rel_is_ref(rrel) || rel_is_ref(rrel2) || is_processed(lrel) || is_processed(rrel))
    1422             :                                 break;
    1423             : 
    1424             :                         /* push down as long as the operators allow this
    1425             :                                 and the relation is equal.
    1426             :                         */
    1427         546 :                         if (lrel != rrel || lrel != rrel2 ||
    1428         527 :                                 (!is_select(lrel->op) &&
    1429          69 :                                  !(is_semi(lrel->op) && !rel_is_ref(lrel->l)) &&
    1430           0 :                                  lrel->op != op_join &&
    1431             :                                  lrel->op != op_left))
    1432             :                                 break;
    1433             :                         /* pushing through left head of a left join is allowed */
    1434         527 :                         if (lrel->op == op_left && (!ln->next || lrel->l != ln->next->data))
    1435             :                                 break;
    1436         527 :                         p = lrel;
    1437             :                 }
    1438             :         } else {
    1439      786660 :                 for (ln = l->h, rn = r->h; ln && rn; ln = ln->next, rn = rn->next ) {
    1440      783902 :                         lrel = ln->data;
    1441      783902 :                         rrel = rn->data;
    1442             : 
    1443      783902 :                         if (rel_is_ref(lrel) || rel_is_ref(rrel) || is_processed(lrel) || is_processed(rrel))
    1444             :                                 break;
    1445             : 
    1446             :                         /* push down as long as the operators allow this
    1447             :                                 and the relation is equal.
    1448             :                         */
    1449      745130 :                         if (lrel != rrel ||
    1450      614366 :                                 (!is_select(lrel->op) &&
    1451      611092 :                                  !(is_semi(lrel->op) && !rel_is_ref(lrel->l)) &&
    1452        1660 :                                  lrel->op != op_join &&
    1453             :                                  lrel->op != op_left))
    1454             :                                 break;
    1455             :                         /* pushing through left head of a left join is allowed */
    1456      612706 :                         if (lrel->op == op_left && (!ln->next || lrel->l != ln->next->data))
    1457             :                                 break;
    1458      612706 :                         p = lrel;
    1459             :                 }
    1460             :         }
    1461      174474 :         if (!lrel || !rrel || (r2 && !rrel2))
    1462             :                 return NULL;
    1463             : 
    1464             :         /* filter on columns of this relation */
    1465      174474 :         if ((lrel == rrel && (!r2 || lrel == rrel2) && lrel->op != op_join) || rel_is_ref(p)) {
    1466        2832 :                 if (is_select(lrel->op) && !rel_is_ref(lrel)) {
    1467        1152 :                         lrel = rel_select_push_exp_down(sql, lrel, e);
    1468        1680 :                 } else if (p && is_select(p->op) && !rel_is_ref(p)) {
    1469        1659 :                         p = rel_select_push_exp_down(sql, p, e);
    1470             :                 } else {
    1471          21 :                         sql_rel *n = rel_select(sql->sa, lrel, e);
    1472             : 
    1473          21 :                         if (p && p != lrel) {
    1474          21 :                                 if (p->l == lrel)
    1475          10 :                                         p->l = n;
    1476             :                                 else
    1477          11 :                                         p->r = n;
    1478             :                         } else {
    1479             :                                 rel = n;
    1480             :                         }
    1481             :                 }
    1482        2832 :                 return rel;
    1483             :         }
    1484             : 
    1485      171642 :         rel_join_add_exp( sql->sa, p, e);
    1486      171642 :         return rel;
    1487             : }
    1488             : 
    1489             : sql_rel *
    1490       18572 : rel_or(mvc *sql, sql_rel *rel, sql_rel *l, sql_rel *r, list *oexps, list *lexps, list *rexps)
    1491             : {
    1492       18572 :         sql_rel *ll = l->l, *rl = r->l;
    1493       18572 :         list *ls, *rs;
    1494             : 
    1495       18572 :         assert(!lexps || l == r);
    1496       18572 :         if (l == r && lexps) { /* merge both lists */
    1497          42 :                 sql_exp *e = exp_or(sql->sa, lexps, rexps, 0);
    1498          42 :                 list *nl = oexps?oexps:new_exp_list(sql->sa);
    1499             : 
    1500          42 :                 rel_destroy(r);
    1501          42 :                 append(nl, e);
    1502          42 :                 if (is_outerjoin(l->op) && is_processed(l))
    1503           0 :                         l = rel_select(sql->sa, l, NULL);
    1504          42 :                 l->exps = nl;
    1505          42 :                 return l;
    1506             :         }
    1507             : 
    1508             :         /* favor or expressions over union */
    1509       18530 :         if (l->op == r->op && is_select(l->op) &&
    1510       18530 :             ll == rl && ll == rel && !rel_is_ref(l) && !rel_is_ref(r)) {
    1511       18530 :                 sql_exp *e = exp_or(sql->sa, l->exps, r->exps, 0);
    1512       18530 :                 list *nl = new_exp_list(sql->sa);
    1513             : 
    1514       18530 :                 rel_destroy(r);
    1515       18530 :                 append(nl, e);
    1516       18530 :                 l->exps = nl;
    1517             : 
    1518             :                 /* merge and expressions */
    1519       18530 :                 ll = l->l;
    1520       20874 :                 while (ll && is_select(ll->op) && !rel_is_ref(ll)) {
    1521        2344 :                         list_merge(l->exps, ll->exps, (fdup)NULL);
    1522        2344 :                         l->l = ll->l;
    1523        2344 :                         ll->l = NULL;
    1524        2344 :                         rel_destroy(ll);
    1525        2344 :                         ll = l->l;
    1526             :                 }
    1527             :                 return l;
    1528             :         }
    1529             : 
    1530           0 :         if (rel) {
    1531           0 :                 ls = rel_projections(sql, rel, NULL, 1, 1);
    1532           0 :                 rs = rel_projections(sql, rel, NULL, 1, 1);
    1533             :         } else {
    1534           0 :                 ls = rel_projections(sql, l, NULL, 1, 1);
    1535           0 :                 rs = rel_projections(sql, r, NULL, 1, 1);
    1536             :         }
    1537           0 :         set_processed(l);
    1538           0 :         set_processed(r);
    1539           0 :         rel = rel_setop_check_types(sql, l, r, ls, rs, op_union);
    1540           0 :         if (!rel)
    1541             :                 return NULL;
    1542           0 :         rel_setop_set_exps(sql, rel, rel_projections(sql, rel, NULL, 1, 1), false);
    1543           0 :         set_processed(rel);
    1544           0 :         rel->nrcols = list_length(rel->exps);
    1545           0 :         rel = rel_distinct(rel);
    1546           0 :         if (!rel)
    1547             :                 return NULL;
    1548           0 :         if (exps_card(l->exps) <= CARD_AGGR &&
    1549           0 :             exps_card(r->exps) <= CARD_AGGR)
    1550             :         {
    1551           0 :                 rel->card = exps_card(l->exps);
    1552           0 :                 exps_fix_card( rel->exps, rel->card);
    1553             :         }
    1554             :         return rel;
    1555             : }
    1556             : 
    1557             : sql_table *
    1558        4059 : rel_ddl_table_get(sql_rel *r)
    1559             : {
    1560        4059 :         if (r->flag == ddl_alter_table || r->flag == ddl_create_table || r->flag == ddl_create_view) {
    1561        4059 :                 sql_exp *e = r->exps->t->data;
    1562        4059 :                 atom *a = e->l;
    1563             : 
    1564        4059 :                 return a->data.val.pval;
    1565             :         }
    1566             :         return NULL;
    1567             : }
    1568             : 
    1569             : sql_rel *
    1570        2330 : rel_ddl_basetable_get(sql_rel *r)
    1571             : {
    1572        2330 :         if (r->flag == ddl_alter_table || r->flag == ddl_create_table || r->flag == ddl_create_view) {
    1573        2330 :                 return r->l;
    1574             :         }
    1575             :         return NULL;
    1576             : }
    1577             : 
    1578             : static sql_exp *
    1579          31 : exps_find_identity(list *exps, sql_rel *p)
    1580             : {
    1581          31 :         node *n;
    1582             : 
    1583         113 :         for (n=exps->h; n; n = n->next) {
    1584          83 :                 sql_exp *e = n->data;
    1585             : 
    1586          83 :                 if (is_identity(e, p))
    1587           1 :                         return e;
    1588             :         }
    1589             :         return NULL;
    1590             : }
    1591             : 
    1592             : static sql_rel *
    1593          82 : _rel_add_identity(mvc *sql, sql_rel *rel, sql_exp **exp)
    1594             : {
    1595          82 :         list *exps = rel_projections(sql, rel, NULL, 1, 1);
    1596          82 :         sql_exp *e = NULL;
    1597             : 
    1598          82 :         if (list_empty(exps)) {
    1599           0 :                 *exp = NULL;
    1600           0 :                 return rel;
    1601             :         }
    1602          82 :         if (!is_simple_project(rel->op) || need_distinct(rel) || !list_empty(rel->r) || rel_is_ref(rel))
    1603          53 :                 rel = rel_project(sql->sa, rel, exps);
    1604             :         /* filter parameters out */
    1605         164 :         for (node *n = rel->exps->h ; n && !e ; n = n->next) {
    1606          82 :                 sql_exp *re = n->data;
    1607             : 
    1608          82 :                 if (exp_subtype(re))
    1609          82 :                         e = re;
    1610             :         }
    1611          82 :         if (!e)
    1612           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query projection must have at least one parameter with known SQL type");
    1613             : 
    1614          82 :         e = exp_column(sql->sa, exp_relname(e), exp_name(e), exp_subtype(e), rel->card, has_nil(e), is_unique(e), is_intern(e));
    1615          82 :         e = exp_unop(sql->sa, e, sql_bind_func(sql, "sys", "identity", exp_subtype(e), NULL, F_FUNC, true));
    1616          82 :         set_intern(e);
    1617          82 :         set_has_no_nil(e);
    1618          82 :         set_unique(e);
    1619          82 :         e->p = prop_create(sql->sa, PROP_HASHCOL, e->p);
    1620          82 :         *exp = exp_label(sql->sa, e, ++sql->label);
    1621          82 :         (void) rel_project_add_exp(sql, rel, e);
    1622          82 :         return rel;
    1623             : }
    1624             : 
    1625             : sql_rel *
    1626          98 : rel_add_identity(mvc *sql, sql_rel *rel, sql_exp **exp)
    1627             : {
    1628          98 :         if (rel && is_basetable(rel->op)) { /* for base table relations just use TID column as identity */
    1629          15 :                 *exp = basetable_get_tid_or_add_it(sql, rel);
    1630          15 :                 return rel;
    1631             :         }
    1632          83 :         if (rel && is_simple_project(rel->op) && !need_distinct(rel) && (*exp = exps_find_identity(rel->exps, rel->l)) != NULL)
    1633             :                 return rel;
    1634          82 :         return _rel_add_identity(sql, rel, exp);
    1635             : }
    1636             : 
    1637             : sql_rel *
    1638           0 : rel_add_identity2(mvc *sql, sql_rel *rel, sql_exp **exp)
    1639             : {
    1640           0 :         sql_rel *l = rel, *p = rel;
    1641             : 
    1642           0 :         if (rel && is_basetable(rel->op)) { /* for base table relations just use TID column as identity */
    1643           0 :                 *exp = basetable_get_tid_or_add_it(sql, rel);
    1644           0 :                 return rel;
    1645             :         }
    1646           0 :         if (rel && is_simple_project(rel->op) && !need_distinct(rel) && (*exp = exps_find_identity(rel->exps, rel->l)) != NULL)
    1647             :                 return rel;
    1648           0 :         while(l && !is_set(l->op) && rel_has_freevar(sql, l) && l->l) {
    1649             :                 p = l;
    1650             :                 l = l->l;
    1651             :         }
    1652           0 :         if (l != p) {
    1653           0 :                 sql_rel *o = rel;
    1654           0 :                 sql_exp *id;
    1655             : 
    1656           0 :                 if (!(p->l = _rel_add_identity(sql, l, exp)))
    1657             :                         return NULL;
    1658           0 :                 l = p->l;
    1659           0 :                 id = exp_ref(sql, *exp);
    1660           0 :                 while (o && o != l) {
    1661           0 :                         *exp = id;
    1662           0 :                         if (is_project(o->op))
    1663           0 :                                 rel_project_add_exp(sql, o, id);
    1664           0 :                         o = o->l;
    1665             :                 }
    1666             :                 return rel;
    1667             :         }
    1668           0 :         return _rel_add_identity(sql, rel, exp);
    1669             : }
    1670             : 
    1671             : static sql_exp *
    1672        1482 : rel_find_column_(sql_allocator *sa, list *exps, const char *tname, const char *cname)
    1673             : {
    1674        1482 :         int ambiguous = 0, multi = 0;
    1675        1482 :         sql_exp *e = exps_bind_column2(exps, tname, cname, &multi);
    1676        1482 :         if (!e && cname[0] == '%' && !tname)
    1677           0 :                 e = exps_bind_column(exps, cname, &ambiguous, &multi, 0);
    1678        1482 :         if (e && !ambiguous && !multi)
    1679        1481 :                 return exp_alias(sa, exp_relname(e), exp_name(e), exp_relname(e), cname, exp_subtype(e), e->card, has_nil(e), is_unique(e), is_intern(e));
    1680             :         return NULL;
    1681             : }
    1682             : 
    1683             : sql_exp *
    1684        1482 : rel_find_column(sql_allocator *sa, sql_rel *rel, const char *tname, const char *cname )
    1685             : {
    1686        1771 :         sql_exp *e = NULL;
    1687             : 
    1688        1771 :         if (!rel)
    1689             :                 return NULL;
    1690        1771 :         if (rel->exps && (is_project(rel->op) || is_base(rel->op)) && (e = rel_find_column_(sa, rel->exps, tname, cname)))
    1691             :                 return e;
    1692         290 :         if ((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->l) {
    1693           1 :                 if (!is_processed(rel))
    1694             :                         return rel_find_column(sa, rel->l, tname, cname);
    1695         289 :         } else if (is_set(rel->op)) {
    1696           0 :                 assert(is_processed(rel));
    1697             :                 return NULL;
    1698             :         } else if (is_join(rel->op)) {
    1699           0 :                 e = rel_find_column(sa, rel->l, tname, cname);
    1700             : 
    1701           0 :                 if (e && (is_right(rel->op) || is_full(rel->op)))
    1702           0 :                         set_has_nil(e);
    1703           0 :                 if (!e) {
    1704           0 :                         e = rel_find_column(sa, rel->r, tname, cname);
    1705           0 :                         if (e && (is_left(rel->op) || is_full(rel->op)))
    1706           0 :                                 set_has_nil(e);
    1707             :                 }
    1708           0 :                 if (!e && !list_empty(rel->attr))
    1709           0 :                         e = rel_find_column_(sa, rel->attr, tname, cname);
    1710           0 :                 if (e)
    1711           0 :                         set_not_unique(e);
    1712           0 :                 return e;
    1713             :         } else if (is_semi(rel->op) ||
    1714             :                    is_select(rel->op) ||
    1715             :                    is_topn(rel->op) ||
    1716             :                    is_sample(rel->op)) {
    1717         289 :                 if (rel->l)
    1718             :                         return rel_find_column(sa, rel->l, tname, cname);
    1719             :         }
    1720             :         return NULL;
    1721             : }
    1722             : 
    1723             : int
    1724           0 : rel_in_rel(sql_rel *super, sql_rel *sub)
    1725             : {
    1726           0 :         if (!super)
    1727             :                 return 0;
    1728           0 :         if (super == sub)
    1729             :                 return 1;
    1730           0 :         if (is_join(super->op) || is_semi(super->op) || is_set(super->op) || is_modify(super->op) || is_ddl(super->op))
    1731           0 :                 return rel_in_rel(super->l, sub) || rel_in_rel(super->r, sub);
    1732             :         if (is_select(super->op) || is_simple_project(super->op) || is_groupby(super->op) || is_topn(super->op) || is_sample(super->op))
    1733           0 :                 return rel_in_rel(super->l, sub);
    1734             :         return 0;
    1735             : }
    1736             : 
    1737             : sql_rel*
    1738          12 : rel_parent(sql_rel *rel)
    1739             : {
    1740          12 :         if (rel->l && (is_project(rel->op) || is_topn(rel->op) || is_sample(rel->op))) {
    1741          12 :                 sql_rel *l = rel->l;
    1742          12 :                 if (is_project(l->op))
    1743          12 :                         return l;
    1744             :         }
    1745             :         return rel;
    1746             : }
    1747             : 
    1748             : sql_exp *
    1749       26602 : lastexp(sql_rel *rel)
    1750             : {
    1751       26602 :         if (!is_processed(rel) || is_topn(rel->op) || is_sample(rel->op))
    1752          12 :                 rel = rel_parent(rel);
    1753       26602 :         assert(list_length(rel->exps));
    1754       26602 :         assert(is_project(rel->op) || rel->op == op_table);
    1755       26602 :         return rel->exps->t->data;
    1756             : }
    1757             : 
    1758             : sql_rel *
    1759        5723 : rel_return_zero_or_one(mvc *sql, sql_rel *rel, exp_kind ek)
    1760             : {
    1761        5723 :         if (ek.card < card_set && rel->card > CARD_ATOM) {
    1762        4368 :                 list *exps = rel->exps;
    1763             : 
    1764        4368 :                 assert (is_simple_project(rel->op) || is_set(rel->op));
    1765        4368 :                 rel = rel_groupby(sql, rel, NULL);
    1766        8746 :                 for(node *n = exps->h; n; n=n->next) {
    1767        4378 :                         sql_exp *e = n->data;
    1768        4378 :                         if (!has_label(e))
    1769          49 :                                 exp_label(sql->sa, e, ++sql->label);
    1770        4378 :                         sql_subtype *t = exp_subtype(e); /* parameters don't have a type defined, for those use 'void' one */
    1771        4378 :                         sql_subfunc *zero_or_one = sql_bind_func(sql, "sys", "zero_or_one", t ? t : sql_bind_localtype("void"), NULL, F_AGGR, true);
    1772             : 
    1773        4378 :                         e = exp_ref(sql, e);
    1774        4378 :                         e = exp_aggr1(sql->sa, e, zero_or_one, 0, 0, CARD_ATOM, has_nil(e));
    1775        4378 :                         (void)rel_groupby_add_aggr(sql, rel, e);
    1776             :                 }
    1777        4368 :                 set_processed(rel);
    1778             :         }
    1779        5723 :         return rel;
    1780             : }
    1781             : 
    1782             : sql_rel *
    1783       35454 : rel_zero_or_one(mvc *sql, sql_rel *rel, exp_kind ek)
    1784             : {
    1785       35454 :         if (is_topn(rel->op) || is_sample(rel->op))
    1786          17 :                 rel = rel_project(sql->sa, rel, rel_projections(sql, rel, NULL, 1, 0));
    1787       35454 :         if (ek.card < card_set && rel->card > CARD_ATOM) {
    1788        9039 :                 assert (is_simple_project(rel->op) || is_set(rel->op));
    1789             : 
    1790        9039 :                 list *exps = rel->exps;
    1791       18106 :                 for(node *n = exps->h; n; n=n->next) {
    1792        9067 :                         sql_exp *e = n->data;
    1793        9067 :                         if (!has_label(e))
    1794        9028 :                                 exp_label(sql->sa, e, ++sql->label);
    1795             :                 }
    1796        9039 :                 set_single(rel);
    1797             :         } else {
    1798       26415 :                 sql_exp *e = lastexp(rel);
    1799       26415 :                 if (!has_label(e))
    1800       12668 :                         exp_label(sql->sa, e, ++sql->label);
    1801             :         }
    1802       35454 :         return rel;
    1803             : }
    1804             : 
    1805             : static sql_rel *
    1806        8898 : refs_find_rel(list *refs, sql_rel *rel)
    1807             : {
    1808        8898 :         node *n;
    1809             : 
    1810       20117 :         for(n=refs->h; n; n = n->next->next) {
    1811       15778 :                 sql_rel *ref = n->data;
    1812       15778 :                 sql_rel *s = n->next->data;
    1813             : 
    1814       15778 :                 if (rel == ref)
    1815             :                         return s;
    1816             :         }
    1817             :         return NULL;
    1818             : }
    1819             : 
    1820             : static int exp_deps(mvc *sql, sql_exp *e, list *refs, list *l);
    1821             : 
    1822             : static int
    1823      700824 : exps_deps(mvc *sql, list *exps, list *refs, list *l)
    1824             : {
    1825             : 
    1826     2941152 :         for(node *n = exps->h; n; n = n->next)
    1827     2240328 :                 if (exp_deps(sql, n->data, refs, l) != 0)
    1828             :                         return -1;
    1829             :         return 0;
    1830             : }
    1831             : 
    1832             : static int
    1833     6822594 : id_cmp(sql_base *id1, sql_base *id2)
    1834             : {
    1835     6822594 :         if (id1->id == id2->id)
    1836       85707 :                 return 0;
    1837             :         return -1;
    1838             : }
    1839             : 
    1840             : static list *
    1841      744584 : cond_append(list *l, sql_base *b)
    1842             : {
    1843      744584 :         if (b->id >= FUNC_OIDS && !list_find(l, b, (fcmp) &id_cmp))
    1844      351934 :                 list_append(l, b);
    1845      744584 :         return l;
    1846             : }
    1847             : 
    1848             : static int rel_deps(mvc *sql, sql_rel *r, list *refs, list *l);
    1849             : 
    1850             : static int
    1851     2425726 : exp_deps(mvc *sql, sql_exp *e, list *refs, list *l)
    1852             : {
    1853     2573830 :         if (mvc_highwater(sql)) {
    1854           0 :                 (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    1855           0 :                 return -1;
    1856             :         }
    1857             : 
    1858     2573830 :         switch(e->type) {
    1859       43819 :         case e_psm:
    1860       43819 :                 if (e->flag & PSM_SET || e->flag & PSM_RETURN || e->flag & PSM_EXCEPTION) {
    1861       18801 :                         return exp_deps(sql, e->l, refs, l);
    1862       25018 :                 } else if (e->flag & PSM_VAR) {
    1863             :                         return 0;
    1864       20372 :                 } else if (e->flag & PSM_WHILE || e->flag & PSM_IF) {
    1865        6152 :                         if (exp_deps(sql, e->l, refs, l) != 0 || exps_deps(sql, e->r, refs, l) != 0)
    1866           0 :                                 return -1;
    1867        6152 :                         if (e->flag & PSM_IF && e->f)
    1868         740 :                                 return exps_deps(sql, e->f, refs, l);
    1869       14220 :                 } else if (e->flag & PSM_REL) {
    1870       14220 :                         sql_rel *rel = e->l;
    1871       14220 :                         return rel_deps(sql, rel, refs, l);
    1872             :                 }
    1873             :                 break;
    1874      878168 :         case e_atom:
    1875      878168 :                 if (e->f && exps_deps(sql, e->f, refs, l) != 0)
    1876             :                         return -1;
    1877             :                 break;
    1878             :         case e_column:
    1879             :                 break;
    1880      129272 :         case e_convert:
    1881      129272 :                 return exp_deps(sql, e->l, refs, l);
    1882      314878 :         case e_func: {
    1883      314878 :                 sql_subfunc *f = e->f;
    1884             : 
    1885      314878 :                 if (e->l && exps_deps(sql, e->l, refs, l) != 0)
    1886             :                         return -1;
    1887      314878 :                 cond_append(l, &f->func->base);
    1888      314878 :                 if (e->l && list_length(e->l) == 2 && strcmp(f->func->base.name, "next_value_for") == 0) {
    1889             :                         /* add dependency on seq nr */
    1890          82 :                         list *nl = e->l;
    1891          82 :                         sql_exp *schname = nl->h->data, *seqname = nl->t->data;
    1892          82 :                         char *sch_name = is_atom(schname->type) && schname->l ? ((atom*)schname->l)->data.val.sval : NULL;
    1893          82 :                         char *seq_name = is_atom(seqname->type) && seqname->l ? ((atom*)seqname->l)->data.val.sval : NULL;
    1894             : 
    1895          82 :                         if (sch_name && seq_name) {
    1896          82 :                                 sql_schema *sche = mvc_bind_schema(sql, sch_name);
    1897          82 :                                 if (sche) {
    1898          82 :                                         sql_sequence *seq = find_sql_sequence(sql->session->tr, sche, seq_name);
    1899          82 :                                         if (seq)
    1900          82 :                                                 cond_append(l, &seq->base);
    1901             :                                 }
    1902             :                         }
    1903             :                 }
    1904             :         } break;
    1905       19739 :         case e_aggr: {
    1906       19739 :                 sql_subfunc *a = e->f;
    1907             : 
    1908       19739 :                 if (e->l && exps_deps(sql, e->l, refs, l) != 0)
    1909             :                         return -1;
    1910       19739 :                 cond_append(l, &a->func->base);
    1911       19739 :         } break;
    1912       91896 :         case e_cmp: {
    1913       91896 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
    1914         250 :                         if (e->flag == cmp_filter) {
    1915          17 :                                 sql_subfunc *f = e->f;
    1916          17 :                                 cond_append(l, &f->func->base);
    1917             :                         }
    1918         500 :                         if (exps_deps(sql, e->l, refs, l) != 0 ||
    1919         250 :                                 exps_deps(sql, e->r, refs, l) != 0)
    1920           0 :                                 return -1;
    1921       91646 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
    1922        8092 :                         if (exp_deps(sql, e->l, refs, l) != 0 ||
    1923        4046 :                                 exps_deps(sql, e->r, refs, l) != 0)
    1924           0 :                                 return -1;
    1925             :                 } else {
    1926      175200 :                         if (exp_deps(sql, e->l, refs, l) != 0 ||
    1927       87600 :                                 exp_deps(sql, e->r, refs, l) != 0)
    1928           0 :                                 return -1;
    1929       87600 :                         if (e->f)
    1930             :                                 return exp_deps(sql, e->f, refs, l);
    1931             :                 }
    1932             :         }       break;
    1933             :         }
    1934             :         return 0;
    1935             : }
    1936             : 
    1937             : static int
    1938      470323 : rel_deps(mvc *sql, sql_rel *r, list *refs, list *l)
    1939             : {
    1940      470323 :         if (mvc_highwater(sql)) {
    1941           0 :                 (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    1942           0 :                 return -1;
    1943             :         }
    1944             : 
    1945      470323 :         if (!r)
    1946             :                 return 0;
    1947             : 
    1948      470457 :         if (rel_is_ref(r) && refs_find_rel(refs, r)) /* already handled */
    1949             :                 return 0;
    1950      457000 :         switch (r->op) {
    1951       97697 :         case op_basetable: {
    1952       97697 :                 sql_table *t = r->l;
    1953             : 
    1954       97697 :                 cond_append(l, &t->base);
    1955             :                 /* find all used columns */
    1956      439056 :                 for (node *en = r->exps->h; en; en = en->next) {
    1957      341359 :                         sql_exp *exp = en->data;
    1958      341359 :                         const char *oname = exp->r;
    1959             : 
    1960      341359 :                         assert(!is_func(exp->type));
    1961      341359 :                         if (oname[0] == '%' && strcmp(oname, TID) == 0) {
    1962       33255 :                                 continue;
    1963      308104 :                         } else if (oname[0] == '%') {
    1964         212 :                                 sql_idx *i = find_sql_idx(t, oname+1);
    1965         212 :                                 if (i) {
    1966         211 :                                         cond_append(l, &i->base);
    1967         211 :                                         continue;
    1968             :                                 }
    1969             :                         }
    1970      307893 :                         sql_column *c = find_sql_column(t, oname);
    1971      307893 :                         if (!c)
    1972             :                                 return -1;
    1973      307893 :                         cond_append(l, &c->base);
    1974             :                 }
    1975             :         } break;
    1976        4067 :         case op_table: {
    1977        4067 :                 if ((IS_TABLE_PROD_FUNC(r->flag) || r->flag == TABLE_FROM_RELATION) && r->r) { /* table producing function, excluding rel_relational_func cases */
    1978        4067 :                         sql_exp *op = r->r;
    1979        4067 :                         sql_subfunc *f = op->f;
    1980        4067 :                         cond_append(l, &f->func->base);
    1981             :                 }
    1982             :         } break;
    1983       77050 :         case op_join:
    1984             :         case op_left:
    1985             :         case op_right:
    1986             :         case op_full:
    1987             :         case op_semi:
    1988             :         case op_anti:
    1989             :         case op_union:
    1990             :         case op_except:
    1991             :         case op_inter:
    1992             : 
    1993             :         case op_insert:
    1994             :         case op_update:
    1995             :         case op_delete:
    1996             :         case op_merge:
    1997      154100 :                 if (rel_deps(sql, r->l, refs, l) != 0 ||
    1998       77050 :                         rel_deps(sql, r->r, refs, l) != 0)
    1999           0 :                         return -1;
    2000             :                 break;
    2001      163660 :         case op_project:
    2002             :         case op_select:
    2003             :         case op_groupby:
    2004             :         case op_topn:
    2005             :         case op_sample:
    2006             :         case op_truncate:
    2007      163660 :                 if (rel_deps(sql, r->l, refs, l) != 0)
    2008             :                         return -1;
    2009             :                 break;
    2010      114526 :         case op_ddl:
    2011      114526 :                 if (r->flag == ddl_output || r->flag == ddl_create_seq || r->flag == ddl_alter_seq || r->flag == ddl_alter_table || r->flag == ddl_create_table || r->flag == ddl_create_view) {
    2012          21 :                         if (rel_deps(sql, r->l, refs, l) != 0)
    2013             :                                 return -1;
    2014             :                 } else if (r->flag == ddl_list || r->flag == ddl_exception) {
    2015           0 :                         if (rel_deps(sql, r->l, refs, l) != 0 ||
    2016           0 :                                 rel_deps(sql, r->r, refs, l) != 0)
    2017           0 :                                 return -1;
    2018             :                 }
    2019             :                 break;
    2020             :         }
    2021      457000 :         if (!is_base(r->op) && r->exps) {
    2022      343622 :                 if (exps_deps(sql, r->exps, refs, l) != 0)
    2023             :                         return -1;
    2024             :         }
    2025      457000 :         if ((is_simple_project(r->op) || is_groupby(r->op)) && r->r) {
    2026       18122 :                 if (exps_deps(sql, r->r, refs, l) != 0)
    2027             :                         return -1;
    2028             :         }
    2029      457000 :         if (rel_is_ref(r)) {
    2030        4339 :                 list_append(refs, r);
    2031        4339 :                 list_append(refs, l);
    2032             :         }
    2033             :         return 0;
    2034             : }
    2035             : 
    2036             : list *
    2037      138322 : rel_dependencies(mvc *sql, sql_rel *r)
    2038             : {
    2039      138322 :         list *refs = sa_list(sql->sa);
    2040      138322 :         list *l = sa_list(sql->sa);
    2041             : 
    2042      138322 :         if (rel_deps(sql, r, refs, l) != 0)
    2043           0 :                 return NULL;
    2044             :         return l;
    2045             : }
    2046             : 
    2047             : static list *exps_exp_visitor(visitor *v, sql_rel *rel, list *exps, int depth, exp_rewrite_fptr exp_rewriter, bool topdown, bool relations_topdown);
    2048             : 
    2049             : static inline list *
    2050       39483 : exps_exps_exp_visitor(visitor *v, sql_rel *rel, list *lists, int depth, exp_rewrite_fptr exp_rewriter, bool topdown, bool relations_topdown)
    2051             : {
    2052       39483 :         node *n;
    2053             : 
    2054       39483 :         if (list_empty(lists))
    2055             :                 return lists;
    2056       86628 :         for (n = lists->h; n; n = n->next) {
    2057       47145 :                 if (n->data && (n->data = exps_exp_visitor(v, rel, n->data, depth, exp_rewriter, topdown, relations_topdown)) == NULL)
    2058             :                         return NULL;
    2059             :         }
    2060             :         return lists;
    2061             : }
    2062             : 
    2063             : static sql_rel *rel_exp_visitor(visitor *v, sql_rel *rel, exp_rewrite_fptr exp_rewriter, bool topdown, bool relations_topdown);
    2064             : 
    2065             : static sql_exp *
    2066    76162847 : exp_visitor(visitor *v, sql_rel *rel, sql_exp *e, int depth, exp_rewrite_fptr exp_rewriter, bool topdown, bool relations_topdown, bool *changed)
    2067             : {
    2068    76162847 :         if (mvc_highwater(v->sql))
    2069           0 :                 return sql_error(v->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    2070             : 
    2071    76170826 :         assert(e);
    2072    76170826 :         if (topdown) {
    2073         874 :                 int changes = v->changes;
    2074         874 :                 if (!(e = exp_rewriter(v, rel, e, depth)))
    2075             :                         return NULL;
    2076         874 :                 *changed |= v->changes > changes;
    2077             :         }
    2078             : 
    2079    76170826 :         switch(e->type) {
    2080             :         case e_column:
    2081             :                 break;
    2082     2205827 :         case e_convert:
    2083     2205827 :                 if  ((e->l = exp_visitor(v, rel, e->l, depth+1, exp_rewriter, topdown, relations_topdown, changed)) == NULL)
    2084             :                         return NULL;
    2085             :                 break;
    2086     3961593 :         case e_aggr:
    2087             :         case e_func:
    2088     3961593 :                 if (e->r) /* rewrite rank -r is list of lists */
    2089       39483 :                         if ((e->r = exps_exps_exp_visitor(v, rel, e->r, depth+1, exp_rewriter, topdown, relations_topdown)) == NULL)
    2090             :                                 return NULL;
    2091     3961593 :                 if (e->l)
    2092     3831716 :                         if ((e->l = exps_exp_visitor(v, rel, e->l, depth+1, exp_rewriter, topdown, relations_topdown)) == NULL)
    2093             :                                 return NULL;
    2094             :                 break;
    2095     3211879 :         case e_cmp:
    2096     3211879 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
    2097      167425 :                         if ((e->l = exps_exp_visitor(v, rel, e->l, depth+1, exp_rewriter, topdown, relations_topdown)) == NULL)
    2098             :                                 return NULL;
    2099      167425 :                         if ((e->r = exps_exp_visitor(v, rel, e->r, depth+1, exp_rewriter, topdown, relations_topdown)) == NULL)
    2100             :                                 return NULL;
    2101     3044454 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
    2102      195173 :                         if ((e->l = exp_visitor(v, rel, e->l, depth+1, exp_rewriter, topdown, relations_topdown, changed)) == NULL)
    2103             :                                 return NULL;
    2104      195173 :                         if ((e->r = exps_exp_visitor(v, rel, e->r, depth+1, exp_rewriter, topdown, relations_topdown)) == NULL)
    2105             :                                 return NULL;
    2106             :                 } else {
    2107     2849281 :                         if ((e->l = exp_visitor(v, rel, e->l, depth+1, exp_rewriter, topdown, relations_topdown, changed)) == NULL)
    2108             :                                 return NULL;
    2109     2849281 :                         if ((e->r = exp_visitor(v, rel, e->r, depth+1, exp_rewriter, topdown, relations_topdown, changed)) == NULL)
    2110             :                                 return NULL;
    2111     2849281 :                         if (e->f && (e->f = exp_visitor(v, rel, e->f, depth+1, exp_rewriter, topdown, relations_topdown, changed)) == NULL)
    2112             :                                 return NULL;
    2113             :                 }
    2114             :                 break;
    2115      369545 :         case e_psm:
    2116      369545 :                 if (e->flag & PSM_SET || e->flag & PSM_RETURN || e->flag & PSM_EXCEPTION) {
    2117      114208 :                         if ((e->l = exp_visitor(v, rel, e->l, depth+1, exp_rewriter, topdown, relations_topdown, changed)) == NULL)
    2118             :                                 return NULL;
    2119      255337 :                 } else if (e->flag & PSM_VAR) {
    2120             :                         return e;
    2121      225471 :                 } else if (e->flag & PSM_WHILE || e->flag & PSM_IF) {
    2122       35134 :                         if ((e->l = exp_visitor(v, rel, e->l, depth+1, exp_rewriter, topdown, relations_topdown, changed)) == NULL)
    2123             :                                 return NULL;
    2124       35134 :                         if ((e->r = exps_exp_visitor(v, rel, e->r, depth+1, exp_rewriter, topdown, relations_topdown)) == NULL)
    2125             :                                 return NULL;
    2126       35134 :                         if (e->flag == PSM_IF && e->f && (e->f = exps_exp_visitor(v, rel, e->f, depth+1, exp_rewriter, topdown, relations_topdown)) == NULL)
    2127             :                                 return NULL;
    2128      190337 :                 } else if (e->flag & PSM_REL) {
    2129      190337 :                         if ((e->l = rel_exp_visitor(v, e->l, exp_rewriter, topdown, relations_topdown)) == NULL)
    2130             :                                 return NULL;
    2131             :                 }
    2132             :                 break;
    2133    24136160 :         case e_atom:
    2134    24136160 :                 if (e->f)
    2135      790447 :                         if ((e->f = exps_exp_visitor(v, rel, e->f, depth+1, exp_rewriter, topdown, relations_topdown)) == NULL)
    2136             :                                 return NULL;
    2137             :                 break;
    2138             :         }
    2139    76140940 :         if (!topdown) {
    2140    76132013 :                 int changes = v->changes;
    2141    76132013 :                 if (!(e = exp_rewriter(v, rel, e, depth)))
    2142             :                         return NULL;
    2143    76133151 :                 *changed |= v->changes > changes;
    2144             :         }
    2145             :         return e;
    2146             : }
    2147             : 
    2148             : static list *
    2149    19349378 : exps_exp_visitor(visitor *v, sql_rel *rel, list *exps, int depth, exp_rewrite_fptr exp_rewriter, bool topdown, bool relations_topdown)
    2150             : {
    2151    19349378 :         bool changed = false;
    2152    19349378 :         if (list_empty(exps))
    2153             :                 return exps;
    2154    87287537 :         for (node *n = exps->h; n; n = n->next)
    2155    67969580 :                 if (n->data && (n->data = exp_visitor(v, rel, n->data, depth, exp_rewriter, topdown, relations_topdown, &changed)) == NULL)
    2156             :                         return NULL;
    2157    19317957 :         if (changed && depth == 0) /* only level 0 exps use hash, so remove only on those */
    2158       17864 :                 list_hash_clear(exps);
    2159             :         return exps;
    2160             : }
    2161             : 
    2162             : static inline sql_rel *
    2163    14546404 : rel_exp_visitor(visitor *v, sql_rel *rel, exp_rewrite_fptr exp_rewriter, bool topdown, bool relations_topdown)
    2164             : {
    2165    14546404 :         if (mvc_highwater(v->sql))
    2166           0 :                 return sql_error(v->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    2167             : 
    2168    14546826 :         if (!rel)
    2169             :                 return rel;
    2170             : 
    2171    14546805 :         if (relations_topdown) {
    2172     4427665 :                 if (rel->exps && (rel->exps = exps_exp_visitor(v, rel, rel->exps, 0, exp_rewriter, topdown, relations_topdown)) == NULL)
    2173             :                         return NULL;
    2174     4427662 :                 if ((is_groupby(rel->op) || is_simple_project(rel->op)) && rel->r && (rel->r = exps_exp_visitor(v, rel, rel->r, 0, exp_rewriter, topdown, relations_topdown)) == NULL)
    2175             :                         return NULL;
    2176             :         }
    2177             : 
    2178    14546802 :         switch(rel->op){
    2179             :         case op_basetable:
    2180             :                 break;
    2181       46399 :         case op_table:
    2182       46399 :                 if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION) {
    2183       46306 :                         if (rel->l)
    2184         567 :                                 if ((rel->l = rel_exp_visitor(v, rel->l, exp_rewriter, topdown, relations_topdown)) == NULL)
    2185             :                                         return NULL;
    2186             :                 }
    2187             :                 break;
    2188     2025932 :         case op_ddl:
    2189     2025932 :                 if (rel->flag == ddl_output || rel->flag == ddl_create_seq || rel->flag == ddl_alter_seq || rel->flag == ddl_alter_table || rel->flag == ddl_create_table || rel->flag == ddl_create_view) {
    2190      186617 :                         if (rel->l)
    2191      184848 :                                 if ((rel->l = rel_exp_visitor(v, rel->l, exp_rewriter, topdown, relations_topdown)) == NULL)
    2192             :                                         return NULL;
    2193             :                 } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
    2194        1892 :                         if (rel->l)
    2195        1743 :                                 if ((rel->l = rel_exp_visitor(v, rel->l, exp_rewriter, topdown, relations_topdown)) == NULL)
    2196             :                                         return NULL;
    2197        1892 :                         if (rel->r)
    2198        1659 :                                 if ((rel->r = rel_exp_visitor(v, rel->r, exp_rewriter, topdown, relations_topdown)) == NULL)
    2199             :                                         return NULL;
    2200             :                 }
    2201             :                 break;
    2202     2507146 :         case op_insert:
    2203             :         case op_update:
    2204             :         case op_delete:
    2205             :         case op_merge:
    2206             : 
    2207             :         case op_join:
    2208             :         case op_left:
    2209             :         case op_right:
    2210             :         case op_full:
    2211             :         case op_semi:
    2212             :         case op_anti:
    2213             : 
    2214             :         case op_union:
    2215             :         case op_inter:
    2216             :         case op_except:
    2217     2507146 :                 if (rel->l)
    2218     2507146 :                         if ((rel->l = rel_exp_visitor(v, rel->l, exp_rewriter, topdown, relations_topdown)) == NULL)
    2219             :                                 return NULL;
    2220     2507143 :                 if (rel->r)
    2221     2505016 :                         if ((rel->r = rel_exp_visitor(v, rel->r, exp_rewriter, topdown, relations_topdown)) == NULL)
    2222             :                                 return NULL;
    2223             :                 break;
    2224     6530863 :         case op_select:
    2225             :         case op_topn:
    2226             :         case op_sample:
    2227             :         case op_project:
    2228             :         case op_groupby:
    2229             :         case op_truncate:
    2230     6530863 :                 if (rel->l)
    2231     5568856 :                         if ((rel->l = rel_exp_visitor(v, rel->l, exp_rewriter, topdown, relations_topdown)) == NULL)
    2232             :                                 return NULL;
    2233             :                 break;
    2234             :         }
    2235             : 
    2236    14546764 :         if (!relations_topdown) {
    2237    10119019 :                 if (rel->exps && (rel->exps = exps_exp_visitor(v, rel, rel->exps, 0, exp_rewriter, topdown, relations_topdown)) == NULL)
    2238             :                         return NULL;
    2239    10119036 :                 if ((is_groupby(rel->op) || is_simple_project(rel->op)) && rel->r && (rel->r = exps_exp_visitor(v, rel, rel->r, 0, exp_rewriter, topdown, relations_topdown)) == NULL)
    2240             :                         return NULL;
    2241             :         }
    2242             : 
    2243             :         return rel;
    2244             : }
    2245             : 
    2246             : sql_rel *
    2247           0 : rel_exp_visitor_topdown(visitor *v, sql_rel *rel, exp_rewrite_fptr exp_rewriter, bool relations_topdown)
    2248             : {
    2249           0 :         return rel_exp_visitor(v, rel, exp_rewriter, true, relations_topdown);
    2250             : }
    2251             : 
    2252             : sql_rel *
    2253     3586720 : rel_exp_visitor_bottomup(visitor *v, sql_rel *rel, exp_rewrite_fptr exp_rewriter, bool relations_topdown)
    2254             : {
    2255     3586720 :         return rel_exp_visitor(v, rel, exp_rewriter, false, relations_topdown);
    2256             : }
    2257             : 
    2258             : static list *exps_rel_visitor(visitor *v, list *exps, rel_rewrite_fptr rel_rewriter, bool topdown);
    2259             : static list *exps_exps_rel_visitor(visitor *v, list *lists, rel_rewrite_fptr rel_rewriter, bool topdown);
    2260             : 
    2261             : static sql_exp *
    2262   380768818 : exp_rel_visitor(visitor *v, sql_exp *e, rel_rewrite_fptr rel_rewriter, bool topdown)
    2263             : {
    2264   380768818 :         if (mvc_highwater(v->sql))
    2265           0 :                 return sql_error(v->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    2266             : 
    2267   380792721 :         assert(e);
    2268   380792721 :         switch(e->type) {
    2269             :         case e_column:
    2270             :                 break;
    2271    12721074 :         case e_convert:
    2272    12721074 :                 if ((e->l = exp_rel_visitor(v, e->l, rel_rewriter, topdown)) == NULL)
    2273             :                         return NULL;
    2274             :                 break;
    2275    22328403 :         case e_aggr:
    2276             :         case e_func:
    2277    22328403 :                 if (e->r) /* rewrite rank */
    2278       62012 :                         if ((e->r = exps_exps_rel_visitor(v, e->r, rel_rewriter, topdown)) == NULL)
    2279             :                                 return NULL;
    2280    22328403 :                 if (e->l)
    2281    21500178 :                         if ((e->l = exps_rel_visitor(v, e->l, rel_rewriter, topdown)) == NULL)
    2282             :                                 return NULL;
    2283             :                 break;
    2284    23002653 :         case e_cmp:
    2285    23002653 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
    2286      781675 :                         if ((e->l = exps_rel_visitor(v, e->l, rel_rewriter, topdown)) == NULL)
    2287             :                                 return NULL;
    2288      781675 :                         if ((e->r = exps_rel_visitor(v, e->r, rel_rewriter, topdown)) == NULL)
    2289             :                                 return NULL;
    2290    22220978 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
    2291     1470599 :                         if ((e->l = exp_rel_visitor(v, e->l, rel_rewriter, topdown)) == NULL)
    2292             :                                 return NULL;
    2293     1470599 :                         if ((e->r = exps_rel_visitor(v, e->r, rel_rewriter, topdown)) == NULL)
    2294             :                                 return NULL;
    2295             :                 } else {
    2296    20750379 :                         if ((e->l = exp_rel_visitor(v, e->l, rel_rewriter, topdown)) == NULL)
    2297             :                                 return NULL;
    2298    20750380 :                         if ((e->r = exp_rel_visitor(v, e->r, rel_rewriter, topdown)) == NULL)
    2299             :                                 return NULL;
    2300    20750380 :                         if (e->f && (e->f = exp_rel_visitor(v, e->f, rel_rewriter, topdown)) == NULL)
    2301             :                                 return NULL;
    2302             :                 }
    2303             :                 break;
    2304     1914586 :         case e_psm:
    2305     1914586 :                 if (e->flag & PSM_SET || e->flag & PSM_RETURN || e->flag & PSM_EXCEPTION) {
    2306      630720 :                         if ((e->l = exp_rel_visitor(v, e->l, rel_rewriter, topdown)) == NULL)
    2307             :                                 return NULL;
    2308     1283866 :                 } else if (e->flag & PSM_VAR) {
    2309             :                         return e;
    2310     1092384 :                 } else if (e->flag & PSM_WHILE || e->flag & PSM_IF) {
    2311      170120 :                         if ((e->l = exp_rel_visitor(v, e->l, rel_rewriter, topdown)) == NULL)
    2312             :                                 return NULL;
    2313      170120 :                         if ((e->r = exps_rel_visitor(v, e->r, rel_rewriter, topdown)) == NULL)
    2314             :                                 return NULL;
    2315      170120 :                         if (e->flag == PSM_IF && e->f && (e->f = exps_rel_visitor(v, e->f, rel_rewriter, topdown)) == NULL)
    2316             :                                 return NULL;
    2317      922264 :                 } else if (e->flag & PSM_REL) {
    2318      922264 :                         sql_rel *(*func)(visitor *, sql_rel *, rel_rewrite_fptr) = topdown ? rel_visitor_topdown : rel_visitor_bottomup;
    2319      922264 :                         if ((e->l = func(v, e->l, rel_rewriter)) == NULL)
    2320             :                                 return NULL;
    2321             :                 }
    2322             :                 break;
    2323    72190254 :         case e_atom:
    2324    72190254 :                 if (e->f)
    2325     1532878 :                         if ((e->f = exps_rel_visitor(v, e->f, rel_rewriter, topdown)) == NULL)
    2326             :                                 return NULL;
    2327             :                 break;
    2328             :         }
    2329             :         return e;
    2330             : }
    2331             : 
    2332             : static list *
    2333   102024984 : exps_rel_visitor(visitor *v, list *exps, rel_rewrite_fptr rel_rewriter, bool topdown)
    2334             : {
    2335   102024984 :         if (list_empty(exps))
    2336             :                 return exps;
    2337   425906593 :         for (node *n = exps->h; n; n = n->next)
    2338   324248940 :                 if (n->data && (n->data = exp_rel_visitor(v, n->data, rel_rewriter, topdown)) == NULL)
    2339             :                         return NULL;
    2340             :         return exps;
    2341             : }
    2342             : 
    2343             : static list *
    2344       62012 : exps_exps_rel_visitor(visitor *v, list *lists, rel_rewrite_fptr rel_rewriter, bool topdown)
    2345             : {
    2346       62012 :         if (list_empty(lists))
    2347             :                 return lists;
    2348      124024 :         for (node *n = lists->h; n; n = n->next)
    2349       62012 :                 if (n->data && (n->data = exps_rel_visitor(v, n->data, rel_rewriter, topdown)) == NULL)
    2350             :                         return NULL;
    2351             :         return lists;
    2352             : }
    2353             : 
    2354             : static inline sql_rel *
    2355    75688190 : do_rel_visitor(visitor *v, sql_rel *rel, rel_rewrite_fptr rel_rewriter, bool topdown)
    2356             : {
    2357    75688190 :         if (rel->exps && (rel->exps = exps_rel_visitor(v, rel->exps, rel_rewriter, topdown)) == NULL)
    2358             :                 return NULL;
    2359    75686805 :         if ((is_groupby(rel->op) || is_simple_project(rel->op)) && rel->r && (rel->r = exps_rel_visitor(v, rel->r, rel_rewriter, topdown)) == NULL)
    2360             :                 return NULL;
    2361    75686805 :         int changes = v->changes;
    2362    75686805 :         rel = rel_rewriter(v, rel);
    2363    75688877 :         if (rel && rel->exps && v->changes > changes) {
    2364      296290 :                 list_hash_clear(rel->exps);
    2365      296290 :                 if ((is_groupby(rel->op) || is_simple_project(rel->op)) && rel->r)
    2366       12203 :                         list_hash_clear(rel->r);
    2367             :         }
    2368             :         return rel;
    2369             : }
    2370             : 
    2371             : static inline sql_rel *
    2372    75689044 : rel_visitor(visitor *v, sql_rel *rel, rel_rewrite_fptr rel_rewriter, bool topdown)
    2373             : {
    2374    75689044 :         sql_rel *parent = v->parent;
    2375             : 
    2376    75689044 :         if (mvc_highwater(v->sql))
    2377           0 :                 return sql_error(v->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    2378             : 
    2379    75690854 :         if (!rel)
    2380             :                 return NULL;
    2381             : 
    2382    75690795 :         if (topdown && !(rel = do_rel_visitor(v, rel, rel_rewriter, true)))
    2383             :                 return NULL;
    2384             : 
    2385    75690748 :         sql_rel *(*func)(visitor *, sql_rel *, rel_rewrite_fptr) = topdown ? rel_visitor_topdown : rel_visitor_bottomup;
    2386             : 
    2387    75690748 :         v->parent = rel;
    2388    75690748 :         switch(rel->op){
    2389             :         case op_basetable:
    2390             :                 break;
    2391      150535 :         case op_table:
    2392      150535 :                 if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION) {
    2393      150102 :                         if (rel->l)
    2394        2921 :                                 if ((rel->l = func(v, rel->l, rel_rewriter)) == NULL)
    2395             :                                         return NULL;
    2396             :                 }
    2397             :                 break;
    2398     3928207 :         case op_ddl:
    2399     3928207 :                 if (rel->flag == ddl_output || rel->flag == ddl_create_seq || rel->flag == ddl_alter_seq || rel->flag == ddl_alter_table || rel->flag == ddl_create_table || rel->flag == ddl_create_view) {
    2400      414138 :                         if (rel->l)
    2401      410560 :                                 if ((rel->l = func(v, rel->l, rel_rewriter)) == NULL)
    2402             :                                         return NULL;
    2403             :                 } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
    2404       13766 :                         if (rel->l)
    2405       10090 :                                 if ((rel->l = func(v, rel->l, rel_rewriter)) == NULL)
    2406             :                                         return NULL;
    2407       13766 :                         if (rel->r)
    2408       12751 :                                 if ((rel->r = func(v, rel->r, rel_rewriter)) == NULL)
    2409             :                                         return NULL;
    2410             :                 } else if (rel->flag == ddl_psm) {
    2411      278322 :                         if ((rel->exps = exps_rel_visitor(v, rel->exps, rel_rewriter, topdown)) == NULL)
    2412             :                                 return NULL;
    2413             :                 }
    2414             :                 break;
    2415    16656585 :         case op_insert:
    2416             :         case op_update:
    2417             :         case op_delete:
    2418             :         case op_merge:
    2419             : 
    2420             :         case op_join:
    2421             :         case op_left:
    2422             :         case op_right:
    2423             :         case op_full:
    2424             :         case op_semi:
    2425             :         case op_anti:
    2426             : 
    2427             :         case op_union:
    2428             :         case op_inter:
    2429             :         case op_except:
    2430    16656585 :                 if (rel->l)
    2431    16656585 :                         if ((rel->l = func(v, rel->l, rel_rewriter)) == NULL)
    2432             :                                 return NULL;
    2433    16656546 :                 if (rel->r)
    2434    16642238 :                         if ((rel->r = func(v, rel->r, rel_rewriter)) == NULL)
    2435             :                                 return NULL;
    2436             :                 break;
    2437    35732514 :         case op_select:
    2438             :         case op_topn:
    2439             :         case op_sample:
    2440             :         case op_project:
    2441             :         case op_groupby:
    2442             :         case op_truncate:
    2443    35732514 :                 if (rel->l)
    2444    33266016 :                         if ((rel->l = func(v, rel->l, rel_rewriter)) == NULL)
    2445             :                                 return NULL;
    2446             :                 break;
    2447             :         }
    2448    75690579 :         v->parent = parent;
    2449             : 
    2450    75690579 :         if (!topdown)
    2451    47084708 :                 rel = do_rel_visitor(v, rel, rel_rewriter, false);
    2452             :         return rel;
    2453             : }
    2454             : 
    2455             : sql_rel *
    2456    28604674 : rel_visitor_topdown(visitor *v, sql_rel *rel, rel_rewrite_fptr rel_rewriter)
    2457             : {
    2458    28604674 :         v->depth++;
    2459    28604674 :         rel = rel_visitor(v, rel, rel_rewriter, true);
    2460    28604653 :         v->depth--;
    2461    28604653 :         return rel;
    2462             : }
    2463             : 
    2464             : sql_rel *
    2465    47085766 : rel_visitor_bottomup(visitor *v, sql_rel *rel, rel_rewrite_fptr rel_rewriter)
    2466             : {
    2467    47085766 :         v->depth++;
    2468    47085766 :         rel = rel_visitor(v, rel, rel_rewriter, false);
    2469    47085390 :         v->depth--;
    2470    47085390 :         return rel;
    2471             : }
    2472             : 
    2473             : list *
    2474         276 : exps_exp_visitor_topdown(visitor *v, sql_rel *rel, list *exps, int depth, exp_rewrite_fptr exp_rewriter, bool relations_topdown)
    2475             : {
    2476         276 :         return exps_exp_visitor(v, rel, exps, depth, exp_rewriter, true, relations_topdown);
    2477             : }
    2478             : 
    2479             : list *
    2480      553691 : exps_exp_visitor_bottomup(visitor *v, sql_rel *rel, list *exps, int depth, exp_rewrite_fptr exp_rewriter, bool relations_topdown)
    2481             : {
    2482      553691 :         return exps_exp_visitor(v, rel, exps, depth, exp_rewriter, false, relations_topdown);
    2483             : }
    2484             : 
    2485             : static bool
    2486       99396 : exps_rebind_exp(mvc *sql, sql_rel *rel, list *exps)
    2487             : {
    2488       99396 :         bool ok = true;
    2489             : 
    2490       99396 :         if (mvc_highwater(sql)) {
    2491           0 :                 (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    2492           0 :                 return false;
    2493             :         }
    2494             : 
    2495       99396 :         if (list_empty(exps))
    2496             :                 return true;
    2497      124406 :         for (node *n = exps->h; n && ok; n = n->next)
    2498       78162 :                 ok &= rel_rebind_exp(sql, rel, n->data);
    2499             :         return ok;
    2500             : }
    2501             : 
    2502             : bool
    2503     6285690 : rel_rebind_exp(mvc *sql, sql_rel *rel, sql_exp *e)
    2504             : {
    2505     6344942 :         if (mvc_highwater(sql)) {
    2506           0 :                 (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    2507           0 :                 return false;
    2508             :         }
    2509             : 
    2510     6344942 :         switch (e->type) {
    2511       59252 :         case e_convert:
    2512       59252 :                 return rel_rebind_exp(sql, rel, e->l);
    2513       27726 :         case e_aggr:
    2514             :         case e_func:
    2515       27726 :                 return exps_rebind_exp(sql, rel, e->l);
    2516     2721637 :         case e_cmp:
    2517     2721637 :                 if (e->flag == cmp_in || e->flag == cmp_notin)
    2518        8211 :                         return rel_rebind_exp(sql, rel, e->l) && exps_rebind_exp(sql, rel, e->r);
    2519     2715489 :                 if (e->flag == cmp_or || e->flag == cmp_filter)
    2520       18866 :                         return exps_rebind_exp(sql, rel, e->l) && exps_rebind_exp(sql, rel, e->r);
    2521     5409812 :                 return rel_rebind_exp(sql, rel, e->l) && rel_rebind_exp(sql, rel, e->r) && (!e->f || rel_rebind_exp(sql, rel, e->f));
    2522     3483161 :         case e_column:
    2523     3483161 :                 if (e->freevar)
    2524             :                         return true;
    2525     3483147 :                 return rel_find_exp(rel, e) != NULL;
    2526       53161 :         case e_atom:
    2527       53161 :                 return exps_rebind_exp(sql, rel, e->f);
    2528             :         case e_psm:
    2529             :                 return true;
    2530             :         }
    2531             :         return true;
    2532             : }
    2533             : 
    2534             : static sql_exp *
    2535         456 : _exp_freevar_offset(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    2536             : {
    2537         456 :         (void)rel; (void)depth;
    2538             :         /* visitor will handle recursion, ie only need to check columns here */
    2539         456 :         int vf = is_freevar(e);
    2540         456 :         if (v->changes < vf)
    2541         316 :                 v->changes=vf;
    2542         456 :         return e;
    2543             : }
    2544             : 
    2545             : int
    2546         306 : exp_freevar_offset(mvc *sql, sql_exp *e)
    2547             : {
    2548         306 :         bool changed = false;
    2549         306 :         visitor v = { .sql = sql };
    2550             : 
    2551         306 :         (void) changed;
    2552         306 :         exp_visitor(&v, NULL, e, 0, &_exp_freevar_offset, true, true, &changed);
    2553             :         /* freevar offset is passed via changes */
    2554         306 :         return (v.changes);
    2555             : }

Generated by: LCOV version 1.14