LCOV - code coverage report
Current view: top level - sql/server - rel_unnest.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2571 2879 89.3 %
Date: 2024-11-15 19:37:45 Functions: 89 90 98.9 %

          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_optimizer_private.h"
      15             : #include "sql_decimal.h"
      16             : #include "rel_unnest.h"
      17             : #include "rel_basetable.h"
      18             : #include "rel_exp.h"
      19             : #include "rel_select.h"
      20             : #include "rel_rewriter.h"
      21             : 
      22             : static void
      23       19504 : exp_set_freevar(mvc *sql, sql_exp *e, sql_rel *r)
      24             : {
      25       20504 :         switch(e->type) {
      26           0 :         case e_cmp:
      27           0 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
      28           0 :                         exps_set_freevar(sql, e->l, r);
      29           0 :                         exps_set_freevar(sql, e->r, r);
      30           0 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
      31           0 :                         exp_set_freevar(sql, e->l, r);
      32           0 :                         exps_set_freevar(sql, e->r, r);
      33             :                 } else {
      34           0 :                         exp_set_freevar(sql, e->l, r);
      35           0 :                         exp_set_freevar(sql, e->r, r);
      36           0 :                         if (e->f)
      37             :                                 exp_set_freevar(sql, e->f, r);
      38             :                 }
      39             :                 break;
      40        1000 :         case e_convert:
      41        1000 :                 exp_set_freevar(sql, e->l, r);
      42        1000 :                 break;
      43        5642 :         case e_func:
      44             :         case e_aggr:
      45        5642 :                 if (e->l)
      46        5642 :                         exps_set_freevar(sql, e->l, r);
      47             :                 break;
      48        7647 :         case e_column:
      49        7647 :                 if (rel_find_nid(r, e->nid))
      50             :                         return;
      51        3630 :                 set_freevar(e, 0);
      52        3630 :                 break;
      53        6215 :         case e_atom:
      54        6215 :                 if (e->f)
      55           0 :                         exps_set_freevar(sql, e->f, r);
      56             :                 break;
      57             :         case e_psm:
      58             :                 break;
      59             :         }
      60             : }
      61             : 
      62             : void
      63        5642 : exps_set_freevar(mvc *sql, list *exps, sql_rel *r)
      64             : {
      65        5642 :         node *n;
      66             : 
      67        5642 :         if (list_empty(exps))
      68             :                 return;
      69       16697 :         for(n = exps->h; n; n = n->next)
      70       11055 :                 exp_set_freevar(sql, n->data, r);
      71             : }
      72             : 
      73             : /* check if the set is distinct (ie we did a domain reduction for the general unnest) for the set of free variables */
      74             : static int
      75        9453 : is_distinct_set(mvc *sql, sql_rel *rel, list *ad)
      76             : {
      77        9499 :         int distinct = 0;
      78        9499 :         if (ad && is_groupby(rel->op) && (list_empty(rel->r) || exp_match_list(rel->r, ad)))
      79          39 :                 return 1;
      80        9460 :         distinct = need_distinct(rel);
      81        9460 :         if (is_project(rel->op) && rel->l && !distinct)
      82             :                 distinct = is_distinct_set(sql, rel->l, ad);
      83             :         return distinct;
      84             : }
      85             : 
      86             : int
      87    13359053 : exp_has_freevar(mvc *sql, sql_exp *e)
      88             : {
      89    13498578 :         if (mvc_highwater(sql)) {
      90         169 :                 (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
      91         169 :                 return 0;
      92             :         }
      93             : 
      94    13498993 :         if (is_freevar(e))
      95      121261 :                 return is_freevar(e);
      96    13377732 :         switch(e->type) {
      97     1652331 :         case e_cmp:
      98     1652331 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
      99       55379 :                         return (exps_have_freevar(sql, e->l) || exps_have_freevar(sql, e->r));
     100     1597581 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
     101      130601 :                         return (exp_has_freevar(sql, e->l) || exps_have_freevar(sql, e->r));
     102             :                 } else {
     103     2933980 :                         return (exp_has_freevar(sql, e->l) || exp_has_freevar(sql, e->r) ||
     104     1362435 :                             (e->f && exp_has_freevar(sql, e->f)));
     105             :                 }
     106      139525 :                 break;
     107      139525 :         case e_convert:
     108      139525 :                 return exp_has_freevar(sql, e->l);
     109      930473 :         case e_func:
     110             :         case e_aggr:
     111      930473 :                 if (e->l)
     112      898638 :                         return exps_have_freevar(sql, e->l);
     113             :                 /* fall through */
     114             :         case e_psm:
     115       33896 :                 if (exp_is_rel(e))
     116        2061 :                         return rel_has_freevar(sql, e->l);
     117             :                 break;
     118     2969887 :         case e_atom:
     119     2969887 :                 if (e->f)
     120      143803 :                         return exps_have_freevar(sql, e->f);
     121             :                 break;
     122             :         case e_column:
     123             :         default:
     124             :                 return 0;
     125             :         }
     126             :         return 0;
     127             : }
     128             : 
     129             : int
     130     4074042 : exps_have_freevar(mvc *sql, list *exps)
     131             : {
     132     4074042 :         if (mvc_highwater(sql)) {
     133           0 :                 (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     134           0 :                 return 0;
     135             :         }
     136     4074420 :         if (!exps)
     137             :                 return 0;
     138    13519478 :         for (node *n = exps->h; n; n = n->next) {
     139     9799041 :                 int vf = 0;
     140     9799041 :                 sql_exp *e = n->data;
     141     9799041 :                 if ((vf =exp_has_freevar(sql, e)) != 0)
     142      161351 :                         return vf;
     143             :         }
     144             :         return 0;
     145             : }
     146             : 
     147             : int
     148     3263399 : rel_has_freevar(mvc *sql, sql_rel *rel)
     149             : {
     150     3263399 :         if (mvc_highwater(sql)) {
     151           0 :                 (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     152           0 :                 return 0;
     153             :         }
     154             : 
     155     3263399 :         if (is_basetable(rel->op)) {
     156             :                 return 0;
     157     2460116 :         } else if (is_base(rel->op)) {
     158         746 :                 return exps_have_freevar(sql, rel->exps) ||
     159         373 :                         (rel->l && rel_has_freevar(sql, rel->l));
     160     2459743 :         } else if (is_simple_project(rel->op) || is_groupby(rel->op) || is_select(rel->op) || is_topn(rel->op) || is_sample(rel->op)) {
     161     1677701 :                 if ((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->r && exps_have_freevar(sql, rel->r))
     162             :                         return 1;
     163     3354658 :                 return exps_have_freevar(sql, rel->exps) ||
     164     1580607 :                         (rel->l && rel_has_freevar(sql, rel->l));
     165             :         } else if (is_join(rel->op) || is_set(rel->op) || is_semi(rel->op) || is_modify(rel->op)) {
     166     1433854 :                 return exps_have_freevar(sql, rel->exps) ||
     167     1432876 :                         rel_has_freevar(sql, rel->l) || rel_has_freevar(sql, rel->r);
     168             :         } else if (is_munion(rel->op)) {
     169       64200 :                 int v = exps_have_freevar(sql, rel->exps);
     170       64200 :                 list *l = rel->l;
     171      180520 :                 for (node *n = l->h; n && !v; n = n->next)
     172      116320 :                         v = rel_has_freevar(sql, n->data);
     173       64200 :                 return v;
     174             :         }
     175             :         return 0;
     176             : }
     177             : 
     178             : static void exps_only_freevar(sql_query *query, list *exps, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols);
     179             : static void rel_only_freevar(sql_query *query, sql_rel *rel, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols);
     180             : 
     181             : void /* look for expressions with either only freevars or atoms */
     182       82863 : exp_only_freevar(sql_query *query, sql_exp *e, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols)
     183             : {
     184       84580 :         if (mvc_highwater(query->sql)) {
     185           0 :                 (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     186           0 :                 return ;
     187             :         }
     188             : 
     189       84580 :         if (is_freevar(e)) {
     190         404 :                 sql_rel *outer;
     191             : 
     192         404 :                 *found_one_freevar = true;
     193         404 :                 if (e->type == e_column) {
     194         404 :                         if ((outer = query_fetch_outer(query, is_freevar(e)-1))) {
     195         389 :                                 sql_exp *a = rel_find_exp(outer, e);
     196         389 :                                 if (!a || !is_aggr(a->type)) {
     197         375 :                                         if (!*ungrouped_cols)
     198         349 :                                                 *ungrouped_cols = new_exp_list(query->sql->sa);
     199         375 :                                         list_append(*ungrouped_cols, e);
     200             :                                 }
     201             :                         }
     202             :                 }
     203         404 :                 return ;
     204             :         }
     205       84176 :         switch(e->type) {
     206          18 :         case e_cmp:
     207          18 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
     208           2 :                         exps_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
     209           2 :                         exps_only_freevar(query, e->r, arguments_correlated, found_one_freevar, ungrouped_cols);
     210          16 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
     211           2 :                         exp_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
     212           2 :                         exps_only_freevar(query, e->r, arguments_correlated, found_one_freevar, ungrouped_cols);
     213             :                 } else {
     214          14 :                         exp_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
     215          14 :                         exp_only_freevar(query, e->r, arguments_correlated, found_one_freevar, ungrouped_cols);
     216          14 :                         if (e->f)
     217             :                                 exp_only_freevar(query, e->f, arguments_correlated, found_one_freevar, ungrouped_cols);
     218             :                 }
     219             :                 break;
     220        1715 :         case e_convert:
     221        1715 :                 exp_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
     222        1715 :                 break;
     223       23255 :         case e_func:
     224             :         case e_aggr:
     225       23255 :                 if (e->l)
     226       23255 :                         exps_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
     227             :                 break;
     228          53 :         case e_psm:
     229          53 :                 if (exp_is_rel(e))
     230          53 :                         rel_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
     231             :                 break;
     232       15929 :         case e_atom:
     233       15929 :                 if (e->f)
     234          17 :                         exps_only_freevar(query, e->f, arguments_correlated, found_one_freevar, ungrouped_cols);
     235             :                 break;
     236       43206 :         case e_column:
     237       43206 :                 *arguments_correlated = 0;
     238       43206 :                 break;
     239             :         }
     240             : }
     241             : 
     242             : void
     243       23324 : exps_only_freevar(sql_query *query, list *exps, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols)
     244             : {
     245       23324 :         if (mvc_highwater(query->sql)) {
     246           0 :                 (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     247           0 :                 return ;
     248             :         }
     249       23324 :         if (!exps)
     250             :                 return ;
     251       72525 :         for (node *n = exps->h; n ; n = n->next)
     252       49201 :                 exp_only_freevar(query, n->data, arguments_correlated, found_one_freevar, ungrouped_cols);
     253             : }
     254             : 
     255             : void
     256          53 : rel_only_freevar(sql_query *query, sql_rel *rel, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols)
     257             : {
     258         138 :         if (mvc_highwater(query->sql)) {
     259           0 :                 (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     260           0 :                 return ;
     261             :         }
     262             : 
     263         138 :         if (is_basetable(rel->op)) {
     264             :                 return ;
     265         111 :         } else if (is_base(rel->op)) {
     266           0 :                 exps_only_freevar(query, rel->exps, arguments_correlated, found_one_freevar, ungrouped_cols);
     267           0 :                 if (rel->r)
     268             :                         rel_only_freevar(query, rel->r, arguments_correlated, found_one_freevar, ungrouped_cols);
     269         111 :         } else if (is_simple_project(rel->op) || is_groupby(rel->op) || is_select(rel->op) || is_topn(rel->op) || is_sample(rel->op)) {
     270         111 :                 if ((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->r)
     271           5 :                         exps_only_freevar(query, rel->r, arguments_correlated, found_one_freevar, ungrouped_cols);
     272         111 :                 if (rel->card > CARD_ATOM)
     273          41 :                         exps_only_freevar(query, rel->exps, arguments_correlated, found_one_freevar, ungrouped_cols);
     274         111 :                 if (rel->l)
     275             :                         rel_only_freevar(query, rel->l, arguments_correlated, found_one_freevar, ungrouped_cols);
     276             :         } else if (is_join(rel->op) || is_set(rel->op) || is_semi(rel->op) || is_modify(rel->op)) {
     277           0 :                 exps_only_freevar(query, rel->exps, arguments_correlated, found_one_freevar, ungrouped_cols);
     278           0 :                 rel_only_freevar(query, rel->l, arguments_correlated, found_one_freevar, ungrouped_cols);
     279           0 :                 rel_only_freevar(query, rel->r, arguments_correlated, found_one_freevar, ungrouped_cols);
     280             :         } else if (is_munion(rel->op)) {
     281           0 :                 exps_only_freevar(query, rel->exps, arguments_correlated, found_one_freevar, ungrouped_cols);
     282           0 :                 list *l = rel->l;
     283           0 :                 for (node *n = l->h; n; n = n->next)
     284           0 :                         rel_only_freevar(query, n->data, arguments_correlated, found_one_freevar, ungrouped_cols);
     285             :         }
     286             :         return ;
     287             : }
     288             : 
     289             : static int
     290       66756 : freevar_equal( sql_exp *e1, sql_exp *e2)
     291             : {
     292       66756 :         assert(e1 && e2 && is_freevar(e1) && is_freevar(e2));
     293       66756 :         if (e1 == e2)
     294             :                 return 0;
     295       66620 :         if (e1->type != e_column || e2->type != e_column)
     296             :                 return -1;
     297       66620 :         return (e1->nid != e2->nid);
     298             : }
     299             : 
     300             : static list *
     301      660530 : merge_freevar(list *l, list *r, bool all)
     302             : {
     303      660530 :         if (!l)
     304             :                 return r;
     305      148399 :         if (!r)
     306             :                 return l;
     307       32850 :         r  = list_merge(l, r, (fdup)NULL);
     308       32850 :         if (all)
     309             :                 return r;
     310       32757 :         return list_distinct(r, (fcmp)freevar_equal, (fdup)NULL);
     311             : }
     312             : 
     313             : static list * exps_freevar(mvc *sql, list *exps);
     314             : static list * rel_freevar(mvc *sql, sql_rel *rel);
     315             : 
     316             : static list *
     317      663923 : exp_freevar(mvc *sql, sql_exp *e, bool all)
     318             : {
     319      663923 :         if (mvc_highwater(sql))
     320           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     321             : 
     322      663923 :         switch(e->type) {
     323      299340 :         case e_column:
     324      299340 :                 if (is_freevar(e))
     325       87072 :                         return append(sa_list(sql->sa), e);
     326             :                 break;
     327       14454 :         case e_convert:
     328       14454 :                 return exp_freevar(sql, e->l, all);
     329       99909 :         case e_aggr:
     330             :         case e_func:
     331       99909 :                 if (e->l)
     332       88002 :                         return exps_freevar(sql, e->l);
     333             :                 break;
     334       80861 :         case e_cmp:
     335       80861 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
     336         733 :                         list *l = exps_freevar(sql, e->l);
     337         733 :                         list *r = exps_freevar(sql, e->r);
     338         733 :                         return merge_freevar(l, r, all);
     339       80128 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
     340          12 :                         list *l = exp_freevar(sql, e->l, all);
     341          12 :                         list *r = exps_freevar(sql, e->r);
     342          12 :                         return merge_freevar(l, r, all);
     343             :                 } else {
     344       80116 :                         list *l = exp_freevar(sql, e->l, all);
     345       80116 :                         list *r = exp_freevar(sql, e->r, all);
     346       80116 :                         l = merge_freevar(l, r, all);
     347       80116 :                         if (e->f) {
     348         164 :                                 r = exp_freevar(sql, e->f, all);
     349         164 :                                 return merge_freevar(l, r, all);
     350             :                         }
     351             :                         return l;
     352             :                 }
     353          52 :                 break;
     354          52 :         case e_psm:
     355          52 :                 if (exp_is_rel(e))
     356          52 :                         if (rel_has_freevar(sql, e->l))
     357          36 :                                 return rel_freevar(sql, e->l);
     358             :                 return NULL;
     359      169307 :         case e_atom:
     360      169307 :                 if (e->f)
     361          41 :                         return exps_freevar(sql, e->f);
     362             :                 return NULL;
     363             :         default:
     364             :                 return NULL;
     365             :         }
     366             :         return NULL;
     367             : }
     368             : 
     369             : static list *
     370      253596 : exps_freevar(mvc *sql, list *exps)
     371             : {
     372      253596 :         node *n;
     373      253596 :         list *c = NULL;
     374             : 
     375      253596 :         if (mvc_highwater(sql))
     376           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     377      253596 :         if (!exps)
     378             :                 return NULL;
     379      656855 :         for (n = exps->h; n; n = n->next) {
     380      404725 :                 sql_exp *e = n->data;
     381      404725 :                 list *var = exp_freevar(sql, e, false);
     382             : 
     383      404725 :                 c = merge_freevar(c,var, false);
     384             :         }
     385             :         return c;
     386             : }
     387             : 
     388             : static list *
     389      211349 : rel_freevar(mvc *sql, sql_rel *rel)
     390             : {
     391      211349 :         list *lexps = NULL, *rexps = NULL, *exps = NULL;
     392             : 
     393      211349 :         if (mvc_highwater(sql))
     394           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     395      211349 :         if (!rel)
     396             :                 return NULL;
     397      196101 :         switch(rel->op) {
     398        2447 :         case op_join:
     399             :         case op_left:
     400             :         case op_right:
     401             :         case op_full:
     402        2447 :                 exps = exps_freevar(sql, rel->exps);
     403        2447 :                 lexps = rel_freevar(sql, rel->l);
     404        2447 :                 rexps = rel_freevar(sql, rel->r);
     405        2447 :                 lexps = merge_freevar(lexps, rexps, false);
     406        2447 :                 exps = merge_freevar(exps, lexps, false);
     407        2447 :                 return exps;
     408             : 
     409             :         case op_basetable:
     410             :                 return NULL;
     411         135 :         case op_table: {
     412         135 :                 sql_exp *call = rel->r;
     413         135 :                 if (rel->flag != TRIGGER_WRAPPER && rel->l)
     414         104 :                         lexps = rel_freevar(sql, rel->l);
     415         135 :                 exps = (rel->flag != TRIGGER_WRAPPER && call)?exps_freevar(sql, call->l):NULL;
     416         135 :                 return merge_freevar(exps, lexps, false);
     417             :         }
     418         247 :         case op_union:
     419             :         case op_except:
     420             :         case op_inter:
     421         247 :                 exps = exps_freevar(sql, rel->exps);
     422         247 :                 lexps = rel_freevar(sql, rel->l);
     423         247 :                 rexps = rel_freevar(sql, rel->r);
     424         247 :                 lexps = merge_freevar(lexps, rexps, false);
     425         247 :                 exps = merge_freevar(exps, lexps, false);
     426         247 :                 return exps;
     427        7712 :         case op_munion:
     428        7712 :                 exps = exps_freevar(sql, rel->exps);
     429       23136 :                 for (node *n = ((list*)rel->l)->h; n; n = n->next) {
     430       15424 :                         lexps = rel_freevar(sql, n->data);
     431       15424 :                         exps = merge_freevar(exps, lexps, false);
     432             :                 }
     433             :                 return exps;
     434      150611 :         case op_ddl:
     435             :         case op_semi:
     436             :         case op_anti:
     437             : 
     438             :         case op_select:
     439             :         case op_topn:
     440             :         case op_sample:
     441             : 
     442             :         case op_groupby:
     443             :         case op_project:
     444      150611 :                 exps = exps_freevar(sql, rel->exps);
     445      150611 :                 lexps = rel_freevar(sql, rel->l);
     446      150611 :                 if (rel->r) {
     447        3222 :                         if (is_groupby(rel->op) || is_simple_project(rel->op))
     448        2923 :                                 rexps = exps_freevar(sql, rel->r);
     449             :                         else
     450         299 :                                 rexps = rel_freevar(sql, rel->r);
     451        3222 :                         lexps = merge_freevar(lexps, rexps, false);
     452             :                 }
     453      150611 :                 exps = merge_freevar(exps, lexps, false);
     454      150611 :                 return exps;
     455             :         default:
     456             :                 return NULL;
     457             :         }
     458             : 
     459             : }
     460             : 
     461             : static list *
     462       33992 : rel_dependent_var(mvc *sql, sql_rel *l, sql_rel *r)
     463             : {
     464       33992 :         list *res = NULL;
     465             : 
     466       33992 :         if (rel_has_freevar(sql, r)){
     467       33907 :                 list *freevar = rel_freevar(sql, r);
     468       33907 :                 if (freevar) {
     469       33907 :                         node *n;
     470       33907 :                         list *boundvar = rel_projections(sql, l, NULL, 1, 0);
     471             : 
     472       86367 :                         for(n = freevar->h; n; n = n->next) {
     473       52460 :                                 sql_exp *e = n->data, *ne = NULL;
     474             :                                 /* each freevar should be an e_column */
     475       52460 :                                 ne = exps_bind_nid(boundvar, e->nid);
     476       52460 :                                 if (ne) {
     477       52164 :                                         if (!res)
     478       33773 :                                                 res = sa_list(sql->sa);
     479       52164 :                                         append(res, ne);
     480             :                                 }
     481             :                         }
     482             :                 }
     483             :         }
     484       33992 :         return res;
     485             : }
     486             : 
     487             : /*
     488             :  * try to bind any freevar in the expression e
     489             :  */
     490             : void
     491       84336 : rel_bind_var(mvc *sql, sql_rel *rel, sql_exp *e)
     492             : {
     493       84336 :         list *fvs = exp_freevar(sql, e, true);
     494             : 
     495       84336 :         if (fvs) {
     496       14735 :                 node *n;
     497             : 
     498       29633 :                 for(n = fvs->h; n; n=n->next) {
     499       14898 :                         sql_exp *e = n->data;
     500             : 
     501       14898 :                         if (is_freevar(e) && (exp_is_atom(e) || rel_find_exp(rel,e)))
     502       10768 :                                 reset_freevar(e);
     503             :                 }
     504             :         }
     505       84336 : }
     506             : 
     507             : void
     508       17086 : rel_bind_vars(mvc *sql, sql_rel *rel, list *exps)
     509             : {
     510       17086 :         if (list_empty(exps))
     511             :                 return;
     512       79256 :         for(node *n=exps->h; n; n = n->next)
     513       62243 :                 rel_bind_var(sql, rel, n->data);
     514             : }
     515             : 
     516             : static sql_exp * push_up_project_exp(mvc *sql, sql_rel *rel, sql_exp *e);
     517             : 
     518             : static list *
     519        9767 : push_up_project_exps(mvc *sql, sql_rel *rel, list *exps)
     520             : {
     521        9767 :         node *n;
     522             : 
     523        9767 :         if (!exps)
     524             :                 return exps;
     525             : 
     526         896 :         for(n=exps->h; n; n=n->next) {
     527         380 :                 sql_exp *e = n->data;
     528             : 
     529         380 :                 n->data = push_up_project_exp(sql, rel, e);
     530             :         }
     531         516 :         list_hash_clear(exps);
     532         516 :         return exps;
     533             : }
     534             : 
     535             : static sql_exp *
     536        1017 : push_up_project_exp(mvc *sql, sql_rel *rel, sql_exp *e)
     537             : {
     538        1059 :         if (mvc_highwater(sql))
     539           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     540             : 
     541        1059 :         switch(e->type) {
     542         294 :         case e_cmp:
     543         294 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
     544           8 :                         e->l = push_up_project_exps(sql, rel, e->l);
     545           8 :                         e->r = push_up_project_exps(sql, rel, e->r);
     546           8 :                         return e;
     547         286 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
     548           0 :                         e->l = push_up_project_exp(sql, rel, e->l);
     549           0 :                         e->r = push_up_project_exps(sql, rel, e->r);
     550           0 :                         return e;
     551             :                 } else {
     552         286 :                         e->l = push_up_project_exp(sql, rel, e->l);
     553         286 :                         e->r = push_up_project_exp(sql, rel, e->r);
     554         286 :                         if (e->f)
     555           1 :                                 e->f = push_up_project_exp(sql, rel, e->f);
     556             :                 }
     557             :                 break;
     558          64 :         case e_convert:
     559          64 :                 e->l = push_up_project_exp(sql, rel, e->l);
     560          64 :                 break;
     561          46 :         case e_func:
     562             :         case e_aggr:
     563          46 :                 if (e->l)
     564          46 :                         e->l = push_up_project_exps(sql, rel, e->l);
     565             :                 break;
     566         533 :         case e_column:
     567             :                 {
     568         533 :                         sql_exp *ne;
     569             : 
     570             :                         /* include project or just lookup */
     571         533 :                         assert(e->nid);
     572         533 :                         ne = exps_bind_nid(rel->exps, e->nid);
     573         533 :                         if (ne) {
     574         252 :                                 if (ne->type == e_column) {
     575             :                                         /* deref alias */
     576         210 :                                         e->l = ne->l;
     577         210 :                                         e->r = ne->r;
     578         210 :                                         e->nid = ne->nid;
     579             :                                 } else {
     580          42 :                                         ne = exp_copy(sql, ne);
     581          42 :                                         return push_up_project_exp(sql, rel, ne);
     582             :                                 }
     583             :                         }
     584             :                 } break;
     585         122 :         case e_atom:
     586         122 :                 if (e->f)
     587           0 :                         e->f = push_up_project_exps(sql, rel, e->f);
     588             :                 break;
     589             :         case e_psm:
     590             :                 break;
     591             :         }
     592             :         return e;
     593             : }
     594             : 
     595             : static sql_exp *exp_rewrite(mvc *sql, sql_rel *rel, sql_exp *e, list *ad);
     596             : 
     597             : static list *
     598        2498 : exps_rewrite(mvc *sql, sql_rel *rel, list *exps, list *ad)
     599             : {
     600        2498 :         list *nexps;
     601        2498 :         node *n;
     602             : 
     603        2498 :         if (list_empty(exps))
     604             :                 return exps;
     605        2481 :         nexps = sa_list(sql->sa);
     606        7872 :         for(n=exps->h; n; n = n->next)
     607        5391 :                 append(nexps, exp_rewrite(sql, rel, n->data, ad));
     608             :         return nexps;
     609             : }
     610             : 
     611             : /* recursively rewrite some functions */
     612             : static sql_exp *
     613       12090 : exp_rewrite(mvc *sql, sql_rel *rel, sql_exp *e, list *ad)
     614             : {
     615       12090 :         sql_subfunc *sf;
     616             : 
     617       12090 :         if (e->type == e_convert) {
     618         103 :                 e->l = exp_rewrite(sql, rel, e->l, ad);
     619         103 :                 return e;
     620             :         }
     621       11987 :         if (e->type != e_func)
     622             :                 return e;
     623        2498 :         e->l = exps_rewrite(sql, rel, e->l, ad);
     624        2498 :         sf = e->f;
     625             :         /* window functions need to be run per freevars */
     626        2498 :         if (sf->func->type == F_ANALYTIC && strcmp(sf->func->base.name, "window_bound") != 0 && strcmp(sf->func->base.name, "diff") != 0 && ad) {
     627          59 :                 sql_subtype *bt = sql_bind_localtype("bit");
     628          59 :                 list *rankopargs = e->l, *gbe = ((list*)e->r)->h->data;
     629          59 :                 sql_exp *pe = list_empty(gbe) ? NULL : (sql_exp*)gbe->t->data, *last;
     630          81 :                 bool has_pe = pe != NULL;
     631          81 :                 int i = 0;
     632             : 
     633          22 :                 if (!pe || pe->type != e_func || strcmp(((sql_subfunc *)pe->f)->func->base.name, "diff") != 0)
     634             :                         pe = NULL;
     635             : 
     636         137 :                 for(node *d = ad->h; d; d=d->next) {
     637          78 :                         sql_subfunc *df;
     638          78 :                         sql_exp *de = d->data;
     639          78 :                         list *args = sa_list(sql->sa);
     640          78 :                         if (pe) {
     641          19 :                                 df = sql_bind_func(sql, NULL, "diff", bt, exp_subtype(de), F_ANALYTIC, true, true);
     642          19 :                                 append(args, pe);
     643             :                         } else {
     644          59 :                                 df = sql_bind_func(sql, NULL, "diff", exp_subtype(de), NULL, F_ANALYTIC, true, true);
     645             :                         }
     646          78 :                         assert(df);
     647          78 :                         append(args, de);
     648          78 :                         pe = exp_op(sql->sa, args, df);
     649             :                 }
     650             : 
     651         129 :                 for (node *n = rankopargs->h; n ; n = n->next, i++) { /* at rel_select pe is added right after the function's arguments */
     652         129 :                         if (i == list_length(sf->func->ops)) {
     653          59 :                                 n->data = pe;
     654          59 :                                 break;
     655             :                         }
     656             :                 }
     657          59 :                 last = rankopargs->t->data; /* if the window function has bounds calls, update them */
     658          59 :                 if (last && last->type == e_func && !strcmp(((sql_subfunc *)last->f)->func->base.name, "window_bound")) {
     659          17 :                         sql_exp *window1 = list_fetch(rankopargs, list_length(rankopargs) - 2), *window2 = list_fetch(rankopargs, list_length(rankopargs) - 1);
     660          17 :                         list *lw1 = window1->l, *lw2 = window2->l; /* the value functions require bound functions always */
     661             : 
     662          17 :                         if (has_pe) {
     663           8 :                                 assert(list_length(window1->l) == 6);
     664           8 :                                 lw1->h->data = exp_copy(sql, pe);
     665           8 :                                 lw2->h->data = exp_copy(sql, pe);
     666             :                         } else {
     667           9 :                                 window1->l = list_prepend(lw1, exp_copy(sql, pe));
     668           9 :                                 window2->l = list_prepend(lw2, exp_copy(sql, pe));
     669             :                         }
     670             :                 }
     671             :         }
     672             :         return e;
     673             : }
     674             : 
     675             : static sql_exp *
     676        1291 : rel_reduce2one_exp(mvc *sql, sql_rel *sq)
     677             : {
     678        1291 :         sql_exp *e = NULL;
     679             : 
     680        1291 :         if (list_empty(sq->exps))
     681             :                 return NULL;
     682        1291 :         if (list_length(sq->exps) == 1)
     683        1148 :                 return sq->exps->t->data;
     684         322 :         for(node *n = sq->exps->h; n && !e; n = n->next) {
     685         179 :                 sql_exp *t = n->data;
     686             : 
     687         179 :                 if (!is_freevar(t))
     688         140 :                         e = t;
     689             :         }
     690         143 :         if (!e)
     691           3 :                 e = sq->exps->t->data;
     692         143 :         sq->exps = append(sa_list(sql->sa), e);
     693         143 :         return e;
     694             : }
     695             : 
     696             : static sql_exp *
     697          19 : rel_bound_exp(mvc *sql, sql_rel *rel )
     698             : {
     699          38 :         while (rel->l) {
     700          38 :                 rel = rel->l;
     701          38 :                 if (is_base(rel->op) || is_project(rel->op))
     702             :                         break;
     703             :         }
     704             : 
     705          19 :         if (rel && !list_empty(rel->exps)) {
     706          19 :                 for(node *n = rel->exps->h; n; n = n->next){
     707          19 :                         sql_exp *e = n->data;
     708             : 
     709          19 :                         if (exp_is_atom(e))
     710           8 :                                 return e;
     711          11 :                         if (!exp_has_freevar(sql, e))
     712          11 :                                 return exp_ref(sql, e);
     713             :                 }
     714             :         }
     715           0 :         if (rel && is_project(rel->op)) /* add dummy expression */
     716           0 :                 return rel_project_add_exp(sql, rel, exp_atom_bool(sql->sa, 1));
     717             :         return NULL;
     718             : }
     719             : 
     720             : /*
     721             :  * join j was just rewritten, but some join expressions may now
     722             :  * be too low in de relation rel. These need to move up.
     723             :  * */
     724             : static void
     725        4341 : move_join_exps(mvc *sql, sql_rel *j, sql_rel *rel)
     726             : {
     727        4341 :         node *n;
     728        4341 :         list *exps = rel->exps;
     729             : 
     730        4341 :         if (list_empty(exps))
     731             :                 return;
     732           4 :         rel->exps = sa_list(sql->sa);
     733           4 :         if (!j->exps)
     734           4 :                 j->exps = sa_list(sql->sa);
     735           8 :         for(n = exps->h; n; n = n->next){
     736           4 :                 sql_exp *e = n->data;
     737             : 
     738           4 :                 if (rel_rebind_exp(sql, rel, e)) {
     739           1 :                         if (exp_has_freevar(sql, e))
     740           0 :                                 rel_bind_var(sql, rel->l, e);
     741           1 :                         append(rel->exps, e);
     742             :                 } else {
     743           3 :                         if (exp_has_freevar(sql, e))
     744           0 :                                 rel_bind_var(sql, j->l, e);
     745           3 :                         append(j->exps, e);
     746             :                 }
     747             :         }
     748             : }
     749             : 
     750             : static sql_rel *
     751        4258 : rel_general_unnest(mvc *sql, sql_rel *rel, list *ad)
     752             : {
     753        4258 :         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel) && ad) {
     754        4258 :                 list *fd;
     755        4258 :                 node *n, *m;
     756             : 
     757        4258 :                 sql_rel *l = rel->l, *r = rel->r, *inner_r;
     758             : 
     759             :                 /* cleanup empty selects (should be done before any rel_dup(l) */
     760        4258 :                 if (l && is_select(l->op) && list_empty(l->exps) && !rel_is_ref(l)) {
     761           0 :                         rel->l = l->l;
     762           0 :                         l->l = NULL;
     763           0 :                         rel_destroy(l);
     764           0 :                         l = rel->l;
     765             :                 }
     766             :                 /* rewrite T1 dependent join T2 -> T1 join D dependent join T2, where the T1/D join adds (equality) predicates (for the Domain (ad)) and D is are the distinct(projected(ad) from T1)  */
     767        4258 :                 sql_rel *D = rel_project(sql->sa, rel_dup(l), exps_copy(sql, ad));
     768        4258 :                 set_distinct(D);
     769             : 
     770        4258 :                 int single = is_single(r);
     771        4258 :                 reset_single(r);
     772        4258 :                 sql_rel *or = r;
     773        4258 :                 r = rel_crossproduct(sql->sa, D, r, rel->op);
     774        4258 :                 if (single)
     775           9 :                         set_single(or);
     776        4258 :                 r->op = op_join;
     777        4258 :                 move_join_exps(sql, rel, r);
     778        4258 :                 set_dependent(r);
     779        4258 :                 set_processed(r);
     780        4258 :                 inner_r = r;
     781             : 
     782        4258 :                 r = rel_project(sql->sa, r, (is_semi(inner_r->op))?sa_list(sql->sa):rel_projections(sql, r->r, NULL, 1, 1));
     783             : 
     784        4258 :                 if (!is_semi(inner_r->op))  { /* skip the free vars */
     785        4258 :                         list *exps = sa_list(sql->sa);
     786             : 
     787        9317 :                         for(node *n=r->exps->h; n; n = n->next) {
     788        5059 :                                 sql_exp *e = n->data, *ne = NULL;
     789             : 
     790        5059 :                                 if (e->nid)
     791        5059 :                                         ne = exps_bind_nid(ad, e->nid);
     792        5059 :                                 if (or && is_groupby(or->op) && or->r) { /* is e a reference to an group by col */
     793          64 :                                         sql_exp *gbe = exps_bind_nid(or->r, e->nid);
     794          64 :                                         if (gbe)
     795          44 :                                                 ne = exps_bind_nid(ad, gbe->nid);
     796             :                                 }
     797        5059 :                                 if (!ne)
     798        5007 :                                         append(exps,e);
     799             :                         }
     800        4258 :                         r->exps = exps;
     801             :                 }
     802             : 
     803             :                 /* append ad + rename */
     804        4258 :                 fd = exps_label(sql, exps_copy(sql, ad));
     805       11586 :                 for (n = ad->h, m = fd->h; n && m; n = n->next, m = m->next) {
     806        7328 :                         sql_exp *l = n->data, *r = m->data, *e;
     807             : 
     808        7328 :                         l = exp_ref(sql, l);
     809        7328 :                         r = exp_ref(sql, r);
     810        7328 :                         e = exp_compare(sql->sa, l, r, cmp_equal);
     811        7328 :                         set_semantics(e);
     812        7328 :                         if (!rel->exps)
     813        4174 :                                 rel->exps = sa_list(sql->sa);
     814        7328 :                         append(rel->exps, e);
     815             :                 }
     816        4258 :                 list_merge(r->exps, fd, (fdup)NULL);
     817        4258 :                 rel->r = r;
     818        4258 :                 reset_dependent(rel);
     819        4258 :                 return rel;
     820             :         }
     821             :         return rel;
     822             : }
     823             : 
     824             : static sql_rel *
     825        9705 : push_up_project(mvc *sql, sql_rel *rel, list *ad)
     826             : {
     827        9705 :         sql_rel *r = rel->r;
     828             : 
     829        9705 :         assert(is_simple_project(r->op));
     830        9705 :         if (rel_is_ref(r)) {
     831          11 :                 sql_rel *nr = rel_project(sql->sa, r->l ? rel_dup(r->l) : NULL, exps_copy(sql, r->exps));
     832             : 
     833          11 :                 if (is_single(r))
     834           0 :                         set_single(nr);
     835          11 :                 if (need_distinct(r))
     836           0 :                         set_distinct(nr);
     837          11 :                 nr->p = prop_copy(sql->sa, r->p);
     838          11 :                 nr->r = exps_copy(sql, r->r);
     839          11 :                 rel_destroy(r);
     840          11 :                 rel->r = r = nr;
     841             :         }
     842             : 
     843             :         /* input rel is dependent outerjoin with on the right a project, we first try to push inner side expressions down (because these cannot be pushed up) */
     844        9705 :         if (rel && is_join(rel->op) && is_dependent(rel)) {
     845        9582 :                 sql_rel *r = rel->r;
     846             : 
     847             :                 /* find constant expressions and move these down */
     848        9582 :                 if (r && r->op == op_project) {
     849        9582 :                         node *n;
     850        9582 :                         list *nexps = NULL;
     851        9582 :                         list *cexps = NULL;
     852        9582 :                         sql_rel *l = r->l;
     853             : 
     854        9599 :                         while (l && is_simple_project(l->op) && l->l) {
     855             :                                 /* if current project is  just one constant, remove lower project */
     856         703 :                                 if (list_length(r->exps) == 1) {
     857         328 :                                         sql_exp *e = r->exps->h->data;
     858             : 
     859         328 :                                         if (exp_is_atom(e)) {
     860          17 :                                                 r->l = rel_dup(l->l);
     861          17 :                                                 rel_destroy(l);
     862          17 :                                                 l = r->l;
     863          17 :                                                 continue;
     864             :                                         }
     865             :                                 }
     866             :                                 break;
     867             :                         }
     868             : 
     869        9582 :                         if (l && (is_select(l->op) || l->op == op_join || is_semi(l->op)) && !rel_is_ref(l) && list_empty(r->attr)) {
     870        4225 :                                 if (!list_empty(r->exps)) {
     871       11182 :                                         for(n=r->exps->h; n; n=n->next) {
     872        6957 :                                                 sql_exp *e = n->data;
     873             : 
     874        6957 :                                                 if (exp_is_atom(e) || rel_find_exp(l->l,e)) { /* move down */
     875        6845 :                                                         if (!cexps)
     876        4185 :                                                                 cexps = sa_list(sql->sa);
     877        6845 :                                                         append(cexps, e);
     878             :                                                 } else {
     879         112 :                                                         if (!nexps)
     880          70 :                                                                 nexps = sa_list(sql->sa);
     881         112 :                                                         append(nexps, e);
     882             :                                                 }
     883             :                                         }
     884             :                                 }
     885        4225 :                                 if (cexps) {
     886        4185 :                                         sql_rel *p = l->l = rel_project( sql->sa, l->l,
     887        4185 :                                                 rel_projections(sql, l->l, NULL, 1, 1));
     888        4185 :                                         p->exps = list_distinct(list_merge(p->exps, cexps, (fdup)NULL), (fcmp)exp_equal, (fdup)NULL);
     889        4185 :                                         if (list_empty(nexps)) {
     890        4155 :                                                 rel->r = l; /* remove empty project */
     891             :                                         } else {
     892         109 :                                                 for (n = cexps->h; n; n = n->next) { /* add pushed down renamed expressions */
     893          79 :                                                         sql_exp *e = n->data;
     894          79 :                                                         append(nexps, exp_ref(sql, e));
     895             :                                                 }
     896          30 :                                                 r->exps = nexps;
     897             :                                         }
     898             :                                 }
     899             :                         }
     900             :                 }
     901             :         }
     902             :         /* input rel is dependent join with on the right a project */
     903        9705 :         if (rel && is_join(rel->op) && is_dependent(rel)) {
     904        9582 :                 sql_rel *r = rel->r;
     905             : 
     906             :                 /* merge project expressions into the join expressions  */
     907        9582 :                 rel->exps = push_up_project_exps(sql, r, rel->exps);
     908             : 
     909        9582 :                 if (r && r->op == op_project) {
     910        5427 :                         sql_exp *id = NULL;
     911        5427 :                         node *m;
     912             : 
     913        5427 :                         if (!r->l) {
     914         571 :                                 sql_rel *l = rel->l;
     915         571 :                                 l = rel_dup(l);
     916         571 :                                 if (!is_project(l->op) || rel_is_ref(l))
     917         571 :                                         l = rel_project( sql->sa, l, rel_projections(sql, l, NULL, 1, 1));
     918             : 
     919         571 :                                 if (is_left(rel->op) && !list_empty(rel->attr)) {
     920          10 :                                         assert(list_length(rel->exps)==1);
     921          10 :                                         sql_exp *e = rel->exps->h->data;
     922          10 :                                         sql_exp *oe = rel->attr->h->data;
     923          10 :                                         rel_project_add_exp(sql, l, e);
     924          10 :                                         if (exp_is_atom(oe) && exp_is_false(oe))
     925           3 :                                                 e->flag = cmp_notequal;
     926          10 :                                         exp_setalias(e, oe->alias.label, exp_relname(oe), exp_name(oe));
     927             :                                 }
     928         571 :                                 if (!list_empty(r->exps)) {
     929        1165 :                                         for (m=r->exps->h; m; m = m->next) {
     930         594 :                                                 sql_exp *e = m->data;
     931             : 
     932         594 :                                                 if (exp_has_freevar(sql, e))
     933         581 :                                                         rel_bind_var(sql, l, e);
     934         594 :                                                 append(l->exps, e);
     935             :                                         }
     936             :                                 }
     937         571 :                                 rel_destroy(rel);
     938         571 :                                 return l;
     939             :                         }
     940             :                         /* move project up, ie all attributes of left + the old expression list */
     941        4856 :                         sql_rel *n = rel_project( sql->sa, (r->l)?rel:rel->l,
     942        4856 :                                         rel_projections(sql, rel->l, NULL, 1, 1));
     943             : 
     944        4856 :                         if (is_left(rel->op) && !list_empty(rel->attr))
     945         137 :                                 rel_project_add_exp(sql, n, exp_ref(sql, rel->attr->h->data));
     946        4856 :                         if (list_empty(rel->attr) && !list_empty(r->exps)) {
     947       11315 :                                 for (m=r->exps->h; m; m = m->next) {
     948        6597 :                                         sql_exp *e = m->data;
     949             : 
     950        6597 :                                         if (!is_freevar(e) || exp_name(e)) { /* only skip full freevars */
     951        6597 :                                                 if (exp_has_freevar(sql, e) || is_atom(e->type)) {
     952         790 :                                                         rel_bind_var(sql, rel->l, e);
     953         790 :                                                         if (is_left(rel->op)) { /* add ifthenelse */
     954             :                                                                 /* if id is NULL then NULL else e */
     955         136 :                                                                 sql_subtype *tp = exp_subtype(e);
     956         136 :                                                                 if (!tp)
     957           1 :                                                                         return sql_error(sql, 10, SQLSTATE(42000) "Query projection must have at least one parameter with known SQL type");
     958         135 :                                                                 if (!id) {
     959         134 :                                                                         sql_rel *l = r->l;
     960         134 :                                                                         if (is_join(l->op))
     961          19 :                                                                                 id = rel_bound_exp(sql, r);
     962             :                                                                         else
     963         115 :                                                                                 r->l = rel_add_identity(sql, r->l, &id);
     964             :                                                                 }
     965         135 :                                                                 sql_exp *ne = rel_unop_(sql, NULL, exp_ref(sql, id), "sys", "isnull", card_value);
     966         135 :                                                                 set_has_no_nil(ne);
     967         135 :                                                                 ne = rel_nop_(sql, NULL, ne, exp_null(sql->sa, tp), e, NULL, "sys", "ifthenelse", card_value);
     968         135 :                                                                 exp_prop_alias(sql->sa, ne, e);
     969         135 :                                                                 e = ne;
     970             :                                                         }
     971             :                                                 }
     972             :                                         }
     973        6596 :                                         if (r->l)
     974        6596 :                                                 e = exp_rewrite(sql, r->l, e, ad);
     975        6596 :                                         append(n->exps, e);
     976             :                                 }
     977             :                         }
     978        4855 :                         if (!list_empty(r->r)) {
     979          32 :                                 list *exps = r->r, *oexps = n->r = sa_list(sql->sa);
     980             : 
     981          86 :                                 for (m=exps->h; m; m = m->next) {
     982          54 :                                         sql_exp *e = m->data;
     983             : 
     984          54 :                                         if (!is_freevar(e) || exp_name(e)) { /* only skip full freevars */
     985          54 :                                                 if (exp_has_freevar(sql, e))
     986           4 :                                                         rel_bind_var(sql, rel->l, e);
     987             :                                         }
     988          54 :                                         append(oexps, e);
     989             :                                 }
     990             :                         }
     991             :                         /* remove old project */
     992        4855 :                         if (r->l) {
     993        4855 :                                 rel->r = r->l;
     994        4855 :                                 r->l = NULL;
     995             :                         }
     996        4855 :                         rel_destroy(r);
     997        4855 :                         return n;
     998             :                 }
     999             :         }
    1000             :         /* a dependent semi/anti join with a project on the right side, could be removed */
    1001        4278 :         if (rel && is_semi(rel->op) && is_dependent(rel)) {
    1002         123 :                 sql_rel *r = rel->r;
    1003             : 
    1004             :                 /* merge project expressions into the join expressions  */
    1005         123 :                 rel->exps = push_up_project_exps(sql, r, rel->exps);
    1006         123 :                 rel_bind_vars(sql, rel, rel->exps);
    1007             : 
    1008         123 :                 if (r && r->op == op_project && r->l) {
    1009             :                         /* remove old project */
    1010         113 :                         rel->r = rel_dup(r->l);
    1011         113 :                         rel_destroy(r);
    1012         113 :                         return rel;
    1013          10 :                 } else if (r && r->op == op_project) {
    1014             :                         /* remove freevars from projection */
    1015          10 :                         list *exps = r->exps, *nexps = sa_list(sql->sa);
    1016          10 :                         node *m;
    1017             : 
    1018          10 :                         if (!list_empty(exps)) {
    1019          20 :                                 for (m=exps->h; m; m = m->next) {
    1020          10 :                                         sql_exp *e = m->data;
    1021             : 
    1022          10 :                                         if (!exp_has_freevar(sql, e))
    1023           0 :                                                 append(nexps, e);
    1024             :                                 }
    1025             :                         }
    1026          10 :                         if (list_empty(nexps)) {
    1027          10 :                                 assert(!r->l);
    1028             :                                 /* remove old project and change outer into select */
    1029          10 :                                 rel->r = NULL;
    1030          10 :                                 rel_destroy(r);
    1031          10 :                                 operator_type op = rel->op;
    1032          10 :                                 rel->op = op_select;
    1033          10 :                                 if (!list_empty(rel->exps)) {
    1034          17 :                                         for(m=rel->exps->h; m; m = m->next) {
    1035           9 :                                                 sql_exp *e = m->data;
    1036             : 
    1037           9 :                                                 if (op == op_anti && is_compare(e->type) && e->flag == cmp_equal)
    1038           3 :                                                         e->flag = cmp_notequal;
    1039           0 :                                                 else if (op == op_anti && is_compare(e->type) && e->flag == cmp_notequal)
    1040           0 :                                                         e->flag = cmp_equal;
    1041             :                                         }
    1042             :                                 }
    1043          10 :                                 return rel;
    1044             :                         }
    1045           0 :                         r->exps = nexps;
    1046             :                 }
    1047             :         }
    1048             :         return rel;
    1049             : }
    1050             : 
    1051             : static sql_rel *
    1052           5 : push_up_topn_and_sample(mvc *sql, sql_rel *rel)
    1053             : {
    1054             :         /* a dependent semi/anti join with a project on the right side, could be removed */
    1055           5 :         if (rel && (is_semi(rel->op) || is_join(rel->op)) && is_dependent(rel)) {
    1056           5 :                 sql_rel *r = rel->r;
    1057             : 
    1058           5 :                 if (r && (is_topn(r->op) || is_sample(r->op))) {
    1059             :                         /* remove old topn/sample */
    1060           5 :                         sql_rel *(*func) (allocator *, sql_rel *, list *) = is_topn(r->op) ? rel_topn : rel_sample;
    1061           5 :                         rel->r = rel_dup(r->l);
    1062           5 :                         rel = func(sql->sa, rel, r->exps);
    1063           5 :                         set_processed(rel);
    1064           5 :                         rel_destroy(r);
    1065           5 :                         return rel;
    1066             :                 }
    1067             :         }
    1068             :         return rel;
    1069             : }
    1070             : 
    1071             : static sql_rel *
    1072        7541 : push_up_select(mvc *sql, sql_rel *rel, list *ad)
    1073             : {
    1074        7541 :         sql_rel *d = rel->l;
    1075        7541 :         sql_rel *r = rel->r;
    1076        7541 :         int inner = 0;
    1077             : 
    1078        7541 :         if (rel && is_dependent(rel) && r && is_select(r->op)) {
    1079        7541 :                 sql_rel *rl = r->l;
    1080             : 
    1081        7541 :                 if (rl && rel_has_freevar(sql, rl)) {
    1082        2044 :                         list *inner_ad = rel_dependent_var(sql, d, rl);
    1083             : 
    1084        2044 :                         inner = !list_empty(inner_ad);
    1085             :                 }
    1086             :         }
    1087        2044 :         if (inner && is_left(rel->op) && !need_distinct(d))
    1088          30 :                 return rel_general_unnest(sql, rel, ad);
    1089             :         /* input rel is dependent join with on the right a select */
    1090        7511 :         if ((!inner || is_semi(rel->op)) && rel && is_dependent(rel)) {
    1091        5528 :                 sql_rel *r = rel->r;
    1092             : 
    1093        5528 :                 if (r && is_select(r->op)) { /* move into join */
    1094        5528 :                         node *n;
    1095             : 
    1096        5528 :                         if (!list_empty(r->exps)) {
    1097       12160 :                                 for (n=r->exps->h; n; n = n->next) {
    1098        6632 :                                         sql_exp *e = n->data;
    1099             : 
    1100        6632 :                                         e = exp_copy(sql, e);
    1101        6632 :                                         if (exp_has_freevar(sql, e))
    1102        6617 :                                                 rel_bind_var(sql, rel->l, e);
    1103        6632 :                                         rel_join_add_exp(sql->sa, rel, e);
    1104             :                                 }
    1105             :                         }
    1106             :                         /* remove select */
    1107        5528 :                         rel->r = rel_dup(r->l);
    1108        5528 :                         rel_destroy(r);
    1109        5528 :                         r = rel->r;
    1110        5528 :                         if (is_single(r)) {
    1111           2 :                                 set_single(rel);
    1112           2 :                                 rel->op = op_left;
    1113             :                         }
    1114        5528 :                         if (!inner)
    1115        5497 :                                 reset_dependent(rel);
    1116             :                 }
    1117        1983 :         } else if (rel && is_join(rel->op) && is_dependent(rel)) {
    1118        1983 :                 int cp = rel_is_ref(r);
    1119        1983 :                 sql_rel *r = rel->r;
    1120        1983 :                 list *exps = r->exps;
    1121             : 
    1122             :                 /* remove select */
    1123        1983 :                 rel->r = rel_dup(r->l);
    1124        1983 :                 rel = rel_select(sql->sa, rel, NULL);
    1125        1983 :                 rel->exps = !cp?exps:exps_copy(sql, exps);
    1126        1983 :                 rel_bind_vars(sql, rel, rel->exps);
    1127        1983 :                 set_processed(rel);
    1128        1983 :                 rel_destroy(r);
    1129             :         }
    1130             :         return rel;
    1131             : }
    1132             : 
    1133             : static int
    1134          14 : exps_is_constant( list *exps )
    1135             : {
    1136          14 :         sql_exp *e;
    1137             : 
    1138          14 :         if (!exps || list_empty(exps))
    1139           0 :                 return 1;
    1140          14 :         if (list_length(exps) > 1)
    1141             :                 return 0;
    1142          14 :         e = exps->h->data;
    1143          14 :         return exp_is_atom(e);
    1144             : }
    1145             : 
    1146             : static int
    1147      158852 : exp_is_count(sql_exp *e, sql_rel *rel)
    1148             : {
    1149      238859 :         if (!e || !rel)
    1150             :                 return 0;
    1151      230446 :         if (is_alias(e->type) && is_project(rel->op) && !is_set(rel->op)) {
    1152             :                 /* if the relop is n-ary (like munion) we need to retrieve its
    1153             :                  * first operands which lives in the list at rel->l
    1154             :                  */
    1155       80007 :                 sql_rel *pr = is_munion(rel->op) ? ((list*)rel->l)->h->data : rel->l;
    1156       80007 :                 sql_exp *ne = rel_find_exp(pr, e);
    1157       80007 :                 return exp_is_count(ne, pr);
    1158             :         }
    1159      150439 :         if (is_aggr(e->type) && exp_aggr_is_count(e))
    1160             :                 return 1;
    1161             :         return 0;
    1162             : }
    1163             : 
    1164             : static sql_rel *
    1165        2873 : push_up_groupby(mvc *sql, sql_rel *rel, list *ad)
    1166             : {
    1167             :         /* input rel is dependent join with on the right a groupby */
    1168        2873 :         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
    1169        2873 :                 sql_rel *l = rel->l, *r = rel->r;
    1170             : 
    1171             :                 /* left of rel should be a set */
    1172        2873 :                 if (l && is_distinct_set(sql, l, ad) && r && is_groupby(r->op)) {
    1173        2873 :                         list *sexps, *jexps, *a = rel_projections(sql, rel->l, NULL, 1, 1);
    1174        2873 :                         node *n;
    1175        2873 :                         sql_exp *id = NULL;
    1176             : 
    1177             :                         /* move groupby up, ie add attributes of left + the old expression list */
    1178             : 
    1179        2873 :                         if (l && list_length(a) > 1 && !need_distinct(l)) { /* add identity call only if there's more than one column in the groupby */
    1180           2 :                                 if (!(rel->l = rel_add_identity(sql, l, &id))) /* add identity call for group by */
    1181             :                                         return NULL;
    1182           2 :                                 assert(id);
    1183             :                         }
    1184             : 
    1185        2873 :                         if (rel->op == op_semi)
    1186           1 :                                 rel->op = op_join;
    1187        2873 :                         if (rel->op == op_anti) {
    1188           0 :                                 rel->op = op_join;
    1189             :                                 /* need to change all exps */
    1190           0 :                                 if (!list_empty(rel->exps)) {
    1191           0 :                                         for(node *n = rel->exps->h; n; n = n->next) {
    1192           0 :                                                 sql_exp *e = n->data;
    1193           0 :                                                 e->anti = !e->anti;
    1194             :                                         }
    1195             :                                 }
    1196             :                         }
    1197             : 
    1198        2873 :                         if (!list_empty(r->exps)) {
    1199        5887 :                                 for (n = r->exps->h; n; n = n->next ) {
    1200        3014 :                                         sql_exp *e = n->data;
    1201             : 
    1202             :                                         /* count_nil(* or constant) -> count(t.TID) */
    1203        3014 :                                         if (exp_is_count(e, r) && (!e->l || exps_is_constant(e->l))) {
    1204        2355 :                                                 sql_rel *p = r->l; /* ugh */
    1205        2355 :                                                 sql_rel *pp = r;
    1206        4967 :                                                 while(p && p->l && (!is_project(p->op) && !is_base(p->op))) { /* find first project */
    1207             :                                                         pp = p;
    1208             :                                                         p = p->l;
    1209             :                                                 }
    1210        2355 :                                                 if (p && p->l && is_project(p->op) && list_empty(p->exps)) { /* skip empty project */
    1211           1 :                                                         pp = p;
    1212           1 :                                                         p = p->l;
    1213             :                                                 }
    1214        2355 :                                                 sql_exp *col = list_length(p->exps) ? p->exps->t->data : NULL;
    1215        2355 :                                                 const char *cname = col ? exp_name(col) : NULL;
    1216             : 
    1217        2355 :                                                 if ((!cname || strcmp(cname, TID) != 0) && !(pp->l = p = rel_add_identity(sql, p, &col)))
    1218           0 :                                                         return NULL;
    1219        2355 :                                                 col = exp_ref(sql, col);
    1220        2355 :                                                 append(e->l=sa_list(sql->sa), col);
    1221        2355 :                                                 set_no_nil(e);
    1222             :                                         }
    1223        3014 :                                         if (exp_has_freevar(sql, e))
    1224           6 :                                                 rel_bind_var(sql, rel->l, e);
    1225             :                                 }
    1226             :                         }
    1227        2873 :                         r->exps = list_distinct(list_merge(r->exps, a, (fdup)NULL), (fcmp)exp_equal, (fdup)NULL);
    1228        2873 :                         if (list_empty(r->r)) {
    1229        2821 :                                 if (id)
    1230           2 :                                         r->r = list_append(sa_list(sql->sa), exp_ref(sql, id));
    1231             :                                 else
    1232        2819 :                                         r->r = exps_copy(sql, a);
    1233        2821 :                                 r->card = CARD_AGGR;
    1234             :                                 /* After the unnesting, the cardinality of the aggregate function becomes larger */
    1235        9646 :                                 for(node *n = r->exps->h; n; n = n->next) {
    1236        6825 :                                         sql_exp *e = n->data;
    1237             : 
    1238        6825 :                                         e->card = CARD_AGGR;
    1239             :                                 }
    1240             :                         } else {
    1241         118 :                                 for (n = ((list*)r->r)->h; n; n = n->next ) {
    1242          66 :                                         sql_exp *e = n->data;
    1243             : 
    1244          66 :                                         if (exp_has_freevar(sql, e))
    1245          25 :                                                 rel_bind_var(sql, rel->l, e);
    1246             :                                 }
    1247          52 :                                 if (id)
    1248           0 :                                         list_append(r->r, exp_ref(sql, id));
    1249             :                                 else
    1250          52 :                                         r->r = list_distinct(list_merge(r->r, exps_copy(sql, a), (fdup)NULL), (fcmp)exp_equal, (fdup)NULL);
    1251             :                         }
    1252             : 
    1253        2873 :                         if (!r->l) {
    1254           0 :                                 r->l = rel->l;
    1255           0 :                                 rel->l = NULL;
    1256           0 :                                 rel->r = NULL;
    1257           0 :                                 rel_destroy(rel);
    1258             :                                 /* merge (distinct) projects / group by (over the same group by cols) */
    1259           0 :                                 while (r->l && exps_have_freevar(sql, r->exps)) {
    1260           0 :                                         sql_rel *l = r->l;
    1261             : 
    1262           0 :                                         if (!is_project(l->op))
    1263             :                                                 break;
    1264           0 :                                         if (l->op == op_project && need_distinct(l)) { /* TODO: check if group by exps and distinct list are equal */
    1265           0 :                                                 r->l = rel_dup(l->l);
    1266           0 :                                                 rel_destroy(l);
    1267             :                                         }
    1268           0 :                                         if (is_groupby(l->op)) { /* TODO: check if group by exps and distinct list are equal */
    1269             :                                                 /* add aggr exps of r to l, replace r by l */
    1270           0 :                                                 if (!list_empty(r->exps)) {
    1271           0 :                                                         for(node *n = r->exps->h; n; n = n->next) {
    1272           0 :                                                                 sql_exp *e = n->data;
    1273             : 
    1274           0 :                                                                 if (e->type == e_aggr)
    1275           0 :                                                                         append(l->exps, e);
    1276           0 :                                                                 if (exp_has_freevar(sql, e))
    1277           0 :                                                                         rel_bind_var(sql, l, e);
    1278             :                                                         }
    1279             :                                                 }
    1280           0 :                                                 r->l = NULL;
    1281           0 :                                                 rel_destroy(r);
    1282           0 :                                                 r = l;
    1283             :                                         }
    1284             :                                 }
    1285           0 :                                 return r;
    1286             :                         } else {
    1287        2873 :                                 rel->r = r->l;
    1288        2873 :                                 r->l = rel;
    1289             :                         }
    1290             :                         /* check if a join expression needs to be moved above the group by (into a select) */
    1291        2873 :                         sexps = sa_list(sql->sa);
    1292        2873 :                         jexps = sa_list(sql->sa);
    1293        2873 :                         if (!list_empty(rel->exps)) {
    1294           2 :                                 for (n = rel->exps->h; n; n = n->next ) {
    1295           1 :                                         sql_exp *e = n->data;
    1296             : 
    1297           1 :                                         if (rel_find_exp(rel, e)) {
    1298           0 :                                                 append(jexps, e);
    1299             :                                         } else {
    1300           1 :                                                 append(sexps, e);
    1301             :                                         }
    1302             :                                 }
    1303             :                         }
    1304        2873 :                         rel->exps = jexps;
    1305        2873 :                         if (list_length(sexps)) {
    1306           1 :                                 r = rel_select(sql->sa, r, NULL);
    1307           1 :                                 r->exps = sexps;
    1308           1 :                                 set_processed(r);
    1309             :                         }
    1310        2873 :                         return r;
    1311             :                 }
    1312             :         }
    1313             :         return rel;
    1314             : }
    1315             : 
    1316             : static sql_rel *
    1317           0 : push_up_select_l(mvc *sql, sql_rel *rel)
    1318             : {
    1319           0 :         (void)sql;
    1320             :         /* input rel is dependent join with on the right a project */
    1321           0 :         if (rel && (is_join(rel->op) || is_semi(rel->op))) {
    1322           0 :                 sql_rel *l = rel->l;
    1323             : 
    1324           0 :                 if (is_select(l->op) && rel_has_freevar(sql, l) && !rel_is_ref(l) ) {
    1325             :                         /* push up select (above join) */
    1326           0 :                         rel->l = l->l;
    1327           0 :                         l->l = rel;
    1328           0 :                         return l;
    1329             :                 }
    1330             :         }
    1331             :         return rel;
    1332             : }
    1333             : 
    1334             : static void
    1335          11 : bind_join_vars(mvc *sql, sql_rel *rel)
    1336             : {
    1337          11 :         if (list_empty(rel->exps))
    1338             :                 return;
    1339          32 :         for(node *n = rel->exps->h; n; n = n->next){
    1340          21 :                 sql_exp *e = n->data;
    1341             : 
    1342          21 :                 if (exp_has_freevar(sql, e))
    1343          16 :                         rel_bind_var(sql, rel->l, e);
    1344             :         }
    1345             : }
    1346             : 
    1347             : static sql_rel * rewrite_outer2inner_union(visitor *v, sql_rel *rel);
    1348             : 
    1349             : static sql_rel *
    1350         176 : push_up_join(mvc *sql, sql_rel *rel, list *ad)
    1351             : {
    1352             :         /* input rel is dependent join */
    1353         176 :         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
    1354         176 :                 sql_rel *d = rel->l, *j = rel->r;
    1355             : 
    1356             :                 /* left of rel should be a set */
    1357         176 :                 if (d && is_distinct_set(sql, d, ad) && j && (is_join(j->op) || is_semi(j->op))) {
    1358         176 :                         sql_rel *jl = j->l, *jr = j->r;
    1359             :                         /* op_join if F(jl) intersect A(D) = empty -> jl join (D djoin jr)
    1360             :                          *            F(jr) intersect A(D) = empty -> (D djoin jl) join jr
    1361             :                          *       else (D djoin jl) natural join (D djoin jr)
    1362             :                          *
    1363             :                          * */
    1364         176 :                         list *rd = NULL, *ld = NULL;
    1365         176 :                         int labelleft = j->op == op_right;
    1366             : 
    1367         176 :                         if (is_semi(j->op) && is_select(jl->op) && rel_has_freevar(sql, jl) && !rel_is_ref(jl)) {
    1368           0 :                                 rel->r = j = push_up_select_l(sql, j);
    1369           0 :                                 return rel; /* ie try again */
    1370             :                         }
    1371         176 :                         rd = (j->op != op_full && j->op != op_right)?rel_dependent_var(sql, d, jr):(list*)1;
    1372         176 :                         ld = ((j->op == op_join || j->op == op_right))?rel_dependent_var(sql, d, jl):(list*)1;
    1373             : 
    1374         176 :                         if (is_outerjoin(j->op) && j->exps && !list_empty(rel->attr)) {
    1375           1 :                                 visitor v = { .sql = sql };
    1376           1 :                                 rel->r = j = rewrite_outer2inner_union(&v, j);
    1377           1 :                                 if (!j)
    1378             :                                         return NULL;
    1379           1 :                                 return rel;
    1380             :                         }
    1381             : 
    1382         175 :                         if (ld && rd) {
    1383          92 :                                 node *m;
    1384          92 :                                 sql_rel *n, *nr, *nj, *nl;
    1385          92 :                                 list *inner_exps = exps_copy(sql, j->exps);
    1386          92 :                                 list *outer_exps = exps_copy(sql, rel->exps);
    1387          92 :                                 list *attr = j->attr;
    1388          92 :                                 int single = is_single(j);
    1389             : 
    1390          92 :                                 rel->r = rel_dup(jl);
    1391          92 :                                 rel->exps = sa_list(sql->sa);
    1392          92 :                                 nj = rel_crossproduct(sql->sa, rel_dup(d), rel_dup(jr), j->op);
    1393          92 :                                 set_processed(nj);
    1394          92 :                                 rel_destroy(j);
    1395          92 :                                 j = nj;
    1396          92 :                                 set_dependent(j);
    1397          92 :                                 n = rel_crossproduct(sql->sa, rel, j, j->op);
    1398          92 :                                 n->exps = outer_exps;
    1399          92 :                                 if (single)
    1400           8 :                                         set_single(n);
    1401          92 :                                 if (!n->exps)
    1402          68 :                                         n->exps = inner_exps;
    1403             :                                 else
    1404          24 :                                         n->exps = list_merge(n->exps, inner_exps, (fdup)NULL);
    1405          92 :                                 j->op = rel->op;
    1406          92 :                                 if (is_semi(rel->op)) {
    1407           1 :                                         j->op = op_left;
    1408           1 :                                         rel->op = op_left;
    1409             :                                 }
    1410          92 :                                 nl = n->l = rel_project(sql->sa, n->l, rel_projections(sql, n->l, NULL, 1, 1));
    1411          92 :                                 nr = n->r;
    1412          92 :                                 nr = n->r = rel_project(sql->sa, n->r, is_semi(nr->op)?sa_list(sql->sa):rel_projections(sql, nr->r, NULL, 1, 1));
    1413             :                                 /* add nr->l exps with labels */
    1414             :                                 /* create jexps */
    1415          92 :                                 if (!n->exps)
    1416          45 :                                         n->exps = sa_list(sql->sa);
    1417          92 :                                 if (!list_empty(d->exps)) {
    1418         247 :                                         for (m = d->exps->h; m; m = m->next) {
    1419         155 :                                                 sql_exp *e = m->data, *le, *re, *je;
    1420             : 
    1421         155 :                                                 le = exp_ref(sql, e);
    1422         155 :                                                 re = exp_ref(sql, e);
    1423             : 
    1424         155 :                                                 if (labelleft) {
    1425           7 :                                                         sql_exp *f = NULL;
    1426           7 :                                                         if ((f=rel_find_exp(nl, le)) != NULL)
    1427           7 :                                                                 le = f;
    1428           7 :                                                         if (!has_label(le))
    1429           7 :                                                                 le = exp_label(sql->sa, le, ++sql->label);
    1430           7 :                                                         if (!f)
    1431           0 :                                                                 append(nl->exps, le);
    1432           7 :                                                         le = exp_ref(sql, le);
    1433             :                                                 }
    1434             : 
    1435           7 :                                                 if (!labelleft)
    1436         148 :                                                         re = exp_label(sql->sa, re, ++sql->label);
    1437         155 :                                                 append(nr->exps, re);
    1438         155 :                                                 re = exp_ref(sql, re);
    1439         155 :                                                 je = exp_compare(sql->sa, le, re, cmp_equal);
    1440         155 :                                                 set_semantics(je);
    1441         155 :                                                 append(n->exps, je);
    1442             :                                         }
    1443             :                                 }
    1444          92 :                                 list_hash_clear(nl->exps);
    1445          92 :                                 n->attr = attr;
    1446          92 :                                 set_processed(n);
    1447          92 :                                 rel_bind_vars(sql, n, n->exps);
    1448          92 :                                 return n;
    1449             :                         }
    1450             : 
    1451          83 :                         if (!rd) {
    1452          44 :                                 rel->r = rel_dup(jl);
    1453          44 :                                 sql_rel *nj = rel_crossproduct(sql->sa, rel, rel_dup(jr), j->op);
    1454          44 :                                 if (is_single(j))
    1455           2 :                                         set_single(nj);
    1456          44 :                                 nj->exps = exps_copy(sql, j->exps);
    1457          44 :                                 nj->attr = j->attr;
    1458          44 :                                 set_processed(nj);
    1459          44 :                                 rel_destroy(j);
    1460          44 :                                 j = nj;
    1461          44 :                                 if (is_semi(rel->op))
    1462           0 :                                         rel->op = op_left;
    1463          44 :                                 move_join_exps(sql, j, rel);
    1464          44 :                                 rel_bind_vars(sql, j, j->exps);
    1465          44 :                                 return j;
    1466             :                         }
    1467          39 :                         if (!ld) {
    1468          39 :                                 rel->r = rel_dup(jr);
    1469          39 :                                 sql_rel *nj = rel_crossproduct(sql->sa, rel_dup(jl), rel, j->op);
    1470          39 :                                 if (is_single(j))
    1471          12 :                                         set_single(nj);
    1472          39 :                                 nj->exps = exps_copy(sql, j->exps);
    1473          39 :                                 nj->attr = j->attr;
    1474          39 :                                 set_processed(nj);
    1475          39 :                                 rel_destroy(j);
    1476          39 :                                 j = nj;
    1477          39 :                                 if (is_semi(rel->op))
    1478           3 :                                         rel->op = op_left;
    1479          39 :                                 move_join_exps(sql, j, rel);
    1480          39 :                                 rel_bind_vars(sql, j, j->exps);
    1481          39 :                                 return j;
    1482             :                         }
    1483           0 :                         assert(0);
    1484             :                         return rel;
    1485             :                 }
    1486             :         }
    1487             :         return rel;
    1488             : }
    1489             : 
    1490             : static sql_rel *
    1491          41 : push_up_set(mvc *sql, sql_rel *rel, list *ad)
    1492             : {
    1493          41 :         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
    1494          41 :                 int single = is_single(rel);
    1495          41 :                 sql_rel *d = rel->l, *s = rel->r;
    1496          82 :                 int need_distinct = is_semi(rel->op) && need_distinct(d);
    1497             : 
    1498             :                 /* left of rel should be a set */
    1499          82 :                 if (d && is_distinct_set(sql, d, ad) && s && is_set(s->op)) {
    1500          41 :                         assert(s->op != op_union);
    1501          41 :                         sql_rel *sl = s->l, *sr = s->r, *ns;
    1502             : 
    1503          41 :                         sl = rel_project(sql->sa, rel_dup(sl), rel_projections(sql, sl, NULL, 1, 1));
    1504          95 :                         for (node *n = sl->exps->h, *m = s->exps->h; n && m; n = n->next, m = m->next)
    1505          54 :                                 exp_prop_alias(sql->sa, n->data, m->data);
    1506          41 :                         list_hash_clear(sl->exps);
    1507          41 :                         sr = rel_project(sql->sa, rel_dup(sr), rel_projections(sql, sr, NULL, 1, 1));
    1508          95 :                         for (node *n = sr->exps->h, *m = s->exps->h; n && m; n = n->next, m = m->next)
    1509          54 :                                 exp_prop_alias(sql->sa, n->data, m->data);
    1510          41 :                         list_hash_clear(sr->exps);
    1511             : 
    1512          41 :                         int llen = list_length(sl->exps), rlen = list_length(sr->exps), l = 0;
    1513             : 
    1514          41 :                         if (llen != rlen) {
    1515           0 :                                 if (llen < rlen) {
    1516           0 :                                         list *nr = sa_list(sql->sa);
    1517           0 :                                         for(node *n = sr->exps->h ; n && l < llen; n=n->next, l++)
    1518           0 :                                                         append(nr, n->data);
    1519           0 :                                         sr->exps = nr;
    1520           0 :                                         sr->nrcols = list_length(nr);
    1521             :                                 } else {
    1522           0 :                                         list *nl = sa_list(sql->sa);
    1523           0 :                                         for(node *n = sl->exps->h; n && l < rlen; n=n->next, l++)
    1524           0 :                                                         append(nl, n->data);
    1525           0 :                                         sl->exps = nl;
    1526           0 :                                         sl->nrcols = list_length(nl);
    1527             :                                 }
    1528             :                         }
    1529             : 
    1530             :                         /* D djoin (sl setop sr) -> (D djoin sl) setop (D djoin sr) */
    1531          41 :                         sl = rel_crossproduct(sql->sa, rel_dup(d), sl, rel->op);
    1532          41 :                         sl->exps = exps_copy(sql, rel->exps);
    1533          41 :                         set_dependent(sl);
    1534          41 :                         set_processed(sl);
    1535          41 :                         sr = rel_crossproduct(sql->sa, rel_dup(d), sr, rel->op);
    1536          41 :                         sr->exps = exps_copy(sql, rel->exps);
    1537          41 :                         set_dependent(sr);
    1538          41 :                         set_processed(sr);
    1539          41 :                         ns = rel_setop(sql->sa, sl, sr, s->op);
    1540          41 :                         ns->exps = exps_copy(sql, s->exps);
    1541          41 :                         set_processed(ns);
    1542          41 :                         if (single || is_single(s))
    1543           2 :                                 set_single(ns);
    1544          41 :                         if (need_distinct || need_distinct(s))
    1545          35 :                                 set_distinct(ns);
    1546             : 
    1547          41 :                         if (is_join(rel->op) && !is_semi(rel->op)) {
    1548          41 :                                 list *sexps = sa_list(sql->sa), *dexps = rel_projections(sql, d, NULL, 1, 1);
    1549         110 :                                 for (node *m = dexps->h; m; m = m->next) {
    1550          69 :                                         sql_exp *e = m->data;
    1551             : 
    1552          69 :                                         list_append(sexps, exp_ref(sql, e));
    1553             :                                 }
    1554          41 :                                 ns->exps = list_merge(sexps, ns->exps, (fdup)NULL);
    1555             :                         }
    1556             :                         /* add/remove projections to inner parts of the union (as we push a join or semijoin down) */
    1557          41 :                         ns->l = rel_project(sql->sa, ns->l, rel_projections(sql, ns->l, NULL, 1, 1));
    1558          41 :                         ns->r = rel_project(sql->sa, ns->r, rel_projections(sql, ns->r, NULL, 1, 1));
    1559          41 :                         if (is_semi(rel->op)) /* only push left side of semi/anti join */
    1560           0 :                                 ns->exps = rel_projections(sql, ns->l, NULL, 1, 1);
    1561          41 :                         if (rel->op == op_anti && s->op == op_inter) {
    1562           0 :                                 list *urs = sa_list(sql->sa);
    1563           0 :                                 urs = append(urs, ns->l);
    1564           0 :                                 urs = append(urs, ns->r);
    1565           0 :                                 rel_inplace_setop_n_ary(sql, ns, urs, op_munion, ns->exps);
    1566             :                         }
    1567          41 :                         rel_destroy(rel);
    1568          41 :                         return ns;
    1569             :                 }
    1570             :         }
    1571             :         return rel;
    1572             : }
    1573             : 
    1574             : static sql_rel *
    1575        1531 : push_up_munion(mvc *sql, sql_rel *rel, list *ad)
    1576             : {
    1577        1531 :         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
    1578        1531 :                 int single = is_single(rel);
    1579        1531 :                 sql_rel *d = rel->l, *s = rel->r;
    1580        1531 :                 int need_distinct = is_semi(rel->op) && need_distinct(d);
    1581        1531 :                 int len = 0, need_length_reduction = 0;
    1582             : 
    1583             :                 /* left of rel should be a set */
    1584        1531 :                 list *rlist = sa_list(sql->sa);
    1585        1531 :                 if (d && is_distinct_set(sql, d, ad) && s && is_munion(s->op)) {
    1586        1531 :                         list *iu = s->l;
    1587        4593 :                         for(node *n = iu->h; n; n = n->next) {
    1588        3062 :                                 sql_rel *sl = n->data;
    1589        3062 :                                 sl = rel_project(sql->sa, rel_dup(sl), rel_projections(sql, sl, NULL, 1, 1));
    1590        6194 :                                 for (node *n = sl->exps->h, *m = s->exps->h; n && m; n = n->next, m = m->next)
    1591        3132 :                                         exp_prop_alias(sql->sa, n->data, m->data);
    1592        3062 :                                 list_hash_clear(sl->exps);
    1593        3062 :                                 rlist = append(rlist, sl);
    1594        3062 :                                 if (len && len != list_length(sl->exps))
    1595        1214 :                                         need_length_reduction = 1;
    1596        1531 :                                 if (!len || len > list_length(sl->exps))
    1597        2499 :                                         len = list_length(sl->exps);
    1598             :                         }
    1599             : 
    1600        1531 :                         if (need_length_reduction) {
    1601        3642 :                                 for(node *n = rlist->h; n; n = n->next) {
    1602        2428 :                                         sql_rel *r = n->data;
    1603        2428 :                                         if (list_length(r->exps) > len) {
    1604        1214 :                                                 list *nr = sa_list(sql->sa);
    1605        1214 :                                                 int l = 0;
    1606        2428 :                                                 for(node *m = r->exps->h ; m && l < len; m = m->next, l++)
    1607        1214 :                                                         append(nr, m->data);
    1608        1214 :                                                 r->exps = nr;
    1609        1214 :                                                 r->nrcols = list_length(nr);
    1610             :                                         }
    1611             :                                 }
    1612             :                         }
    1613             : 
    1614        4593 :                         for(node *n = rlist->h; n; n = n->next) {
    1615             :                                 /* D djoin (sl setop sr) -> (D djoin sl) setop (D djoin sr) */
    1616        3062 :                                 sql_rel *sl = n->data;
    1617        3062 :                                 sl = rel_crossproduct(sql->sa, rel_dup(d), sl, rel->op);
    1618        3062 :                                 sl->exps = exps_copy(sql, rel->exps);
    1619        3062 :                                 set_dependent(sl);
    1620        3062 :                                 set_processed(sl);
    1621        3062 :                                 n->data = sl;
    1622             :                         }
    1623             : 
    1624        1531 :                         sql_rel *ns = rel_setop_n_ary(sql->sa, rlist, s->op);
    1625        1531 :                         ns->exps = exps_copy(sql, s->exps);
    1626        1531 :                         set_processed(ns);
    1627        1531 :                         if (single || is_single(s))
    1628           4 :                                 set_single(ns);
    1629        1531 :                         if (need_distinct || need_distinct(s))
    1630          38 :                                 set_distinct(ns);
    1631             : 
    1632        1531 :                         if (is_join(rel->op) && !is_semi(rel->op)) {
    1633        1524 :                                 list *sexps = sa_list(sql->sa), *dexps = rel_projections(sql, d, NULL, 1, 1);
    1634        5674 :                                 for (node *m = dexps->h; m; m = m->next) {
    1635        4150 :                                         sql_exp *e = m->data;
    1636             : 
    1637        4150 :                                         list_append(sexps, exp_ref(sql, e));
    1638             :                                 }
    1639        1524 :                                 ns->exps = list_merge(sexps, ns->exps, (fdup)NULL);
    1640             :                         }
    1641             :                         /* add/remove projections to inner parts of the union (as we push a join or semijoin down) */
    1642        4593 :                         for(node *n = rlist->h; n; n = n->next) {
    1643        3062 :                                 sql_rel *sl = n->data;
    1644        3062 :                                 n->data = rel_project(sql->sa, sl, rel_projections(sql, sl, NULL, 1, 1));
    1645             :                         }
    1646        1531 :                         if (is_semi(rel->op)) { /* only project left of semi/anti join */
    1647           7 :                                 sql_rel *sf = rlist->h->data;
    1648           7 :                                 ns->exps = rel_projections(sql, sf, NULL, 1, 1);
    1649             :                         }
    1650        1531 :                         if (rel->op == op_anti && s->op == op_munion) {
    1651             :                                 /* chain the munion list of relations into a pair-wise op_inter chain */
    1652           2 :                                 sql_rel *cl = rlist->h->data, *cr = rlist->h->next->data;
    1653           2 :                                 ns->op = op_inter;
    1654           2 :                                 if (list_length(rlist) > 2) {
    1655           0 :                                         for (node *n = rlist->h->next->next; n; n = n->next) {
    1656           0 :                                                 cr = rel_setop(sql->sa, cr, n->data, op_inter);
    1657           0 :                                                 cr->exps = exps_copy(sql, ns->exps);
    1658             :                                         }
    1659             :                                 }
    1660           2 :                                 ns->l = cl;
    1661           2 :                                 ns->r = cr;
    1662             :                         }
    1663        1531 :                         rel_destroy(rel);
    1664        1531 :                         return ns;
    1665             :                 }
    1666             :         }
    1667             :         return rel;
    1668             : }
    1669             : 
    1670             : static sql_rel * rel_unnest_dependent(mvc *sql, sql_rel *rel);
    1671             : 
    1672             : static sql_rel *
    1673          23 : push_up_table(mvc *sql, sql_rel *rel)
    1674             : {
    1675          23 :         (void)sql;
    1676          23 :         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
    1677          23 :                 sql_rel *d = rel->l, *tf = rel->r;
    1678          23 :                 sql_exp *id = NULL;
    1679             : 
    1680             :                 /* push d into function */
    1681             :                 /* change join's into cross apply, ie tf(rel) -> (results tf, row-id). */
    1682          23 :                 if (d && tf && is_base(tf->op)) {
    1683          23 :                         if (tf->l) {
    1684          23 :                                 sql_rel *l = tf->l;
    1685             : 
    1686          23 :                                 assert(tf->flag == TABLE_FROM_RELATION || !l->l);
    1687          23 :                                 sql_exp *tfe = tf->r;
    1688          23 :                                 list *ops = tfe->l;
    1689          23 :                                 if (!(rel->l = d = rel_add_identity(sql, d, &id)))
    1690          23 :                                         return NULL;
    1691          23 :                                 id = exp_ref(sql, id);
    1692          23 :                                 list *exps = rel_projections(sql, l, NULL, 1, 1);
    1693          23 :                                 list_append(exps, id);
    1694          23 :                                 l = tf->l = rel_crossproduct(sql->sa, rel_dup(d), l, op_join);
    1695          23 :                                 set_dependent(l);
    1696          23 :                                 set_processed(l);
    1697          23 :                                 tf->l = rel_unnest_dependent(sql, l);
    1698          23 :                                 tf->l = rel_project(sql->sa, tf->l, exps);
    1699          23 :                                 id = exp_ref(sql, id);
    1700          23 :                                 list_append(ops, id);
    1701          23 :                                 id = exp_ref(sql, id);
    1702             :                         } else {
    1703           0 :                                 assert(0);
    1704             :                                 tf->l = rel_dup(d);
    1705             :                         }
    1706             :                         /* we should add the identity in the resulting projection list */
    1707          23 :                         if (id) {
    1708          23 :                                 sql_exp *ne = exp_copy(sql, id);
    1709             : 
    1710          23 :                                 ne = exp_label(sql->sa, ne, ++sql->label);
    1711          23 :                                 ne = exp_ref(sql, ne);
    1712          23 :                                 list_prepend(tf->exps, ne);
    1713          23 :                                 ne = exp_ref(sql, ne);
    1714             : 
    1715             :                                 /* join on id */
    1716          23 :                                 ne = exp_compare(sql->sa, id, ne, cmp_equal);
    1717          23 :                                 if (!rel->exps)
    1718          21 :                                         rel->exps = sa_list(sql->sa);
    1719          23 :                                 list_append(rel->exps, ne);
    1720             :                         }
    1721          23 :                         reset_dependent(rel);
    1722          23 :                         return rel;
    1723             :                 }
    1724             :         }
    1725             :         return rel;
    1726             : }
    1727             : 
    1728             : static bool
    1729        9713 : exps_have_rank(list *exps)
    1730             : {
    1731        9713 :         if (!exps)
    1732             :                 return false;
    1733       24043 :         for(node *n=exps->h; n; n = n->next) {
    1734       14429 :                 sql_exp *e = n->data;
    1735       14429 :                 if (is_analytic(e))
    1736             :                         return true;
    1737             :         }
    1738             :         return false;
    1739             : }
    1740             : 
    1741             : static sql_rel *
    1742      649352 : rel_unnest_dependent(mvc *sql, sql_rel *rel)
    1743             : {
    1744      671241 :         sql_rel *nrel = rel;
    1745             : 
    1746      671241 :         if (mvc_highwater(sql))
    1747           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    1748             : 
    1749             :         /* current unnest only possible for equality joins, <, <> etc needs more work */
    1750      671241 :         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
    1751             :                 /* howto find out the left is a set */
    1752       30574 :                 sql_rel *l, *r;
    1753             : 
    1754       30574 :                 l = rel->l;
    1755       30574 :                 r = rel->r;
    1756             : 
    1757       30574 :                 if (rel_has_freevar(sql, l)) {
    1758          40 :                         rel->l = rel_unnest_dependent(sql, rel->l);
    1759          40 :                         if (rel_has_freevar(sql, rel->l)) {
    1760          40 :                                 if (rel->op == op_right) {
    1761           0 :                                         sql_rel *l = rel->l;
    1762             : 
    1763           0 :                                         rel->l = rel->r;
    1764           0 :                                         rel->r = l;
    1765           0 :                                         rel->op = op_left;
    1766           0 :                                         return rel_unnest_dependent(sql, rel);
    1767          40 :                                 } else if (rel->op == op_left && list_empty(rel->attr) && !rel_has_freevar(sql, rel->r) && rel_dependent_var(sql, rel->r, rel->l)) {
    1768           0 :                                         sql_rel *l = rel->l;
    1769             : 
    1770           0 :                                         rel->l = rel->r;
    1771           0 :                                         rel->r = l;
    1772           0 :                                         rel->op = op_right;
    1773           0 :                                         return rel_unnest_dependent(sql, rel);
    1774             :                                 }
    1775             :                         }
    1776             :                 }
    1777             : 
    1778       30574 :                 if (!rel_has_freevar(sql, r)) {
    1779        4427 :                         if (rel_has_freevar(sql, l) && is_innerjoin(rel->op) && !rel->exps) {
    1780           5 :                                 rel->l = r;
    1781           5 :                                 rel->r = l;
    1782           5 :                                 l = rel->l;
    1783           5 :                                 r = rel->r;
    1784             :                         } else {
    1785        4422 :                                 reset_dependent(rel);
    1786        4422 :                                 return rel;
    1787             :                         }
    1788             :                 }
    1789             : 
    1790             :                 /* try to push dependent join down */
    1791       26152 :                 if (rel_has_freevar(sql, r)) {
    1792       26152 :                         list *ad = rel_dependent_var(sql, rel->l, rel->r);
    1793             : 
    1794       26152 :                         if (list_empty(ad)) {
    1795          12 :                                 reset_dependent(rel);
    1796          12 :                                 return rel;
    1797             :                         }
    1798       26140 :                         if (r && is_select(r->op)) {
    1799        7547 :                                 sql_rel *l = r->l;
    1800             : 
    1801        7547 :                                 if (!rel_is_ref(r) && l && !rel_is_ref(l) && l->op == op_join && list_empty(l->exps)) {
    1802           6 :                                         l->exps = r->exps;
    1803           6 :                                         r->l = NULL;
    1804           6 :                                         rel_destroy(r);
    1805           6 :                                         rel->r = l;
    1806           6 :                                         return rel_unnest_dependent(sql, rel);
    1807             :                                 }
    1808             :                         }
    1809             : 
    1810       26134 :                         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
    1811       26134 :                                 sql_rel *j = rel->r;
    1812             : 
    1813       26134 :                                 if (j->op == op_join && !rel_is_ref(rel) && !rel_is_ref(j) && j->exps && exps_have_freevar(sql, j->exps)) {
    1814          11 :                                         rel->exps =  rel->exps?list_merge(rel->exps, j->exps, (fdup)NULL):j->exps;
    1815          11 :                                         j->exps = NULL;
    1816          11 :                                         bind_join_vars(sql, rel);
    1817          11 :                                         return rel_unnest_dependent(sql, rel);
    1818             :                                 }
    1819             :                         }
    1820             : 
    1821       26123 :                         if (r && is_simple_project(r->op) && ((!r->r && !exps_have_rank(r->exps)) || (!exps_have_freevar(sql, r->exps) && !exps_have_unsafe(r->exps, true, false)) || is_distinct_set(sql, l, ad))) {
    1822        9705 :                                 rel = push_up_project(sql, rel, ad);
    1823        9705 :                                 return rel_unnest_dependent(sql, rel);
    1824             :                         }
    1825             : 
    1826       16418 :                         if (r && (is_topn(r->op) || is_sample(r->op))) {
    1827           5 :                                 rel = push_up_topn_and_sample(sql, rel);
    1828           5 :                                 return rel_unnest_dependent(sql, rel);
    1829             :                         }
    1830             : 
    1831       16413 :                         if (r && is_select(r->op) && ad) {
    1832        7541 :                                 rel = push_up_select(sql, rel, ad);
    1833        7541 :                                 return rel_unnest_dependent(sql, rel);
    1834             :                         }
    1835             : 
    1836        8872 :                         if (r && is_groupby(r->op) && !is_left(rel->op) && is_distinct_set(sql, l, ad)) {
    1837        2873 :                                 rel = push_up_groupby(sql, rel, ad);
    1838        2873 :                                 return rel_unnest_dependent(sql, rel);
    1839             :                         }
    1840             : 
    1841        5999 :                         if (r && (is_join(r->op) || is_semi(r->op)) && is_distinct_set(sql, l, ad)) {
    1842         176 :                                 rel = push_up_join(sql, rel, ad);
    1843         176 :                                 return rel_unnest_dependent(sql, rel);
    1844             :                         }
    1845             : 
    1846        5823 :                         if (r && is_set(r->op) && !is_left(rel->op) && rel->op != op_anti && is_distinct_set(sql, l, ad)) {
    1847          41 :                                 rel = push_up_set(sql, rel, ad);
    1848          41 :                                 return rel_unnest_dependent(sql, rel);
    1849             :                         }
    1850             : 
    1851        5782 :                         if (r && is_munion(r->op) && !is_left(rel->op) && is_distinct_set(sql, l, ad)) {
    1852        1531 :                                 rel = push_up_munion(sql, rel, ad);
    1853        1531 :                                 return rel_unnest_dependent(sql, rel);
    1854             :                         }
    1855             : 
    1856        4251 :                         if (r && is_base(r->op)) {
    1857          23 :                                 rel = push_up_table(sql, rel); /* rewrite into cross apply */
    1858          23 :                                 return rel;
    1859             :                         }
    1860             : 
    1861             :                         /* fallback */
    1862        4228 :                         if (ad != NULL)
    1863        4228 :                                 rel = rel_general_unnest(sql, rel, ad);
    1864             : 
    1865             :                         /* no dependent variables */
    1866        4228 :                         reset_dependent(rel);
    1867        4228 :                         rel->r = rel_unnest_dependent(sql, rel->r);
    1868             :                 } else {
    1869           0 :                         rel->l = rel_unnest_dependent(sql, rel->l);
    1870           0 :                         rel->r = rel_unnest_dependent(sql, rel->r);
    1871             :                 }
    1872             :         } else {
    1873      629745 :                 if (rel && (is_simple_project(rel->op) || is_groupby(rel->op) || is_select(rel->op) || is_topn(rel->op) || is_sample(rel->op)))
    1874      308360 :                         rel->l = rel_unnest_dependent(sql, rel->l);
    1875             :                 else if (rel && (is_join(rel->op) || is_semi(rel->op) ||  is_set(rel->op) || is_modify(rel->op) || is_ddl(rel->op))) {
    1876      153415 :                         rel->l = rel_unnest_dependent(sql, rel->l);
    1877      153415 :                         rel->r = rel_unnest_dependent(sql, rel->r);
    1878             :                 } else if (rel && (is_munion(rel->op))) {
    1879       10428 :                         list *l = rel->l;
    1880       31284 :                         for (node *n = l->h; n; n = n->next)
    1881       20856 :                                 n->data = rel_unnest_dependent(sql, n->data);
    1882             :                 }
    1883             :         }
    1884             :         return nrel;
    1885             : }
    1886             : 
    1887             : static list * add_missing_project_exps(mvc *sql, sql_rel *rel, list *exps);
    1888             : 
    1889             : static sql_exp *
    1890       12161 : add_missing_project_exp(mvc *sql, sql_rel *rel, sql_exp *e)
    1891             : {
    1892       12161 :         if (is_freevar(e))
    1893             :                 return e;
    1894        8178 :         if (is_convert(e->type)) {
    1895          65 :                 e->l = add_missing_project_exp(sql, rel, e->l);
    1896        8113 :         } else if (is_compare(e->type)) {
    1897        4048 :                 if (e->flag == cmp_in || e->flag == cmp_notin) {
    1898           2 :                         e->l = add_missing_project_exp(sql, rel, e->l);
    1899           2 :                         e->r = add_missing_project_exps(sql, rel, e->r);
    1900        4046 :                 } else if (e->flag == cmp_or || e->flag == cmp_filter) {
    1901          42 :                         e->l = add_missing_project_exps(sql, rel, e->l);
    1902          42 :                         e->r = add_missing_project_exps(sql, rel, e->r);
    1903             :                 } else {
    1904        4004 :                         e->l = add_missing_project_exp(sql, rel, e->l);
    1905        4004 :                         e->r = add_missing_project_exp(sql, rel, e->r);
    1906        4004 :                         if (e->f)
    1907          11 :                                 e->f = add_missing_project_exp(sql, rel, e->f);
    1908             :                 }
    1909        4065 :         } else if (is_atom(e->type)) {
    1910         185 :                 if (is_values(e))
    1911           0 :                         e->f = add_missing_project_exps(sql, rel, e->f);
    1912         185 :                 return e;
    1913             :         }
    1914        3880 :         else if (!list_find_exp(rel->exps, e)) {
    1915        3796 :                 if (!e->alias.label)
    1916          39 :                         exp_label(sql->sa, e, ++sql->label);
    1917        3796 :                 append(rel->exps, e);
    1918        3796 :                 return exp_ref(sql, e);
    1919             :         }
    1920             :         return e;
    1921             : }
    1922             : 
    1923             : static list *
    1924        3989 : add_missing_project_exps(mvc *sql, sql_rel *rel, list *exps)
    1925             : {
    1926        3989 :         if (list_empty(exps))
    1927             :                 return exps;
    1928        8064 :         for(node *n = exps->h; n; n = n->next)
    1929        4075 :                 n->data = add_missing_project_exp(sql, rel, n->data);
    1930             :         return exps;
    1931             : }
    1932             : 
    1933             : static sql_rel *
    1934        4433 : push_up_select2(visitor *v, sql_rel *rel)
    1935             : {
    1936        4433 :         sql_rel *l = rel->l;
    1937        4433 :         sql_rel *r = rel->r;
    1938             : 
    1939             :         /* TODO make sure we do not have empty selects */
    1940        4433 :         if (is_simple_project(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) {
    1941        3903 :                 sql_rel *nl = rel_select(v->sql->sa, rel, NULL);
    1942        3903 :                 nl->exps = add_missing_project_exps(v->sql, rel, l->exps);
    1943        3903 :                 l->exps = NULL;
    1944        3903 :                 rel->l = rel_dup(l->l);
    1945        3903 :                 rel_destroy(l);
    1946        3903 :                 rel_bind_vars(v->sql, nl, nl->exps);
    1947        3903 :                 v->changes++;
    1948        3903 :                 return nl;
    1949             :         }
    1950         530 :         if (!is_single(rel) && is_innerjoin(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) {
    1951          22 :                 sql_rel *nl = rel_select(v->sql->sa, rel, NULL);
    1952          22 :                 nl->exps = l->exps;
    1953          22 :                 l->exps = NULL;
    1954          22 :                 rel->l = rel_dup(l->l);
    1955          22 :                 rel_destroy(l);
    1956          22 :                 rel_bind_vars(v->sql, nl, nl->exps);
    1957          22 :                 v->changes++;
    1958          22 :                 nl->l = push_up_select2(v, nl->l);
    1959          22 :                 return nl;
    1960             :         }
    1961         508 :         if (is_single(rel) && is_innerjoin(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) {
    1962           0 :                 if (rel->exps)
    1963           0 :                         rel->exps = list_merge(rel->exps, l->exps, NULL);
    1964             :                 else
    1965           0 :                         rel->exps = l->exps;
    1966           0 :                 l->exps = NULL;
    1967           0 :                 rel->l = rel_dup(l->l);
    1968           0 :                 rel_destroy(l);
    1969           0 :                 rel_bind_vars(v->sql, rel, rel->exps);
    1970           0 :                 v->changes++;
    1971           0 :                 rel = push_up_select2(v, rel);
    1972           0 :                 return rel;
    1973             :         }
    1974         508 :         if (!is_single(rel) && is_innerjoin(rel->op) && r && is_select(r->op) && exps_have_freevar(v->sql, r->exps) && !rel_is_ref(r)) {
    1975          13 :                 sql_rel *nr = rel_select(v->sql->sa, rel, NULL);
    1976          13 :                 nr->exps = r->exps;
    1977          13 :                 r->exps = NULL;
    1978          13 :                 rel->r = rel_dup(r->l);
    1979          13 :                 rel_destroy(r);
    1980          13 :                 rel_bind_vars(v->sql, nr, nr->exps);
    1981          13 :                 v->changes++;
    1982          13 :                 return nr;
    1983             :         }
    1984         495 :         if (is_single(rel) && is_innerjoin(rel->op) && r && is_select(r->op) && exps_have_freevar(v->sql, r->exps) && !rel_is_ref(r)) {
    1985           8 :                 if (rel->exps)
    1986           0 :                         rel->exps = list_merge(rel->exps, r->exps, NULL);
    1987             :                 else
    1988           8 :                         rel->exps = r->exps;
    1989           8 :                 r->exps = NULL;
    1990           8 :                 rel->r = rel_dup(r->l);
    1991           8 :                 rel_destroy(r);
    1992           8 :                 rel_bind_vars(v->sql, rel, rel->exps);
    1993           8 :                 v->changes++;
    1994           8 :                 return rel;
    1995             :         }
    1996         487 :         if (is_left(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) {
    1997          14 :                 sql_rel *nl = rel_select(v->sql->sa, rel, NULL);
    1998          14 :                 nl->exps = l->exps;
    1999          14 :                 l->exps = NULL;
    2000          14 :                 rel->l = rel_dup(l->l);
    2001          14 :                 rel_destroy(l);
    2002          14 :                 rel_bind_vars(v->sql, nl, nl->exps);
    2003          14 :                 v->changes++;
    2004          14 :                 nl->l = push_up_select2(v, nl->l);
    2005          14 :                 return nl;
    2006             :         }
    2007         473 :         if (is_left(rel->op) && r && is_select(r->op) && exps_have_freevar(v->sql, r->exps) && !rel_is_ref(r)) {
    2008         435 :                 if (rel->exps)
    2009          44 :                         rel->exps = list_merge(rel->exps, r->exps, NULL);
    2010             :                 else
    2011         391 :                         rel->exps = r->exps;
    2012         435 :                 r->exps = NULL;
    2013         435 :                 rel->r = rel_dup(r->l);
    2014         435 :                 rel_destroy(r);
    2015         435 :                 rel_bind_vars(v->sql, rel, rel->exps);
    2016         435 :                 v->changes++;
    2017         435 :                 return rel;
    2018             :         }
    2019          38 :         if (is_right(rel->op) && r && is_select(r->op) && exps_have_freevar(v->sql, r->exps) && !rel_is_ref(r)) {
    2020           1 :                 sql_rel *nr = rel_select(v->sql->sa, rel, NULL);
    2021           1 :                 nr->exps = r->exps;
    2022           1 :                 r->exps = NULL;
    2023           1 :                 rel->r = rel_dup(r->l);
    2024           1 :                 rel_destroy(r);
    2025           1 :                 rel_bind_vars(v->sql, nr, nr->exps);
    2026           1 :                 v->changes++;
    2027           1 :                 nr->l = push_up_select2(v, nr->l);
    2028           1 :                 return nr;
    2029             :         }
    2030          37 :         if (is_right(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) {
    2031           3 :                 if (rel->exps)
    2032           3 :                         rel->exps = list_merge(rel->exps, l->exps, NULL);
    2033             :                 else
    2034           0 :                         rel->exps = l->exps;
    2035           3 :                 l->exps = NULL;
    2036           3 :                 rel->l = rel_dup(l->l);
    2037           3 :                 rel_destroy(l);
    2038           3 :                 rel_bind_vars(v->sql, rel, rel->exps);
    2039           3 :                 v->changes++;
    2040           3 :                 return rel;
    2041             :         }
    2042             :         return rel;
    2043             : }
    2044             : 
    2045             : static sql_rel *
    2046     2153785 : _rel_unnest(visitor *v, sql_rel *rel)
    2047             : {
    2048     2153785 :         sql_rel *l = rel->l;
    2049     2153785 :         sql_rel *r = rel->r;
    2050             :         /* try to push select up */
    2051     2153785 :         if (!rel_is_ref(rel) && ((is_simple_project(rel->op) && !rel->r && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) ||
    2052     2133909 :             (is_join(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) ||
    2053     2133870 :             (is_join(rel->op) && r && is_select(r->op) && exps_have_freevar(v->sql, r->exps) && !rel_is_ref(r)))) {
    2054        4396 :                 rel = push_up_select2(v, rel);
    2055        4396 :                 if (rel && is_select(rel->op)) {
    2056        3953 :                         sql_rel *l = rel->l;
    2057        3953 :                         if (is_dependent(l)) {
    2058          18 :                                 rel->l = l = rel_unnest_dependent(v->sql, l);
    2059          18 :                                 v->changes++;
    2060             :                         }
    2061             :                 }
    2062             :         }
    2063     2153785 :         if (is_dependent(rel)) {
    2064        8997 :                 rel = rel_unnest_dependent(v->sql, rel);
    2065        8997 :                 v->changes++;
    2066             :         }
    2067     2153785 :         return rel;
    2068             : }
    2069             : 
    2070             : static void exp_reset_props(sql_rel *rel, sql_exp *e, bool setnil);
    2071             : 
    2072             : static void
    2073         114 : exps_reset_props(sql_rel *rel, list *exps, bool setnil)
    2074             : {
    2075         114 :         if (!list_empty(exps))
    2076         310 :                 for(node *n=exps->h; n; n=n->next)
    2077         196 :                         exp_reset_props(rel, n->data, setnil);
    2078         114 : }
    2079             : 
    2080             : static void
    2081       20804 : exp_reset_props(sql_rel *rel, sql_exp *e, bool setnil)
    2082             : {
    2083       20804 :         switch (e->type) {
    2084       18728 :         case e_column: {
    2085       18728 :                 if (setnil && (((is_right(rel->op) || is_full(rel->op)) && rel_find_exp(rel->l, e) != NULL) ||
    2086       14041 :                         ((is_left(rel->op) || is_full(rel->op)) && rel_find_exp(rel->r, e) != NULL)))
    2087       13948 :                         set_has_nil(e);
    2088             :         } break;
    2089          65 :         case e_convert: {
    2090          65 :                 exp_reset_props(rel, e->l, setnil);
    2091          65 :                 if (setnil && has_nil((sql_exp*)e->l))
    2092          30 :                         set_has_nil(e);
    2093             :         } break;
    2094          86 :         case e_func: {
    2095          86 :                 sql_subfunc *f = e->f;
    2096             : 
    2097          86 :                 exps_reset_props(rel, e->l, setnil);
    2098          86 :                 if (setnil && !f->func->semantics && e->l && have_nil(e->l))
    2099          16 :                         set_has_nil(e);
    2100             :         } break;
    2101           0 :         case e_aggr: {
    2102           0 :                 sql_subfunc *a = e->f;
    2103             : 
    2104           0 :                 exps_reset_props(rel, e->l, setnil);
    2105           0 :                 if (setnil && (a->func->s || strcmp(a->func->base.name, "count") != 0) && !a->func->semantics && !has_nil(e) && e->l && have_nil(e->l))
    2106           0 :                         set_has_nil(e);
    2107             :         } break;
    2108          59 :         case e_cmp: {
    2109          59 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
    2110          14 :                         exps_reset_props(rel, e->l, setnil);
    2111          14 :                         exps_reset_props(rel, e->r, setnil);
    2112          14 :                         if (setnil && (have_nil(e->l) || have_nil(e->r)))
    2113          14 :                                 set_has_nil(e);
    2114          45 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
    2115           0 :                         exp_reset_props(rel, e->l, setnil);
    2116           0 :                         exps_reset_props(rel, e->r, setnil);
    2117           0 :                         if (setnil && (has_nil((sql_exp*)e->l) || have_nil(e->r)))
    2118           0 :                                 set_has_nil(e);
    2119             :                 } else {
    2120          45 :                         exp_reset_props(rel, e->l, setnil);
    2121          45 :                         exp_reset_props(rel, e->r, setnil);
    2122          45 :                         if (e->f)
    2123           5 :                                 exp_reset_props(rel, e->f, setnil);
    2124          45 :                         if (setnil && !is_semantics(e) && (((sql_exp*)e->l) || has_nil((sql_exp*)e->r) || (e->f && has_nil((sql_exp*)e->f))))
    2125          39 :                                 set_has_nil(e);
    2126             :                 }
    2127             :         } break;
    2128             :         default:
    2129             :                 break;
    2130             :         }
    2131       20804 :         set_not_unique(e);
    2132       20804 : }
    2133             : 
    2134             : static sql_exp *
    2135       21032 : rewrite_inner(mvc *sql, sql_rel *rel, sql_rel *inner, operator_type op, sql_rel **rewrite)
    2136             : {
    2137       21032 :         int single = is_single(inner);
    2138       21032 :         sql_rel *d = NULL;
    2139             : 
    2140       21032 :         reset_single(inner);
    2141       21032 :         if (single && is_project(rel->op))
    2142       21032 :                 op = op_left;
    2143             : 
    2144       21032 :         if (is_join(rel->op)){
    2145           7 :                 if (rel_has_freevar(sql, inner)) {
    2146           0 :                         list *rv = rel_dependent_var(sql, rel->r, inner);
    2147           0 :                         if (!list_empty(rv))
    2148           0 :                                 d = rel->r = rel_crossproduct(sql->sa, rel->r, inner, op);
    2149             :                         else
    2150           0 :                                 d = rel->l = rel_crossproduct(sql->sa, rel->l, inner, op);
    2151           7 :                 } else if (is_right(rel->op))
    2152           4 :                         d = rel->l = rel_crossproduct(sql->sa, rel->l, inner, op);
    2153             :                 else
    2154           3 :                         d = rel->r = rel_crossproduct(sql->sa, rel->r, inner, op);
    2155           7 :                 if (single)
    2156           5 :                         set_single(d);
    2157           7 :                 set_processed(d);
    2158       21025 :         } else if (is_project(rel->op)){ /* projection -> op_left */
    2159       13429 :                 if (rel->l || single || op == op_left) {
    2160       13405 :                         if ((single || op == op_left) && !rel->l) {
    2161         539 :                                 sql_exp *e = exp_atom_bool(sql->sa, 1);
    2162         539 :                                 exp_label(sql->sa, e, ++sql->label);
    2163         539 :                                 rel->l = rel_project(sql->sa, rel->l, list_append(sa_list(sql->sa), e));
    2164             :                         }
    2165       13405 :                         d = rel->l = rel_crossproduct(sql->sa, rel->l, inner, op_left);
    2166       13405 :                         if (single)
    2167        1566 :                                 set_single(d);
    2168       13405 :                         set_processed(d);
    2169             :                 } else {
    2170          24 :                         d = rel->l = inner;
    2171             :                 }
    2172             :         } else {
    2173        7596 :                 d = rel->l = rel_crossproduct(sql->sa, rel->l, inner, op);
    2174        7596 :                 if (single)
    2175        1980 :                         set_single(d);
    2176        7596 :                 set_processed(d);
    2177             :         }
    2178       21032 :         assert(d);
    2179       21032 :         if (rel_has_freevar(sql, inner)) {
    2180        5580 :                 list *dv = rel_dependent_var(sql, d, inner);
    2181        5580 :                 list *fv = rel_freevar(sql, inner);
    2182             :                 /* check if the inner depends on the new join (d) or one level up */
    2183        5580 :                 if (list_length(dv))
    2184        5463 :                         set_dependent(d);
    2185        5580 :                 if (list_length(fv) != list_length(dv))
    2186         184 :                         set_dependent(rel);
    2187             :         }
    2188       21032 :         if (rewrite)
    2189       20390 :                 *rewrite = d;
    2190       21032 :         if (is_project(inner->op))
    2191       21024 :                 return inner->exps->t->data;
    2192             :         return NULL;
    2193             : }
    2194             : 
    2195             : static sql_exp *
    2196    10163593 : rewrite_exp_rel(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    2197             : {
    2198    10163593 :         if (exp_has_rel(e) && !is_ddl(rel->op)) {
    2199        9410 :                 sql_rel *rewrite = NULL;
    2200       13662 :                 sql_exp *ne = rewrite_inner(v->sql, rel, exp_rel_get_rel(v->sql->sa, e), depth?op_left:op_join, &rewrite);
    2201             : 
    2202        9410 :                 if (!ne)
    2203           1 :                         return ne;
    2204        9409 :                 if (exp_is_rel(e)) {
    2205        9409 :                         ne = exp_ref(v->sql, ne);
    2206        9409 :                         if (exp_name(e))
    2207        9409 :                                 exp_prop_alias(v->sql->sa, ne, e);
    2208        9409 :                         if (!exp_name(ne))
    2209           0 :                                 ne = exp_label(v->sql->sa, ne, ++v->sql->label);
    2210             :                         e = ne;
    2211             :                 } else {
    2212           0 :                         e = exp_rel_update_exp(v->sql, e, false);
    2213             :                 }
    2214        9409 :                 exp_reset_props(rewrite, e, is_left(rewrite->op));
    2215        9409 :                 v->changes++;
    2216             :         }
    2217             :         return e;
    2218             : }
    2219             : 
    2220             : /* add an dummy true projection column */
    2221             : static inline sql_rel *
    2222     2099841 : rewrite_empty_project(visitor *v, sql_rel *rel)
    2223             : {
    2224     2099841 :         if ((is_simple_project(rel->op) || is_groupby(rel->op)) && list_empty(rel->exps)) {
    2225          29 :                 sql_exp *e = exp_atom_bool(v->sql->sa, 1);
    2226             : 
    2227          29 :                 exp_label(v->sql->sa, e, ++v->sql->label);
    2228          29 :                 list_append(rel->exps, e);
    2229          29 :                 v->changes++;
    2230             :         }
    2231     2099858 :         return rel;
    2232             : }
    2233             : 
    2234             : /*
    2235             :  * For decimals and intervals we need to adjust the scale for some operations.
    2236             :  *
    2237             :  * TODO move the decimal scale handling to this function.
    2238             :  */
    2239             : #define is_division(sf) (strcmp(sf->func->base.name, "sql_div") == 0)
    2240             : #define is_multiplication(sf) (strcmp(sf->func->base.name, "sql_mul") == 0)
    2241             : 
    2242             : static inline sql_exp *
    2243    12587886 : exp_physical_types(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    2244             : {
    2245    12587886 :         (void)rel;
    2246    12587886 :         (void)depth;
    2247    12587886 :         sql_exp *ne = e;
    2248             : 
    2249    12587886 :         if (!e || (e->type != e_func && e->type != e_convert) || !e->l)
    2250             :                 return e;
    2251             : 
    2252      686620 :         if (e->type != e_convert) {
    2253      548694 :                 list *args = e->l;
    2254      548694 :                 sql_subfunc *f = e->f;
    2255             : 
    2256             :                 /* multiplication and division on decimals */
    2257      548694 :                 if (is_multiplication(f) && list_length(args) == 2) {
    2258       19856 :                         sql_exp *le = args->h->data;
    2259       19856 :                         sql_subtype *lt = exp_subtype(le);
    2260             : 
    2261       19856 :                         if (lt->type->eclass == EC_SEC || lt->type->eclass == EC_MONTH) {
    2262          49 :                                 sql_exp *re = args->h->next->data;
    2263          49 :                                 sql_subtype *rt = exp_subtype(re);
    2264             : 
    2265          49 :                                 if (rt->type->eclass == EC_DEC && rt->scale) {
    2266           7 :                                         int scale = (int) rt->scale; /* shift with scale */
    2267           7 :                                         sql_subtype *it = sql_bind_localtype(lt->type->impl);
    2268           7 :                                         sql_subfunc *c = sql_bind_func(v->sql, "sys", "scale_down", lt, it, F_FUNC, true, true);
    2269             : 
    2270           7 :                                         if (!c) {
    2271           0 :                                                 TRC_CRITICAL(SQL_PARSER, "scale_down missing (%s)\n", lt->type->impl);
    2272           0 :                                                 return NULL;
    2273             :                                         }
    2274             : #ifdef HAVE_HGE
    2275           7 :                                         hge val = scale2value(scale);
    2276             : #else
    2277             :                                         lng val = scale2value(scale);
    2278             : #endif
    2279           7 :                                         atom *a = atom_int(v->sql->sa, it, val);
    2280           7 :                                         ne = exp_binop(v->sql->sa, e, exp_atom(v->sql->sa, a), c);
    2281             :                                 }
    2282             :                         }
    2283      528838 :                 } else if (is_division(f) && list_length(args) == 2) {
    2284        2216 :                         sql_exp *le = args->h->data;
    2285        2216 :                         sql_subtype *lt = exp_subtype(le);
    2286             : 
    2287        2216 :                         if (lt->type->eclass == EC_SEC || lt->type->eclass == EC_MONTH) {
    2288          35 :                                 sql_exp *re = args->h->next->data;
    2289          35 :                                 sql_subtype *rt = exp_subtype(re);
    2290             : 
    2291          35 :                                 if (rt->type->eclass == EC_DEC && rt->scale) {
    2292          10 :                                         int scale = (int) rt->scale; /* shift with scale */
    2293             : #ifdef HAVE_HGE
    2294          10 :                                         hge val = scale2value(scale);
    2295             : #else
    2296             :                                         lng val = scale2value(scale);
    2297             : #endif
    2298             : 
    2299          10 :                                         if (lt->type->eclass == EC_SEC) {
    2300           5 :                                                 sql_subtype *it = sql_bind_localtype(lt->type->impl);
    2301           5 :                                                 sql_subfunc *c = sql_bind_func(v->sql, "sys", "scale_up", lt, it, F_FUNC, true, true);
    2302             : 
    2303           5 :                                                 if (!c) {
    2304           0 :                                                         TRC_CRITICAL(SQL_PARSER, "scale_up missing (%s)\n", lt->type->impl);
    2305           0 :                                                         return NULL;
    2306             :                                                 }
    2307           5 :                                                 atom *a = atom_int(v->sql->sa, it, val);
    2308           5 :                                                 ne = exp_binop(v->sql->sa, e, exp_atom(v->sql->sa, a), c);
    2309             :                                         } else { /* EC_MONTH */
    2310           5 :                                                 sql_subtype *it = sql_bind_localtype(rt->type->impl);
    2311           5 :                                                 sql_subfunc *c = sql_bind_func(v->sql, "sys", "scale_down", rt, it, F_FUNC, true, true);
    2312             : 
    2313           5 :                                                 if (!c) {
    2314           0 :                                                         TRC_CRITICAL(SQL_PARSER, "scale_down missing (%s)\n", lt->type->impl);
    2315           0 :                                                         return NULL;
    2316             :                                                 }
    2317           5 :                                                 atom *a = atom_int(v->sql->sa, it, val);
    2318           5 :                                                 args->h->next->data = exp_binop(v->sql->sa, args->h->next->data, exp_atom(v->sql->sa, a), c);
    2319             :                                         }
    2320             :                                 }
    2321             :                         }
    2322             :                 }
    2323             :         }
    2324      686620 :         if (ne != e) {
    2325          12 :                 if (exp_name(e))
    2326           1 :                         exp_prop_alias(v->sql->sa, ne, e);
    2327          12 :                 v->changes++;
    2328             :         }
    2329             :         return ne;
    2330             : }
    2331             : 
    2332             : static sql_exp *
    2333    12587901 : exp_reset_card_and_freevar_set_physical_type(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    2334             : {
    2335    12587901 :         if (e->type == e_func && e->r) /* mark as normal (analytic) function now */
    2336        6154 :                 e->r = NULL;
    2337    12587901 :         reset_freevar(e); /* unnesting is done, we can remove the freevar flag */
    2338             : 
    2339    12587901 :         if (!(e = exp_physical_types(v, rel, e, depth))) /* for decimals and intervals we need to adjust the scale for some operations */
    2340             :                 return NULL;
    2341    12588627 :         if (!rel->l)
    2342             :                 return e;
    2343             : 
    2344     9410632 :         switch(rel->op){
    2345     6321791 :         case op_select:
    2346             :         case op_join:
    2347             :         case op_left:
    2348             :         case op_right:
    2349             :         case op_full:
    2350             :         case op_semi:
    2351             :         case op_anti:
    2352             :         case op_project: {
    2353     6321791 :                 switch(e->type) {
    2354      476201 :                 case e_aggr:
    2355             :                 case e_func: {
    2356      476201 :                         e->card = list_empty(e->l)?rel?rel->card:(unsigned)CARD_MULTI:exps_card(e->l);
    2357      476201 :                 } break;
    2358     4292838 :                 case e_column: {
    2359     4292838 :                         sql_exp *le = NULL, *re = NULL;
    2360     4292838 :                         bool underjoinl = false, underjoinr = false;
    2361             : 
    2362     4292838 :                         le = rel_find_exp_and_corresponding_rel(rel->l, e, false, NULL, &underjoinl);
    2363     4292816 :                         if (!is_simple_project(rel->op) && !is_inter(rel->op) && !is_except(rel->op) && !is_semi(rel->op) && rel->r) {
    2364      504433 :                                 re = rel_find_exp_and_corresponding_rel(rel->r, e, false, NULL, &underjoinr);
    2365             :                                 /* if the expression is found under a join, the cardinality expands to multi */
    2366      504433 :                                 e->card = MAX(le?underjoinl?CARD_MULTI:le->card:CARD_ATOM, re?underjoinr?CARD_MULTI:re->card:CARD_ATOM);
    2367     3788383 :                         } else if (e->card == CARD_ATOM) { /* unnested columns vs atoms */
    2368      197562 :                                 e->card = le?underjoinl?CARD_MULTI:le->card:CARD_ATOM;
    2369             :                         } else { /* general case */
    2370     3590821 :                                 e->card = (le && !underjoinl)?le->card:CARD_MULTI;
    2371             :                         }
    2372     4292816 :                         } break;
    2373      110056 :                 case e_convert: {
    2374      110056 :                         e->card = exp_card(e->l);
    2375      110056 :                 } break;
    2376      553701 :                 case e_cmp: {
    2377      553701 :                         if (e->flag == cmp_or || e->flag == cmp_filter) {
    2378       22544 :                                 e->card = MAX(exps_card(e->l), exps_card(e->r));
    2379      531157 :                         } else if (e->flag == cmp_in || e->flag == cmp_notin) {
    2380       37831 :                                 e->card = MAX(exp_card(e->l), exps_card(e->r));
    2381             :                         } else {
    2382      493326 :                                 e->card = MAX(exp_card(e->l), exp_card(e->r));
    2383      493326 :                                 if (e->f)
    2384        4323 :                                         e->card = MAX(e->card, exp_card(e->f));
    2385             :                         }
    2386             :                 } break;
    2387             :                 case e_atom:
    2388             :                 case e_psm:
    2389             :                         break;
    2390             :                 }
    2391             :         } break;
    2392      247890 :         case op_inter:
    2393             :         case op_except:
    2394             :         case op_union:
    2395             :         case op_munion: {
    2396      247890 :                 e->card = CARD_MULTI;
    2397      247890 :         } break;
    2398      128923 :         case op_groupby: {
    2399      128923 :                 switch(e->type) {
    2400       37741 :                 case e_aggr:
    2401       37741 :                         e->card = rel->card;
    2402       37741 :                         break;
    2403       83799 :                 case e_column: {
    2404       83799 :                         if (e->card == CARD_ATOM) { /* unnested columns vs atoms */
    2405        4906 :                                 sql_exp *le = rel_find_exp(rel->l, e);
    2406             :                                 /* if it's from the left relation, it's either a constant or column, so set to min between le->card and aggr */
    2407        4906 :                                 e->card = le?MIN(le->card, CARD_AGGR):CARD_ATOM;
    2408             :                         } else {
    2409       78893 :                                 e->card = rel->card;
    2410             :                         }
    2411             :                 } break;
    2412             :                 default:
    2413             :                         break;
    2414             :                 }
    2415             :         } break;
    2416             :         default:
    2417             :                 break;
    2418             :         }
    2419     9410610 :         if (is_simple_project(rel->op) && need_distinct(rel)) /* Need distinct, all expressions should have CARD_AGGR at max */
    2420       61554 :                 e->card = MIN(e->card, CARD_AGGR);
    2421     9410610 :         if (!is_mset(rel->op) && (!is_groupby(rel->op) || !list_empty(rel->r))) /* global groupings have atomic cardinality */
    2422     9146590 :                 rel->card = MAX(e->card, rel->card); /* the relation cardinality may get updated too */
    2423             :         return e;
    2424             : }
    2425             : 
    2426             : static sql_exp *
    2427         158 : exp_set_type(mvc *sql, sql_exp *te, sql_exp *e)
    2428             : {
    2429         158 :         if (te->type == e_convert) {
    2430          14 :                 if (e->type == e_column)  {
    2431          14 :                                 int label = e->alias.label;
    2432          14 :                                 e = exp_convert(sql, e, exp_subtype(e), exp_subtype(te));
    2433          14 :                                 e->alias.label = label;
    2434             :                 } else {
    2435           0 :                         e->tpe = *exp_subtype(te);
    2436           0 :                         if (e->l)
    2437           0 :                                 e->l = atom_set_type(sql->sa, e->l, &e->tpe);
    2438             :                 }
    2439             :         }
    2440         158 :         return e;
    2441             : }
    2442             : 
    2443             : static sql_rel *
    2444     2774777 : rel_set_type(visitor *v, sql_rel *rel)
    2445             : {
    2446     2774777 :         if (is_project(rel->op) && rel->l) {
    2447      894974 :                 if (is_set(rel->op)) {
    2448        2919 :                         sql_rel *l = rel->l, *r = rel->r;
    2449        2919 :                         list *exps = l->exps;
    2450        5838 :                         while(exps) {
    2451       24230 :                                 for(node *n = exps->h, *m = rel->exps->h; n && m; n = n->next, m = m->next) {
    2452       18392 :                                         sql_exp *e = n->data;
    2453       18392 :                                         sql_subtype *t = exp_subtype(e);
    2454             : 
    2455       18392 :                                         if (t && !t->type->localtype)
    2456           6 :                                                 n->data = exp_set_type(v->sql, m->data, e);
    2457             :                                 }
    2458        5838 :                                 if (exps != r->exps)
    2459             :                                         exps = r->exps;
    2460             :                                 else
    2461             :                                         exps = NULL;
    2462             :                         }
    2463             :                 } else if (is_munion(rel->op)) {
    2464       80949 :                         list *l = rel->l;
    2465      243677 :                         for(node *m = l->h; m; m = m->next) {
    2466      162728 :                                 sql_rel *r = m->data;
    2467      162728 :                                 list *exps = r->exps;
    2468      653854 :                                 for(node *n = exps->h, *m = rel->exps->h; n && m; n = n->next, m = m->next) {
    2469      491126 :                                         sql_exp *e = n->data;
    2470      491126 :                                         sql_subtype *t = exp_subtype(e);
    2471             : 
    2472      491126 :                                         if (t && !t->type->localtype)
    2473         152 :                                                 n->data = exp_set_type(v->sql, m->data, e);
    2474             :                                 }
    2475             :                         }
    2476             :                 } else if ((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->l) {
    2477      811106 :                         list *exps = rel->exps;
    2478      849751 :                         while(exps) {
    2479     4419600 :                                 for(node *n = exps->h; n; n = n->next) {
    2480     3591730 :                                         sql_exp *te = n->data;
    2481     3591730 :                                         if (te->type == e_convert) {
    2482       60204 :                                                 sql_exp *l = te->l;
    2483       60204 :                                                 if (l->type == e_column) {
    2484       44516 :                                                         sql_rel *sl = rel->l;
    2485       44516 :                                                         sql_exp *e = rel_find_exp(sl, l);
    2486       44503 :                                                         if (!e)
    2487           0 :                                                                 continue;
    2488       44503 :                                                         if (is_groupby(sl->op) && exp_equal(e, l) == 0) {
    2489         789 :                                                                 sql_exp *e2 = list_find_exp(sl->r, l);
    2490         789 :                                                                 if (e2) {
    2491       44503 :                                                                         e = e2;
    2492             :                                                                 }
    2493             :                                                         }
    2494       44503 :                                                         sql_subtype *t = exp_subtype(e);
    2495             : 
    2496       44503 :                                                         if (t && !t->type->localtype) {
    2497         198 :                                                                 if (e && e->type == e_column) {
    2498          10 :                                                                         sql_rel *l = rel->l;
    2499          10 :                                                                         if (is_project(l->op)) {
    2500          26 :                                                                                 for(node *n = l->exps->h; n; n = n->next) {
    2501          26 :                                                                                         if (n->data == e) {
    2502          10 :                                                                                                 int label = e->alias.label;
    2503          10 :                                                                                                 n->data = e = exp_convert(v->sql, e, t, exp_subtype(te));
    2504          10 :                                                                                                 e->alias.label = label;
    2505          10 :                                                                                                 break;
    2506             :                                                                                         }
    2507             :                                                                                 }
    2508             :                                                                         }
    2509             :                                                                 } else {
    2510         188 :                                                                         e->tpe = *exp_subtype(te);
    2511         188 :                                                                         if (e->l && e->type == e_atom)
    2512         187 :                                                                                 e->l = atom_set_type(v->sql->sa, e->l, &e->tpe);
    2513             :                                                                 }
    2514             :                                                         }
    2515             :                                                 }
    2516     3531526 :                                         } else if (te->type == e_atom && !te->f) {
    2517      155526 :                                                 sql_subtype *t = exp_subtype(te);
    2518      155570 :                                                 if (t && !t->type->localtype) {
    2519         137 :                                                         te->tpe = *sql_bind_localtype("bte");
    2520         137 :                                                         if (te->l)
    2521         137 :                                                                 te->l = atom_set_type(v->sql->sa, te->l, &te->tpe);
    2522           8 :                                                 } else if (!t && !te->l && !te->r) { /* parameter, set type, or return ERR?? */
    2523           8 :                                                         sql_arg *a = sql_bind_paramnr(v->sql, te->flag);
    2524           8 :                                                         if (!a->type.type)
    2525           8 :                                                                 return sql_error(v->sql, 10, SQLSTATE(42000) "Could not determine type for argument number %d", te->flag+1);
    2526           0 :                                                         te->tpe = a->type;
    2527             :                                                 }
    2528             :                                         }
    2529             :                                 }
    2530      827870 :                                 if (is_groupby(rel->op) && exps != rel->r)
    2531             :                                         exps = rel->r;
    2532             :                                 else
    2533             :                                         exps = NULL;
    2534             :                         }
    2535             :                 }
    2536             :         }
    2537             :         return rel;
    2538             : }
    2539             : 
    2540             : static list*
    2541        4414 : aggrs_split_args(mvc *sql, list *aggrs, list *exps, int is_groupby_list)
    2542             : {
    2543        4414 :         bool clear_hash = false;
    2544             : 
    2545        4414 :         if (list_empty(aggrs))
    2546             :                 return aggrs;
    2547       18284 :         for (node *n=aggrs->h; n; n = n->next) {
    2548       14378 :                 sql_exp *a = n->data;
    2549             : 
    2550       14378 :                 if (is_func(a->type) && !is_groupby_list)
    2551          10 :                         continue;
    2552       14368 :                 if (!is_aggr(a->type)) {
    2553        9952 :                         sql_exp *e1 = a, *found = NULL;
    2554             : 
    2555       32008 :                         for (node *nn = exps->h; nn && !found; nn = nn->next) {
    2556       22056 :                                 sql_exp *e2 = nn->data;
    2557             : 
    2558       22056 :                                 if (is_referenced_by(e2, e1) || !exp_equal(e1, e2))
    2559             :                                         found = e2;
    2560             :                         }
    2561        9952 :                         if (!found) {
    2562        4976 :                                 if (!exp_name(e1))
    2563           0 :                                         e1 = exp_label(sql->sa, e1, ++sql->label);
    2564        4976 :                                 append(exps, e1);
    2565             :                         } else {
    2566             :                                 e1 = found;
    2567             :                         }
    2568        9952 :                         e1 = exp_ref(sql, e1);
    2569        9952 :                         n->data = e1; /* replace by reference */
    2570        9952 :                         clear_hash = true;
    2571        9952 :                         continue;
    2572             :                 }
    2573        4416 :                 list *args = a->l;
    2574        4416 :                 list *r = a->r;
    2575        4416 :                 node *rn = r?r->h:NULL;
    2576             : 
    2577        9476 :                 while(args) {
    2578        5060 :                         if (!list_empty(args)) {
    2579       12060 :                                 for (node *an = args->h; an; an = an->next) {
    2580        7000 :                                         sql_exp *e1 = an->data, *found = NULL, *eo = e1;
    2581             :                                         /* we keep converts as they reuse names of inner columns */
    2582        7000 :                                         int convert = is_convert(e1->type);
    2583             : 
    2584        7000 :                                         if (convert)
    2585          95 :                                                 e1 = e1->l;
    2586       36274 :                                         for (node *nn = exps->h; nn && !found; nn = nn->next) {
    2587       29274 :                                                 sql_exp *e2 = nn->data;
    2588             : 
    2589       29274 :                                                 if (!exp_equal(e1, e2))
    2590         309 :                                                         found = e2;
    2591             :                                         }
    2592        7000 :                                         if (!found) {
    2593        6691 :                                                 if (!e1->alias.label)
    2594        5541 :                                                         e1 = exp_label(sql->sa, e1, ++sql->label);
    2595        6691 :                                                 append(exps, e1);
    2596             :                                         } else {
    2597             :                                                 e1 = found;
    2598             :                                         }
    2599        7000 :                                         if (!e1->alias.label)
    2600           0 :                                                 e1 = exp_label(sql->sa, e1, ++sql->label);
    2601        7000 :                                         e1 = exp_ref(sql, e1);
    2602             :                                         /* replace by reference */
    2603        7000 :                                         if (convert) {
    2604          95 :                                                 eo->l = e1;
    2605             :                                         } else {
    2606        6905 :                                                 an->data = e1;
    2607        6905 :                                                 clear_hash = true;
    2608             :                                         }
    2609             :                                 }
    2610             :                         }
    2611        5060 :                         if (rn) {
    2612         946 :                                 args = rn->data;
    2613         946 :                                 rn = rn->next;
    2614             :                         } else {
    2615             :                                 args = NULL;
    2616             :                         }
    2617             :                 }
    2618             :         }
    2619        3906 :         if (clear_hash)
    2620        3852 :                 list_hash_clear(aggrs);
    2621             :         return aggrs;
    2622             : }
    2623             : 
    2624             : /* make sure e_func expressions don't appear on groupby expression lists */
    2625             : static sql_rel *
    2626        2207 : aggrs_split_funcs(mvc *sql, sql_rel *rel)
    2627             : {
    2628        2207 :         if (!list_empty(rel->exps)) {
    2629        2207 :                 list *projs = NULL;
    2630       11609 :                 for (node *n = rel->exps->h; n;) {
    2631        9402 :                         node *next = n->next;
    2632        9402 :                         sql_exp *e = n->data;
    2633             : 
    2634        9402 :                         if (e->type == e_func || exps_find_exp(projs, e)) {
    2635          10 :                                 if (!projs)
    2636          10 :                                         projs = sa_list(sql->sa);
    2637          10 :                                 list_append(projs, e);
    2638          10 :                                 list_remove_node(rel->exps, NULL, n);
    2639             :                         }
    2640             :                         n = next;
    2641             :                 }
    2642        2207 :                 if (!list_empty(projs)) {
    2643             :                         /* the grouping relation may have more than 1 reference, a replacement is needed */
    2644          10 :                         sql_rel *l = rel_dup_copy(sql->sa, rel);
    2645          10 :                         list *nexps = list_merge(rel_projections(sql, l, NULL, 1, 1), projs, NULL);
    2646          10 :                         rel = rel_inplace_project(sql->sa, rel, l, nexps);
    2647          10 :                         rel->card = exps_card(nexps);
    2648             :                 }
    2649             :         }
    2650        2207 :         return rel;
    2651             : }
    2652             : 
    2653             : static int
    2654       62028 : exps_complex(list *exps)
    2655             : {
    2656       62028 :         if (list_empty(exps))
    2657             :                 return 0;
    2658       50996 :         for(node *n = exps->h; n; n = n->next) {
    2659       30516 :                 sql_exp *e = n->data;
    2660             : 
    2661       30516 :                 if (e->type != e_column && e->type != e_atom)
    2662             :                         return 1;
    2663             :         }
    2664             :         return 0;
    2665             : }
    2666             : 
    2667             : static int
    2668       29189 : aggrs_complex(list *exps)
    2669             : {
    2670       29189 :         if (list_empty(exps))
    2671             :                 return 0;
    2672       72462 :         for(node *n = exps->h; n; n = n->next) {
    2673       45349 :                 sql_exp *e = n->data;
    2674             : 
    2675       45349 :                 if (e->type == e_func || (e->type == e_aggr && exps_complex(e->l)))
    2676        2076 :                         return 1;
    2677             :         }
    2678             :         return 0;
    2679             : }
    2680             : 
    2681             : /* simplify aggregates, ie push functions under the groupby relation */
    2682             : /* rel visitor */
    2683             : static inline sql_rel *
    2684     2100245 : rewrite_aggregates(visitor *v, sql_rel *rel)
    2685             : {
    2686     2100245 :         if (is_groupby(rel->op) && (exps_complex(rel->r) || aggrs_complex(rel->exps))) {
    2687        2207 :                 list *exps = sa_list(v->sql->sa);
    2688             : 
    2689        2207 :                 rel->r = aggrs_split_args(v->sql, rel->r, exps, 1);
    2690        2207 :                 rel->exps = aggrs_split_args(v->sql, rel->exps, exps, 0);
    2691        2207 :                 rel->l = rel_project(v->sql->sa, rel->l, exps);
    2692        2207 :                 rel = aggrs_split_funcs(v->sql, rel);
    2693        2207 :                 v->changes++;
    2694        2207 :                 return rel;
    2695             :         }
    2696             :         return rel;
    2697             : }
    2698             : 
    2699             : static inline sql_rel *
    2700     2099819 : rewrite_split_select_exps(visitor *v, sql_rel *rel)
    2701             : {
    2702     2099819 :         if (is_select(rel->op) && !list_empty(rel->exps)) {
    2703      151060 :                 int i = 0;
    2704      151060 :                 bool has_complex_exps = false, has_simple_exps = false, *complex_exps = SA_NEW_ARRAY(v->sql->ta, bool, list_length(rel->exps));
    2705             : 
    2706      320997 :                 for (node *n = rel->exps->h ; n ; n = n->next) {
    2707      169937 :                         sql_exp *e = n->data;
    2708             : 
    2709      169937 :                         if (exp_has_rel(e) || exp_has_freevar(v->sql, e)) {
    2710       14448 :                                 complex_exps[i] = true;
    2711       14448 :                                 has_complex_exps = true;
    2712             :                         } else {
    2713      155489 :                                 complex_exps[i] = false;
    2714      155489 :                                 has_simple_exps = true;
    2715             :                         }
    2716      169937 :                         i++;
    2717             :                 }
    2718             : 
    2719      151060 :                 if (has_complex_exps && has_simple_exps) {
    2720        2812 :                         sql_rel *nsel = rel_select_copy(v->sql->sa, rel->l, NULL);
    2721        2812 :                         rel->l = nsel;
    2722             : 
    2723        2812 :                         i = 0;
    2724        9139 :                         for (node *n = rel->exps->h ; n ; ) {
    2725        6327 :                                 node *nxt = n->next;
    2726             : 
    2727        6327 :                                 if (!complex_exps[i]) {
    2728        3375 :                                         rel_select_add_exp(v->sql->sa, nsel, n->data);
    2729        3375 :                                         list_remove_node(rel->exps, NULL, n);
    2730             :                                 }
    2731        6327 :                                 n = nxt;
    2732        6327 :                                 i++;
    2733             :                         }
    2734        2812 :                         set_processed(nsel);
    2735        2812 :                         v->changes++;
    2736             :                 }
    2737             :         }
    2738     2099819 :         return rel;
    2739             : }
    2740             : 
    2741             : static void /* replace diff arguments to avoid duplicate work. The arguments must be iterated in this order! */
    2742        8603 : diff_replace_arguments(mvc *sql, sql_exp *e, list *ordering, int *pos, int *i)
    2743             : {
    2744        8603 :         if (e->type == e_func && !strcmp(((sql_subfunc*)e->f)->func->base.name, "diff")) {
    2745        2682 :                 list *args = (list*)e->l;
    2746        2682 :                 sql_exp *first = args->h->data, *second = list_length(args) == 2 ? args->h->next->data : NULL;
    2747             : 
    2748        2682 :                 if (first->type == e_func && !strcmp(((sql_subfunc*)first->f)->func->base.name, "diff")) {
    2749          76 :                         diff_replace_arguments(sql, first, ordering, pos, i);
    2750             :                 } else {
    2751        2606 :                         sql_exp *ne = args->h->data = exp_ref(sql, list_fetch(ordering, pos[*i]));
    2752        2606 :                         set_descending(ne);
    2753        2606 :                         set_nulls_first(ne);
    2754        2606 :                         *i = *i + 1;
    2755             :                 }
    2756        2682 :                 if (second && second->type == e_func && !strcmp(((sql_subfunc*)second->f)->func->base.name, "diff")) {
    2757             :                         diff_replace_arguments(sql, second, ordering, pos, i);
    2758             :                 } else if (second) {
    2759          76 :                         sql_exp *ne = args->h->next->data = exp_ref(sql, list_fetch(ordering, pos[*i]));
    2760          76 :                         set_descending(ne);
    2761          76 :                         set_nulls_first(ne);
    2762          76 :                         *i = *i + 1;
    2763             :                 }
    2764             :         }
    2765        8603 : }
    2766             : 
    2767             : /* exp visitor */
    2768             : static inline sql_exp *
    2769     8384791 : rewrite_rank(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    2770             : {
    2771     8384791 :         sql_rel *rell = NULL;
    2772             : 
    2773     8384791 :         if (!is_simple_project(rel->op) || e->type != e_func || list_length(e->r) < 2 /* e->r means window function */)
    2774     8378637 :                 return e;
    2775             : 
    2776        6154 :         (void)depth;
    2777             :         /* ranks/window functions only exist in the projection */
    2778        6154 :         list *l = e->l, *r = e->r, *gbe = r->h->data, *obe = r->h->next->data;
    2779             : 
    2780        6154 :         int needed = (gbe || obe);
    2781        6154 :         if (l)
    2782       20449 :                 for (node *n = l->h; n && !needed; n = n->next) {
    2783       14295 :                         sql_exp *e = n->data;
    2784       14295 :                         needed = e->ref;
    2785             :                 }
    2786             : 
    2787        6154 :         if (needed) {
    2788        1734 :                 rell = rel->l = rel_project(v->sql->sa, rel->l, rel_projections(v->sql, rel->l, NULL, 1, 1));
    2789       11175 :                 for (node *n = l->h; n; n = n->next) {
    2790        9441 :                         sql_exp *e = n->data;
    2791             : 
    2792        9441 :                         if (e->ref) {
    2793         308 :                                 e->ref = 0;
    2794         308 :                                 append(rell->exps, e);
    2795         308 :                                 n->data = exp_ref(v->sql, e);
    2796             :                         }
    2797             :                 }
    2798             :         }
    2799             : 
    2800             :         /* The following array remembers the original positions of gbe and obe expressions to replace them in order later at diff_replace_arguments */
    2801        6154 :         if (gbe || obe) {
    2802        1678 :                 int gbeoffset = list_length(gbe), i = 0, added = 0;
    2803        1678 :                 int *pos = SA_NEW_ARRAY(v->sql->ta, int, gbeoffset + list_length(obe));
    2804        1678 :                 if (gbe)
    2805        2221 :                         for (i = 0 ; i < gbeoffset ; i++)
    2806        1126 :                                 pos[i] = i;
    2807             : 
    2808        1678 :                 if (gbe && obe) {
    2809         928 :                         gbe = list_merge(sa_list(v->sql->sa), gbe, (fdup)NULL); /* make sure the p->r is a different list than the gbe list */
    2810         928 :                         i = 0;
    2811        1875 :                         for(node *n = gbe->h ; n ; n = n->next) {
    2812         947 :                                 sql_exp *e = n->data;
    2813         947 :                                 set_partitioning(e);
    2814             :                         }
    2815        1878 :                         for(node *n = obe->h ; n ; n = n->next, i++) {
    2816         950 :                                 sql_exp *e1 = n->data;
    2817         950 :                                 bool found = false;
    2818         950 :                                 int j = 0;
    2819             : 
    2820        1636 :                                 for(node *nn = gbe->h ; nn ; nn = nn->next, j++) {
    2821        1009 :                                         sql_exp *e2 = nn->data;
    2822             :                                         /* the partition expression order should be the same as the one in the order by clause (if it's in there as well) */
    2823        1009 :                                         if (exp_match(e1, e2)) {
    2824         323 :                                                 if (is_ascending(e1))
    2825         221 :                                                         set_ascending(e2);
    2826             :                                                 else
    2827         102 :                                                         set_descending(e2);
    2828         323 :                                                 if (nulls_last(e1))
    2829         102 :                                                         set_nulls_last(e2);
    2830             :                                                 else
    2831         221 :                                                         set_nulls_first(e2);
    2832         323 :                                                 found = true;
    2833         323 :                                                 break;
    2834             :                                         }
    2835             :                                 }
    2836         950 :                                 if (!found) {
    2837         627 :                                         pos[gbeoffset + i] = gbeoffset + added;
    2838         627 :                                         added++;
    2839         627 :                                         append(gbe, e1);
    2840             :                                 } else {
    2841         323 :                                         pos[gbeoffset + i] = j;
    2842             :                                 }
    2843             :                         }
    2844         750 :                 } else if (obe) {
    2845         583 :                         assert(!gbe);
    2846         583 :                         i = 0;
    2847        1189 :                         for(node *n = obe->h ; n ; n = n->next, i++) {
    2848         606 :                                 sql_exp *oe = n->data;
    2849         606 :                                 if (!exps_find_exp(rell->exps, oe)) {
    2850          22 :                                         sql_exp *ne = exp_ref(v->sql, oe);
    2851             : 
    2852          22 :                                         if (is_ascending(oe))
    2853          20 :                                                 set_ascending(ne);
    2854          22 :                                         if (nulls_last(oe))
    2855           4 :                                                 set_nulls_last(ne);
    2856             :                                         /* disable sorting info (ie back to defaults) */
    2857          22 :                                         set_descending(oe);
    2858          22 :                                         set_nulls_first(oe);
    2859          22 :                                         n->data = ne;
    2860          22 :                                         append(rell->exps, oe);
    2861             :                                 }
    2862         606 :                                 pos[i] = i;
    2863             :                         }
    2864             :                         gbe = obe;
    2865             :                 }
    2866             : 
    2867        1678 :                 list *ordering = sa_list(v->sql->sa); /* add exps from gbe and obe as ordering expressions */
    2868        4037 :                 for(node *n = gbe->h ; n ; n = n->next) {
    2869        2359 :                         sql_exp *next = n->data;
    2870        2359 :                         sql_exp *found = exps_find_exp(rell->exps, next);
    2871        2429 :                         sql_exp *ref = exp_ref(v->sql, found ? found : next);
    2872             : 
    2873        2359 :                         if (is_partitioning(next))
    2874         947 :                                 set_partitioning(ref);
    2875        2359 :                         if (is_ascending(next))
    2876        1849 :                                 set_ascending(ref);
    2877        2359 :                         if (nulls_last(next))
    2878         515 :                                 set_nulls_last(ref);
    2879        2359 :                         set_descending(next);
    2880        2359 :                         set_nulls_first(next);
    2881        2359 :                         if (!found)
    2882          70 :                                 list_append(rell->exps, next);
    2883        2359 :                         list_append(ordering, ref);
    2884             :                 }
    2885        1678 :                 rell = rel_project(v->sql->sa, rell, rel_projections(v->sql, rell, NULL, 1, 1));
    2886        1678 :                 rell->r = ordering;
    2887        1678 :                 rel->l = rell;
    2888             : 
    2889             :                 /* remove obe argument, so this function won't be called again on this expression */
    2890        1678 :                 list_remove_node(r, NULL, r->t);
    2891             : 
    2892             :                 /* add project with rank */
    2893        1678 :                 rell = rel->l = rel_project(v->sql->sa, rel->l, rel_projections(v->sql, rell->l, NULL, 1, 1));
    2894        1678 :                 i = 0;
    2895             : 
    2896       10779 :                 for (node *n = l->h; n ; n = n->next) { /* replace the updated arguments */
    2897        9101 :                         sql_exp *e = n->data;
    2898             : 
    2899        9101 :                         if (e->type == e_func && !strcmp(((sql_subfunc*)e->f)->func->base.name, "window_bound"))
    2900         574 :                                 continue;
    2901        8527 :                         diff_replace_arguments(v->sql, e, ordering, pos, &i);
    2902             :                 }
    2903             : 
    2904        1678 :                 sql_exp *b1 = (sql_exp*) list_fetch(l, list_length(l) - 2); /* the 'window_bound' calls are added after the function arguments and frame type */
    2905        1678 :                 sql_exp *b2 = (sql_exp*) list_fetch(l, list_length(l) - 1);
    2906             : 
    2907        1678 :                 if (b1 && b1->type == e_func && !strcmp(((sql_subfunc*)b1->f)->func->base.name, "window_bound")) {
    2908         287 :                         list *ll = b1->l;
    2909         287 :                         rell = rel->l = rel_project(v->sql->sa, rell, rel_projections(v->sql, rell, NULL, 1, 1));
    2910             : 
    2911         287 :                         int pe_pos = list_length(l) - 5; /* append the new partition expression to the list of expressions */
    2912         287 :                         sql_exp *pe = (sql_exp*) list_fetch(l, pe_pos);
    2913         287 :                         list_append(rell->exps, pe);
    2914             : 
    2915         287 :                         if (list_length(ll) == 6) { /* update partition definition for window function input if that's the case */
    2916         186 :                                 ((list*)b1->l)->h->data = exp_ref(v->sql, pe);
    2917         186 :                                 ((list*)b2->l)->h->data = exp_ref(v->sql, pe);
    2918             :                         }
    2919         287 :                         i = 0; /* the partition may get a new reference, update it on the window function list of arguments as well */
    2920         686 :                         for (node *n = l->h; n ; n = n->next, i++) {
    2921         686 :                                 if (i == pe_pos) {
    2922         287 :                                         n->data = exp_ref(v->sql, pe);
    2923         287 :                                         break;
    2924             :                                 }
    2925             :                         }
    2926             : 
    2927         287 :                         sql_exp *frame_type = (sql_exp*) list_fetch(l, list_length(l) - 3);
    2928         287 :                         atom *a = frame_type->l;
    2929         287 :                         int nr = (int)atom_get_int(a);
    2930             : 
    2931         287 :                         if (nr == FRAME_RANGE && obe) { /* for range we pass the last order by column (otherwise it's either invalid or is a special case)*/
    2932         112 :                                 int oe_pos = list_length(ll) - 5;
    2933         112 :                                 sql_exp *oe = (sql_exp*) list_fetch(ll, oe_pos);
    2934         112 :                                 if (oe->type != e_column && oe->type != e_atom) {
    2935           4 :                                         sql_exp *common  = list_fetch(ordering, pos[gbeoffset + list_length(obe) - 1]);
    2936             : 
    2937           4 :                                         if (list_length(ll) == 5) {
    2938           2 :                                                 ((list*)b1->l)->h->data = exp_ref(v->sql, common);
    2939           2 :                                                 ((list*)b2->l)->h->data = exp_ref(v->sql, common);
    2940             :                                         } else {
    2941           2 :                                                 ((list*)b1->l)->h->next->data = exp_ref(v->sql, common);
    2942           2 :                                                 ((list*)b2->l)->h->next->data = exp_ref(v->sql, common);
    2943             :                                         }
    2944             :                                 }
    2945         175 :                         } else if (nr == FRAME_ROWS || nr == FRAME_GROUPS) {
    2946         161 :                                 int oe_pos = list_length(l) - 4; /* for groups and rows, we push the ordering diff call, reference it back */
    2947             :                                 /* now this is the tricky, part, the ordering expression, may be a column, or any projection, only the later requires the push down */
    2948         161 :                                 sql_exp *oe = (sql_exp*) list_fetch(l, oe_pos);
    2949         161 :                                 if (oe->type != e_column && oe->type != e_atom) {
    2950         152 :                                         list_append(rell->exps, oe);
    2951             : 
    2952         152 :                                         if (list_length(ll) == 5) {
    2953          38 :                                                 ((list*)b1->l)->h->data = exp_ref(v->sql, oe);
    2954          38 :                                                 ((list*)b2->l)->h->data = exp_ref(v->sql, oe);
    2955             :                                         } else {
    2956         114 :                                                 ((list*)b1->l)->h->next->data = exp_ref(v->sql, oe);
    2957         114 :                                                 ((list*)b2->l)->h->next->data = exp_ref(v->sql, oe);
    2958             :                                         }
    2959             :                                 }
    2960             :                         }
    2961             :                 }
    2962             : 
    2963             :                 /* move rank down add ref */
    2964        1678 :                 if (!exp_name(e))
    2965        1016 :                         e = exp_label(v->sql->sa, e, ++v->sql->label);
    2966        1678 :                 append(rell->exps, e);
    2967        1678 :                 e = exp_ref(v->sql, e);
    2968        1678 :                 v->changes++;
    2969             :         } else {
    2970             :                 /* remove obe argument, so this function won't be called again on this expression */
    2971        4476 :                 list_remove_node(r, NULL, r->t);
    2972        4476 :                 v->changes++;
    2973             :         }
    2974             :         return e;
    2975             : }
    2976             : 
    2977             : static sql_rel *
    2978        7030 : rel_union_exps(mvc *sql, sql_exp **l, list *vals, int is_tuple)
    2979             : {
    2980        7030 :         sql_rel *u = NULL;
    2981        7030 :         list *exps = NULL;
    2982             : 
    2983        7030 :         if (mvc_highwater(sql))
    2984           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    2985             : 
    2986       14088 :         for (node *n=vals->h; n; n = n->next) {
    2987        7058 :                 sql_exp *ve = n->data, *r, *s;
    2988        7058 :                 sql_rel *sq = NULL;
    2989        7058 :                 int freevar = 0;
    2990             : 
    2991        7058 :                 exp_label(sql->sa, ve, ++sql->label); /* an alias is needed */
    2992        7058 :                 if (exp_has_rel(ve)) {
    2993        7003 :                         sq = exp_rel_get_rel(sql->sa, ve); /* get subquery */
    2994             :                 } else {
    2995          55 :                         sq = rel_project(sql->sa, NULL, append(sa_list(sql->sa), ve));
    2996          55 :                         if (!exp_is_atom(ve))
    2997          20 :                                 freevar = 1;
    2998          55 :                         set_processed(sq);
    2999             :                 }
    3000        7058 :                 if (is_tuple) { /* cast each one */
    3001        5811 :                         for (node *m=sq->exps->h, *o = ((list *)(*l)->f)->h; m && o; m = m->next, o = o->next) {
    3002        4052 :                                 r = m->data;
    3003        4052 :                                 s = o->data;
    3004        4052 :                                 if (rel_convert_types(sql, NULL, NULL, &s, &r, 1, type_equal) < 0)
    3005           0 :                                         return NULL;
    3006        4052 :                                 m->data = r;
    3007             :                         }
    3008             :                 } else {
    3009        5299 :                         sq->nrcols = list_length(sq->exps);
    3010             :                         /* union a project[(values(a),..,(b),(c)]  with freevars */
    3011        5299 :                         if (sq->card > CARD_ATOM && rel_has_freevar(sql, sq) && is_project(sq->op) &&
    3012         110 :                                 !sq->l && sq->nrcols == 1 && is_values((sql_exp*)sq->exps->h->data)) {
    3013             :                                 /* needs check on projection */
    3014           0 :                                 sql_exp *vals = sq->exps->h->data;
    3015           0 :                                 if (!(sq = rel_union_exps(sql, l, exp_get_values(vals), is_tuple)))
    3016             :                                         return NULL;
    3017             :                         } else {
    3018        5299 :                                 if (rel_convert_types(sql, NULL, NULL, l, &ve, 1, type_equal) < 0)
    3019             :                                         return NULL;
    3020             :                                 /* flatten expressions */
    3021        5299 :                                 if (exp_has_rel(ve)) {
    3022        5244 :                                         ve = exp_rel_update_exp(sql, ve, false);
    3023        5244 :                                         sq = rel_project(sql->sa, sq, append(sa_list(sql->sa), ve));
    3024        5244 :                                         set_processed(sq);
    3025             :                                 }
    3026        5299 :                                 if (freevar)
    3027          20 :                                         exp_set_freevar(sql, ve, sq);
    3028             :                         }
    3029             :                 }
    3030        7058 :                 if (!u) {
    3031             :                         u = sq;
    3032             :                 } else {
    3033          28 :                         list *urs = sa_list(sql->sa);
    3034          28 :                         urs = append(urs, u);
    3035          28 :                         urs = append(urs, sq);
    3036          28 :                         u = rel_setop_n_ary(sql->sa, urs, op_munion);
    3037          28 :                         rel_setop_n_ary_set_exps(sql, u, exps, false);
    3038          28 :                         set_distinct(u);
    3039          28 :                         set_processed(u);
    3040             :                 }
    3041        7058 :                 exps = rel_projections(sql, sq, NULL, 1/*keep names */, 1);
    3042             :         }
    3043             :         return u;
    3044             : }
    3045             : 
    3046             : static sql_exp *
    3047       10157 : exp_in_project(mvc *sql, sql_exp **l, list *vals, int anyequal)
    3048             : {
    3049       10157 :         sql_exp *e = NULL;
    3050             : 
    3051       65265 :         for(node *n=vals->h; n; n = n->next) {
    3052       55108 :                 sql_exp *r = n->data, *ne;
    3053             : 
    3054       55108 :                 if (rel_convert_types(sql, NULL, NULL, l, &r, 1, type_equal_no_any) < 0)
    3055           0 :                         return NULL;
    3056       55108 :                 if (anyequal)
    3057       54903 :                         ne = rel_binop_(sql, NULL, *l, r, "sys", "=", card_value, true);
    3058             :                 else
    3059         205 :                         ne = rel_binop_(sql, NULL, *l, r, "sys", "<>", card_value, true);
    3060       55108 :                 if (!e) {
    3061             :                         e = ne;
    3062       44951 :                 } else if (anyequal) {
    3063       44844 :                         e = rel_binop_(sql, NULL, e, ne, "sys", "or", card_value, true);
    3064             :                 } else {
    3065         107 :                         e = rel_binop_(sql, NULL, e, ne, "sys", "and", card_value, true);
    3066             :                 }
    3067             :         }
    3068             :         return e;
    3069             : }
    3070             : 
    3071             : static sql_exp *
    3072          73 : exp_in_compare(mvc *sql, sql_exp **l, list *vals, int anyequal)
    3073             : {
    3074          73 :         int vals_only = 1;
    3075             : 
    3076         239 :         for(node *n=vals->h; n; n = n->next) {
    3077         166 :                 sql_exp *r = n->data;
    3078             : 
    3079         166 :                 if (rel_convert_types(sql, NULL, NULL, l, &r, 1, type_equal_no_any) < 0)
    3080           0 :                         return NULL;
    3081         166 :                 n->data = r;
    3082         166 :                 if (!exp_is_atom(r))
    3083         123 :                         vals_only = 0;
    3084             :         }
    3085          73 :         if (vals_only)
    3086           5 :                 return exp_in(sql->sa, *l, vals, anyequal?cmp_in:cmp_notin);
    3087             : 
    3088          70 :         if (!(*l = exp_in_project(sql, l, vals, anyequal)))
    3089             :                 return NULL;
    3090          70 :         return exp_compare(sql->sa, *l, exp_atom_bool(sql->sa, 1), cmp_equal);
    3091             : }
    3092             : 
    3093             : /* exp visitor */
    3094             : static inline sql_exp *
    3095      399609 : rewrite_anyequal(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    3096             : {
    3097      399609 :         assert(e->type == e_func);
    3098             : 
    3099      399609 :         sql_subfunc *sf = e->f;
    3100      399609 :         if (is_ddl(rel->op))
    3101             :                 return e;
    3102      326202 :         if (is_anyequal_func(sf) && !list_empty(e->l)) {
    3103       17191 :                 list *l = e->l;
    3104       17191 :                 mvc *sql = v->sql;
    3105             : 
    3106       17191 :                 if (list_length(l) == 2) { /* input is a set */
    3107             : 
    3108       17191 :                         sql_exp *ile = l->h->data, *le, *re = l->h->next->data;
    3109       17191 :                         sql_rel *lsq = NULL, *rsq = NULL;
    3110       17191 :                         int is_tuple = 0;
    3111             : 
    3112       17191 :                         if (exp_has_rel(ile))
    3113          43 :                                 lsq = exp_rel_get_rel(sql->sa, ile); /* get subquery */
    3114             : 
    3115          43 :                         if (lsq)
    3116          43 :                                 le = exp_rel_update_exp(sql, ile, false);
    3117             :                         else
    3118       17148 :                                 le = ile;
    3119             : 
    3120       17191 :                         if (is_values(le)) /* exp_values */
    3121       17191 :                                 is_tuple = 1;
    3122             : 
    3123             :                         /* re should be a values list */
    3124       17191 :                         if (!lsq && !is_tuple && is_values(re) && !exps_have_rel_exp(re->f)) { /* exp_values */
    3125       10160 :                                 list *vals = re->f;
    3126             : 
    3127       10160 :                                 rel_bind_var(sql, rel->l, le);
    3128       10160 :                                 rel_bind_vars(sql, rel->l, vals);
    3129       10160 :                                 if (depth == 0 && is_select(rel->op)) {
    3130          73 :                                         v->changes++;
    3131          73 :                                         return exp_in_compare(sql, &le, vals, is_anyequal(sf));
    3132             :                                 } else {
    3133       10087 :                                         le = exp_in_project(sql, &le, vals, is_anyequal(sf));
    3134       10087 :                                         if (le && exp_name(e))
    3135         634 :                                                 exp_prop_alias(sql->sa, le, e);
    3136       10087 :                                         v->changes++;
    3137       10087 :                                         return le;
    3138             :                                 }
    3139        7031 :                         } else if (!lsq && !exps_have_rel_exp(re->f) && !is_tuple) {
    3140             :                                 return e; /* leave as is, handled later */
    3141        6988 :                         } else if (!lsq && re->f && !exps_have_rel_exp(re->f) && exps_are_atoms(re->f) && is_tuple) {
    3142           1 :                                 return exp_in(sql->sa, le, re->f, is_anyequal(sf) ? cmp_in : cmp_notin);
    3143             :                         }
    3144             : 
    3145        7030 :                         if (is_atom(re->type) && re->f) { /* exp_values */
    3146             :                                 /* flatten using unions */
    3147        7030 :                                 rsq = rel_union_exps(sql, &le, re->f, is_tuple);
    3148        7030 :                                 if (!rsq)
    3149             :                                         return NULL;
    3150        7030 :                                 if (!is_tuple) {
    3151        5271 :                                         re = rsq->exps->t->data;
    3152             : 
    3153        5271 :                                         if (!is_tuple && is_func(re->type))
    3154           3 :                                                 depth++;
    3155             : 
    3156        5271 :                                         if (rsq && lsq)
    3157          42 :                                                 exp_set_freevar(sql, re, rsq);
    3158        5271 :                                         if (!is_tuple && !is_freevar(re)) {
    3159        5263 :                                                 assert(re->alias.label);
    3160        5263 :                                                 list_hash_clear(rsq->exps);
    3161        5263 :                                                 re = exp_ref(sql, re);
    3162           8 :                                         } else if (has_label(re)) {
    3163           8 :                                                 re = exp_ref(sql, re);
    3164             :                                         }
    3165             :                                 }
    3166        7030 :                                 set_processed(rsq);
    3167             :                         }
    3168             : 
    3169        7030 :                         if (is_project(rel->op) || ((is_select(rel->op) || is_outerjoin(rel->op)) && depth > 0)) {
    3170             :                                 /* we introduced extra selects */
    3171        2620 :                                 assert(is_project(rel->op) || is_select(rel->op) || is_outerjoin(rel->op));
    3172             : 
    3173        2620 :                                 sql_rel *join = NULL;
    3174        2620 :                                 if (lsq) {
    3175          33 :                                         sql_rel *rewrite = NULL;
    3176          33 :                                         (void)rewrite_inner(sql, rel, lsq, op_left, &rewrite);
    3177          33 :                                         exp_reset_props(rewrite, le, is_left(rewrite->op));
    3178          33 :                                         join = (is_full(rel->op)||is_left(rel->op))?rel->r:rel->l;
    3179             :                                 }
    3180        2620 :                                 if (rsq) {
    3181        2620 :                                         (void)rewrite_inner(sql, rel, rsq, op_left, &join);
    3182        2620 :                                         exp_reset_props(join, re, is_left(join->op));
    3183             :                                 }
    3184        2620 :                                 assert(join && is_join(join->op));
    3185        2620 :                                 if (join && !join->exps)
    3186        2620 :                                         join->exps = sa_list(sql->sa);
    3187        2620 :                                 bool use_any = 0;
    3188        2620 :                                 if (is_tuple) {
    3189           5 :                                         list *t = le->f;
    3190           5 :                                         int s1 = list_length(t), s2 = rsq?list_length(rsq->exps):0;
    3191             : 
    3192             :                                         /* find out list of right expression */
    3193           5 :                                         if (s1 != s2)
    3194           0 :                                                 return sql_error(sql, 02, SQLSTATE(42000) "Subquery has too %s columns", (s2 < s1) ? "few" : "many");
    3195          15 :                                         for (node *n = t->h, *m = rsq->exps->h; n && m; n = n->next, m = m->next ) {
    3196          10 :                                                 sql_exp *le = n->data;
    3197          10 :                                                 sql_exp *re = m->data;
    3198             : 
    3199          10 :                                                 re = exp_ref(sql, re);
    3200             : 
    3201          10 :                                                 sql_exp *inexp = exp_compare(v->sql->sa, le, re, cmp_equal);
    3202          10 :                                                 if (inexp)
    3203          10 :                                                         set_any(inexp);
    3204          10 :                                                 append(join->exps, inexp);
    3205             :                                         }
    3206           5 :                                         return sql_error(sql, 02, SQLSTATE(42000) "Tuple matching at projections not implemented in the backend yet");
    3207             :                                 } else {
    3208        2615 :                                         use_any = true;
    3209        2615 :                                         sql_exp *inexp = exp_compare(v->sql->sa, le, re, cmp_equal);
    3210        2615 :                                         if (inexp)
    3211        2615 :                                                 set_any(inexp);
    3212        2615 :                                         exp_set_freevar(sql, le, join);
    3213        2615 :                                         rel_bind_var(sql, join, inexp);
    3214        2615 :                                         append(join->exps, inexp);
    3215        2615 :                                         if (exp_has_freevar(v->sql, inexp) && is_join(rel->op))
    3216           0 :                                                 set_dependent(rel);
    3217             :                                 }
    3218        2615 :                                 v->changes++;
    3219        2615 :                                 if (join) {
    3220        2615 :                                         if (!join->attr)
    3221        2615 :                                                 join->attr = sa_list(sql->sa);
    3222        2615 :                                         sql_exp *a = exp_atom_bool(v->sql->sa, !use_any?1:is_anyequal(sf));
    3223        2615 :                                         if (!e->alias.label)
    3224        2575 :                                                 a = exp_label(v->sql->sa, a, ++v->sql->label); /* unique name */
    3225             :                                         else
    3226          40 :                                                 exp_setalias(a, e->alias.label, exp_relname(e), exp_name(e));
    3227        2615 :                                         re = exp_ref(sql, a);
    3228        2615 :                                         set_has_nil(re); /* outerjoins could have introduced nils */
    3229        2615 :                                         re->card = CARD_MULTI; /* mark as multi value, the real attribute is introduced later */
    3230        2615 :                                         append(join->attr, a);
    3231        2615 :                                         assert(is_project(rel->op) || depth);
    3232        2615 :                                         if ((is_project(rel->op) || depth))
    3233             :                                                 return re;
    3234             :                                 }
    3235           0 :                                 set_has_nil(le); /* outer joins could have introduced nils */
    3236           0 :                                 set_has_nil(re); /* outer joins could have introduced nils */
    3237           0 :                                 return exp_compare(v->sql->sa, le, re, is_anyequal(sf)?cmp_equal:cmp_notequal);
    3238             :                         } else {
    3239        4410 :                                 sql_rel *rewrite = NULL;
    3240        4410 :                                 if (lsq) {
    3241          18 :                                         (void)rewrite_inner(sql, rel, lsq, rel->card<=CARD_ATOM?op_left:op_join, &rewrite);
    3242          10 :                                         exp_reset_props(rewrite, le, is_left(rewrite->op));
    3243             :                                 }
    3244        4410 :                                 if (rsq) {
    3245        4410 :                                         operator_type op = is_anyequal(sf)?op_semi:op_anti;
    3246        4410 :                                         (void)rewrite_inner(sql, rel, rsq, op, &rewrite);
    3247        4410 :                                         exp_reset_props(rewrite, re, is_left(rewrite->op));
    3248             :                                 }
    3249        4410 :                                 if (!rewrite)
    3250             :                                         return NULL;
    3251        4410 :                                 if (is_tuple) {
    3252        1754 :                                         list *t = le->f;
    3253        1754 :                                         int s1 = list_length(t), s2 = list_length(rsq->exps);
    3254             : 
    3255             :                                         /* find out list of right expression */
    3256        1754 :                                         if (s1 != s2)
    3257           0 :                                                 return sql_error(sql, 02, SQLSTATE(42000) "Subquery has too %s columns", (s2 < s1) ? "few" : "many");
    3258        1754 :                                         if (!rewrite->exps)
    3259        1754 :                                                 rewrite->exps = sa_list(sql->sa);
    3260        5796 :                                         for (node *n = t->h, *m = rsq->exps->h; n && m; n = n->next, m = m->next )
    3261        4042 :                                                 append(rewrite->exps, exp_compare(sql->sa, n->data, exp_ref(sql, m->data), cmp_equal));
    3262        1754 :                                         v->changes++;
    3263        1754 :                                         return exp_atom_bool(sql->sa, 1);
    3264             :                                 } else {
    3265        2656 :                                         if (exp_has_freevar(sql, le))
    3266           1 :                                                 rel_bind_var(sql, rel, le);
    3267        2656 :                                         if (!rewrite)
    3268             :                                                 return NULL;
    3269        2656 :                                         if (!rewrite->exps)
    3270        2656 :                                                 rewrite->exps = sa_list(sql->sa);
    3271        2656 :                                         append(rewrite->exps, exp_compare(sql->sa, le, exp_ref(sql, re), cmp_equal));
    3272        2656 :                                         v->changes++;
    3273        2656 :                                         return exp_atom_bool(sql->sa, 1);
    3274             :                                 }
    3275             :                         }
    3276             :                 }
    3277             :         }
    3278             :         return e;
    3279             : }
    3280             : 
    3281             : /* exp visitor */
    3282             : /* rewrite compare expressions including quantifiers any and all */
    3283             : static inline sql_exp *
    3284      381103 : rewrite_compare(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    3285             : {
    3286      381103 :         assert(e->type == e_func);
    3287             : 
    3288      381103 :         if (is_ddl(rel->op))
    3289             :                 return e;
    3290             : 
    3291      307701 :         sql_subfunc *sf = e->f;
    3292      307701 :         if (is_compare_func(sf) && !list_empty(e->l)) {
    3293       34676 :                 list *l = e->l;
    3294             : 
    3295             :                 /* TODO handle range expressions */
    3296       34676 :                 if (list_length(l) == 2) { /* input is a set */
    3297       34676 :                         char *op = sf->func->base.name;
    3298             : 
    3299       34676 :                         sql_exp *ile = l->h->data, *le, *re = l->h->next->data, *rnull = NULL;
    3300       34676 :                         sql_rel *lsq = NULL, *rsq = NULL;
    3301       34676 :                         int is_tuple = 0; /* TODO add this feature, ie select (1,2) = (1,2) etc */
    3302             :                                          /* cleanup tuple handling by introducing an expression for tuples */
    3303       34676 :                         int quantifier = e->flag;
    3304             : 
    3305             :                         /* possibly this is already done ? */
    3306       34676 :                         if (exp_has_rel(ile)) {
    3307          60 :                                 depth += exp_rel_depth(ile);
    3308          60 :                                 lsq = exp_rel_get_rel(v->sql->sa, ile); /* get subquery */
    3309             :                         }
    3310             : 
    3311          60 :                         if (lsq)
    3312          60 :                                 le = exp_rel_update_exp(v->sql, ile, false);
    3313             :                         else
    3314       34616 :                                 le = ile;
    3315             : 
    3316       34676 :                         if (exp_has_rel(re))
    3317        3203 :                                 rsq = exp_rel_get_rel(v->sql->sa, re); /* get subquery */
    3318        3203 :                         if (rsq) {
    3319        3203 :                                 if (!lsq && is_simple_project(rsq->op) && !rsq->l) {
    3320          11 :                                         sql_exp *ire = rsq->exps->h->data;
    3321          11 :                                         if (is_values(ire) && list_length(ire->f) == 1 && !is_values(le)) {
    3322           0 :                                                 list *exps = ire->f;
    3323           0 :                                                 re = exps->h->data;
    3324           0 :                                                 rsq = exp_rel_get_rel(v->sql->sa, re);
    3325             :                                         }
    3326             :                                 }
    3327          29 :                                 if (rsq)
    3328        3203 :                                         re = exp_rel_update_exp(v->sql, re, false);
    3329             :                         }
    3330             : 
    3331       34676 :                         if (is_values(le)) /* exp_values */
    3332       34676 :                                 is_tuple = 1;
    3333             : 
    3334       34676 :                         if (!is_tuple && !lsq && !rsq) { /* trivial case, just re-write into a comparison */
    3335       31437 :                                 e->flag = 0; /* remove quantifier */
    3336             : 
    3337       31437 :                                 if (rel_convert_types(v->sql, NULL, NULL, &le, &re, 1, type_equal) < 0)
    3338             :                                         return NULL;
    3339       31437 :                                 if (depth == 0 && is_select(rel->op)) {
    3340           1 :                                         v->changes++;
    3341           1 :                                         return exp_compare(v->sql->sa, le, re, compare_str2type(op));
    3342             :                                 } else {
    3343             :                                         return e;
    3344             :                                         /*
    3345             :                                         le = exp_compare_func(v->sql, le, re, op, 0);
    3346             :                                         if (exp_name(e))
    3347             :                                                 exp_prop_alias(v->sql->sa, le, e);
    3348             :                                         v->changes++;
    3349             :                                         return le;
    3350             :                                         */
    3351             :                                 }
    3352             :                         }
    3353        3239 :                         if (!is_tuple && is_values(re) && !exps_have_rel_exp(re->f)) { /* exp_values */
    3354           0 :                                 list *vals = re->f;
    3355             : 
    3356           0 :                                 if (depth == 0 && is_select(rel->op)) {
    3357           0 :                                         v->changes++;
    3358           0 :                                         return exp_in_compare(v->sql, &le, vals, is_anyequal(sf));
    3359             :                                 } else {
    3360           0 :                                         le = exp_in_project(v->sql, &le, vals, is_anyequal(sf));
    3361           0 :                                         if (le && exp_name(e))
    3362           0 :                                                 exp_prop_alias(v->sql->sa, le, e);
    3363           0 :                                         v->changes++;
    3364           0 :                                         return le;
    3365             :                                 }
    3366             :                         }
    3367             : 
    3368        3239 :                         if (is_values(re)) { /* exp_values */
    3369             :                                 /* flatten using unions */
    3370           0 :                                 rsq = rel_union_exps(v->sql, &le, re->f, is_tuple);
    3371           0 :                                 if (!rsq)
    3372             :                                         return NULL;
    3373           0 :                                 re = rsq->exps->t->data;
    3374           0 :                                 set_processed(rsq);
    3375             :                         }
    3376             : 
    3377        3239 :                         int is_cnt = 0;
    3378        3239 :                         if (rsq) {
    3379        3203 :                                 sql_exp *r = exps_bind_nid(rsq->exps, re->nid);
    3380        3203 :                                 is_cnt = exp_is_count(r, rsq);
    3381             :                         }
    3382        3239 :                         if (is_project(rel->op) || depth > 0 || quantifier || is_cnt) {
    3383        1241 :                                 sql_rel *sq = lsq;
    3384             : 
    3385        1241 :                                 assert(!is_tuple);
    3386             : 
    3387        1241 :                                 if (!lsq)
    3388        1241 :                                         lsq = rel->l;
    3389          57 :                                 if (sq) {
    3390          57 :                                         sql_rel *rewrite = NULL;
    3391          57 :                                         operator_type op = (depth||quantifier)?op_left:op_join;
    3392          57 :                                         (void)rewrite_inner(v->sql, rel, sq, op, &rewrite);
    3393          57 :                                         exp_reset_props(rewrite, le, is_left(rewrite->op));
    3394          57 :                                         rel_bind_var(v->sql, rel, le);
    3395             :                                 }
    3396        1241 :                                 if (quantifier) {
    3397         174 :                                         sql_subfunc *a;
    3398             : 
    3399         174 :                                         rsq = rel_groupby(v->sql, rsq, NULL);
    3400         174 :                                         a = sql_bind_func(v->sql, "sys", "null", exp_subtype(re), NULL, F_AGGR, true, true);
    3401         174 :                                         rnull = exp_aggr1(v->sql->sa, re, a, 0, 1, CARD_AGGR, has_nil(re));
    3402         174 :                                         rnull = rel_groupby_add_aggr(v->sql, rsq, rnull);
    3403             : 
    3404         174 :                                         if (is_notequal_func(sf))
    3405         174 :                                                 op = "=";
    3406         174 :                                         if (op[0] == '<') {
    3407          50 :                                                 a = sql_bind_func(v->sql, "sys", (quantifier==1)?"max":"min", exp_subtype(re), NULL, F_AGGR, true, true);
    3408         140 :                                         } else if (op[0] == '>') {
    3409          97 :                                                 a = sql_bind_func(v->sql, "sys", (quantifier==1)?"min":"max", exp_subtype(re), NULL, F_AGGR, true, true);
    3410             :                                         } else /* (op[0] == '=')*/ /* only = ALL */ {
    3411          75 :                                                 a = sql_bind_func(v->sql, "sys", "all", exp_subtype(re), NULL, F_AGGR, true, true);
    3412          75 :                                                 is_cnt = 1;
    3413             :                                         }
    3414         174 :                                         re = exp_aggr1(v->sql->sa, re, a, 0, 1, CARD_AGGR, has_nil(re));
    3415         174 :                                         re = rel_groupby_add_aggr(v->sql, rsq, re);
    3416         174 :                                         set_processed(rsq);
    3417             :                                 }
    3418        1241 :                                 if (rsq) {
    3419        1206 :                                         sql_rel *rewrite = NULL;
    3420        1206 :                                         operator_type op = ((!quantifier && depth > 0)||is_cnt||quantifier)?op_left:op_join;
    3421        1206 :                                         (void)rewrite_inner(v->sql, rel, rsq, op, &rewrite);
    3422        1206 :                                         exp_reset_props(rewrite, re, is_left(rewrite->op));
    3423        1206 :                                         rel_bind_var(v->sql, rel, re);
    3424             :                                 }
    3425             : 
    3426        1241 :                                 if (rel_convert_types(v->sql, NULL, NULL, &le, &re, 1, type_equal) < 0)
    3427             :                                         return NULL;
    3428        1241 :                                 if (rnull) { /* complex compare operator */
    3429         174 :                                         sql_exp *lnull = rel_unop_(v->sql, rel, le, "sys", "isnull", card_value);
    3430         174 :                                         set_has_no_nil(lnull);
    3431         174 :                                         le = exp_compare_func(v->sql, le, re, op, 0);
    3432         297 :                                         sql_subfunc *f = sql_bind_func3(v->sql, "sys", (quantifier==1)?"any":"all", exp_subtype(le), exp_subtype(lnull), exp_subtype(rnull), F_FUNC, true);
    3433         174 :                                         le = exp_op3(v->sql->sa, le, lnull, rnull, f);
    3434         174 :                                         if (is_select(rel->op) && depth == 0) {
    3435          91 :                                                 le = exp_compare(v->sql->sa, le, exp_atom_bool(v->sql->sa, is_notequal_func(sf) ? 0 : 1), cmp_equal);
    3436         126 :                                         } else if (is_notequal_func(sf)) {
    3437          15 :                                                 le = rel_unop_(v->sql, rel, le, "sys", "not", card_value);
    3438             :                                         }
    3439        1067 :                                 } else if (is_project(rel->op) || depth) {
    3440        1057 :                                         le = exp_compare_func(v->sql, le, re, op, 0);
    3441             :                                 } else {
    3442          10 :                                         v->changes++;
    3443          10 :                                         return exp_compare(v->sql->sa, le, re, compare_str2type(op));
    3444             :                                 }
    3445        1231 :                                 if (exp_name(e))
    3446          53 :                                         exp_prop_alias(v->sql->sa, le, e);
    3447        1231 :                                 v->changes++;
    3448        1231 :                                 return le;
    3449             :                         } else {
    3450        1998 :                                 if (lsq) {
    3451           3 :                                         sql_rel *rewrite = NULL;
    3452           3 :                                         (void)rewrite_inner(v->sql, rel, lsq, op_join, &rewrite);
    3453           3 :                                         exp_reset_props(rewrite, le, is_left(rewrite->op));
    3454             :                                 }
    3455        1998 :                                 if (rsq) {
    3456        1997 :                                         sql_rel *rewrite = NULL;
    3457        1997 :                                         operator_type op = !is_tuple?op_join:is_anyequal(sf)?op_semi:op_anti;
    3458        1997 :                                         (void)rewrite_inner(v->sql, rel, rsq, op, &rewrite);
    3459        1997 :                                         exp_reset_props(rewrite, re, is_left(rewrite->op));
    3460             :                                 }
    3461        1998 :                                 if (is_tuple) {
    3462           0 :                                         list *t = le->f;
    3463           0 :                                         list *l = sa_list(v->sql->sa);
    3464           0 :                                         list *r = sa_list(v->sql->sa);
    3465           0 :                                         int s1 = list_length(t), s2 = list_length(rsq->exps); /* subtract identity column */
    3466             : 
    3467             :                                         /* find out list of right expression */
    3468           0 :                                         if (s1 != s2)
    3469           0 :                                                 return sql_error(v->sql, 02, SQLSTATE(42000) "Subquery has too %s columns", (s2 < s1) ? "few" : "many");
    3470           0 :                                         for (node *n = t->h, *m = rsq->exps->h; n && m; n = n->next, m = m->next ) {
    3471           0 :                                                 sql_exp *le = n->data;
    3472           0 :                                                 sql_exp *re = m->data;
    3473             : 
    3474           0 :                                                 append(l, le);
    3475           0 :                                                 append(r, re);
    3476             :                                         }
    3477           0 :                                         v->changes++;
    3478           0 :                                         return exp_compare(v->sql->sa, exp_values(v->sql->sa, l), exp_values(v->sql->sa, r), compare_str2type(op));
    3479             :                                 } else {
    3480        1998 :                                         if (exp_has_freevar(v->sql, le))
    3481          15 :                                                 rel_bind_var(v->sql, rel, le);
    3482        1998 :                                         if (rel_convert_types(v->sql, NULL, NULL, &le, &re, 1, type_equal) < 0)
    3483             :                                                 return NULL;
    3484        1998 :                                         v->changes++;
    3485        1998 :                                         return exp_compare(v->sql->sa, le, re, compare_str2type(op));
    3486             :                                 }
    3487             :                         }
    3488             :                 }
    3489             :         }
    3490             :         return e;
    3491             : }
    3492             : 
    3493             : static sql_rel *
    3494     2148284 : rewrite_join2semi(visitor *v, sql_rel *rel)
    3495             : {
    3496     2148284 :         if (mvc_highwater(v->sql))
    3497           0 :                 return sql_error(v->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    3498             : 
    3499     2148632 :         if (is_select(rel->op) && !list_empty(rel->exps)) {
    3500      157297 :                 sql_rel *j = rel->l, *jl = j->l, *ojl = jl;
    3501      157297 :                 int needed = 0, changed = 0;
    3502             : 
    3503      157297 :                 if (!j || (!is_join(j->op) && !is_semi(j->op)) || !list_empty(j->exps))
    3504      153448 :                         return rel;
    3505             :                 /* if needed first push select exps down under the join */
    3506        7994 :                 for (node *n = rel->exps->h; n;) {
    3507        4145 :                         node *next = n->next;
    3508        4145 :                         sql_exp *e = n->data;
    3509        4145 :                         sql_subfunc *sf = e->f;
    3510             : 
    3511        4145 :                         if (is_func(e->type) && is_anyequal_func(sf)) {
    3512           0 :                                 if (exp_card(e) > CARD_ATOM && rel_has_all_exps(jl, e->l)) {
    3513           0 :                                         if (!is_select(jl->op) || rel_is_ref(jl))
    3514           0 :                                                 j->l = jl = rel_select(v->sql->sa, jl, NULL);
    3515           0 :                                         rel_select_add_exp(v->sql->sa, jl, e);
    3516           0 :                                         list_remove_node(rel->exps, NULL, n);
    3517           0 :                                         changed = 1;
    3518           0 :                                         v->changes++;
    3519             :                                 } else {
    3520             :                                         needed = 1;
    3521             :                                 }
    3522             :                         }
    3523             :                         n = next;
    3524             :                 }
    3525        3849 :                 if (ojl != jl)
    3526           0 :                         set_processed(jl);
    3527        3849 :                 if (changed && !(j->l = rewrite_join2semi(v, j->l)))
    3528             :                         return NULL;
    3529        3849 :                 if (!needed)
    3530        3849 :                         return try_remove_empty_select(v, rel);
    3531           0 :                 if (!j->exps)
    3532           0 :                         j->exps = sa_list(v->sql->sa);
    3533           0 :                 list *sexps = sa_list(v->sql->sa);
    3534           0 :                 for (node *n = rel->exps->h; n; ) {
    3535           0 :                         node *next = n->next;
    3536           0 :                         sql_exp *e = n->data;
    3537           0 :                         sql_subfunc *sf = e->f;
    3538             : 
    3539             :                         /* Any compare expression based only on the left side will be split into a
    3540             :                          * select under the anti join.
    3541             :                          */
    3542           0 :                         assert((is_func(e->type) && is_anyequal_func(sf)) || e->type == e_cmp);
    3543           0 :                         if ((is_func(e->type) && is_anyequal_func(sf)) || !rel_rebind_exp(v->sql, j->l, e)) {
    3544           0 :                                 if (e->type == e_cmp) {
    3545           0 :                                         append(j->exps, e);
    3546             :                                 } else {
    3547           0 :                                         list *args = e->l;
    3548           0 :                                         sql_exp *l, *r;
    3549             : 
    3550           0 :                                         assert(list_length(args)==2);
    3551           0 :                                         l = args->h->data;
    3552           0 :                                         r = args->h->next->data;
    3553           0 :                                         j->op = (is_anyequal(sf))?op_semi:op_anti;
    3554             : 
    3555           0 :                                         if (is_values(l)) {
    3556           0 :                                                 assert(is_values(r));
    3557           0 :                                                 list *ll = l->f, *rl = r->f;
    3558           0 :                                                 for(node *n=ll->h, *m=rl->h; n && m; n=n->next, m=m->next) {
    3559           0 :                                                         e = exp_compare(v->sql->sa, n->data, m->data, cmp_equal );
    3560           0 :                                                         append(j->exps, e);
    3561             :                                                 }
    3562             :                                         } else {
    3563           0 :                                                 e = exp_compare(v->sql->sa, l, r, cmp_equal);
    3564           0 :                                                 if (e && j->op == op_anti)
    3565           0 :                                                         set_semantics(e);
    3566           0 :                                                 append(j->exps, e);
    3567             :                                         }
    3568             :                                 }
    3569           0 :                                 list_remove_node(rel->exps, NULL, n);
    3570           0 :                         } else if (!rel_rebind_exp(v->sql, j->r, e) && j->op == op_anti) {
    3571           0 :                                 append(sexps, e);
    3572           0 :                                 list_remove_node(rel->exps, NULL, n);
    3573             :                         }
    3574             :                         n = next;
    3575             :                 }
    3576           0 :                 v->changes++;
    3577           0 :                 if (list_length(sexps)) {
    3578           0 :                         sql_rel *jl = j->l = rel_select(v->sql->sa, j->l, NULL);
    3579           0 :                         set_processed(jl);
    3580           0 :                         jl->exps = sexps;
    3581             :                 }
    3582           0 :                 rel = try_remove_empty_select(v, rel);
    3583             :         }
    3584             :         return rel;
    3585             : }
    3586             : 
    3587             : /* exp visitor */
    3588             : static sql_exp *
    3589      382418 : rewrite_exists(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    3590             : {
    3591      382418 :         assert(e->type == e_func);
    3592             : 
    3593      382418 :         sql_subfunc *sf = e->f;
    3594      382418 :         if (is_exists_func(sf) && !list_empty(e->l)) {
    3595        1315 :                 list *l = e->l;
    3596             : 
    3597        1315 :                 if (list_length(l) == 1) { /* exp_values */
    3598        1315 :                         sql_exp *ie = l->h->data, *le;
    3599        1315 :                         sql_rel *sq = NULL;
    3600             : 
    3601        1315 :                         if (!exp_is_rel(ie)) { /* exists over a constant or a single value */
    3602          24 :                                 le = exp_atom_bool(v->sql->sa, is_exists(sf)?1:0);
    3603          24 :                                 if (depth == 0 && is_select(rel->op))
    3604           0 :                                         le = exp_compare(v->sql->sa, le, exp_atom_bool(v->sql->sa, 1), cmp_equal);
    3605          24 :                                 else if (exp_name(e))
    3606           0 :                                         exp_prop_alias(v->sql->sa, le, e);
    3607          24 :                                 v->changes++;
    3608          24 :                                 return le;
    3609             :                         }
    3610             : 
    3611        1291 :                         sq = exp_rel_get_rel(v->sql->sa, ie); /* get subquery */
    3612             :                         /* number of expressions in set relations must match the children */
    3613        1291 :                         if (!is_project(sq->op) || (is_set(sq->op) && list_length(sq->exps) > 1) || (is_simple_project(sq->op) && !list_empty(sq->r)))
    3614           4 :                                 sq = rel_project(v->sql->sa, sq, rel_projections(v->sql, sq, NULL, 1, 1));
    3615           4 :                         if (!sq)
    3616             :                                 return NULL;
    3617        1291 :                         le = rel_reduce2one_exp(v->sql, sq);
    3618        1291 :                         if (!le->alias.label)
    3619         745 :                                 exp_label(v->sql->sa, le, ++v->sql->label);
    3620        1291 :                         le = exp_ref(v->sql, le);
    3621             : 
    3622        1291 :                         if (depth >= 1 && is_ddl(rel->op)) { /* exists is at a ddl statement, it must be inside at least a relation */
    3623           5 :                                 sq = rel_groupby(v->sql, sq, NULL);
    3624           5 :                                 sql_subfunc *ea = sql_bind_func(v->sql, "sys", is_exists(sf)?"exist":"not_exist", exp_subtype(le), NULL, F_AGGR, true, true);
    3625           5 :                                 le = rel_groupby_add_aggr(v->sql, sq, exp_aggr1(v->sql->sa, le, ea, 0, 0, CARD_AGGR, 0));
    3626           5 :                                 return exp_rel(v->sql, sq);
    3627             :                         }
    3628        1286 :                         if (is_project(rel->op) || depth > 0 || is_outerjoin(rel->op)) {
    3629         644 :                                 sql_rel *join = NULL, *rewrite = NULL;
    3630             : 
    3631         644 :                                 (void)rewrite_inner(v->sql, rel, sq, op_left, &rewrite);
    3632         644 :                                 exp_reset_props(rewrite, le, is_left(rewrite->op));
    3633         644 :                                 join = (is_full(rel->op)||is_left(rel->op))?rel->r:rel->l;
    3634         644 :                                 if (!join)
    3635             :                                         return NULL;
    3636         644 :                                 if (join && !join->exps)
    3637         644 :                                         join->exps = sa_list(v->sql->sa);
    3638         644 :                                 v->changes++;
    3639         644 :                                 if (join) {
    3640         644 :                                         if (!join->attr)
    3641         644 :                                                 join->attr = sa_list(v->sql->sa);
    3642         644 :                                         sql_exp *a = exp_atom_bool(v->sql->sa, is_exists(sf));
    3643         644 :                                         set_no_nil(a);
    3644         644 :                                         if (!e->alias.label)
    3645         626 :                                                 exp_label(v->sql->sa, a, ++v->sql->label);
    3646             :                                         else
    3647          18 :                                                 exp_setalias(a, e->alias.label, exp_relname(e), exp_name(e));
    3648         644 :                                         le = exp_ref(v->sql, a);
    3649         644 :                                         le->card = CARD_MULTI; /* mark as multi value, the real attribute is introduced later */
    3650         644 :                                         append(join->attr, a);
    3651         644 :                                         assert(is_project(rel->op) || depth);
    3652         644 :                                         if ((is_project(rel->op) || depth))
    3653             :                                                 return le;
    3654             :                                 }
    3655           0 :                                 set_has_nil(le); /* outer joins could have introduced nils */
    3656           0 :                                 return le;
    3657             :                         } else { /* rewrite into semi/anti join */
    3658         669 :                                 (void)rewrite_inner(v->sql, rel, sq, is_exists(sf)?op_semi:op_anti, NULL);
    3659         642 :                                 v->changes++;
    3660         642 :                                 return exp_compare(v->sql->sa, exp_atom_bool(v->sql->sa, 1), exp_atom_bool(v->sql->sa, 1), cmp_equal);
    3661             :                         }
    3662             :                         v->changes++;
    3663             :                         return le;
    3664             :                 }
    3665             :         }
    3666             :         return e;
    3667             : }
    3668             : 
    3669             : /* exp visitor */
    3670             : static sql_exp *
    3671    10060309 : rewrite_ifthenelse(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    3672             : {
    3673    10060309 :         (void)depth;
    3674             :         /* for ifthenelse and rank flatten referenced inner expressions */
    3675    10060309 :         if (e->ref) {
    3676          47 :                 sql_rel *r = rel->l = rel_project(v->sql->sa, rel->l, rel_projections(v->sql, rel->l, NULL, 1, 1));
    3677             : 
    3678          47 :                 e->ref = 0;
    3679          47 :                 set_processed(r);
    3680          47 :                 append(r->exps, e);
    3681          47 :                 v->changes++;
    3682          47 :                 return exp_ref(v->sql, e);
    3683             :         }
    3684             : 
    3685    10060262 :         sql_subfunc *sf;
    3686    10060262 :         if (e->type != e_func)
    3687             :                 return e;
    3688             : 
    3689      471345 :         sf = e->f;
    3690             :         /* TODO also handle ifthenelse with more than 3 arguments */
    3691      471345 :         if (is_case_func(sf) && !list_empty(e->l) && list_length(e->l) == 3 && rel_has_freevar(v->sql, rel)) {
    3692        2003 :                 list *l = e->l;
    3693             : 
    3694             :                 /* remove unnecessary = true expressions under ifthenelse */
    3695        8012 :                 for (node *n = l->h ; n ; n = n->next) {
    3696        6009 :                         sql_exp *e = n->data;
    3697             : 
    3698        6009 :                         if (e->type == e_cmp && e->flag == cmp_equal && exp_is_true(e) && exp_is_true(e->r))
    3699           0 :                                 n->data = e->l;
    3700             :                 }
    3701             : 
    3702        2003 :                 sql_exp *cond = l->h->data;
    3703        2003 :                 sql_exp *then_exp = l->h->next->data;
    3704        2003 :                 sql_exp *else_exp = l->h->next->next->data;
    3705        2003 :                 sql_exp *not_cond;
    3706             : 
    3707        2003 :                 if (!exp_has_rel(cond) && (exp_has_rel(then_exp) || exp_has_rel(else_exp))) {
    3708        1443 :                         bool single = false;
    3709             :                         /* return sql_error(v->sql, 10, SQLSTATE(42000) "time to rewrite into union\n");
    3710             :                            union(
    3711             :                                 select(
    3712             :                                         project [then]
    3713             :                                 )[cond]
    3714             :                                 select(
    3715             :                                         project [else]
    3716             :                                 )[not(cond) or cond is null]
    3717             :                           ) [ cols ] */
    3718        1443 :                         sql_rel *lsq = NULL, *rsq = NULL, *usq = NULL;
    3719        1443 :                         list *urs = sa_list(v->sql->sa);
    3720             : 
    3721        1443 :                         if (exp_has_rel(then_exp)) {
    3722        1197 :                                 lsq = exp_rel_get_rel(v->sql->sa, then_exp);
    3723        1197 :                                 then_exp = exp_rel_update_exp(v->sql, then_exp, false);
    3724        1197 :                                 if (is_single(lsq))
    3725        1194 :                                         single = true;
    3726        1197 :                                 reset_single(lsq);
    3727             :                         }
    3728        1443 :                         exp_set_freevar(v->sql, then_exp, lsq);
    3729        1443 :                         exp_label(v->sql->sa, then_exp, ++v->sql->label);
    3730        1443 :                         lsq = rel_project(v->sql->sa, lsq, append(sa_list(v->sql->sa), then_exp));
    3731        1443 :                         exp_set_freevar(v->sql, cond, lsq);
    3732        1443 :                         set_processed(lsq);
    3733        1443 :                         lsq = rel_select(v->sql->sa, lsq, exp_compare(v->sql->sa, cond, exp_atom_bool(v->sql->sa, 1), cmp_equal));
    3734        1443 :                         set_processed(lsq);
    3735        1443 :                         if (exp_has_rel(else_exp)) {
    3736         246 :                                 rsq = exp_rel_get_rel(v->sql->sa, else_exp);
    3737         246 :                                 else_exp = exp_rel_update_exp(v->sql, else_exp, false);
    3738         246 :                                 if (is_single(rsq))
    3739         246 :                                         single = true;
    3740         246 :                                 reset_single(rsq);
    3741             :                         }
    3742        1443 :                         exp_set_freevar(v->sql, else_exp, rsq);
    3743        1443 :                         exp_label(v->sql->sa, else_exp, ++v->sql->label);
    3744        1443 :                         rsq = rel_project(v->sql->sa, rsq, append(sa_list(v->sql->sa), else_exp));
    3745        1443 :                         cond = exp_copy(v->sql, cond);
    3746        1443 :                         exp_set_freevar(v->sql, cond, rsq);
    3747        1443 :                         not_cond = exp_compare(v->sql->sa, cond, exp_atom_bool(v->sql->sa, 1), cmp_notequal);
    3748        1443 :                         set_semantics(not_cond); /* also compare nulls */
    3749        1443 :                         set_processed(rsq);
    3750        1443 :                         rsq = rel_select(v->sql->sa, rsq, not_cond);
    3751        1443 :                         set_processed(rsq);
    3752        1443 :                         urs = append(urs, lsq);
    3753        1443 :                         urs = append(urs, rsq);
    3754        1443 :                         usq = rel_setop_n_ary(v->sql->sa, urs, op_munion);
    3755        1443 :                         rel_setop_n_ary_set_exps(v->sql, usq, append(sa_list(v->sql->sa), exp_ref(v->sql, e)), false);
    3756        1443 :                         if (single)
    3757        1440 :                                 set_single(usq);
    3758        1443 :                         set_processed(usq);
    3759        1443 :                         e = exp_rel(v->sql, usq);
    3760        1443 :                         v->changes++;
    3761             :                 }
    3762             :         }
    3763             :         return e;
    3764             : }
    3765             : 
    3766             : static list *
    3767      288812 : rewrite_compare_exps(visitor *v, sql_rel *rel, list *exps)
    3768             : {
    3769      288812 :         if (mvc_highwater(v->sql))
    3770           0 :                 return sql_error(v->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    3771      288812 :         if (list_empty(exps))
    3772             :                 return exps;
    3773             : 
    3774      621604 :         for(node *n = exps->h; n; n = n->next) {
    3775      332792 :                 sql_exp *e = n->data;
    3776             : 
    3777      332792 :                 if (!is_compare(e->type)) {
    3778        4776 :                         sql_subtype bt;
    3779        4776 :                         sql_find_subtype(&bt, "boolean", 0, 0);
    3780        4776 :                         if (!(e = exp_check_type(v->sql, &bt, rel, e, type_equal)))
    3781           0 :                                 return NULL;
    3782        4776 :                         n->data = e = exp_compare(v->sql->sa, e, exp_atom_bool(v->sql->sa, 1), cmp_equal);
    3783        4776 :                         v->changes++;
    3784             :                 }
    3785      332792 :                 if (is_compare(e->type) && e->flag == cmp_or) {
    3786       16739 :                         if (!(e->l = rewrite_compare_exps(v, rel, e->l)))
    3787             :                                 return NULL;
    3788       16739 :                         if (!(e->r = rewrite_compare_exps(v, rel, e->r)))
    3789             :                                 return NULL;
    3790             :                 }
    3791             :         }
    3792             :         return exps;
    3793             : }
    3794             : 
    3795             : /* add an dummy true projection column */
    3796             : static inline sql_rel *
    3797     2148685 : rewrite_compare_exp(visitor *v, sql_rel *rel)
    3798             : {
    3799     2148685 :         if ((is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) && !list_empty(rel->exps))
    3800      255334 :                 if (!(rel->exps = rewrite_compare_exps(v, rel, rel->exps)))
    3801             :                         return NULL;
    3802             :         return rel;
    3803             : }
    3804             : 
    3805             : static inline sql_rel *
    3806     2148885 : rewrite_remove_xp_project(visitor *v, sql_rel *rel)
    3807             : {
    3808     2148885 :         if (rel->op == op_join && list_empty(rel->exps) && !rel_is_ref(rel)) {
    3809       24931 :                 sql_rel *r = rel->r;
    3810             : 
    3811       24931 :                 if (is_simple_project(r->op) && r->l && !project_unsafe(r, 1)) {
    3812        2645 :                         sql_rel *rl = r->l;
    3813             : 
    3814        2645 :                         if (is_simple_project(rl->op) && !rl->l && list_length(rl->exps) == 1) {
    3815         104 :                                 sql_exp *t = rl->exps->h->data;
    3816             : 
    3817         104 :                                 if (is_atom(t->type) && !exp_name(t)) { /* atom with out alias cannot be used later */
    3818           0 :                                         sql_rel *nrel = rel->l;
    3819           0 :                                         rel->l = NULL;
    3820           0 :                                         rel_destroy(rel);
    3821           0 :                                         rel = rel_project(v->sql->sa, nrel, rel_projections(v->sql, nrel, NULL, 1, 1));
    3822           0 :                                         list_merge(rel->exps, r->exps, (fdup)NULL);
    3823           0 :                                         set_processed(rel);
    3824           0 :                                         v->changes++;
    3825             :                                 }
    3826             :                         }
    3827             :                 }
    3828             :         }
    3829     2148885 :         return rel;
    3830             : }
    3831             : 
    3832             : static inline sql_rel *
    3833     2770301 : rewrite_remove_xp(visitor *v, sql_rel *rel)
    3834             : {
    3835     2770301 :         if (rel->op == op_join && list_empty(rel->exps) && !rel_is_ref(rel)) {
    3836       45630 :                 sql_rel *r = rel->r;
    3837             : 
    3838       45630 :                 if (is_simple_project(r->op) && !r->l && list_length(r->exps) == 1) {
    3839         283 :                         sql_exp *t = r->exps->h->data;
    3840             : 
    3841         283 :                         if (is_atom(t->type) && !exp_name(t)) { /* atom with out alias cannot be used later */
    3842           0 :                                 sql_rel *nrel = rel->l;
    3843           0 :                                 rel->l = NULL;
    3844           0 :                                 rel_destroy(rel);
    3845           0 :                                 rel = nrel;
    3846           0 :                                 v->changes++;
    3847             :                         }
    3848             :                 }
    3849             :         }
    3850     2770301 :         return rel;
    3851             : }
    3852             : 
    3853             : /* rel visitor */
    3854             : static sql_rel *
    3855     2759352 : rewrite_fix_count(visitor *v, sql_rel *rel)
    3856             : {
    3857     2759352 :         if (rel->op == op_left && !is_single(rel)) {
    3858       69401 :                 int rel_changes = 0;
    3859       69401 :                 sql_rel *r = rel->r;
    3860             : 
    3861       69401 :                 if (!is_rewrite_fix_count_used(r->used)) {
    3862       64389 :                         list *rexps = r->exps, *exps = NULL;
    3863             : 
    3864       64389 :                         if (!is_project(r->op))
    3865       10043 :                                 rexps = rel_projections(v->sql, r, NULL, 1, 1);
    3866             : 
    3867      206423 :                         for(node *n = rexps->h; n && !rel_changes; n=n->next) {
    3868      142034 :                                 sql_exp *e = n->data;
    3869             : 
    3870      142034 :                                 if (exp_is_count(e, r))
    3871        7180 :                                         rel_changes = 1;
    3872             :                         }
    3873       64389 :                         if (!rel_changes)
    3874             :                                 return rel;
    3875             : 
    3876        7180 :                         if (r->exps == rexps)
    3877        7180 :                                 rexps = rel_projections(v->sql, r, NULL, 1, 1);
    3878       17781 :                         for(node *n = rexps->h; n; n=n->next) {
    3879       10601 :                                 sql_exp *e = n->data, *ne;
    3880             : 
    3881       10601 :                                 if (exp_is_count(e, r)) {
    3882             :                                         /* rewrite count in subquery */
    3883        2362 :                                         list *args, *targs;
    3884        2362 :                                         sql_subfunc *isnil = sql_bind_func(v->sql, "sys", "isnull", exp_subtype(e), NULL, F_FUNC, true, true), *ifthen;
    3885             : 
    3886        2362 :                                         ne = exp_unop(v->sql->sa, e, isnil);
    3887        2362 :                                         set_has_no_nil(ne);
    3888        2362 :                                         targs = sa_list(v->sql->sa);
    3889        2362 :                                         append(targs, sql_bind_localtype("bit"));
    3890        2362 :                                         append(targs, exp_subtype(e));
    3891        2362 :                                         append(targs, exp_subtype(e));
    3892        2362 :                                         ifthen = sql_bind_func_(v->sql, "sys", "ifthenelse", targs, F_FUNC, true, true);
    3893        2362 :                                         args = sa_list(v->sql->sa);
    3894        2362 :                                         append(args, ne);
    3895        2362 :                                         append(args, exp_atom(v->sql->sa, atom_zero_value(v->sql->sa, exp_subtype(e))));
    3896        2362 :                                         append(args, e);
    3897        2362 :                                         ne = exp_op(v->sql->sa, args, ifthen);
    3898        2362 :                                         if (exp_name(e))
    3899        2362 :                                                 exp_prop_alias(v->sql->sa, ne, e);
    3900        2362 :                                         n->data = ne;
    3901             :                                 }
    3902             :                         }
    3903        7180 :                         exps = list_merge(rel_projections(v->sql, rel->l, NULL, 1, 1), rexps, (fdup)NULL);
    3904        7180 :                         rel = rel_project(v->sql->sa, rel, exps);
    3905        7180 :                         set_processed(rel);
    3906        7180 :                         r->used |= rewrite_fix_count_used;
    3907        7180 :                         v->changes++;
    3908             :                 }
    3909             :         }
    3910             :         return rel;
    3911             : }
    3912             : 
    3913             : static inline sql_rel *
    3914     2770538 : rewrite_groupings(visitor *v, sql_rel *rel)
    3915             : {
    3916     2770538 :         prop *found;
    3917             : 
    3918     2770538 :         if (is_groupby(rel->op)) {
    3919             :                 /* ROLLUP, CUBE, GROUPING SETS cases */
    3920       38153 :                 if ((found = find_prop(rel->p, PROP_GROUPINGS))) {
    3921         111 :                         list *sets = (list*) found->value.pval;
    3922         111 :                         list *grpr = sa_list(v->sql->sa);
    3923             : 
    3924         111 :                         rel->p = prop_remove(rel->p, found); /* remove property */
    3925         637 :                         for (node *n = sets->h ; n ; n = n->next) {
    3926         526 :                                 sql_rel *nrel;
    3927         526 :                                 list *l = (list*) n->data, *exps = sa_list(v->sql->sa), *pexps = sa_list(v->sql->sa);
    3928             : 
    3929         526 :                                 l = list_flatten(l);
    3930         526 :                                 nrel = rel_groupby(v->sql, rel_dup(rel->l), l);
    3931             : 
    3932        3377 :                                 for (node *m = rel->exps->h ; m ; m = m->next) {
    3933        2851 :                                         sql_exp *e = (sql_exp*) m->data, *ne = NULL;
    3934        2851 :                                         sql_subfunc *agr = (sql_subfunc*) e->f;
    3935             : 
    3936        3227 :                                         if (e->type == e_aggr && !agr->func->s && !strcmp(agr->func->base.name, "grouping")) {
    3937             :                                                 /* replace grouping aggregate calls with constants */
    3938         376 :                                                 sql_subtype tpe = ((sql_arg*) agr->func->res->h->data)->type;
    3939         376 :                                                 list *groups = (list*) e->l;
    3940         376 :                                                 atom *a = atom_int(v->sql->sa, &tpe, 0);
    3941             : #ifdef HAVE_HGE
    3942         376 :                                                 hge counter = (hge) list_length(groups) - 1;
    3943             : #else
    3944             :                                                 lng counter = (lng) list_length(groups) - 1;
    3945             : #endif
    3946         376 :                                                 assert(groups && list_length(groups) > 0);
    3947             : 
    3948        1196 :                                                 for (node *nn = groups->h ; nn ; nn = nn->next) {
    3949         820 :                                                         sql_exp *exp = (sql_exp*) nn->data;
    3950         820 :                                                         if (!exps_find_exp(l, exp)) {
    3951         415 :                                                                 switch (ATOMstorage(a->data.vtype)) {
    3952         379 :                                                                         case TYPE_bte:
    3953         379 :                                                                                 a->data.val.btval += (bte) (1 << counter);
    3954         379 :                                                                                 break;
    3955          36 :                                                                         case TYPE_sht:
    3956          36 :                                                                                 a->data.val.shval += (sht) (1 << counter);
    3957          36 :                                                                                 break;
    3958           0 :                                                                         case TYPE_int:
    3959           0 :                                                                                 a->data.val.ival += (int) (1 << counter);
    3960           0 :                                                                                 break;
    3961           0 :                                                                         case TYPE_lng:
    3962           0 :                                                                                 a->data.val.lval += (lng) (1 << counter);
    3963           0 :                                                                                 break;
    3964             : #ifdef HAVE_HGE
    3965           0 :                                                                         case TYPE_hge:
    3966           0 :                                                                                 a->data.val.hval += (hge) (1 << counter);
    3967           0 :                                                                                 break;
    3968             : #endif
    3969             :                                                                         default:
    3970           0 :                                                                                 assert(0);
    3971             :                                                                 }
    3972             :                                                         }
    3973         820 :                                                         counter--;
    3974             :                                                 }
    3975             : 
    3976         376 :                                                 ne = exp_atom(v->sql->sa, a);
    3977         376 :                                                 if (exp_name(e))
    3978         376 :                                                         exp_prop_alias(v->sql->sa, ne, e);
    3979        2475 :                                         } else if (e->type == e_column && !exps_find_exp(l, e) && !has_label(e)) {
    3980             :                                                 /* do not include in the output of the group by, but add to the project as null */
    3981         745 :                                                 ne = exp_atom(v->sql->sa, atom_general(v->sql->sa, exp_subtype(e), NULL, 0));
    3982         745 :                                                 if (exp_name(e))
    3983         745 :                                                         exp_prop_alias(v->sql->sa, ne, e);
    3984             :                                         } else {
    3985        1730 :                                                 sql_exp *ec = exp_copy(v->sql, e);
    3986        1730 :                                                 ne = exp_ref(v->sql, ec);
    3987        1730 :                                                 append(exps, ec);
    3988             :                                         }
    3989        2851 :                                         append(pexps, ne);
    3990             :                                 }
    3991         526 :                                 if (list_empty(exps)) {
    3992          24 :                                         sql_exp *e = exp_atom_bool(v->sql->sa, 1);
    3993          24 :                                         exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
    3994          24 :                                         list_append(exps, e);
    3995             :                                 }
    3996         526 :                                 nrel->exps = exps;
    3997         526 :                                 if (!list_empty(rel->r) && !list_empty(nrel->r)) { /* aliases on grouping columns, ugh */
    3998        1290 :                                         for (node *n = ((list*)nrel->r)->h; n; n = n->next) {
    3999         857 :                                                 sql_exp *e = n->data;
    4000         857 :                                                 sql_exp *ne = exps_bind_nid(rel->r, e->alias.label);
    4001         857 :                                                 if (ne)
    4002         857 :                                                         n->data = exp_copy(v->sql, ne);
    4003             :                                         }
    4004         433 :                                         list_hash_clear(nrel->r);
    4005             :                                 }
    4006         526 :                                 set_processed(nrel);
    4007         526 :                                 if (list_empty(pexps)) {
    4008           0 :                                         sql_exp *e = exp_atom_bool(v->sql->sa, 1);
    4009           0 :                                         exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
    4010           0 :                                         list_append(pexps, e);
    4011             :                                 }
    4012         526 :                                 nrel = rel_project(v->sql->sa, nrel, pexps);
    4013         526 :                                 set_processed(nrel);
    4014         526 :                                 grpr = append(grpr, nrel);
    4015             :                         }
    4016             : 
    4017             :                         /* always do relation inplace, so it will be fine when the input group has more than 1 reference */
    4018         111 :                         assert(list_length(grpr) > 0);
    4019         111 :                         if (list_length(grpr) == 0) {
    4020             :                                 return NULL;
    4021         111 :                         } else if (list_length(grpr) == 1) {
    4022           0 :                                 sql_rel *grp = grpr->h->data;
    4023           0 :                                 rel = rel_inplace_project(v->sql->sa, rel, grp, grp->exps);
    4024             :                         } else {
    4025         111 :                                 rel = rel_inplace_setop_n_ary(v->sql, rel, grpr, op_munion, rel_projections(v->sql, rel, NULL, 1, 1));
    4026             :                         }
    4027             : 
    4028         111 :                         v->changes++;
    4029         111 :                         return rel;
    4030             :                 } else {
    4031       38042 :                         bool found_grouping = false;
    4032      108618 :                         for (node *n = rel->exps->h ; n ; n = n->next) {
    4033       70583 :                                 sql_exp *e = (sql_exp*) n->data;
    4034       70583 :                                 sql_subfunc *agr = (sql_subfunc*) e->f;
    4035             : 
    4036       70583 :                                 if (e->type == e_aggr && !agr->func->s && !strcmp(agr->func->base.name, "grouping")) {
    4037             :                                         found_grouping = true;
    4038             :                                         break;
    4039             :                                 }
    4040             :                         }
    4041       38042 :                         if (found_grouping) {
    4042             :                                 /* replace grouping calls with constants of value 0 */
    4043           7 :                                 sql_rel *nrel = rel_groupby(v->sql, rel_dup(rel->l), rel->r);
    4044           7 :                                 list *exps = sa_list(v->sql->sa), *pexps = sa_list(v->sql->sa);
    4045           7 :                                 sql_subtype *bt = sql_bind_localtype("bte");
    4046             : 
    4047          19 :                                 for (node *n = rel->exps->h ; n ; n = n->next) {
    4048          12 :                                         sql_exp *e = (sql_exp*) n->data, *ne;
    4049          12 :                                         sql_subfunc *agr = (sql_subfunc*) e->f;
    4050             : 
    4051          12 :                                         if (e->type == e_aggr && !agr->func->s && !strcmp(agr->func->base.name, "grouping")) {
    4052           7 :                                                 ne = exp_atom(v->sql->sa, atom_int(v->sql->sa, bt, 0));
    4053           7 :                                                 if (exp_name(e))
    4054           7 :                                                         exp_prop_alias(v->sql->sa, ne, e);
    4055             :                                         } else {
    4056           5 :                                                 ne = exp_ref(v->sql, e);
    4057           5 :                                                 append(exps, e);
    4058             :                                         }
    4059          12 :                                         append(pexps, ne);
    4060             :                                 }
    4061           7 :                                 if (list_empty(exps)) {
    4062           4 :                                         sql_exp *e = exp_atom_bool(v->sql->sa, 1);
    4063           4 :                                         exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
    4064           4 :                                         list_append(exps, e);
    4065             :                                 }
    4066           7 :                                 nrel->exps = exps;
    4067           7 :                                 set_processed(nrel);
    4068           7 :                                 if (list_empty(pexps)) {
    4069           0 :                                         sql_exp *e = exp_atom_bool(v->sql->sa, 1);
    4070           0 :                                         exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
    4071           0 :                                         list_append(pexps, e);
    4072             :                                 }
    4073             :                                 /* always do relation inplace, so it will be fine when the input group has more than 1 reference */
    4074           7 :                                 rel = rel_inplace_project(v->sql->sa, rel, nrel, pexps);
    4075           7 :                                 rel->card = exps_card(pexps);
    4076           7 :                                 v->changes++;
    4077           7 :                                 return rel;
    4078             :                         }
    4079             :                 }
    4080             :         }
    4081             :         return rel;
    4082             : }
    4083             : 
    4084             : static int
    4085         122 : include_tid(sql_rel *r)
    4086             : {
    4087         122 :         if (is_basetable(r->op))
    4088          74 :                 r->nrcols = list_length(r->exps);
    4089         122 :         return r->nrcols;
    4090             : }
    4091             : 
    4092             : static sql_rel *
    4093          70 : add_null_projects(visitor *v, sql_rel *prel, sql_rel *irel, bool end)
    4094             : {
    4095          70 :         list *l = NULL;
    4096          70 :         node *n = prel->exps->h;
    4097          70 :         sql_rel *nilrel = rel_project(v->sql->sa, irel, rel_projections(v->sql, irel, NULL, 1, 1));
    4098          70 :         int nr = prel->nrcols - nilrel->nrcols;
    4099          70 :         if (end) {
    4100         115 :                 for(node *m = nilrel->exps->h; n && m; n = n->next, m = m->next)
    4101             :                         ;
    4102             :         } else {
    4103          39 :                 l = sa_list(v->sql->sa);
    4104             :         }
    4105         248 :         for(; nr; n = n->next, nr--) {
    4106         179 :                 sql_exp *e = n->data, *ne;
    4107         179 :                 sql_subtype *tp = exp_subtype(e);
    4108             : 
    4109         179 :                 if (!tp)
    4110           1 :                         return sql_error(v->sql, 10, SQLSTATE(42000) "Cannot rewrite subquery because of parameter with unknown type");
    4111         178 :                 ne = exp_atom(v->sql->sa, atom_general(v->sql->sa, tp, NULL, 0));
    4112         178 :                 assert(e->alias.label);
    4113         178 :                 exp_setalias(ne, e->alias.label, exp_relname(e), exp_name(e));
    4114         178 :                 if (end)
    4115          58 :                         append(nilrel->exps, ne);
    4116             :                 else
    4117         120 :                         append(l, ne);
    4118             :         }
    4119          69 :         if (!end)
    4120          39 :                 nilrel->exps = list_merge(l, nilrel->exps, NULL);
    4121          69 :         nilrel->nrcols = list_length(nilrel->exps);
    4122          69 :         return nilrel;
    4123             : }
    4124             : 
    4125             : static sql_rel *
    4126          61 : rewrite_outer2inner_union(visitor *v, sql_rel *rel)
    4127             : {
    4128          61 :         if (is_outerjoin(rel->op) && rel->flag != MERGE_LEFT) {
    4129          61 :                 int nrcols = rel->nrcols;
    4130             : 
    4131          61 :                 nrcols = include_tid(rel->l);
    4132          61 :                 nrcols += include_tid(rel->r);
    4133          61 :                 rel->nrcols = nrcols;
    4134          61 :                 if (is_left(rel->op)) {
    4135          22 :                         sql_rel *inner = rel_crossproduct(v->sql->sa, rel_dup(rel->l), rel_dup(rel->r),  op_join);
    4136          22 :                         inner->exps = rel->exps;
    4137          22 :                         if(is_dependent(rel))
    4138          16 :                                 set_dependent(inner);
    4139          22 :                         sql_rel *prel = rel_project(v->sql->sa, inner, rel_projections(v->sql, inner, NULL, 1, 1));
    4140          44 :                         sql_rel *except = rel_setop(v->sql->sa,
    4141          22 :                                         rel_project(v->sql->sa, rel_dup(rel->l), rel_projections(v->sql, rel->l, NULL, 1, 1)),
    4142          44 :                                         rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->l, NULL, 1, 1)), op_except);
    4143          22 :                         rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->l, NULL, 1, 1), false);
    4144          22 :                         set_processed(except);
    4145          22 :                         sql_rel *nilrel = add_null_projects(v, prel, except, true);
    4146          22 :                         if (!nilrel)
    4147             :                                 return NULL;
    4148             : 
    4149          21 :                         list *urs = sa_list(v->sql->sa);
    4150          21 :                         urs = append(urs, prel);
    4151          21 :                         urs = append(urs, nilrel);
    4152          21 :                         sql_rel *nrel = rel_setop_n_ary(v->sql->sa, urs, op_munion);
    4153          21 :                         rel_setop_n_ary_set_exps(v->sql, nrel, rel_projections(v->sql, rel, NULL, 1, 1), false);
    4154          21 :                         set_processed(nrel);
    4155          21 :                         if(is_single(rel))
    4156           0 :                                 set_single(nrel);
    4157          21 :                         v->changes++;
    4158          21 :                         rel_destroy(rel);
    4159          21 :                         return nrel;
    4160          39 :                 } else if (is_right(rel->op)) {
    4161          30 :                         sql_rel *inner = rel_crossproduct(v->sql->sa, rel_dup(rel->l), rel_dup(rel->r),  op_join);
    4162          30 :                         inner->exps = rel->exps;
    4163          30 :                         if(is_dependent(rel))
    4164          18 :                                 set_dependent(inner);
    4165          30 :                         sql_rel *prel = rel_project(v->sql->sa, inner, rel_projections(v->sql, inner, NULL, 1, 1));
    4166          60 :                         sql_rel *except = rel_setop(v->sql->sa,
    4167          30 :                                         rel_project(v->sql->sa, rel_dup(rel->r), rel_projections(v->sql, rel->r, NULL, 1, 1)),
    4168          60 :                                         rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->r, NULL, 1, 1)), op_except);
    4169          30 :                         rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->r, NULL, 1, 1), false);
    4170          30 :                         set_processed(except);
    4171          30 :                         sql_rel *nilrel = add_null_projects(v, prel, except, false);
    4172          30 :                         if (!nilrel)
    4173             :                                 return NULL;
    4174             : 
    4175          30 :                         list *urs = sa_list(v->sql->sa);
    4176          30 :                         urs = append(urs, prel);
    4177          30 :                         urs = append(urs, nilrel);
    4178          30 :                         sql_rel *nrel = rel_setop_n_ary(v->sql->sa, urs, op_munion);
    4179          30 :                         rel_setop_n_ary_set_exps(v->sql, nrel, rel_projections(v->sql, rel, NULL, 1, 1), false);
    4180          30 :                         set_processed(nrel);
    4181          30 :                         if(is_single(rel))
    4182           0 :                                 set_single(nrel);
    4183          30 :                         v->changes++;
    4184          30 :                         rel_destroy(rel);
    4185          30 :                         return nrel;
    4186           9 :                 } else if (is_full(rel->op)) {
    4187           9 :                         sql_rel *inner = rel_crossproduct(v->sql->sa, rel_dup(rel->l), rel_dup(rel->r),  op_join);
    4188           9 :                         inner->exps = rel->exps;
    4189           9 :                         if(is_dependent(rel))
    4190           3 :                                 set_dependent(inner);
    4191           9 :                         sql_rel *prel = rel_project(v->sql->sa, inner, rel_projections(v->sql, inner, NULL, 1, 1));
    4192          18 :                         sql_rel *except = rel_setop(v->sql->sa,
    4193           9 :                                         rel_project(v->sql->sa, rel_dup(rel->l), rel_projections(v->sql, rel->l, NULL, 1, 1)),
    4194          18 :                                         rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->l, NULL, 1, 1)), op_except);
    4195           9 :                         rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->l, NULL, 1, 1), false);
    4196           9 :                         set_processed(except);
    4197           9 :                         sql_rel *lrel = add_null_projects(v, prel, except, true);
    4198           9 :                         if (!lrel)
    4199             :                                 return NULL;
    4200             : 
    4201          18 :                         except = rel_setop(v->sql->sa,
    4202           9 :                                         rel_project(v->sql->sa, rel_dup(rel->r), rel_projections(v->sql, rel->r, NULL, 1, 1)),
    4203          18 :                                         rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->r, NULL, 1, 1)), op_except);
    4204           9 :                         rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->r, NULL, 1, 1), false);
    4205           9 :                         set_processed(except);
    4206           9 :                         sql_rel *rrel = add_null_projects(v, prel, except, false);
    4207           9 :                         if (!rrel)
    4208             :                                 return NULL;
    4209             : 
    4210           9 :                         list *urs = sa_list(v->sql->sa);
    4211             :                         /* order matters (see caller logic) */
    4212           9 :                         urs = append(urs, prel);
    4213           9 :                         urs = append(urs, lrel);
    4214           9 :                         urs = append(urs, rrel);
    4215           9 :                         lrel = rel_setop_n_ary(v->sql->sa, urs, op_munion);
    4216           9 :                         rel_setop_n_ary_set_exps(v->sql, lrel, rel_projections(v->sql, rel, NULL, 1, 1), false);
    4217           9 :                         set_processed(lrel);
    4218             : 
    4219           9 :                         if(is_single(rel))
    4220           0 :                                 set_single(lrel);
    4221           9 :                         v->changes++;
    4222           9 :                         rel_destroy(rel);
    4223           9 :                         return lrel;
    4224             :                 }
    4225             :         }
    4226             :         return rel;
    4227             : }
    4228             : 
    4229             : static sql_rel *
    4230     2100084 : rewrite_swap_fullouter(visitor *v, sql_rel *rel)
    4231             : {
    4232     2100084 :         if (is_full(rel->op) && rel_has_freevar(v->sql, rel->r)) { /* swap */
    4233           3 :                 sql_rel *s = rel->r;
    4234           3 :                 rel->r = rel->l;
    4235           3 :                 rel->l = s;
    4236             :         }
    4237     2100084 :         return rel;
    4238             : }
    4239             : 
    4240             : static sql_exp *
    4241    10203312 : rewrite_complex(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    4242             : {
    4243    10203312 :         if (e->type != e_func)
    4244             :                 return e;
    4245             : 
    4246      399609 :         sql_exp *res = rewrite_anyequal(v, rel, e, depth);
    4247      399609 :         if (res == e)
    4248      382418 :                 res = rewrite_exists(v, rel, e, depth);
    4249      399609 :         if (res == e)
    4250      381103 :                 res = rewrite_compare(v, rel, e, depth);
    4251             :         return res;
    4252             : }
    4253             : 
    4254             : static sql_rel *
    4255         103 : flatten_values(visitor *v, sql_rel *rel)
    4256             : {
    4257         103 :         list *exps = sa_list(v->sql->sa);
    4258         103 :         sql_exp *e = rel->exps->h->data;
    4259         103 :         sql_rel *nrel = NULL;
    4260         103 :         list *vals = exp_get_values(e);
    4261         103 :         if (vals) {
    4262         103 :                 list *urs = sa_list(v->sql->sa);
    4263         254 :                 for(int i = 0; i<list_length(vals); i++) {
    4264         151 :                         nrel = rel_project(v->sql->sa, NULL, sa_list(v->sql->sa));
    4265         151 :                         set_processed(nrel);
    4266         344 :                         for(node *n = rel->exps->h; n; n = n->next) {
    4267         193 :                                 sql_exp *e = n->data;
    4268         193 :                                 list *vals = exp_get_values(e);
    4269             : 
    4270         193 :                                 if (vals) {
    4271         193 :                                         if (i == 0)
    4272         127 :                                                 append(exps, exp_ref(v->sql, e));
    4273         193 :                                         sql_exp *val = list_fetch(vals, i);
    4274         193 :                                         exp_setalias(val, e->alias.label, exp_relname(e), exp_name(e));
    4275         193 :                                         append(nrel->exps, val);
    4276         193 :                                         rel_set_exps(nrel, nrel->exps);
    4277             :                                 }
    4278             :                         }
    4279         151 :                         urs = append(urs, nrel);
    4280             :                 }
    4281             : 
    4282         103 :                 if (list_length(urs) == 1) {
    4283          56 :                         if (is_single(rel))
    4284           0 :                                 set_single(nrel);
    4285          56 :                         rel_destroy(rel);
    4286          56 :                         rel = nrel;
    4287             :                 } else {
    4288          47 :                         nrel = rel_setop_n_ary(v->sql->sa, urs, op_munion);
    4289          47 :                         rel_setop_n_ary_set_exps(v->sql, nrel, exps, false);
    4290          47 :                         if (is_single(rel))
    4291           9 :                                 set_single(nrel);
    4292          47 :                         rel_destroy(rel);
    4293          47 :                         rel = nrel;
    4294             :                 }
    4295             : 
    4296         103 :                 v->changes++;
    4297             :         }
    4298         103 :         return rel;
    4299             : }
    4300             : 
    4301             : /* rewrite project [ [multi values], [multi values2] , .. [] ] -> union ) */
    4302             : static inline sql_rel *
    4303     2100188 : rewrite_values(visitor *v, sql_rel *rel)
    4304             : {
    4305     2100188 :         if (!is_simple_project(rel->op) || list_empty(rel->exps) || is_rewrite_values_used(rel->used))
    4306     1422817 :                 return rel;
    4307             : 
    4308      677237 :         sql_exp *e = rel->exps->h->data;
    4309      677237 :         if (!is_values(e) || (!exps_have_rel_exp(rel->exps) && !exps_have_freevar(v->sql, rel->exps)))
    4310      677208 :                 return rel;
    4311         103 :         if (rel_is_ref(rel)) { /* need extra project */
    4312           0 :                 rel->l = rel_project(v->sql->sa, rel->l, rel->exps);
    4313           0 :                 rel->exps = rel_projections(v->sql, rel->l, NULL, 1, 1);
    4314           0 :                 ((sql_rel*)rel->l)->r = rel->r; /* propagate order by exps */
    4315           0 :                 rel->r = NULL;
    4316           0 :                 rel->used |= rewrite_values_used;
    4317           0 :                 v->changes++;
    4318           0 :                 return rel;
    4319             :         }
    4320         103 :         return flatten_values(v, rel);
    4321             : }
    4322             : 
    4323             : static inline sql_rel *
    4324     2100031 : rewrite_rel(visitor *v, sql_rel *rel)
    4325             : {
    4326     2100031 :         if (!is_outerjoin(rel->op) || list_empty(rel->exps) || rel_is_ref(rel))
    4327     2089742 :                 return rel;
    4328       10289 :         sql_rel *l = rel->l, *r = rel->r;
    4329             : 
    4330       10289 :         if ((l && is_project(l->op) && !l->l) ||
    4331        9705 :             (r && is_project(r->op) && !r->l))
    4332             :                 return rel;
    4333             : 
    4334        9680 :         sql_rel *or = rel;
    4335       19691 :         for (node *n = rel->exps->h; n; ) {
    4336       10071 :                 node *next = n->next;
    4337       10071 :                 sql_exp *e = n->data;
    4338             : 
    4339       10071 :                 if (exp_has_rel(e) /*&& exp_has_freevar(v->sql, e)*/) {
    4340          60 :                         list *exps = or->exps;
    4341          60 :                         or->exps = NULL;
    4342          60 :                         sql_rel *ir = exp_rel_get_rel(v->sql->sa, e);
    4343             : 
    4344          60 :                         rel = rewrite_outer2inner_union(v, rel);
    4345          60 :                         if (!rel || or == rel)
    4346             :                                 return rel;
    4347             :                         /* change referenced project into join with outer(ir) */
    4348             :                         /*sql_rel *nr = rel->l;*/
    4349          59 :                         assert(is_munion(rel->op));
    4350          59 :                         sql_rel *nr = ((list*)rel->l)->h->data;
    4351          59 :                         assert(is_project(nr->op));
    4352          59 :                         if (!rel_is_ref(nr))
    4353           0 :                                 nr = nr->l;
    4354          59 :                         sql_rel *s = rel_crossproduct(v->sql->sa, nr->l, ir, op_semi);
    4355          59 :                         s->exps = exps;
    4356          59 :                         set_dependent(s);
    4357          59 :                         nr->l = s;
    4358          59 :                         e = exp_rel_update_exp(v->sql, e, false);
    4359          59 :                         exp_reset_props(nr, e, true);
    4360          59 :                         v->changes++;
    4361          59 :                         break;
    4362             :                 }
    4363             :                 n = next;
    4364             :         }
    4365             :         return rel;
    4366             : }
    4367             : 
    4368             : typedef struct sql_args {
    4369             :         list *args;
    4370             :         list *exps;
    4371             : } sql_args;
    4372             : 
    4373             : static int
    4374         203 : var_name_cmp(sql_arg *v, char *name)
    4375             : {
    4376         203 :         return strcmp(v->name, name);
    4377             : }
    4378             : 
    4379             : static sql_exp *
    4380        3601 : exp_inline_arg(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    4381             : {
    4382        3601 :         (void)rel;
    4383        3601 :         (void)depth;
    4384        3601 :         sql_args *args = v->data;
    4385        3601 :         if (e->type == e_atom && e->r) {
    4386         125 :                 sql_arg *a = e->r;
    4387         125 :                 int level = is_freevar(e);
    4388         125 :                 node *n = list_find(args->args, a->name, (fcmp)&var_name_cmp);
    4389         125 :                 if (n) {
    4390         125 :                         sql_exp *val = list_fetch(args->exps, list_position(args->args, n->data));
    4391         125 :                         val = exp_copy(v->sql, val);
    4392         125 :                         exp_prop_alias(v->sql->sa, val, e);
    4393         125 :                         if (level)
    4394           0 :                                 set_freevar(val, level-1);
    4395         125 :                         return val;
    4396             :                 }
    4397             :         }
    4398             :         return e;
    4399             : }
    4400             : 
    4401             : static sql_rel *
    4402     1559674 : rel_inline_table_func(visitor *v, sql_rel *rel)
    4403             : {
    4404     1559674 :         if (!rel_is_ref(rel) && rel->op == op_table && !rel->l && rel->r) { /* TODO add input relation (rel->l) rewriting */
    4405        2380 :                 sql_exp *opf = rel->r;
    4406        2380 :                 if (opf->type == e_func) {
    4407        2380 :                         sql_subfunc *f = opf->f;
    4408             : 
    4409        2380 :                         if (f->func->vararg || f->func->varres)
    4410             :                                 return rel;
    4411             : 
    4412        1156 :                         if (f->func->lang == FUNC_LANG_SQL && f->func->type == F_UNION) {
    4413         245 :                                 sql_rel *r = rel_parse(v->sql, f->func->s, f->func->query, m_instantiate);
    4414             : 
    4415         245 :                                 if (r && is_ddl(r->op) && list_length(r->exps) == 1) {
    4416         218 :                                         sql_exp *psm = r->exps->h->data;
    4417         218 :                                         if (psm && psm->type == e_psm && psm->flag == PSM_RETURN) {
    4418         216 :                                                 sql_exp *ret = psm->l;
    4419         216 :                                                 if (ret && ret->type == e_psm && ret->flag == PSM_REL) {
    4420         216 :                                                         r = ret->l;
    4421         216 :                                                         list *exps = r->exps;
    4422         216 :                                                         r = rel_project(v->sql->sa, r, sa_list(v->sql->sa));
    4423         693 :                                                         for(node *n = rel->exps->h, *m = exps->h; n && m; n = n->next, m = m->next) {
    4424         477 :                                                                 sql_exp *e = m->data;
    4425         477 :                                                                 sql_exp *pe = n->data;
    4426             : 
    4427         477 :                                                                 if (!e->alias.label)
    4428           6 :                                                                         e = exp_label(v->sql->sa, e, ++v->sql->label);
    4429         477 :                                                                 e = exp_ref(v->sql, e);
    4430         477 :                                                                 exp_setalias(e, pe->alias.label, exp_relname(pe), exp_name(pe));
    4431         477 :                                                                 if (is_freevar(pe))
    4432           0 :                                                                         set_freevar(e, is_freevar(pe)-1);
    4433         477 :                                                                 append(r->exps, e);
    4434             :                                                         }
    4435         216 :                                                         sql_args a;
    4436         216 :                                                         if (f->func->ops) {
    4437         216 :                                                                 a.args = f->func->ops;
    4438         216 :                                                                 a.exps = opf->l;
    4439         216 :                                                                 v->data = &a;
    4440         216 :                                                                 r = rel_exp_visitor_topdown(v, r, &exp_inline_arg, true);
    4441         216 :                                                                 v->data = NULL;
    4442             :                                                         }
    4443         216 :                                                         r = rel_unnest(v->sql, r);
    4444         216 :                                                         return r;
    4445             :                                                 }
    4446             :                                         }
    4447             :                                 }
    4448             :                         }
    4449             :                 }
    4450             :         }
    4451             :         return rel;
    4452             : }
    4453             : 
    4454             : /* add an dummy true projection column */
    4455             : static sql_rel *
    4456     2099615 : rel_unnest_simplify(visitor *v, sql_rel *rel)
    4457             : {
    4458             :         /* at rel_select.c explicit cross-products generate empty selects, if these are not used, they can be removed at rewrite_simplify */
    4459     2099615 :         if (rel && v->sql->emode != m_deps)
    4460     1559652 :                 rel = rel_inline_table_func(v, rel);
    4461     2099901 :         if (rel)
    4462     2099901 :                 rel = rewrite_basetable(v->sql, rel);        /* add proper exps lists */
    4463     2100131 :         if (rel)
    4464     2100131 :                 rel = rewrite_empty_project(v, rel); /* remove empty project/groupby */
    4465     2100136 :         if (rel)
    4466     2100136 :                 rel = rewrite_simplify(v, 0, false, rel);
    4467     2099830 :         if (rel)
    4468     2099830 :                 rel = rewrite_split_select_exps(v, rel); /* has to run before rewrite_complex */
    4469     2100004 :         if (rel)
    4470     2100004 :                 rel = rewrite_swap_fullouter(v, rel);
    4471     2100213 :         if (rel)
    4472     2100213 :                 rel = rewrite_aggregates(v, rel);
    4473     2100268 :         if (rel)
    4474     2100268 :                 rel = rewrite_values(v, rel);
    4475     2100039 :         if (rel)
    4476     2100039 :                 rel = rewrite_rel(v, rel);
    4477     2100192 :         return rel;
    4478             : }
    4479             : 
    4480             : static sql_rel *
    4481     2770466 : rel_unnest_projects(visitor *v, sql_rel *rel)
    4482             : {
    4483     2770466 :         if (rel)
    4484     2770466 :                 rel = rewrite_remove_xp(v, rel);        /* remove crossproducts with project [ atom ] */
    4485     2770446 :         if (rel)
    4486     2770446 :                 rel = rewrite_groupings(v, rel);        /* transform group combinations into union of group relations */
    4487     2770545 :         return rel;
    4488             : }
    4489             : 
    4490             : static sql_rel *
    4491     2148531 : rel_unnest_comparison_rewriters(visitor *v, sql_rel *rel)
    4492             : {
    4493     2148531 :         if (rel)
    4494     2148492 :                 rel = rewrite_join2semi(v, rel);        /* where possible convert anyequal functions into marks */
    4495     2148696 :         if (rel)
    4496     2148696 :                 rel = rewrite_compare_exp(v, rel);      /* only allow for e_cmp in selects and  handling */
    4497     2148875 :         if (rel)
    4498     2148875 :                 rel = rewrite_remove_xp_project(v, rel);        /* remove crossproducts with project ( project [ atom ] ) [ etc ] */
    4499     2148978 :         if (rel)
    4500     2148978 :                 rel = rewrite_simplify(v, 0, false, rel);               /* as expressions got merged before, lets try to simplify again */
    4501     2149028 :         return rel;
    4502             : }
    4503             : 
    4504             : static sql_exp *
    4505     8383072 : rel_simplify_exp_and_rank(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    4506             : {
    4507     8383072 :         if (e)
    4508     8383072 :                 e = rewrite_simplify_exp(v, rel, e, depth);
    4509     8383908 :         if (e)
    4510     8383908 :                 e = rewrite_rank(v, rel, e, depth);
    4511     8385235 :         return e;
    4512             : }
    4513             : 
    4514             : static inline sql_rel *
    4515     3357777 : run_exp_rewriter(visitor *v, sql_rel *rel, exp_rewrite_fptr rewriter, bool direction, const char *name)
    4516             : {
    4517     3357777 :         (void)name;
    4518             :         /*
    4519             : #ifndef NDEBUG
    4520             :         int changes = v->changes;
    4521             :         lng clk = GDKusec();
    4522             :         rel = rel_exp_visitor_bottomup(v, rel, rewriter, direction);
    4523             :         printf("%s %d " LLFMT "\n", name, (v->changes - changes), (GDKusec() - clk));
    4524             :         return rel;
    4525             : #else
    4526             : */
    4527     3357777 :         return rel_exp_visitor_bottomup(v, rel, rewriter, direction);
    4528             : /*#endif*/
    4529             : }
    4530             : 
    4531             : static inline sql_rel *
    4532     3358448 : run_rel_rewriter(visitor *v, sql_rel *rel, rel_rewrite_fptr rewriter, const char *name)
    4533             : {
    4534     3358448 :         (void)name;
    4535             :         /*
    4536             : #ifndef NDEBUG
    4537             :         int changes = v->changes;
    4538             :         lng clk = GDKusec();
    4539             :         rel = rel_visitor_bottomup(v, rel, rewriter);
    4540             :         printf("%s %d " LLFMT "\n", name, (v->changes - changes), (GDKusec() - clk));
    4541             :         return rel;
    4542             : #else
    4543             : */
    4544     3358448 :         return rel_visitor_bottomup(v, rel, rewriter);
    4545             : /*#endif*/
    4546             : }
    4547             : 
    4548             : sql_rel *
    4549      670829 : rel_unnest(mvc *sql, sql_rel *rel)
    4550             : {
    4551      670829 :         visitor v = { .sql = sql };
    4552             : 
    4553      670829 :         rel = run_exp_rewriter(&v, rel, &rel_simplify_exp_and_rank, false, "simplify_exp_and_rank");
    4554      671722 :         rel = run_rel_rewriter(&v, rel, &rel_unnest_simplify, "unnest_simplify");
    4555      671756 :         rel = run_exp_rewriter(&v, rel, &rewrite_complex, true, "rewrite_complex");
    4556      671716 :         rel = run_exp_rewriter(&v, rel, &rewrite_ifthenelse, false, "rewrite_ifthenelse"); /* add isnull handling */
    4557      671722 :         rel = run_exp_rewriter(&v, rel, &rewrite_exp_rel, true, "rewrite_exp_rel");
    4558             : 
    4559      671720 :         rel = run_rel_rewriter(&v, rel, &rel_unnest_comparison_rewriters, "unnest_comparison_rewriters");
    4560      671779 :         rel = run_rel_rewriter(&v, rel, &_rel_unnest, "unnest");
    4561      671729 :         rel = run_rel_rewriter(&v, rel, &rewrite_fix_count, "fix_count");     /* fix count inside a left join (adds a project (if (cnt IS null) then (0) else (cnt)) */
    4562      671498 :         rel = run_rel_rewriter(&v, rel, &rel_unnest_projects, "unnest_projects");
    4563      671754 :         rel = run_exp_rewriter(&v, rel, &exp_reset_card_and_freevar_set_physical_type, false, "exp_reset_card_and_freevar_set_physical_type");
    4564      671672 :         rel = rel_visitor_topdown(&v, rel, &rel_set_type);
    4565      671703 :         return rel;
    4566             : }

Generated by: LCOV version 1.14