LCOV - code coverage report
Current view: top level - sql/server - rel_unnest.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2560 2868 89.3 %
Date: 2024-12-19 20:05:57 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       19513 : exp_set_freevar(mvc *sql, sql_exp *e, sql_rel *r)
      24             : {
      25       20513 :         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        7656 :         case e_column:
      49        7656 :                 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        9469 : is_distinct_set(mvc *sql, sql_rel *rel, list *ad)
      76             : {
      77        9515 :         int distinct = 0;
      78        9515 :         if (ad && is_groupby(rel->op) && (list_empty(rel->r) || exp_match_list(rel->r, ad)))
      79          39 :                 return 1;
      80        9476 :         distinct = need_distinct(rel);
      81        9476 :         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    13860317 : exp_has_freevar(mvc *sql, sql_exp *e)
      88             : {
      89    14007176 :         if (mvc_highwater(sql)) {
      90           5 :                 (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
      91           5 :                 return 0;
      92             :         }
      93             : 
      94    14007171 :         if (is_freevar(e))
      95      121702 :                 return is_freevar(e);
      96    13885469 :         switch(e->type) {
      97     1690185 :         case e_cmp:
      98     1690185 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
      99       56692 :                         return (exps_have_freevar(sql, e->l) || exps_have_freevar(sql, e->r));
     100     1634122 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
     101      131855 :                         return (exp_has_freevar(sql, e->l) || exps_have_freevar(sql, e->r));
     102             :                 } else {
     103     3004554 :                         return (exp_has_freevar(sql, e->l) || exp_has_freevar(sql, e->r) ||
     104     1397281 :                             (e->f && exp_has_freevar(sql, e->f)));
     105             :                 }
     106      146859 :                 break;
     107      146859 :         case e_convert:
     108      146859 :                 return exp_has_freevar(sql, e->l);
     109      969782 :         case e_func:
     110             :         case e_aggr:
     111      969782 :                 if (e->l)
     112      937787 :                         return exps_have_freevar(sql, e->l);
     113             :                 /* fall through */
     114             :         case e_psm:
     115       34056 :                 if (exp_is_rel(e))
     116        2061 :                         return rel_has_freevar(sql, e->l);
     117             :                 break;
     118     3041675 :         case e_atom:
     119     3041675 :                 if (e->f)
     120      145020 :                         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     4171919 : exps_have_freevar(mvc *sql, list *exps)
     131             : {
     132     4171919 :         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     4171921 :         if (!exps)
     137             :                 return 0;
     138    14009718 :         for (node *n = exps->h; n; n = n->next) {
     139    10193108 :                 int vf = 0;
     140    10193108 :                 sql_exp *e = n->data;
     141    10193108 :                 if ((vf =exp_has_freevar(sql, e)) != 0)
     142      161710 :                         return vf;
     143             :         }
     144             :         return 0;
     145             : }
     146             : 
     147             : int
     148     3312857 : rel_has_freevar(mvc *sql, sql_rel *rel)
     149             : {
     150     3312857 :         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     3312857 :         if (is_basetable(rel->op)) {
     156             :                 return 0;
     157     2498770 :         } else if (is_base(rel->op)) {
     158         938 :                 return exps_have_freevar(sql, rel->exps) ||
     159         469 :                         (rel->l && rel_has_freevar(sql, rel->l));
     160     2498301 :         } else if (is_simple_project(rel->op) || is_groupby(rel->op) || is_select(rel->op) || is_topn(rel->op) || is_sample(rel->op)) {
     161     1710105 :                 if ((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->r && exps_have_freevar(sql, rel->r))
     162             :                         return 1;
     163     3419466 :                 return exps_have_freevar(sql, rel->exps) ||
     164     1612734 :                         (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     1441980 :                 return exps_have_freevar(sql, rel->exps) ||
     167     1441002 :                         rel_has_freevar(sql, rel->l) || rel_has_freevar(sql, rel->r);
     168             :         } else if (is_munion(rel->op)) {
     169       66291 :                 int v = exps_have_freevar(sql, rel->exps);
     170       66291 :                 list *l = rel->l;
     171      186793 :                 for (node *n = l->h; n && !v; n = n->next)
     172      120502 :                         v = rel_has_freevar(sql, n->data);
     173       66291 :                 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       56125 : exp_only_freevar(sql_query *query, sql_exp *e, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols)
     183             : {
     184       57898 :         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       57898 :         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       57494 :         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        1771 :         case e_convert:
     221        1771 :                 exp_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
     222        1771 :                 break;
     223       14143 :         case e_func:
     224             :         case e_aggr:
     225       14143 :                 if (e->l)
     226       14143 :                         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       10265 :         case e_atom:
     233       10265 :                 if (e->f)
     234          17 :                         exps_only_freevar(query, e->f, arguments_correlated, found_one_freevar, ungrouped_cols);
     235             :                 break;
     236       31244 :         case e_column:
     237       31244 :                 *arguments_correlated = 0;
     238       31244 :                 break;
     239             :         }
     240             : }
     241             : 
     242             : void
     243       14212 : exps_only_freevar(sql_query *query, list *exps, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols)
     244             : {
     245       14212 :         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       14212 :         if (!exps)
     250             :                 return ;
     251       42989 :         for (node *n = exps->h; n ; n = n->next)
     252       28777 :                 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      662988 : merge_freevar(list *l, list *r, bool all)
     302             : {
     303      662988 :         if (!l)
     304             :                 return r;
     305      148546 :         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      667187 : exp_freevar(mvc *sql, sql_exp *e, bool all)
     318             : {
     319      667187 :         if (mvc_highwater(sql))
     320           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     321             : 
     322      667187 :         switch(e->type) {
     323      300666 :         case e_column:
     324      300666 :                 if (is_freevar(e))
     325       87301 :                         return append(sa_list(sql->sa), e);
     326             :                 break;
     327       14502 :         case e_convert:
     328       14502 :                 return exp_freevar(sql, e->l, all);
     329      100333 :         case e_aggr:
     330             :         case e_func:
     331      100333 :                 if (e->l)
     332       88426 :                         return exps_freevar(sql, e->l);
     333             :                 break;
     334       81297 :         case e_cmp:
     335       81297 :                 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       80564 :                 } 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       80552 :                         list *l = exp_freevar(sql, e->l, all);
     345       80552 :                         list *r = exp_freevar(sql, e->r, all);
     346       80552 :                         l = merge_freevar(l, r, all);
     347       80552 :                         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      170337 :         case e_atom:
     360      170337 :                 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      254477 : exps_freevar(mvc *sql, list *exps)
     371             : {
     372      254477 :         node *n;
     373      254477 :         list *c = NULL;
     374             : 
     375      254477 :         if (mvc_highwater(sql))
     376           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     377      254477 :         if (!exps)
     378             :                 return NULL;
     379      659301 :         for (n = exps->h; n; n = n->next) {
     380      406290 :                 sql_exp *e = n->data;
     381      406290 :                 list *var = exp_freevar(sql, e, false);
     382             : 
     383      406290 :                 c = merge_freevar(c,var, false);
     384             :         }
     385             :         return c;
     386             : }
     387             : 
     388             : static list *
     389      211953 : rel_freevar(mvc *sql, sql_rel *rel)
     390             : {
     391      211953 :         list *lexps = NULL, *rexps = NULL, *exps = NULL;
     392             : 
     393      211953 :         if (mvc_highwater(sql))
     394           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
     395      211953 :         if (!rel)
     396             :                 return NULL;
     397      196705 :         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      151068 :         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      151068 :                 exps = exps_freevar(sql, rel->exps);
     445      151068 :                 lexps = rel_freevar(sql, rel->l);
     446      151068 :                 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      151068 :                 exps = merge_freevar(exps, lexps, false);
     454      151068 :                 return exps;
     455             :         default:
     456             :                 return NULL;
     457             :         }
     458             : 
     459             : }
     460             : 
     461             : static list *
     462       34098 : rel_dependent_var(mvc *sql, sql_rel *l, sql_rel *r)
     463             : {
     464       34098 :         list *res = NULL;
     465             : 
     466       34098 :         if (rel_has_freevar(sql, r)){
     467       34013 :                 list *freevar = rel_freevar(sql, r);
     468       34013 :                 if (freevar) {
     469       34013 :                         node *n;
     470       34013 :                         list *boundvar = rel_projections(sql, l, NULL, 1, 0);
     471             : 
     472       86579 :                         for(n = freevar->h; n; n = n->next) {
     473       52566 :                                 sql_exp *e = n->data, *ne = NULL;
     474             :                                 /* each freevar should be an e_column */
     475       52566 :                                 ne = exps_bind_nid(boundvar, e->nid);
     476       52566 :                                 if (ne) {
     477       52270 :                                         if (!res)
     478       33879 :                                                 res = sa_list(sql->sa);
     479       52270 :                                         append(res, ne);
     480             :                                 }
     481             :                         }
     482             :                 }
     483             :         }
     484       34098 :         return res;
     485             : }
     486             : 
     487             : /*
     488             :  * try to bind any freevar in the expression e
     489             :  */
     490             : void
     491       85115 : rel_bind_var(mvc *sql, sql_rel *rel, sql_exp *e)
     492             : {
     493       85115 :         list *fvs = exp_freevar(sql, e, true);
     494             : 
     495       85115 :         if (fvs) {
     496       14817 :                 node *n;
     497             : 
     498       29797 :                 for(n = fvs->h; n; n=n->next) {
     499       14980 :                         sql_exp *e = n->data;
     500             : 
     501       14980 :                         if (is_freevar(e) && (exp_is_atom(e) || rel_find_exp(rel,e)))
     502       10809 :                                 reset_freevar(e);
     503             :                 }
     504             :         }
     505       85115 : }
     506             : 
     507             : void
     508       17271 : rel_bind_vars(mvc *sql, sql_rel *rel, list *exps)
     509             : {
     510       17271 :         if (list_empty(exps))
     511             :                 return;
     512       80026 :         for(node *n=exps->h; n; n = n->next)
     513       62828 :                 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        9775 : push_up_project_exps(mvc *sql, sql_rel *rel, list *exps)
     520             : {
     521        9775 :         node *n;
     522             : 
     523        9775 :         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        2514 : exps_rewrite(mvc *sql, sql_rel *rel, list *exps, list *ad)
     599             : {
     600        2514 :         list *nexps;
     601        2514 :         node *n;
     602             : 
     603        2514 :         if (list_empty(exps))
     604             :                 return exps;
     605        2497 :         nexps = sa_list(sql->sa);
     606        7920 :         for(n=exps->h; n; n = n->next)
     607        5423 :                 append(nexps, exp_rewrite(sql, rel, n->data, ad));
     608             :         return nexps;
     609             : }
     610             : 
     611             : /* recursively rewrite some functions */
     612             : static sql_exp *
     613       12130 : exp_rewrite(mvc *sql, sql_rel *rel, sql_exp *e, list *ad)
     614             : {
     615       12130 :         sql_subfunc *sf;
     616             : 
     617       12130 :         if (e->type == e_convert) {
     618         103 :                 e->l = exp_rewrite(sql, rel, e->l, ad);
     619         103 :                 return e;
     620             :         }
     621       12027 :         if (e->type != e_func)
     622             :                 return e;
     623        2514 :         e->l = exps_rewrite(sql, rel, e->l, ad);
     624        2514 :         sf = e->f;
     625             :         /* window functions need to be run per freevars */
     626        2514 :         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        1324 : rel_reduce2one_exp(mvc *sql, sql_rel *sq)
     677             : {
     678        1324 :         sql_exp *e = NULL;
     679             : 
     680        1324 :         if (list_empty(sq->exps))
     681             :                 return NULL;
     682        1324 :         if (list_length(sq->exps) == 1)
     683        1148 :                 return sq->exps->t->data;
     684         388 :         for(node *n = sq->exps->h; n && !e; n = n->next) {
     685         212 :                 sql_exp *t = n->data;
     686             : 
     687         212 :                 if (!is_freevar(t))
     688         173 :                         e = t;
     689             :         }
     690         176 :         if (!e)
     691           3 :                 e = sq->exps->t->data;
     692         176 :         sq->exps = append(sa_list(sql->sa), e);
     693         176 :         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        4349 : move_join_exps(mvc *sql, sql_rel *j, sql_rel *rel)
     726             : {
     727        4349 :         node *n;
     728        4349 :         list *exps = rel->exps;
     729             : 
     730        4349 :         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        4266 : rel_general_unnest(mvc *sql, sql_rel *rel, list *ad)
     752             : {
     753        4266 :         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel) && ad) {
     754        4266 :                 list *fd;
     755        4266 :                 node *n, *m;
     756             : 
     757        4266 :                 sql_rel *l = rel->l, *r = rel->r, *inner_r;
     758             : 
     759             :                 /* cleanup empty selects (should be done before any rel_dup(l) */
     760        4266 :                 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        4266 :                 sql_rel *D = rel_project(sql->sa, rel_dup(l), exps_copy(sql, ad));
     768        4266 :                 set_distinct(D);
     769             : 
     770        4266 :                 int single = is_single(r);
     771        4266 :                 reset_single(r);
     772        4266 :                 sql_rel *or = r;
     773        4266 :                 r = rel_crossproduct(sql->sa, D, r, rel->op);
     774        4266 :                 if (single)
     775           9 :                         set_single(or);
     776        4266 :                 r->op = op_join;
     777        4266 :                 move_join_exps(sql, rel, r);
     778        4266 :                 set_dependent(r);
     779        4266 :                 set_processed(r);
     780        4266 :                 inner_r = r;
     781             : 
     782        4266 :                 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        4266 :                 if (!is_semi(inner_r->op))  { /* skip the free vars */
     785        4266 :                         list *exps = sa_list(sql->sa);
     786             : 
     787        9333 :                         for(node *n=r->exps->h; n; n = n->next) {
     788        5067 :                                 sql_exp *e = n->data, *ne = NULL;
     789             : 
     790        5067 :                                 if (e->nid)
     791        5067 :                                         ne = exps_bind_nid(ad, e->nid);
     792        5067 :                                 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        5067 :                                 if (!ne)
     798        5015 :                                         append(exps,e);
     799             :                         }
     800        4266 :                         r->exps = exps;
     801             :                 }
     802             : 
     803             :                 /* append ad + rename */
     804        4266 :                 fd = exps_label(sql, exps_copy(sql, ad));
     805       11602 :                 for (n = ad->h, m = fd->h; n && m; n = n->next, m = m->next) {
     806        7336 :                         sql_exp *l = n->data, *r = m->data, *e;
     807             : 
     808        7336 :                         l = exp_ref(sql, l);
     809        7336 :                         r = exp_ref(sql, r);
     810        7336 :                         e = exp_compare(sql->sa, l, r, cmp_equal);
     811        7336 :                         set_semantics(e);
     812        7336 :                         if (!rel->exps)
     813        4182 :                                 rel->exps = sa_list(sql->sa);
     814        7336 :                         append(rel->exps, e);
     815             :                 }
     816        4266 :                 list_merge(r->exps, fd, (fdup)NULL);
     817        4266 :                 rel->r = r;
     818        4266 :                 reset_dependent(rel);
     819        4266 :                 return rel;
     820             :         }
     821             :         return rel;
     822             : }
     823             : 
     824             : static sql_rel *
     825        9713 : push_up_project(mvc *sql, sql_rel *rel, list *ad)
     826             : {
     827        9713 :         sql_rel *r = rel->r;
     828             : 
     829        9713 :         assert(is_simple_project(r->op));
     830        9713 :         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        9713 :         if (rel && is_join(rel->op) && is_dependent(rel)) {
     845        9590 :                 sql_rel *r = rel->r;
     846             : 
     847             :                 /* find constant expressions and move these down */
     848        9590 :                 if (r && r->op == op_project) {
     849        9590 :                         node *n;
     850        9590 :                         list *nexps = NULL;
     851        9590 :                         list *cexps = NULL;
     852        9590 :                         sql_rel *l = r->l;
     853             : 
     854        9607 :                         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        9590 :                         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        9713 :         if (rel && is_join(rel->op) && is_dependent(rel)) {
     904        9590 :                 sql_rel *r = rel->r;
     905             : 
     906             :                 /* merge project expressions into the join expressions  */
     907        9590 :                 rel->exps = push_up_project_exps(sql, r, rel->exps);
     908             : 
     909        9590 :                 if (r && r->op == op_project) {
     910        5435 :                         sql_exp *id = NULL;
     911        5435 :                         node *m;
     912             : 
     913        5435 :                         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        4864 :                         sql_rel *n = rel_project( sql->sa, (r->l)?rel:rel->l,
     942        4864 :                                         rel_projections(sql, rel->l, NULL, 1, 1));
     943             : 
     944        4864 :                         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        4864 :                         if (list_empty(rel->attr) && !list_empty(r->exps)) {
     947       11331 :                                 for (m=r->exps->h; m; m = m->next) {
     948        6605 :                                         sql_exp *e = m->data;
     949             : 
     950        6605 :                                         if (!is_freevar(e) || exp_name(e)) { /* only skip full freevars */
     951        6605 :                                                 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        6604 :                                         if (r->l)
     974        6604 :                                                 e = exp_rewrite(sql, r->l, e, ad);
     975        6604 :                                         append(n->exps, e);
     976             :                                 }
     977             :                         }
     978        4863 :                         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        4863 :                         if (r->l) {
     993        4863 :                                 rel->r = r->l;
     994        4863 :                                 r->l = NULL;
     995             :                         }
     996        4863 :                         rel_destroy(r);
     997        4863 :                         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        7582 : push_up_select(mvc *sql, sql_rel *rel, list *ad)
    1073             : {
    1074        7582 :         sql_rel *d = rel->l;
    1075        7582 :         sql_rel *r = rel->r;
    1076        7582 :         int inner = 0;
    1077             : 
    1078        7582 :         if (rel && is_dependent(rel) && r && is_select(r->op)) {
    1079        7582 :                 sql_rel *rl = r->l;
    1080             : 
    1081        7582 :                 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        7552 :         if ((!inner || is_semi(rel->op)) && rel && is_dependent(rel)) {
    1091        5569 :                 sql_rel *r = rel->r;
    1092             : 
    1093        5569 :                 if (r && is_select(r->op)) { /* move into join */
    1094        5569 :                         node *n;
    1095             : 
    1096        5569 :                         if (!list_empty(r->exps)) {
    1097       12242 :                                 for (n=r->exps->h; n; n = n->next) {
    1098        6673 :                                         sql_exp *e = n->data;
    1099             : 
    1100        6673 :                                         e = exp_copy(sql, e);
    1101        6673 :                                         if (exp_has_freevar(sql, e))
    1102        6658 :                                                 rel_bind_var(sql, rel->l, e);
    1103        6673 :                                         rel_join_add_exp(sql->sa, rel, e);
    1104             :                                 }
    1105             :                         }
    1106             :                         /* remove select */
    1107        5569 :                         rel->r = rel_dup(r->l);
    1108        5569 :                         rel_destroy(r);
    1109        5569 :                         r = rel->r;
    1110        5569 :                         if (is_single(r)) {
    1111           2 :                                 set_single(rel);
    1112           2 :                                 rel->op = op_left;
    1113             :                         }
    1114        5569 :                         if (!inner)
    1115        5538 :                                 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      171905 : exp_is_count(sql_exp *e, sql_rel *rel)
    1148             : {
    1149      252712 :         if (!e || !rel)
    1150             :                 return 0;
    1151      244139 :         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       80807 :                 sql_rel *pr = is_munion(rel->op) ? ((list*)rel->l)->h->data : rel->l;
    1156       80807 :                 sql_exp *ne = rel_find_exp(pr, e);
    1157       80807 :                 return exp_is_count(ne, pr);
    1158             :         }
    1159      163332 :         if (is_aggr(e->type) && exp_aggr_is_count(e))
    1160             :                 return 1;
    1161             :         return 0;
    1162             : }
    1163             : 
    1164             : static sql_rel *
    1165        2881 : push_up_groupby(mvc *sql, sql_rel *rel, list *ad)
    1166             : {
    1167             :         /* input rel is dependent join with on the right a groupby */
    1168        2881 :         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
    1169        2881 :                 sql_rel *l = rel->l, *r = rel->r;
    1170             : 
    1171             :                 /* left of rel should be a set */
    1172        2881 :                 if (l && is_distinct_set(sql, l, ad) && r && is_groupby(r->op)) {
    1173        2881 :                         list *sexps, *jexps, *a = rel_projections(sql, rel->l, NULL, 1, 1);
    1174        2881 :                         node *n;
    1175        2881 :                         sql_exp *id = NULL;
    1176             : 
    1177             :                         /* move groupby up, ie add attributes of left + the old expression list */
    1178             : 
    1179        2881 :                         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        2881 :                         if (rel->op == op_semi)
    1186           1 :                                 rel->op = op_join;
    1187        2881 :                         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        2881 :                         if (!list_empty(r->exps)) {
    1199        5903 :                                 for (n = r->exps->h; n; n = n->next ) {
    1200        3022 :                                         sql_exp *e = n->data;
    1201             : 
    1202             :                                         /* count_nil(* or constant) -> count(t.TID) */
    1203        3022 :                                         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        3022 :                                         if (exp_has_freevar(sql, e))
    1224           6 :                                                 rel_bind_var(sql, rel->l, e);
    1225             :                                 }
    1226             :                         }
    1227        2881 :                         r->exps = list_distinct(list_merge(r->exps, a, (fdup)NULL), (fcmp)exp_equal, (fdup)NULL);
    1228        2881 :                         if (list_empty(r->r)) {
    1229        2829 :                                 if (id)
    1230           2 :                                         r->r = list_append(sa_list(sql->sa), exp_ref(sql, id));
    1231             :                                 else
    1232        2827 :                                         r->r = exps_copy(sql, a);
    1233        2829 :                                 r->card = CARD_AGGR;
    1234             :                                 /* After the unnesting, the cardinality of the aggregate function becomes larger */
    1235        9670 :                                 for(node *n = r->exps->h; n; n = n->next) {
    1236        6841 :                                         sql_exp *e = n->data;
    1237             : 
    1238        6841 :                                         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        2881 :                         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        2881 :                                 rel->r = r->l;
    1288        2881 :                                 r->l = rel;
    1289             :                         }
    1290             :                         /* check if a join expression needs to be moved above the group by (into a select) */
    1291        2881 :                         sexps = sa_list(sql->sa);
    1292        2881 :                         jexps = sa_list(sql->sa);
    1293        2881 :                         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        2881 :                         rel->exps = jexps;
    1305        2881 :                         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        2881 :                         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        9721 : exps_have_rank(list *exps)
    1730             : {
    1731        9721 :         if (!exps)
    1732             :                 return false;
    1733       24059 :         for(node *n=exps->h; n; n = n->next) {
    1734       14437 :                 sql_exp *e = n->data;
    1735       14437 :                 if (is_analytic(e))
    1736             :                         return true;
    1737             :         }
    1738             :         return false;
    1739             : }
    1740             : 
    1741             : static sql_rel *
    1742      649586 : rel_unnest_dependent(mvc *sql, sql_rel *rel)
    1743             : {
    1744      671532 :         sql_rel *nrel = rel;
    1745             : 
    1746      671532 :         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      671532 :         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
    1751             :                 /* howto find out the left is a set */
    1752       30415 :                 sql_rel *l, *r;
    1753             : 
    1754       30415 :                 l = rel->l;
    1755       30415 :                 r = rel->r;
    1756             : 
    1757       30415 :                 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       30415 :                 if (!rel_has_freevar(sql, r)) {
    1779        4203 :                         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        4198 :                                 reset_dependent(rel);
    1786        4198 :                                 return rel;
    1787             :                         }
    1788             :                 }
    1789             : 
    1790             :                 /* try to push dependent join down */
    1791       26217 :                 if (rel_has_freevar(sql, r)) {
    1792       26217 :                         list *ad = rel_dependent_var(sql, rel->l, rel->r);
    1793             : 
    1794       26217 :                         if (list_empty(ad)) {
    1795          12 :                                 reset_dependent(rel);
    1796          12 :                                 return rel;
    1797             :                         }
    1798       26205 :                         if (r && is_select(r->op)) {
    1799        7588 :                                 sql_rel *l = r->l;
    1800             : 
    1801        7588 :                                 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       26199 :                         if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
    1811       26199 :                                 sql_rel *j = rel->r;
    1812             : 
    1813       26199 :                                 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       26188 :                         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        9713 :                                 rel = push_up_project(sql, rel, ad);
    1823        9713 :                                 return rel_unnest_dependent(sql, rel);
    1824             :                         }
    1825             : 
    1826       16475 :                         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       16470 :                         if (r && is_select(r->op) && ad) {
    1832        7582 :                                 rel = push_up_select(sql, rel, ad);
    1833        7582 :                                 return rel_unnest_dependent(sql, rel);
    1834             :                         }
    1835             : 
    1836        8888 :                         if (r && is_groupby(r->op) && !is_left(rel->op) && is_distinct_set(sql, l, ad)) {
    1837        2881 :                                 rel = push_up_groupby(sql, rel, ad);
    1838        2881 :                                 return rel_unnest_dependent(sql, rel);
    1839             :                         }
    1840             : 
    1841        6007 :                         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        5831 :                         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        5790 :                         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        4259 :                         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        4236 :                         if (ad != NULL)
    1863        4236 :                                 rel = rel_general_unnest(sql, rel, ad);
    1864             : 
    1865             :                         /* no dependent variables */
    1866        4236 :                         reset_dependent(rel);
    1867        4236 :                         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      630195 :                 if (rel && (is_simple_project(rel->op) || is_groupby(rel->op) || is_select(rel->op) || is_topn(rel->op) || is_sample(rel->op)))
    1874      308589 :                         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      153505 :                         rel->l = rel_unnest_dependent(sql, rel->l);
    1877      153505 :                         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       12284 : add_missing_project_exp(mvc *sql, sql_rel *rel, sql_exp *e)
    1891             : {
    1892       12284 :         if (is_freevar(e))
    1893             :                 return e;
    1894        8260 :         if (is_convert(e->type)) {
    1895          65 :                 e->l = add_missing_project_exp(sql, rel, e->l);
    1896        8195 :         } else if (is_compare(e->type)) {
    1897        4089 :                 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        4087 :                 } 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        4045 :                         e->l = add_missing_project_exp(sql, rel, e->l);
    1905        4045 :                         e->r = add_missing_project_exp(sql, rel, e->r);
    1906        4045 :                         if (e->f)
    1907          11 :                                 e->f = add_missing_project_exp(sql, rel, e->f);
    1908             :                 }
    1909        4106 :         } 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        3921 :         else if (!list_find_exp(rel->exps, e)) {
    1915        3837 :                 if (!e->alias.label)
    1916          39 :                         exp_label(sql->sa, e, ++sql->label);
    1917        3837 :                 append(rel->exps, e);
    1918        3837 :                 return exp_ref(sql, e);
    1919             :         }
    1920             :         return e;
    1921             : }
    1922             : 
    1923             : static list *
    1924        4030 : add_missing_project_exps(mvc *sql, sql_rel *rel, list *exps)
    1925             : {
    1926        4030 :         if (list_empty(exps))
    1927             :                 return exps;
    1928        8146 :         for(node *n = exps->h; n; n = n->next)
    1929        4116 :                 n->data = add_missing_project_exp(sql, rel, n->data);
    1930             :         return exps;
    1931             : }
    1932             : 
    1933             : static sql_rel *
    1934        4474 : push_up_select2(visitor *v, sql_rel *rel)
    1935             : {
    1936        4474 :         sql_rel *l = rel->l;
    1937        4474 :         sql_rel *r = rel->r;
    1938             : 
    1939             :         /* TODO make sure we do not have empty selects */
    1940        4474 :         if (is_simple_project(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) {
    1941        3944 :                 sql_rel *nl = rel_select(v->sql->sa, rel, NULL);
    1942        3944 :                 nl->exps = add_missing_project_exps(v->sql, rel, l->exps);
    1943        3944 :                 l->exps = NULL;
    1944        3944 :                 rel->l = rel_dup(l->l);
    1945        3944 :                 rel_destroy(l);
    1946        3944 :                 rel_bind_vars(v->sql, nl, nl->exps);
    1947        3944 :                 v->changes++;
    1948        3944 :                 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     2327074 : _rel_unnest(visitor *v, sql_rel *rel)
    2047             : {
    2048     2327074 :         sql_rel *l = rel->l;
    2049     2327074 :         sql_rel *r = rel->r;
    2050             :         /* try to push select up */
    2051     2327074 :         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     2306350 :             (is_join(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) ||
    2053     2306311 :             (is_join(rel->op) && r && is_select(r->op) && exps_have_freevar(v->sql, r->exps) && !rel_is_ref(r)))) {
    2054        4437 :                 rel = push_up_select2(v, rel);
    2055        4437 :                 if (rel && is_select(rel->op)) {
    2056        3994 :                         sql_rel *l = rel->l;
    2057        3994 :                         if (is_dependent(l)) {
    2058          18 :                                 rel->l = l = rel_unnest_dependent(v->sql, l);
    2059          18 :                                 v->changes++;
    2060             :                         }
    2061             :                 }
    2062             :         }
    2063     2327074 :         if (is_dependent(rel)) {
    2064        8814 :                 rel = rel_unnest_dependent(v->sql, rel);
    2065        8814 :                 v->changes++;
    2066             :         }
    2067     2327074 :         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       23068 : exp_reset_props(sql_rel *rel, sql_exp *e, bool setnil)
    2082             : {
    2083       23068 :         switch (e->type) {
    2084       20670 :         case e_column: {
    2085       20670 :                 if (setnil && (((is_right(rel->op) || is_full(rel->op)) && rel_find_exp(rel->l, e) != NULL) ||
    2086       14218 :                         ((is_left(rel->op) || is_full(rel->op)) && rel_find_exp(rel->r, e) != NULL)))
    2087       14125 :                         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       23068 :         set_not_unique(e);
    2132       23068 : }
    2133             : 
    2134             : static sql_exp *
    2135       23329 : rewrite_inner(mvc *sql, sql_rel *rel, sql_rel *inner, operator_type op, sql_rel **rewrite)
    2136             : {
    2137       23329 :         int single = is_single(inner);
    2138       23329 :         sql_rel *d = NULL;
    2139             : 
    2140       23329 :         reset_single(inner);
    2141       23329 :         if (single && is_project(rel->op))
    2142       23329 :                 op = op_left;
    2143             : 
    2144       23329 :         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       23322 :         } else if (is_project(rel->op)){ /* projection -> op_left */
    2159       13606 :                 if (rel->l || single || op == op_left) {
    2160       13582 :                         if ((single || op == op_left) && !rel->l) {
    2161         547 :                                 sql_exp *e = exp_atom_bool(sql->sa, 1);
    2162         547 :                                 exp_label(sql->sa, e, ++sql->label);
    2163         547 :                                 rel->l = rel_project(sql->sa, rel->l, list_append(sa_list(sql->sa), e));
    2164             :                         }
    2165       13582 :                         d = rel->l = rel_crossproduct(sql->sa, rel->l, inner, op_left);
    2166       13582 :                         if (single)
    2167        1566 :                                 set_single(d);
    2168       13582 :                         set_processed(d);
    2169             :                 } else {
    2170          24 :                         d = rel->l = inner;
    2171             :                 }
    2172             :         } else {
    2173        9716 :                 d = rel->l = rel_crossproduct(sql->sa, rel->l, inner, op);
    2174        9716 :                 if (single)
    2175        3206 :                         set_single(d);
    2176        9716 :                 set_processed(d);
    2177             :         }
    2178       23329 :         assert(d);
    2179       23329 :         if (rel_has_freevar(sql, inner)) {
    2180        5621 :                 list *dv = rel_dependent_var(sql, d, inner);
    2181        5621 :                 list *fv = rel_freevar(sql, inner);
    2182             :                 /* check if the inner depends on the new join (d) or one level up */
    2183        5621 :                 if (list_length(dv))
    2184        5504 :                         set_dependent(d);
    2185        5621 :                 if (list_length(fv) != list_length(dv))
    2186         184 :                         set_dependent(rel);
    2187             :         }
    2188       23329 :         if (rewrite)
    2189       22654 :                 *rewrite = d;
    2190       23329 :         if (is_project(inner->op))
    2191       23321 :                 return inner->exps->t->data;
    2192             :         return NULL;
    2193             : }
    2194             : 
    2195             : static sql_exp *
    2196    11312979 : rewrite_exp_rel(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    2197             : {
    2198    11312979 :         if (exp_has_rel(e) && !is_ddl(rel->op)) {
    2199        9578 :                 sql_rel *rewrite = NULL;
    2200       13838 :                 sql_exp *ne = rewrite_inner(v->sql, rel, exp_rel_get_rel(v->sql->sa, e), depth?op_left:op_join, &rewrite);
    2201             : 
    2202        9578 :                 if (!ne)
    2203           1 :                         return ne;
    2204        9577 :                 if (exp_is_rel(e)) {
    2205        9577 :                         ne = exp_ref(v->sql, ne);
    2206        9577 :                         if (exp_name(e))
    2207        9577 :                                 exp_prop_alias(v->sql->sa, ne, e);
    2208        9577 :                         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        9577 :                 exp_reset_props(rewrite, e, is_left(rewrite->op));
    2215        9577 :                 v->changes++;
    2216             :         }
    2217             :         return e;
    2218             : }
    2219             : 
    2220             : /* add an dummy true projection column */
    2221             : static inline sql_rel *
    2222     2270610 : rewrite_empty_project(visitor *v, sql_rel *rel)
    2223             : {
    2224     2270610 :         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     2270607 :         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    13735960 : exp_physical_types(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    2244             : {
    2245    13735960 :         (void)rel;
    2246    13735960 :         (void)depth;
    2247    13735960 :         sql_exp *ne = e;
    2248             : 
    2249    13735960 :         if (!e || (e->type != e_func && e->type != e_convert) || !e->l)
    2250             :                 return e;
    2251             : 
    2252      712448 :         if (e->type != e_convert) {
    2253      568299 :                 list *args = e->l;
    2254      568299 :                 sql_subfunc *f = e->f;
    2255             : 
    2256             :                 /* multiplication and division on decimals */
    2257      568299 :                 if (is_multiplication(f) && list_length(args) == 2) {
    2258       20036 :                         sql_exp *le = args->h->data;
    2259       20036 :                         sql_subtype *lt = exp_subtype(le);
    2260             : 
    2261       20036 :                         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      548263 :                 } 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      712448 :         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    13735925 : exp_reset_card_and_freevar_set_physical_type(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    2334             : {
    2335    13735925 :         if (e->type == e_func && e->r) /* mark as normal (analytic) function now */
    2336        7786 :                 e->r = NULL;
    2337    13735925 :         reset_freevar(e); /* unnesting is done, we can remove the freevar flag */
    2338             : 
    2339    13735925 :         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    13736131 :         if (!rel->l)
    2342             :                 return e;
    2343             : 
    2344    10258684 :         switch(rel->op){
    2345     6738791 :         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     6738791 :                 switch(e->type) {
    2354      495665 :                 case e_aggr:
    2355             :                 case e_func: {
    2356      495665 :                         e->card = list_empty(e->l)?rel?rel->card:(unsigned)CARD_MULTI:exps_card(e->l);
    2357      495665 :                 } break;
    2358     4625167 :                 case e_column: {
    2359     4625167 :                         sql_exp *le = NULL, *re = NULL;
    2360     4625167 :                         bool underjoinl = false, underjoinr = false;
    2361             : 
    2362     4625167 :                         le = rel_find_exp_and_corresponding_rel(rel->l, e, false, NULL, &underjoinl);
    2363     4625167 :                         if (!is_simple_project(rel->op) && !is_inter(rel->op) && !is_except(rel->op) && !is_semi(rel->op) && rel->r) {
    2364      521629 :                                 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      521629 :                                 e->card = MAX(le?underjoinl?CARD_MULTI:le->card:CARD_ATOM, re?underjoinr?CARD_MULTI:re->card:CARD_ATOM);
    2367     4103538 :                         } else if (e->card == CARD_ATOM) { /* unnested columns vs atoms */
    2368      202321 :                                 e->card = le?underjoinl?CARD_MULTI:le->card:CARD_ATOM;
    2369             :                         } else { /* general case */
    2370     3901217 :                                 e->card = (le && !underjoinl)?le->card:CARD_MULTI;
    2371             :                         }
    2372     4625167 :                         } break;
    2373      116018 :                 case e_convert: {
    2374      116018 :                         e->card = exp_card(e->l);
    2375      116018 :                 } break;
    2376      577506 :                 case e_cmp: {
    2377      577506 :                         if (e->flag == cmp_or || e->flag == cmp_filter) {
    2378       23122 :                                 e->card = MAX(exps_card(e->l), exps_card(e->r));
    2379      554384 :                         } else if (e->flag == cmp_in || e->flag == cmp_notin) {
    2380       38363 :                                 e->card = MAX(exp_card(e->l), exps_card(e->r));
    2381             :                         } else {
    2382      516021 :                                 e->card = MAX(exp_card(e->l), exp_card(e->r));
    2383      516021 :                                 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      262177 :         case op_inter:
    2393             :         case op_except:
    2394             :         case op_union:
    2395             :         case op_munion: {
    2396      262177 :                 e->card = CARD_MULTI;
    2397      262177 :         } break;
    2398      125206 :         case op_groupby: {
    2399      125206 :                 switch(e->type) {
    2400       38252 :                 case e_aggr:
    2401       38252 :                         e->card = rel->card;
    2402       38252 :                         break;
    2403       79571 :                 case e_column: {
    2404       79571 :                         if (e->card == CARD_ATOM) { /* unnested columns vs atoms */
    2405        3968 :                                 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        3968 :                                 e->card = le?MIN(le->card, CARD_AGGR):CARD_ATOM;
    2408             :                         } else {
    2409       75603 :                                 e->card = rel->card;
    2410             :                         }
    2411             :                 } break;
    2412             :                 default:
    2413             :                         break;
    2414             :                 }
    2415             :         } break;
    2416             :         default:
    2417             :                 break;
    2418             :         }
    2419    10258684 :         if (is_simple_project(rel->op) && need_distinct(rel)) /* Need distinct, all expressions should have CARD_AGGR at max */
    2420       57224 :                 e->card = MIN(e->card, CARD_AGGR);
    2421    10258684 :         if (!is_mset(rel->op) && (!is_groupby(rel->op) || !list_empty(rel->r))) /* global groupings have atomic cardinality */
    2422     9980131 :                 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     2948306 : rel_set_type(visitor *v, sql_rel *rel)
    2445             : {
    2446     2948306 :         if (is_project(rel->op) && rel->l) {
    2447      929126 :                 if (is_set(rel->op)) {
    2448        2922 :                         sql_rel *l = rel->l, *r = rel->r;
    2449        2922 :                         list *exps = l->exps;
    2450        5844 :                         while(exps) {
    2451       24250 :                                 for(node *n = exps->h, *m = rel->exps->h; n && m; n = n->next, m = m->next) {
    2452       18406 :                                         sql_exp *e = n->data;
    2453       18406 :                                         sql_subtype *t = exp_subtype(e);
    2454             : 
    2455       18406 :                                         if (t && !t->type->localtype)
    2456           6 :                                                 n->data = exp_set_type(v->sql, m->data, e);
    2457             :                                 }
    2458        5844 :                                 if (exps != r->exps)
    2459             :                                         exps = r->exps;
    2460             :                                 else
    2461             :                                         exps = NULL;
    2462             :                         }
    2463             :                 } else if (is_munion(rel->op)) {
    2464       82989 :                         list *l = rel->l;
    2465      249797 :                         for(node *m = l->h; m; m = m->next) {
    2466      166808 :                                 sql_rel *r = m->data;
    2467      166808 :                                 list *exps = r->exps;
    2468      686514 :                                 for(node *n = exps->h, *m = rel->exps->h; n && m; n = n->next, m = m->next) {
    2469      519706 :                                         sql_exp *e = n->data;
    2470      519706 :                                         sql_subtype *t = exp_subtype(e);
    2471             : 
    2472      519706 :                                         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      843215 :                         list *exps = rel->exps;
    2478      882192 :                         while(exps) {
    2479     4734457 :                                 for(node *n = exps->h; n; n = n->next) {
    2480     3874514 :                                         sql_exp *te = n->data;
    2481     3874514 :                                         if (te->type == e_convert) {
    2482       64733 :                                                 sql_exp *l = te->l;
    2483       64733 :                                                 if (l->type == e_column) {
    2484       47530 :                                                         sql_rel *sl = rel->l;
    2485       47530 :                                                         sql_exp *e = rel_find_exp(sl, l);
    2486       47529 :                                                         if (!e)
    2487           0 :                                                                 continue;
    2488       47529 :                                                         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       47529 :                                                                         e = e2;
    2492             :                                                                 }
    2493             :                                                         }
    2494       47529 :                                                         sql_subtype *t = exp_subtype(e);
    2495             : 
    2496       47529 :                                                         if (t && !t->type->localtype) {
    2497         246 :                                                                 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         236 :                                                                         e->tpe = *exp_subtype(te);
    2511         236 :                                                                         if (e->l && e->type == e_atom)
    2512         235 :                                                                                 e->l = atom_set_type(v->sql->sa, e->l, &e->tpe);
    2513             :                                                                 }
    2514             :                                                         }
    2515             :                                                 }
    2516     3809781 :                                         } else if (te->type == e_atom && !te->f) {
    2517      161808 :                                                 sql_subtype *t = exp_subtype(te);
    2518      161808 :                                                 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      859943 :                                 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        3056 : aggrs_split_args(mvc *sql, list *aggrs, list *exps, int is_groupby_list)
    2542             : {
    2543        3056 :         bool clear_hash = false;
    2544             : 
    2545        3056 :         if (list_empty(aggrs))
    2546             :                 return aggrs;
    2547       13376 :         for (node *n=aggrs->h; n; n = n->next) {
    2548       10836 :                 sql_exp *a = n->data;
    2549             : 
    2550       10836 :                 if (is_func(a->type) && !is_groupby_list)
    2551          10 :                         continue;
    2552       10826 :                 if (!is_aggr(a->type)) {
    2553        7180 :                         sql_exp *e1 = a, *found = NULL;
    2554             : 
    2555       25006 :                         for (node *nn = exps->h; nn && !found; nn = nn->next) {
    2556       17826 :                                 sql_exp *e2 = nn->data;
    2557             : 
    2558       17826 :                                 if (is_referenced_by(e2, e1) || !exp_equal(e1, e2))
    2559             :                                         found = e2;
    2560             :                         }
    2561        7180 :                         if (!found) {
    2562        3590 :                                 if (!exp_name(e1))
    2563           0 :                                         e1 = exp_label(sql->sa, e1, ++sql->label);
    2564        3590 :                                 append(exps, e1);
    2565             :                         } else {
    2566             :                                 e1 = found;
    2567             :                         }
    2568        7180 :                         e1 = exp_ref(sql, e1);
    2569        7180 :                         n->data = e1; /* replace by reference */
    2570        7180 :                         clear_hash = true;
    2571        7180 :                         continue;
    2572             :                 }
    2573        3646 :                 list *args = a->l;
    2574             : 
    2575        3646 :                 if (!list_empty(args)) {
    2576        7642 :                         for (node *an = args->h; an; an = an->next) {
    2577        4322 :                                 sql_exp *e1 = an->data, *found = NULL, *eo = e1;
    2578             :                                 /* we keep converts as they reuse names of inner columns */
    2579        4322 :                                 int convert = is_convert(e1->type);
    2580             : 
    2581        4322 :                                 if (convert)
    2582          95 :                                         e1 = e1->l;
    2583       24762 :                                 for (node *nn = exps->h; nn && !found; nn = nn->next) {
    2584       20440 :                                         sql_exp *e2 = nn->data;
    2585             : 
    2586       20440 :                                         if (!exp_equal(e1, e2))
    2587          74 :                                                 found = e2;
    2588             :                                 }
    2589        4322 :                                 if (!found) {
    2590        4248 :                                         if (!e1->alias.label)
    2591        3785 :                                                 e1 = exp_label(sql->sa, e1, ++sql->label);
    2592        4248 :                                         append(exps, e1);
    2593             :                                 } else {
    2594             :                                         e1 = found;
    2595             :                                 }
    2596        4322 :                                 if (!e1->alias.label)
    2597           0 :                                         e1 = exp_label(sql->sa, e1, ++sql->label);
    2598        4322 :                                 e1 = exp_ref(sql, e1);
    2599             :                                 /* replace by reference */
    2600        4322 :                                 if (convert) {
    2601          95 :                                         eo->l = e1;
    2602             :                                 } else {
    2603        4227 :                                         an->data = e1;
    2604        4227 :                                         clear_hash = true;
    2605             :                                 }
    2606             :                         }
    2607             :                 }
    2608             :         }
    2609        2540 :         if (clear_hash)
    2610        2486 :                 list_hash_clear(aggrs);
    2611             :         return aggrs;
    2612             : }
    2613             : 
    2614             : /* make sure e_func expressions don't appear on groupby expression lists */
    2615             : static sql_rel *
    2616        1528 : aggrs_split_funcs(mvc *sql, sql_rel *rel)
    2617             : {
    2618        1528 :         if (!list_empty(rel->exps)) {
    2619        1528 :                 list *projs = NULL;
    2620        8774 :                 for (node *n = rel->exps->h; n;) {
    2621        7246 :                         node *next = n->next;
    2622        7246 :                         sql_exp *e = n->data;
    2623             : 
    2624        7246 :                         if (e->type == e_func || exps_find_exp(projs, e)) {
    2625          10 :                                 if (!projs)
    2626          10 :                                         projs = sa_list(sql->sa);
    2627          10 :                                 list_append(projs, e);
    2628          10 :                                 list_remove_node(rel->exps, NULL, n);
    2629             :                         }
    2630             :                         n = next;
    2631             :                 }
    2632        1528 :                 if (!list_empty(projs)) {
    2633             :                         /* the grouping relation may have more than 1 reference, a replacement is needed */
    2634          10 :                         sql_rel *l = rel_dup_copy(sql->sa, rel);
    2635          10 :                         list *nexps = list_merge(rel_projections(sql, l, NULL, 1, 1), projs, NULL);
    2636          10 :                         rel = rel_inplace_project(sql->sa, rel, l, nexps);
    2637          10 :                         rel->card = exps_card(nexps);
    2638             :                 }
    2639             :         }
    2640        1528 :         return rel;
    2641             : }
    2642             : 
    2643             : static int
    2644       63164 : exps_complex(list *exps)
    2645             : {
    2646       63164 :         if (list_empty(exps))
    2647             :                 return 0;
    2648       50195 :         for(node *n = exps->h; n; n = n->next) {
    2649       29267 :                 sql_exp *e = n->data;
    2650             : 
    2651       29267 :                 if (e->type != e_column && e->type != e_atom)
    2652             :                         return 1;
    2653             :         }
    2654             :         return 0;
    2655             : }
    2656             : 
    2657             : static int
    2658       29521 : aggrs_complex(list *exps)
    2659             : {
    2660       29521 :         if (list_empty(exps))
    2661             :                 return 0;
    2662       73255 :         for(node *n = exps->h; n; n = n->next) {
    2663       45131 :                 sql_exp *e = n->data;
    2664             : 
    2665       45131 :                 if (e->type == e_func || (e->type == e_aggr && exps_complex(e->l)))
    2666        1397 :                         return 1;
    2667             :         }
    2668             :         return 0;
    2669             : }
    2670             : 
    2671             : /* simplify aggregates, ie push functions under the groupby relation */
    2672             : /* rel visitor */
    2673             : static inline sql_rel *
    2674     2270598 : rewrite_aggregates(visitor *v, sql_rel *rel)
    2675             : {
    2676     2270598 :         if (is_groupby(rel->op) && (exps_complex(rel->r) || aggrs_complex(rel->exps))) {
    2677        1528 :                 list *exps = sa_list(v->sql->sa);
    2678             : 
    2679        1528 :                 rel->r = aggrs_split_args(v->sql, rel->r, exps, 1);
    2680        1528 :                 rel->exps = aggrs_split_args(v->sql, rel->exps, exps, 0);
    2681        1528 :                 rel->l = rel_project(v->sql->sa, rel->l, exps);
    2682        1528 :                 rel = aggrs_split_funcs(v->sql, rel);
    2683        1528 :                 v->changes++;
    2684        1528 :                 return rel;
    2685             :         }
    2686             :         return rel;
    2687             : }
    2688             : 
    2689             : static inline sql_rel *
    2690     2270601 : rewrite_split_select_exps(visitor *v, sql_rel *rel)
    2691             : {
    2692     2270601 :         if (is_select(rel->op) && !list_empty(rel->exps)) {
    2693      162913 :                 int i = 0;
    2694      162913 :                 bool has_complex_exps = false, has_simple_exps = false, *complex_exps = SA_NEW_ARRAY(v->sql->ta, bool, list_length(rel->exps));
    2695             : 
    2696      346687 :                 for (node *n = rel->exps->h ; n ; n = n->next) {
    2697      183774 :                         sql_exp *e = n->data;
    2698             : 
    2699      183774 :                         if (exp_has_rel(e) || exp_has_freevar(v->sql, e)) {
    2700       16607 :                                 complex_exps[i] = true;
    2701       16607 :                                 has_complex_exps = true;
    2702             :                         } else {
    2703      167167 :                                 complex_exps[i] = false;
    2704      167167 :                                 has_simple_exps = true;
    2705             :                         }
    2706      183774 :                         i++;
    2707             :                 }
    2708             : 
    2709      162913 :                 if (has_complex_exps && has_simple_exps) {
    2710        3803 :                         sql_rel *nsel = rel_select_copy(v->sql->sa, rel->l, NULL);
    2711        3803 :                         rel->l = nsel;
    2712             : 
    2713        3803 :                         i = 0;
    2714       12268 :                         for (node *n = rel->exps->h ; n ; ) {
    2715        8465 :                                 node *nxt = n->next;
    2716             : 
    2717        8465 :                                 if (!complex_exps[i]) {
    2718        4489 :                                         rel_select_add_exp(v->sql->sa, nsel, n->data);
    2719        4489 :                                         list_remove_node(rel->exps, NULL, n);
    2720             :                                 }
    2721        8465 :                                 n = nxt;
    2722        8465 :                                 i++;
    2723             :                         }
    2724        3803 :                         set_processed(nsel);
    2725        3803 :                         v->changes++;
    2726             :                 }
    2727             :         }
    2728     2270601 :         return rel;
    2729             : }
    2730             : 
    2731             : static void /* replace diff arguments to avoid duplicate work. The arguments must be iterated in this order! */
    2732       18612 : diff_replace_arguments(mvc *sql, sql_exp *e, list *ordering, int *pos, int *i)
    2733             : {
    2734       18612 :         if (e->type == e_func && !strcmp(((sql_subfunc*)e->f)->func->base.name, "diff")) {
    2735        5780 :                 list *args = (list*)e->l;
    2736        5780 :                 sql_exp *first = args->h->data, *second = list_length(args) == 2 ? args->h->next->data : NULL;
    2737             : 
    2738        5780 :                 if (first->type == e_func && !strcmp(((sql_subfunc*)first->f)->func->base.name, "diff")) {
    2739         187 :                         diff_replace_arguments(sql, first, ordering, pos, i);
    2740             :                 } else {
    2741        5593 :                         sql_exp *ne = args->h->data = exp_ref(sql, list_fetch(ordering, pos[*i]));
    2742        5593 :                         set_descending(ne);
    2743        5593 :                         set_nulls_first(ne);
    2744        5593 :                         *i = *i + 1;
    2745             :                 }
    2746        5780 :                 if (second && second->type == e_func && !strcmp(((sql_subfunc*)second->f)->func->base.name, "diff")) {
    2747             :                         diff_replace_arguments(sql, second, ordering, pos, i);
    2748             :                 } else if (second) {
    2749         187 :                         sql_exp *ne = args->h->next->data = exp_ref(sql, list_fetch(ordering, pos[*i]));
    2750         187 :                         set_descending(ne);
    2751         187 :                         set_nulls_first(ne);
    2752         187 :                         *i = *i + 1;
    2753             :                 }
    2754             :         }
    2755       18612 : }
    2756             : 
    2757             : /* exp visitor */
    2758             : static inline sql_exp *
    2759     9365107 : rewrite_rank(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    2760             : {
    2761     9365107 :         sql_rel *rell = NULL;
    2762             : 
    2763     9365107 :         if (!is_simple_project(rel->op) || e->type != e_func || list_length(e->r) < 2 /* e->r means window function */)
    2764     9357321 :                 return e;
    2765             : 
    2766        7786 :         (void)depth;
    2767             :         /* ranks/window functions only exist in the projection */
    2768        7786 :         list *l = e->l, *r = e->r, *gbe = r->h->data, *obe = r->h->next->data;
    2769             : 
    2770        7786 :         int needed = (gbe || obe);
    2771        7786 :         if (l)
    2772       22501 :                 for (node *n = l->h; n && !needed; n = n->next) {
    2773       14715 :                         sql_exp *e = n->data;
    2774       14715 :                         needed = e->ref;
    2775             :                 }
    2776             : 
    2777        7786 :         if (needed) {
    2778        3224 :                 rell = rel->l = rel_project(v->sql->sa, rel->l, rel_projections(v->sql, rel->l, NULL, 1, 1));
    2779       22567 :                 for (node *n = l->h; n; n = n->next) {
    2780       19343 :                         sql_exp *e = n->data;
    2781             : 
    2782       19343 :                         if (e->ref) {
    2783        1294 :                                 e->ref = 0;
    2784        1294 :                                 append(rell->exps, e);
    2785        1294 :                                 n->data = exp_ref(v->sql, e);
    2786             :                         }
    2787             :                 }
    2788             :         }
    2789             : 
    2790             :         /* The following array remembers the original positions of gbe and obe expressions to replace them in order later at diff_replace_arguments */
    2791        7786 :         if (gbe || obe) {
    2792        3168 :                 int gbeoffset = list_length(gbe), i = 0, added = 0;
    2793        3168 :                 int *pos = SA_NEW_ARRAY(v->sql->ta, int, gbeoffset + list_length(obe));
    2794        3168 :                 if (gbe)
    2795        5182 :                         for (i = 0 ; i < gbeoffset ; i++)
    2796        2607 :                                 pos[i] = i;
    2797             : 
    2798        3168 :                 if (gbe && obe) {
    2799        2425 :                         gbe = list_merge(sa_list(v->sql->sa), gbe, (fdup)NULL); /* make sure the p->r is a different list than the gbe list */
    2800        2425 :                         i = 0;
    2801        4947 :                         for(node *n = obe->h ; n ; n = n->next, i++) {
    2802        2522 :                                 sql_exp *e1 = n->data;
    2803        2522 :                                 bool found = false;
    2804        2522 :                                 int j = 0;
    2805             : 
    2806        4781 :                                 for(node *nn = gbe->h ; nn ; nn = nn->next, j++) {
    2807        2582 :                                         sql_exp *e2 = nn->data;
    2808             :                                         /* the partition expression order should be the same as the one in the order by clause (if it's in there as well) */
    2809        2582 :                                         if (exp_match(e1, e2)) {
    2810         323 :                                                 if (is_ascending(e1))
    2811         239 :                                                         set_ascending(e2);
    2812             :                                                 else
    2813          84 :                                                         set_descending(e2);
    2814         323 :                                                 if (nulls_last(e1))
    2815          84 :                                                         set_nulls_last(e2);
    2816             :                                                 else
    2817         239 :                                                         set_nulls_first(e2);
    2818         323 :                                                 found = true;
    2819         323 :                                                 break;
    2820             :                                         }
    2821             :                                 }
    2822        2522 :                                 if (!found) {
    2823        2199 :                                         pos[gbeoffset + i] = gbeoffset + added;
    2824        2199 :                                         added++;
    2825        2199 :                                         append(gbe, e1);
    2826             :                                 } else {
    2827         323 :                                         pos[gbeoffset + i] = j;
    2828             :                                 }
    2829             :                         }
    2830         743 :                 } else if (obe) {
    2831         593 :                         assert(!gbe);
    2832         593 :                         i = 0;
    2833        1244 :                         for(node *n = obe->h ; n ; n = n->next, i++) {
    2834         651 :                                 sql_exp *oe = n->data;
    2835         651 :                                 if (!exps_find_exp(rell->exps, oe)) {
    2836          22 :                                         sql_exp *ne = exp_ref(v->sql, oe);
    2837             : 
    2838          22 :                                         if (is_ascending(oe))
    2839          20 :                                                 set_ascending(ne);
    2840          22 :                                         if (nulls_last(oe))
    2841           4 :                                                 set_nulls_last(ne);
    2842             :                                         /* disable sorting info (ie back to defaults) */
    2843          22 :                                         set_descending(oe);
    2844          22 :                                         set_nulls_first(oe);
    2845          22 :                                         n->data = ne;
    2846          22 :                                         append(rell->exps, oe);
    2847             :                                 }
    2848         651 :                                 pos[i] = i;
    2849             :                         }
    2850             :                         gbe = obe;
    2851             :                 }
    2852             : 
    2853        3168 :                 list *ordering = sa_list(v->sql->sa); /* add exps from gbe and obe as ordering expressions */
    2854        8625 :                 for(node *n = gbe->h ; n ; n = n->next) {
    2855        5457 :                         sql_exp *next = n->data;
    2856        5457 :                         sql_exp *found = exps_find_exp(rell->exps, next);
    2857        5527 :                         sql_exp *ref = exp_ref(v->sql, found ? found : next);
    2858             : 
    2859        5457 :                         if (is_ascending(next))
    2860        4453 :                                 set_ascending(ref);
    2861        5457 :                         if (nulls_last(next))
    2862        1009 :                                 set_nulls_last(ref);
    2863        5457 :                         set_descending(next);
    2864        5457 :                         set_nulls_first(next);
    2865        5457 :                         if (!found)
    2866          70 :                                 list_append(rell->exps, next);
    2867        5457 :                         list_append(ordering, ref);
    2868             :                 }
    2869        3168 :                 rell = rel_project(v->sql->sa, rell, rel_projections(v->sql, rell, NULL, 1, 1));
    2870        3168 :                 rell->r = ordering;
    2871        3168 :                 rel->l = rell;
    2872             : 
    2873             :                 /* remove obe argument, so this function won't be called again on this expression */
    2874        3168 :                 list_remove_node(r, NULL, r->t);
    2875             : 
    2876             :                 /* add project with rank */
    2877        3168 :                 rell = rel->l = rel_project(v->sql->sa, rel->l, rel_projections(v->sql, rell->l, NULL, 1, 1));
    2878        3168 :                 i = 0;
    2879             : 
    2880       22171 :                 for (node *n = l->h; n ; n = n->next) { /* replace the updated arguments */
    2881       19003 :                         sql_exp *e = n->data;
    2882             : 
    2883       19003 :                         if (e->type == e_func && !strcmp(((sql_subfunc*)e->f)->func->base.name, "window_bound"))
    2884         578 :                                 continue;
    2885       18425 :                         diff_replace_arguments(v->sql, e, ordering, pos, &i);
    2886             :                 }
    2887             : 
    2888        3168 :                 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 */
    2889        3168 :                 sql_exp *b2 = (sql_exp*) list_fetch(l, list_length(l) - 1);
    2890             : 
    2891        3168 :                 if (b1 && b1->type == e_func && !strcmp(((sql_subfunc*)b1->f)->func->base.name, "window_bound")) {
    2892         289 :                         list *ll = b1->l;
    2893         289 :                         rell = rel->l = rel_project(v->sql->sa, rell, rel_projections(v->sql, rell, NULL, 1, 1));
    2894             : 
    2895         289 :                         int pe_pos = list_length(l) - 5; /* append the new partition expression to the list of expressions */
    2896         289 :                         sql_exp *pe = (sql_exp*) list_fetch(l, pe_pos);
    2897         289 :                         list_append(rell->exps, pe);
    2898             : 
    2899         289 :                         if (list_length(ll) == 6) { /* update partition definition for window function input if that's the case */
    2900         186 :                                 ((list*)b1->l)->h->data = exp_ref(v->sql, pe);
    2901         186 :                                 ((list*)b2->l)->h->data = exp_ref(v->sql, pe);
    2902             :                         }
    2903         289 :                         i = 0; /* the partition may get a new reference, update it on the window function list of arguments as well */
    2904         690 :                         for (node *n = l->h; n ; n = n->next, i++) {
    2905         690 :                                 if (i == pe_pos) {
    2906         289 :                                         n->data = exp_ref(v->sql, pe);
    2907         289 :                                         break;
    2908             :                                 }
    2909             :                         }
    2910             : 
    2911         289 :                         sql_exp *frame_type = (sql_exp*) list_fetch(l, list_length(l) - 3);
    2912         289 :                         atom *a = frame_type->l;
    2913         289 :                         int nr = (int)atom_get_int(a);
    2914             : 
    2915         289 :                         if (nr == FRAME_RANGE && obe) { /* for range we pass the last order by column (otherwise it's either invalid or is a special case)*/
    2916         122 :                                 int oe_pos = list_length(ll) - 5;
    2917         122 :                                 sql_exp *oe = (sql_exp*) list_fetch(ll, oe_pos);
    2918         122 :                                 if (oe->type != e_column && oe->type != e_atom) {
    2919           4 :                                         sql_exp *common  = list_fetch(ordering, pos[gbeoffset + list_length(obe) - 1]);
    2920             : 
    2921           4 :                                         if (list_length(ll) == 5) {
    2922           2 :                                                 ((list*)b1->l)->h->data = exp_ref(v->sql, common);
    2923           2 :                                                 ((list*)b2->l)->h->data = exp_ref(v->sql, common);
    2924             :                                         } else {
    2925           2 :                                                 ((list*)b1->l)->h->next->data = exp_ref(v->sql, common);
    2926           2 :                                                 ((list*)b2->l)->h->next->data = exp_ref(v->sql, common);
    2927             :                                         }
    2928             :                                 }
    2929         167 :                         } else if (nr == FRAME_ROWS || nr == FRAME_GROUPS) {
    2930         163 :                                 int oe_pos = list_length(l) - 4; /* for groups and rows, we push the ordering diff call, reference it back */
    2931             :                                 /* now this is the tricky, part, the ordering expression, may be a column, or any projection, only the later requires the push down */
    2932         163 :                                 sql_exp *oe = (sql_exp*) list_fetch(l, oe_pos);
    2933         163 :                                 if (oe->type != e_column && oe->type != e_atom) {
    2934         154 :                                         list_append(rell->exps, oe);
    2935             : 
    2936         154 :                                         if (list_length(ll) == 5) {
    2937          40 :                                                 ((list*)b1->l)->h->data = exp_ref(v->sql, oe);
    2938          40 :                                                 ((list*)b2->l)->h->data = exp_ref(v->sql, oe);
    2939             :                                         } else {
    2940         114 :                                                 ((list*)b1->l)->h->next->data = exp_ref(v->sql, oe);
    2941         114 :                                                 ((list*)b2->l)->h->next->data = exp_ref(v->sql, oe);
    2942             :                                         }
    2943             :                                 }
    2944             :                         }
    2945             :                 }
    2946             : 
    2947             :                 /* move rank down add ref */
    2948        3168 :                 if (!exp_name(e))
    2949        1274 :                         e = exp_label(v->sql->sa, e, ++v->sql->label);
    2950        3168 :                 append(rell->exps, e);
    2951        3168 :                 e = exp_ref(v->sql, e);
    2952        3168 :                 v->changes++;
    2953             :         } else {
    2954             :                 /* remove obe argument, so this function won't be called again on this expression */
    2955        4618 :                 list_remove_node(r, NULL, r->t);
    2956        4618 :                 v->changes++;
    2957             :         }
    2958             :         return e;
    2959             : }
    2960             : 
    2961             : static sql_rel *
    2962        7900 : rel_union_exps(mvc *sql, sql_exp **l, list *vals, int is_tuple)
    2963             : {
    2964        7900 :         sql_rel *u = NULL;
    2965        7900 :         list *exps = NULL;
    2966             : 
    2967        7900 :         if (mvc_highwater(sql))
    2968           0 :                 return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    2969             : 
    2970       15828 :         for (node *n=vals->h; n; n = n->next) {
    2971        7928 :                 sql_exp *ve = n->data, *r, *s;
    2972        7928 :                 sql_rel *sq = NULL;
    2973        7928 :                 int freevar = 0;
    2974             : 
    2975        7928 :                 exp_label(sql->sa, ve, ++sql->label); /* an alias is needed */
    2976        7928 :                 if (exp_has_rel(ve)) {
    2977        7873 :                         sq = exp_rel_get_rel(sql->sa, ve); /* get subquery */
    2978             :                 } else {
    2979          55 :                         sq = rel_project(sql->sa, NULL, append(sa_list(sql->sa), ve));
    2980          55 :                         if (!exp_is_atom(ve))
    2981          20 :                                 freevar = 1;
    2982          55 :                         set_processed(sq);
    2983             :                 }
    2984        7928 :                 if (is_tuple) { /* cast each one */
    2985        6842 :                         for (node *m=sq->exps->h, *o = ((list *)(*l)->f)->h; m && o; m = m->next, o = o->next) {
    2986        4761 :                                 r = m->data;
    2987        4761 :                                 s = o->data;
    2988        4761 :                                 if (rel_convert_types(sql, NULL, NULL, &s, &r, 1, type_equal) < 0)
    2989           0 :                                         return NULL;
    2990        4761 :                                 m->data = r;
    2991             :                         }
    2992             :                 } else {
    2993        5847 :                         sq->nrcols = list_length(sq->exps);
    2994             :                         /* union a project[(values(a),..,(b),(c)]  with freevars */
    2995        5847 :                         if (sq->card > CARD_ATOM && rel_has_freevar(sql, sq) && is_project(sq->op) &&
    2996         110 :                                 !sq->l && sq->nrcols == 1 && is_values((sql_exp*)sq->exps->h->data)) {
    2997             :                                 /* needs check on projection */
    2998           0 :                                 sql_exp *vals = sq->exps->h->data;
    2999           0 :                                 if (!(sq = rel_union_exps(sql, l, exp_get_values(vals), is_tuple)))
    3000             :                                         return NULL;
    3001             :                         } else {
    3002        5847 :                                 if (rel_convert_types(sql, NULL, NULL, l, &ve, 1, type_equal) < 0)
    3003             :                                         return NULL;
    3004             :                                 /* flatten expressions */
    3005        5847 :                                 if (exp_has_rel(ve)) {
    3006        5792 :                                         ve = exp_rel_update_exp(sql, ve, false);
    3007        5792 :                                         sq = rel_project(sql->sa, sq, append(sa_list(sql->sa), ve));
    3008        5792 :                                         set_processed(sq);
    3009             :                                 }
    3010        5847 :                                 if (freevar)
    3011          20 :                                         exp_set_freevar(sql, ve, sq);
    3012             :                         }
    3013             :                 }
    3014        7928 :                 if (!u) {
    3015             :                         u = sq;
    3016             :                 } else {
    3017          28 :                         list *urs = sa_list(sql->sa);
    3018          28 :                         urs = append(urs, u);
    3019          28 :                         urs = append(urs, sq);
    3020          28 :                         u = rel_setop_n_ary(sql->sa, urs, op_munion);
    3021          28 :                         rel_setop_n_ary_set_exps(sql, u, exps, false);
    3022          28 :                         set_distinct(u);
    3023          28 :                         set_processed(u);
    3024             :                 }
    3025        7928 :                 exps = rel_projections(sql, sq, NULL, 1/*keep names */, 1);
    3026             :         }
    3027             :         return u;
    3028             : }
    3029             : 
    3030             : static sql_exp *
    3031       10301 : exp_in_project(mvc *sql, sql_exp **l, list *vals, int anyequal)
    3032             : {
    3033       10301 :         sql_exp *e = NULL;
    3034             : 
    3035       65953 :         for(node *n=vals->h; n; n = n->next) {
    3036       55652 :                 sql_exp *r = n->data, *ne;
    3037             : 
    3038       55652 :                 if (rel_convert_types(sql, NULL, NULL, l, &r, 1, type_equal_no_any) < 0)
    3039           0 :                         return NULL;
    3040       55652 :                 if (anyequal)
    3041       55447 :                         ne = rel_binop_(sql, NULL, *l, r, "sys", "=", card_value, true);
    3042             :                 else
    3043         205 :                         ne = rel_binop_(sql, NULL, *l, r, "sys", "<>", card_value, true);
    3044       55652 :                 if (!e) {
    3045             :                         e = ne;
    3046       45351 :                 } else if (anyequal) {
    3047       45244 :                         e = rel_binop_(sql, NULL, e, ne, "sys", "or", card_value, true);
    3048             :                 } else {
    3049         107 :                         e = rel_binop_(sql, NULL, e, ne, "sys", "and", card_value, true);
    3050             :                 }
    3051             :         }
    3052             :         return e;
    3053             : }
    3054             : 
    3055             : static sql_exp *
    3056          73 : exp_in_compare(mvc *sql, sql_exp **l, list *vals, int anyequal)
    3057             : {
    3058          73 :         int vals_only = 1;
    3059             : 
    3060         239 :         for(node *n=vals->h; n; n = n->next) {
    3061         166 :                 sql_exp *r = n->data;
    3062             : 
    3063         166 :                 if (rel_convert_types(sql, NULL, NULL, l, &r, 1, type_equal_no_any) < 0)
    3064           0 :                         return NULL;
    3065         166 :                 n->data = r;
    3066         166 :                 if (!exp_is_atom(r))
    3067         123 :                         vals_only = 0;
    3068             :         }
    3069          73 :         if (vals_only)
    3070           5 :                 return exp_in(sql->sa, *l, vals, anyequal?cmp_in:cmp_notin);
    3071             : 
    3072          70 :         if (!(*l = exp_in_project(sql, l, vals, anyequal)))
    3073             :                 return NULL;
    3074          70 :         return exp_compare(sql->sa, *l, exp_atom_bool(sql->sa, 1), cmp_equal);
    3075             : }
    3076             : 
    3077             : /* exp visitor */
    3078             : static inline sql_exp *
    3079      425926 : rewrite_anyequal(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    3080             : {
    3081      425926 :         assert(e->type == e_func);
    3082             : 
    3083      425926 :         sql_subfunc *sf = e->f;
    3084      425926 :         if (is_ddl(rel->op))
    3085             :                 return e;
    3086      352200 :         if (is_anyequal_func(sf) && !list_empty(e->l)) {
    3087       18205 :                 list *l = e->l;
    3088       18205 :                 mvc *sql = v->sql;
    3089             : 
    3090       18205 :                 if (list_length(l) == 2) { /* input is a set */
    3091             : 
    3092       18205 :                         sql_exp *ile = l->h->data, *le, *re = l->h->next->data;
    3093       18205 :                         sql_rel *lsq = NULL, *rsq = NULL;
    3094       18205 :                         int is_tuple = 0;
    3095             : 
    3096       18205 :                         if (exp_has_rel(ile))
    3097          43 :                                 lsq = exp_rel_get_rel(sql->sa, ile); /* get subquery */
    3098             : 
    3099          43 :                         if (lsq)
    3100          43 :                                 le = exp_rel_update_exp(sql, ile, false);
    3101             :                         else
    3102       18162 :                                 le = ile;
    3103             : 
    3104       18205 :                         if (is_values(le)) /* exp_values */
    3105       18205 :                                 is_tuple = 1;
    3106             : 
    3107             :                         /* re should be a values list */
    3108       18205 :                         if (!lsq && !is_tuple && is_values(re) && !exps_have_rel_exp(re->f)) { /* exp_values */
    3109       10304 :                                 list *vals = re->f;
    3110             : 
    3111       10304 :                                 rel_bind_var(sql, rel->l, le);
    3112       10304 :                                 rel_bind_vars(sql, rel->l, vals);
    3113       10304 :                                 if (depth == 0 && is_select(rel->op)) {
    3114          73 :                                         v->changes++;
    3115          73 :                                         return exp_in_compare(sql, &le, vals, is_anyequal(sf));
    3116             :                                 } else {
    3117       10231 :                                         le = exp_in_project(sql, &le, vals, is_anyequal(sf));
    3118       10231 :                                         if (le && exp_name(e))
    3119         762 :                                                 exp_prop_alias(sql->sa, le, e);
    3120       10231 :                                         v->changes++;
    3121       10231 :                                         return le;
    3122             :                                 }
    3123        7901 :                         } else if (!lsq && !exps_have_rel_exp(re->f) && !is_tuple) {
    3124             :                                 return e; /* leave as is, handled later */
    3125        7858 :                         } else if (!lsq && re->f && !exps_have_rel_exp(re->f) && exps_are_atoms(re->f) && is_tuple) {
    3126           1 :                                 return exp_in(sql->sa, le, re->f, is_anyequal(sf) ? cmp_in : cmp_notin);
    3127             :                         }
    3128             : 
    3129        7900 :                         if (is_atom(re->type) && re->f) { /* exp_values */
    3130             :                                 /* flatten using unions */
    3131        7900 :                                 rsq = rel_union_exps(sql, &le, re->f, is_tuple);
    3132        7900 :                                 if (!rsq)
    3133             :                                         return NULL;
    3134        7900 :                                 if (!is_tuple) {
    3135        5819 :                                         re = rsq->exps->t->data;
    3136             : 
    3137        5819 :                                         if (!is_tuple && is_func(re->type))
    3138           3 :                                                 depth++;
    3139             : 
    3140        5819 :                                         if (rsq && lsq)
    3141          42 :                                                 exp_set_freevar(sql, re, rsq);
    3142        5819 :                                         if (!is_tuple && !is_freevar(re)) {
    3143        5811 :                                                 assert(re->alias.label);
    3144        5811 :                                                 list_hash_clear(rsq->exps);
    3145        5811 :                                                 re = exp_ref(sql, re);
    3146           8 :                                         } else if (has_label(re)) {
    3147           8 :                                                 re = exp_ref(sql, re);
    3148             :                                         }
    3149             :                                 }
    3150        7900 :                                 set_processed(rsq);
    3151             :                         }
    3152             : 
    3153        7900 :                         if (is_project(rel->op) || ((is_select(rel->op) || is_outerjoin(rel->op)) && depth > 0)) {
    3154             :                                 /* we introduced extra selects */
    3155        2629 :                                 assert(is_project(rel->op) || is_select(rel->op) || is_outerjoin(rel->op));
    3156             : 
    3157        2629 :                                 sql_rel *join = NULL;
    3158        2629 :                                 if (lsq) {
    3159          33 :                                         sql_rel *rewrite = NULL;
    3160          33 :                                         (void)rewrite_inner(sql, rel, lsq, op_left, &rewrite);
    3161          33 :                                         exp_reset_props(rewrite, le, is_left(rewrite->op));
    3162          33 :                                         join = (is_full(rel->op)||is_left(rel->op))?rel->r:rel->l;
    3163             :                                 }
    3164        2629 :                                 if (rsq) {
    3165        2629 :                                         (void)rewrite_inner(sql, rel, rsq, op_left, &join);
    3166        2629 :                                         exp_reset_props(join, re, is_left(join->op));
    3167             :                                 }
    3168        2629 :                                 assert(join && is_join(join->op));
    3169        2629 :                                 if (join && !join->exps)
    3170        2629 :                                         join->exps = sa_list(sql->sa);
    3171        2629 :                                 bool use_any = 0;
    3172        2629 :                                 if (is_tuple) {
    3173           5 :                                         list *t = le->f;
    3174           5 :                                         int s1 = list_length(t), s2 = rsq?list_length(rsq->exps):0;
    3175             : 
    3176             :                                         /* find out list of right expression */
    3177           5 :                                         if (s1 != s2)
    3178           0 :                                                 return sql_error(sql, 02, SQLSTATE(42000) "Subquery has too %s columns", (s2 < s1) ? "few" : "many");
    3179          15 :                                         for (node *n = t->h, *m = rsq->exps->h; n && m; n = n->next, m = m->next ) {
    3180          10 :                                                 sql_exp *le = n->data;
    3181          10 :                                                 sql_exp *re = m->data;
    3182             : 
    3183          10 :                                                 re = exp_ref(sql, re);
    3184             : 
    3185          10 :                                                 sql_exp *inexp = exp_compare(v->sql->sa, le, re, cmp_equal);
    3186          10 :                                                 if (inexp)
    3187          10 :                                                         set_any(inexp);
    3188          10 :                                                 append(join->exps, inexp);
    3189             :                                         }
    3190           5 :                                         return sql_error(sql, 02, SQLSTATE(42000) "Tuple matching at projections not implemented in the backend yet");
    3191             :                                 } else {
    3192        2624 :                                         use_any = true;
    3193        2624 :                                         sql_exp *inexp = exp_compare(v->sql->sa, le, re, cmp_equal);
    3194        2624 :                                         if (inexp)
    3195        2624 :                                                 set_any(inexp);
    3196        2624 :                                         exp_set_freevar(sql, le, join);
    3197        2624 :                                         rel_bind_var(sql, join, inexp);
    3198        2624 :                                         append(join->exps, inexp);
    3199        2624 :                                         if (exp_has_freevar(v->sql, inexp) && is_join(rel->op))
    3200           0 :                                                 set_dependent(rel);
    3201             :                                 }
    3202        2624 :                                 v->changes++;
    3203        2624 :                                 if (join) {
    3204        2624 :                                         if (!join->attr)
    3205        2624 :                                                 join->attr = sa_list(sql->sa);
    3206        2624 :                                         sql_exp *a = exp_atom_bool(v->sql->sa, !use_any?1:is_anyequal(sf));
    3207        2624 :                                         if (!e->alias.label)
    3208        2584 :                                                 a = exp_label(v->sql->sa, a, ++v->sql->label); /* unique name */
    3209             :                                         else
    3210          40 :                                                 exp_setalias(a, e->alias.label, exp_relname(e), exp_name(e));
    3211        2624 :                                         re = exp_ref(sql, a);
    3212        2624 :                                         set_has_nil(re); /* outerjoins could have introduced nils */
    3213        2624 :                                         re->card = CARD_MULTI; /* mark as multi value, the real attribute is introduced later */
    3214        2624 :                                         append(join->attr, a);
    3215        2624 :                                         assert(is_project(rel->op) || depth);
    3216        2624 :                                         if ((is_project(rel->op) || depth))
    3217             :                                                 return re;
    3218             :                                 }
    3219           0 :                                 set_has_nil(le); /* outer joins could have introduced nils */
    3220           0 :                                 set_has_nil(re); /* outer joins could have introduced nils */
    3221           0 :                                 return exp_compare(v->sql->sa, le, re, is_anyequal(sf)?cmp_equal:cmp_notequal);
    3222             :                         } else {
    3223        5271 :                                 sql_rel *rewrite = NULL;
    3224        5271 :                                 if (lsq) {
    3225          18 :                                         (void)rewrite_inner(sql, rel, lsq, rel->card<=CARD_ATOM?op_left:op_join, &rewrite);
    3226          10 :                                         exp_reset_props(rewrite, le, is_left(rewrite->op));
    3227             :                                 }
    3228        5271 :                                 if (rsq) {
    3229        5271 :                                         operator_type op = is_anyequal(sf)?op_semi:op_anti;
    3230        5271 :                                         (void)rewrite_inner(sql, rel, rsq, op, &rewrite);
    3231        5271 :                                         exp_reset_props(rewrite, re, is_left(rewrite->op));
    3232             :                                 }
    3233        5271 :                                 if (!rewrite)
    3234             :                                         return NULL;
    3235        5271 :                                 if (is_tuple) {
    3236        2076 :                                         list *t = le->f;
    3237        2076 :                                         int s1 = list_length(t), s2 = list_length(rsq->exps);
    3238             : 
    3239             :                                         /* find out list of right expression */
    3240        2076 :                                         if (s1 != s2)
    3241           0 :                                                 return sql_error(sql, 02, SQLSTATE(42000) "Subquery has too %s columns", (s2 < s1) ? "few" : "many");
    3242        2076 :                                         if (!rewrite->exps)
    3243        2076 :                                                 rewrite->exps = sa_list(sql->sa);
    3244        6827 :                                         for (node *n = t->h, *m = rsq->exps->h; n && m; n = n->next, m = m->next )
    3245        4751 :                                                 append(rewrite->exps, exp_compare(sql->sa, n->data, exp_ref(sql, m->data), cmp_equal));
    3246        2076 :                                         v->changes++;
    3247        2076 :                                         return exp_atom_bool(sql->sa, 1);
    3248             :                                 } else {
    3249        3195 :                                         if (exp_has_freevar(sql, le))
    3250           1 :                                                 rel_bind_var(sql, rel, le);
    3251        3195 :                                         if (!rewrite)
    3252             :                                                 return NULL;
    3253        3195 :                                         if (!rewrite->exps)
    3254        3195 :                                                 rewrite->exps = sa_list(sql->sa);
    3255        3195 :                                         append(rewrite->exps, exp_compare(sql->sa, le, exp_ref(sql, re), cmp_equal));
    3256        3195 :                                         v->changes++;
    3257        3195 :                                         return exp_atom_bool(sql->sa, 1);
    3258             :                                 }
    3259             :                         }
    3260             :                 }
    3261             :         }
    3262             :         return e;
    3263             : }
    3264             : 
    3265             : /* exp visitor */
    3266             : /* rewrite compare expressions including quantifiers any and all */
    3267             : static inline sql_exp *
    3268      406373 : rewrite_compare(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    3269             : {
    3270      406373 :         assert(e->type == e_func);
    3271             : 
    3272      406373 :         if (is_ddl(rel->op))
    3273             :                 return e;
    3274             : 
    3275      332652 :         sql_subfunc *sf = e->f;
    3276      332652 :         if (is_compare_func(sf) && !list_empty(e->l)) {
    3277       38511 :                 list *l = e->l;
    3278             : 
    3279             :                 /* TODO handle range expressions */
    3280       38511 :                 if (list_length(l) == 2) { /* input is a set */
    3281       38511 :                         char *op = sf->func->base.name;
    3282             : 
    3283       38511 :                         sql_exp *ile = l->h->data, *le, *re = l->h->next->data, *rnull = NULL;
    3284       38511 :                         sql_rel *lsq = NULL, *rsq = NULL;
    3285       38511 :                         int is_tuple = 0; /* TODO add this feature, ie select (1,2) = (1,2) etc */
    3286             :                                          /* cleanup tuple handling by introducing an expression for tuples */
    3287       38511 :                         int quantifier = e->flag;
    3288             : 
    3289             :                         /* possibly this is already done ? */
    3290       38511 :                         if (exp_has_rel(ile)) {
    3291          60 :                                 depth += exp_rel_depth(ile);
    3292          60 :                                 lsq = exp_rel_get_rel(v->sql->sa, ile); /* get subquery */
    3293             :                         }
    3294             : 
    3295          60 :                         if (lsq)
    3296          60 :                                 le = exp_rel_update_exp(v->sql, ile, false);
    3297             :                         else
    3298       38451 :                                 le = ile;
    3299             : 
    3300       38511 :                         if (exp_has_rel(re))
    3301        4429 :                                 rsq = exp_rel_get_rel(v->sql->sa, re); /* get subquery */
    3302        4429 :                         if (rsq) {
    3303        4429 :                                 if (!lsq && is_simple_project(rsq->op) && !rsq->l) {
    3304          11 :                                         sql_exp *ire = rsq->exps->h->data;
    3305          11 :                                         if (is_values(ire) && list_length(ire->f) == 1 && !is_values(le)) {
    3306           0 :                                                 list *exps = ire->f;
    3307           0 :                                                 re = exps->h->data;
    3308           0 :                                                 rsq = exp_rel_get_rel(v->sql->sa, re);
    3309             :                                         }
    3310             :                                 }
    3311          29 :                                 if (rsq)
    3312        4429 :                                         re = exp_rel_update_exp(v->sql, re, false);
    3313             :                         }
    3314             : 
    3315       38511 :                         if (is_values(le)) /* exp_values */
    3316       38511 :                                 is_tuple = 1;
    3317             : 
    3318       38511 :                         if (!is_tuple && !lsq && !rsq) { /* trivial case, just re-write into a comparison */
    3319       34046 :                                 e->flag = 0; /* remove quantifier */
    3320             : 
    3321       34046 :                                 if (rel_convert_types(v->sql, NULL, NULL, &le, &re, 1, type_equal) < 0)
    3322             :                                         return NULL;
    3323       34046 :                                 if (depth == 0 && is_select(rel->op)) {
    3324           1 :                                         v->changes++;
    3325           1 :                                         return exp_compare(v->sql->sa, le, re, compare_str2type(op));
    3326             :                                 } else {
    3327             :                                         return e;
    3328             :                                         /*
    3329             :                                         le = exp_compare_func(v->sql, le, re, op, 0);
    3330             :                                         if (exp_name(e))
    3331             :                                                 exp_prop_alias(v->sql->sa, le, e);
    3332             :                                         v->changes++;
    3333             :                                         return le;
    3334             :                                         */
    3335             :                                 }
    3336             :                         }
    3337        4465 :                         if (!is_tuple && is_values(re) && !exps_have_rel_exp(re->f)) { /* exp_values */
    3338           0 :                                 list *vals = re->f;
    3339             : 
    3340           0 :                                 if (depth == 0 && is_select(rel->op)) {
    3341           0 :                                         v->changes++;
    3342           0 :                                         return exp_in_compare(v->sql, &le, vals, is_anyequal(sf));
    3343             :                                 } else {
    3344           0 :                                         le = exp_in_project(v->sql, &le, vals, is_anyequal(sf));
    3345           0 :                                         if (le && exp_name(e))
    3346           0 :                                                 exp_prop_alias(v->sql->sa, le, e);
    3347           0 :                                         v->changes++;
    3348           0 :                                         return le;
    3349             :                                 }
    3350             :                         }
    3351             : 
    3352        4465 :                         if (is_values(re)) { /* exp_values */
    3353             :                                 /* flatten using unions */
    3354           0 :                                 rsq = rel_union_exps(v->sql, &le, re->f, is_tuple);
    3355           0 :                                 if (!rsq)
    3356             :                                         return NULL;
    3357           0 :                                 re = rsq->exps->t->data;
    3358           0 :                                 set_processed(rsq);
    3359             :                         }
    3360             : 
    3361        4465 :                         int is_cnt = 0;
    3362        4465 :                         if (rsq) {
    3363        4429 :                                 sql_exp *r = exps_bind_nid(rsq->exps, re->nid);
    3364        4429 :                                 is_cnt = exp_is_count(r, rsq);
    3365             :                         }
    3366        4465 :                         if (is_project(rel->op) || depth > 0 || quantifier || is_cnt) {
    3367        1241 :                                 sql_rel *sq = lsq;
    3368             : 
    3369        1241 :                                 assert(!is_tuple);
    3370             : 
    3371        1241 :                                 if (!lsq)
    3372        1241 :                                         lsq = rel->l;
    3373          57 :                                 if (sq) {
    3374          57 :                                         sql_rel *rewrite = NULL;
    3375          57 :                                         operator_type op = (depth||quantifier)?op_left:op_join;
    3376          57 :                                         (void)rewrite_inner(v->sql, rel, sq, op, &rewrite);
    3377          57 :                                         exp_reset_props(rewrite, le, is_left(rewrite->op));
    3378          57 :                                         rel_bind_var(v->sql, rel, le);
    3379             :                                 }
    3380        1241 :                                 if (quantifier) {
    3381         174 :                                         sql_subfunc *a;
    3382             : 
    3383         174 :                                         rsq = rel_groupby(v->sql, rsq, NULL);
    3384         174 :                                         a = sql_bind_func(v->sql, "sys", "null", exp_subtype(re), NULL, F_AGGR, true, true);
    3385         174 :                                         rnull = exp_aggr1(v->sql->sa, re, a, 0, 1, CARD_AGGR, has_nil(re));
    3386         174 :                                         rnull = rel_groupby_add_aggr(v->sql, rsq, rnull);
    3387             : 
    3388         174 :                                         if (is_notequal_func(sf))
    3389         174 :                                                 op = "=";
    3390         174 :                                         if (op[0] == '<') {
    3391          50 :                                                 a = sql_bind_func(v->sql, "sys", (quantifier==1)?"max":"min", exp_subtype(re), NULL, F_AGGR, true, true);
    3392         140 :                                         } else if (op[0] == '>') {
    3393          97 :                                                 a = sql_bind_func(v->sql, "sys", (quantifier==1)?"min":"max", exp_subtype(re), NULL, F_AGGR, true, true);
    3394             :                                         } else /* (op[0] == '=')*/ /* only = ALL */ {
    3395          75 :                                                 a = sql_bind_func(v->sql, "sys", "all", exp_subtype(re), NULL, F_AGGR, true, true);
    3396          75 :                                                 is_cnt = 1;
    3397             :                                         }
    3398         174 :                                         re = exp_aggr1(v->sql->sa, re, a, 0, 1, CARD_AGGR, has_nil(re));
    3399         174 :                                         re = rel_groupby_add_aggr(v->sql, rsq, re);
    3400         174 :                                         set_processed(rsq);
    3401             :                                 }
    3402        1241 :                                 if (rsq) {
    3403        1206 :                                         sql_rel *rewrite = NULL;
    3404        1206 :                                         operator_type op = ((!quantifier && depth > 0)||is_cnt||quantifier)?op_left:op_join;
    3405        1206 :                                         (void)rewrite_inner(v->sql, rel, rsq, op, &rewrite);
    3406        1206 :                                         exp_reset_props(rewrite, re, is_left(rewrite->op));
    3407        1206 :                                         rel_bind_var(v->sql, rel, re);
    3408             :                                 }
    3409             : 
    3410        1241 :                                 if (rel_convert_types(v->sql, NULL, NULL, &le, &re, 1, type_equal) < 0)
    3411             :                                         return NULL;
    3412        1241 :                                 if (rnull) { /* complex compare operator */
    3413         174 :                                         sql_exp *lnull = rel_unop_(v->sql, rel, le, "sys", "isnull", card_value);
    3414         174 :                                         set_has_no_nil(lnull);
    3415         174 :                                         le = exp_compare_func(v->sql, le, re, op, 0);
    3416         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);
    3417         174 :                                         le = exp_op3(v->sql->sa, le, lnull, rnull, f);
    3418         174 :                                         if (is_select(rel->op) && depth == 0) {
    3419          91 :                                                 le = exp_compare(v->sql->sa, le, exp_atom_bool(v->sql->sa, is_notequal_func(sf) ? 0 : 1), cmp_equal);
    3420         126 :                                         } else if (is_notequal_func(sf)) {
    3421          15 :                                                 le = rel_unop_(v->sql, rel, le, "sys", "not", card_value);
    3422             :                                         }
    3423        1067 :                                 } else if (is_project(rel->op) || depth) {
    3424        1057 :                                         le = exp_compare_func(v->sql, le, re, op, 0);
    3425             :                                 } else {
    3426          10 :                                         v->changes++;
    3427          10 :                                         return exp_compare(v->sql->sa, le, re, compare_str2type(op));
    3428             :                                 }
    3429        1231 :                                 if (exp_name(e))
    3430          53 :                                         exp_prop_alias(v->sql->sa, le, e);
    3431        1231 :                                 v->changes++;
    3432        1231 :                                 return le;
    3433             :                         } else {
    3434        3224 :                                 if (lsq) {
    3435           3 :                                         sql_rel *rewrite = NULL;
    3436           3 :                                         (void)rewrite_inner(v->sql, rel, lsq, op_join, &rewrite);
    3437           3 :                                         exp_reset_props(rewrite, le, is_left(rewrite->op));
    3438             :                                 }
    3439        3224 :                                 if (rsq) {
    3440        3223 :                                         sql_rel *rewrite = NULL;
    3441        3223 :                                         operator_type op = !is_tuple?op_join:is_anyequal(sf)?op_semi:op_anti;
    3442        3223 :                                         (void)rewrite_inner(v->sql, rel, rsq, op, &rewrite);
    3443        3223 :                                         exp_reset_props(rewrite, re, is_left(rewrite->op));
    3444             :                                 }
    3445        3224 :                                 if (is_tuple) {
    3446           0 :                                         list *t = le->f;
    3447           0 :                                         list *l = sa_list(v->sql->sa);
    3448           0 :                                         list *r = sa_list(v->sql->sa);
    3449           0 :                                         int s1 = list_length(t), s2 = list_length(rsq->exps); /* subtract identity column */
    3450             : 
    3451             :                                         /* find out list of right expression */
    3452           0 :                                         if (s1 != s2)
    3453           0 :                                                 return sql_error(v->sql, 02, SQLSTATE(42000) "Subquery has too %s columns", (s2 < s1) ? "few" : "many");
    3454           0 :                                         for (node *n = t->h, *m = rsq->exps->h; n && m; n = n->next, m = m->next ) {
    3455           0 :                                                 sql_exp *le = n->data;
    3456           0 :                                                 sql_exp *re = m->data;
    3457             : 
    3458           0 :                                                 append(l, le);
    3459           0 :                                                 append(r, re);
    3460             :                                         }
    3461           0 :                                         v->changes++;
    3462           0 :                                         return exp_compare(v->sql->sa, exp_values(v->sql->sa, l), exp_values(v->sql->sa, r), compare_str2type(op));
    3463             :                                 } else {
    3464        3224 :                                         if (exp_has_freevar(v->sql, le))
    3465          15 :                                                 rel_bind_var(v->sql, rel, le);
    3466        3224 :                                         if (rel_convert_types(v->sql, NULL, NULL, &le, &re, 1, type_equal) < 0)
    3467             :                                                 return NULL;
    3468        3224 :                                         v->changes++;
    3469        3224 :                                         return exp_compare(v->sql->sa, le, re, compare_str2type(op));
    3470             :                                 }
    3471             :                         }
    3472             :                 }
    3473             :         }
    3474             :         return e;
    3475             : }
    3476             : 
    3477             : static sql_rel *
    3478     2322529 : rewrite_join2semi(visitor *v, sql_rel *rel)
    3479             : {
    3480     2322529 :         if (mvc_highwater(v->sql))
    3481           0 :                 return sql_error(v->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    3482             : 
    3483     2322530 :         if (is_select(rel->op) && !list_empty(rel->exps)) {
    3484      170143 :                 sql_rel *j = rel->l, *jl = j->l, *ojl = jl;
    3485      170143 :                 int needed = 0, changed = 0;
    3486             : 
    3487      170143 :                 if (!j || (!is_join(j->op) && !is_semi(j->op)) || !list_empty(j->exps))
    3488      165020 :                         return rel;
    3489             :                 /* if needed first push select exps down under the join */
    3490       10575 :                 for (node *n = rel->exps->h; n;) {
    3491        5452 :                         node *next = n->next;
    3492        5452 :                         sql_exp *e = n->data;
    3493        5452 :                         sql_subfunc *sf = e->f;
    3494             : 
    3495        5452 :                         if (is_func(e->type) && is_anyequal_func(sf)) {
    3496           0 :                                 if (exp_card(e) > CARD_ATOM && rel_has_all_exps(jl, e->l)) {
    3497           0 :                                         if (!is_select(jl->op) || rel_is_ref(jl))
    3498           0 :                                                 j->l = jl = rel_select(v->sql->sa, jl, NULL);
    3499           0 :                                         rel_select_add_exp(v->sql->sa, jl, e);
    3500           0 :                                         list_remove_node(rel->exps, NULL, n);
    3501           0 :                                         changed = 1;
    3502           0 :                                         v->changes++;
    3503             :                                 } else {
    3504             :                                         needed = 1;
    3505             :                                 }
    3506             :                         }
    3507             :                         n = next;
    3508             :                 }
    3509        5123 :                 if (ojl != jl)
    3510           0 :                         set_processed(jl);
    3511        5123 :                 if (changed && !(j->l = rewrite_join2semi(v, j->l)))
    3512             :                         return NULL;
    3513        5123 :                 if (!needed)
    3514        5123 :                         return try_remove_empty_select(v, rel);
    3515           0 :                 if (!j->exps)
    3516           0 :                         j->exps = sa_list(v->sql->sa);
    3517           0 :                 list *sexps = sa_list(v->sql->sa);
    3518           0 :                 for (node *n = rel->exps->h; n; ) {
    3519           0 :                         node *next = n->next;
    3520           0 :                         sql_exp *e = n->data;
    3521           0 :                         sql_subfunc *sf = e->f;
    3522             : 
    3523             :                         /* Any compare expression based only on the left side will be split into a
    3524             :                          * select under the anti join.
    3525             :                          */
    3526           0 :                         assert((is_func(e->type) && is_anyequal_func(sf)) || e->type == e_cmp);
    3527           0 :                         if ((is_func(e->type) && is_anyequal_func(sf)) || !rel_rebind_exp(v->sql, j->l, e)) {
    3528           0 :                                 if (e->type == e_cmp) {
    3529           0 :                                         append(j->exps, e);
    3530             :                                 } else {
    3531           0 :                                         list *args = e->l;
    3532           0 :                                         sql_exp *l, *r;
    3533             : 
    3534           0 :                                         assert(list_length(args)==2);
    3535           0 :                                         l = args->h->data;
    3536           0 :                                         r = args->h->next->data;
    3537           0 :                                         j->op = (is_anyequal(sf))?op_semi:op_anti;
    3538             : 
    3539           0 :                                         if (is_values(l)) {
    3540           0 :                                                 assert(is_values(r));
    3541           0 :                                                 list *ll = l->f, *rl = r->f;
    3542           0 :                                                 for(node *n=ll->h, *m=rl->h; n && m; n=n->next, m=m->next) {
    3543           0 :                                                         e = exp_compare(v->sql->sa, n->data, m->data, cmp_equal );
    3544           0 :                                                         append(j->exps, e);
    3545             :                                                 }
    3546             :                                         } else {
    3547           0 :                                                 e = exp_compare(v->sql->sa, l, r, cmp_equal);
    3548           0 :                                                 if (e && j->op == op_anti)
    3549           0 :                                                         set_semantics(e);
    3550           0 :                                                 append(j->exps, e);
    3551             :                                         }
    3552             :                                 }
    3553           0 :                                 list_remove_node(rel->exps, NULL, n);
    3554           0 :                         } else if (!rel_rebind_exp(v->sql, j->r, e) && j->op == op_anti) {
    3555           0 :                                 append(sexps, e);
    3556           0 :                                 list_remove_node(rel->exps, NULL, n);
    3557             :                         }
    3558             :                         n = next;
    3559             :                 }
    3560           0 :                 v->changes++;
    3561           0 :                 if (list_length(sexps)) {
    3562           0 :                         sql_rel *jl = j->l = rel_select(v->sql->sa, j->l, NULL);
    3563           0 :                         set_processed(jl);
    3564           0 :                         jl->exps = sexps;
    3565             :                 }
    3566           0 :                 rel = try_remove_empty_select(v, rel);
    3567             :         }
    3568             :         return rel;
    3569             : }
    3570             : 
    3571             : /* exp visitor */
    3572             : static sql_exp *
    3573      407721 : rewrite_exists(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    3574             : {
    3575      407721 :         assert(e->type == e_func);
    3576             : 
    3577      407721 :         sql_subfunc *sf = e->f;
    3578      407721 :         if (is_exists_func(sf) && !list_empty(e->l)) {
    3579        1348 :                 list *l = e->l;
    3580             : 
    3581        1348 :                 if (list_length(l) == 1) { /* exp_values */
    3582        1348 :                         sql_exp *ie = l->h->data, *le;
    3583        1348 :                         sql_rel *sq = NULL;
    3584             : 
    3585        1348 :                         if (!exp_is_rel(ie)) { /* exists over a constant or a single value */
    3586          24 :                                 le = exp_atom_bool(v->sql->sa, is_exists(sf)?1:0);
    3587          24 :                                 if (depth == 0 && is_select(rel->op))
    3588           0 :                                         le = exp_compare(v->sql->sa, le, exp_atom_bool(v->sql->sa, 1), cmp_equal);
    3589          24 :                                 else if (exp_name(e))
    3590           0 :                                         exp_prop_alias(v->sql->sa, le, e);
    3591          24 :                                 v->changes++;
    3592          24 :                                 return le;
    3593             :                         }
    3594             : 
    3595        1324 :                         sq = exp_rel_get_rel(v->sql->sa, ie); /* get subquery */
    3596             :                         /* number of expressions in set relations must match the children */
    3597        1324 :                         if (!is_project(sq->op) || (is_set(sq->op) && list_length(sq->exps) > 1) || (is_simple_project(sq->op) && !list_empty(sq->r)))
    3598           4 :                                 sq = rel_project(v->sql->sa, sq, rel_projections(v->sql, sq, NULL, 1, 1));
    3599           4 :                         if (!sq)
    3600             :                                 return NULL;
    3601        1324 :                         le = rel_reduce2one_exp(v->sql, sq);
    3602        1324 :                         if (!le->alias.label)
    3603         745 :                                 exp_label(v->sql->sa, le, ++v->sql->label);
    3604        1324 :                         le = exp_ref(v->sql, le);
    3605             : 
    3606        1324 :                         if (depth >= 1 && is_ddl(rel->op)) { /* exists is at a ddl statement, it must be inside at least a relation */
    3607           5 :                                 sq = rel_groupby(v->sql, sq, NULL);
    3608           5 :                                 sql_subfunc *ea = sql_bind_func(v->sql, "sys", is_exists(sf)?"exist":"not_exist", exp_subtype(le), NULL, F_AGGR, true, true);
    3609           5 :                                 le = rel_groupby_add_aggr(v->sql, sq, exp_aggr1(v->sql->sa, le, ea, 0, 0, CARD_AGGR, 0));
    3610           5 :                                 return exp_rel(v->sql, sq);
    3611             :                         }
    3612        1319 :                         if (is_project(rel->op) || depth > 0 || is_outerjoin(rel->op)) {
    3613         644 :                                 sql_rel *join = NULL, *rewrite = NULL;
    3614             : 
    3615         644 :                                 (void)rewrite_inner(v->sql, rel, sq, op_left, &rewrite);
    3616         644 :                                 exp_reset_props(rewrite, le, is_left(rewrite->op));
    3617         644 :                                 join = (is_full(rel->op)||is_left(rel->op))?rel->r:rel->l;
    3618         644 :                                 if (!join)
    3619             :                                         return NULL;
    3620         644 :                                 if (join && !join->exps)
    3621         644 :                                         join->exps = sa_list(v->sql->sa);
    3622         644 :                                 v->changes++;
    3623         644 :                                 if (join) {
    3624         644 :                                         if (!join->attr)
    3625         644 :                                                 join->attr = sa_list(v->sql->sa);
    3626         644 :                                         sql_exp *a = exp_atom_bool(v->sql->sa, is_exists(sf));
    3627         644 :                                         set_no_nil(a);
    3628         644 :                                         if (!e->alias.label)
    3629         626 :                                                 exp_label(v->sql->sa, a, ++v->sql->label);
    3630             :                                         else
    3631          18 :                                                 exp_setalias(a, e->alias.label, exp_relname(e), exp_name(e));
    3632         644 :                                         le = exp_ref(v->sql, a);
    3633         644 :                                         le->card = CARD_MULTI; /* mark as multi value, the real attribute is introduced later */
    3634         644 :                                         append(join->attr, a);
    3635         644 :                                         assert(is_project(rel->op) || depth);
    3636         644 :                                         if ((is_project(rel->op) || depth))
    3637             :                                                 return le;
    3638             :                                 }
    3639           0 :                                 set_has_nil(le); /* outer joins could have introduced nils */
    3640           0 :                                 return le;
    3641             :                         } else { /* rewrite into semi/anti join */
    3642         702 :                                 (void)rewrite_inner(v->sql, rel, sq, is_exists(sf)?op_semi:op_anti, NULL);
    3643         675 :                                 v->changes++;
    3644         675 :                                 return exp_compare(v->sql->sa, exp_atom_bool(v->sql->sa, 1), exp_atom_bool(v->sql->sa, 1), cmp_equal);
    3645             :                         }
    3646             :                         v->changes++;
    3647             :                         return le;
    3648             :                 }
    3649             :         }
    3650             :         return e;
    3651             : }
    3652             : 
    3653             : /* exp visitor */
    3654             : static sql_exp *
    3655    11209642 : rewrite_ifthenelse(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    3656             : {
    3657    11209642 :         (void)depth;
    3658             :         /* for ifthenelse and rank flatten referenced inner expressions */
    3659    11209642 :         if (e->ref) {
    3660          47 :                 sql_rel *r = rel->l = rel_project(v->sql->sa, rel->l, rel_projections(v->sql, rel->l, NULL, 1, 1));
    3661             : 
    3662          47 :                 e->ref = 0;
    3663          47 :                 set_processed(r);
    3664          47 :                 append(r->exps, e);
    3665          47 :                 v->changes++;
    3666          47 :                 return exp_ref(v->sql, e);
    3667             :         }
    3668             : 
    3669    11209595 :         sql_subfunc *sf;
    3670    11209595 :         if (e->type != e_func)
    3671             :                 return e;
    3672             : 
    3673      491749 :         sf = e->f;
    3674             :         /* TODO also handle ifthenelse with more than 3 arguments */
    3675      491749 :         if (is_case_func(sf) && !list_empty(e->l) && list_length(e->l) == 3 && rel_has_freevar(v->sql, rel)) {
    3676        2003 :                 list *l = e->l;
    3677             : 
    3678             :                 /* remove unnecessary = true expressions under ifthenelse */
    3679        8012 :                 for (node *n = l->h ; n ; n = n->next) {
    3680        6009 :                         sql_exp *e = n->data;
    3681             : 
    3682        6009 :                         if (e->type == e_cmp && e->flag == cmp_equal && exp_is_true(e) && exp_is_true(e->r))
    3683           0 :                                 n->data = e->l;
    3684             :                 }
    3685             : 
    3686        2003 :                 sql_exp *cond = l->h->data;
    3687        2003 :                 sql_exp *then_exp = l->h->next->data;
    3688        2003 :                 sql_exp *else_exp = l->h->next->next->data;
    3689        2003 :                 sql_exp *not_cond;
    3690             : 
    3691        2003 :                 if (!exp_has_rel(cond) && (exp_has_rel(then_exp) || exp_has_rel(else_exp))) {
    3692        1443 :                         bool single = false;
    3693             :                         /* return sql_error(v->sql, 10, SQLSTATE(42000) "time to rewrite into union\n");
    3694             :                            union(
    3695             :                                 select(
    3696             :                                         project [then]
    3697             :                                 )[cond]
    3698             :                                 select(
    3699             :                                         project [else]
    3700             :                                 )[not(cond) or cond is null]
    3701             :                           ) [ cols ] */
    3702        1443 :                         sql_rel *lsq = NULL, *rsq = NULL, *usq = NULL;
    3703        1443 :                         list *urs = sa_list(v->sql->sa);
    3704             : 
    3705        1443 :                         if (exp_has_rel(then_exp)) {
    3706        1197 :                                 lsq = exp_rel_get_rel(v->sql->sa, then_exp);
    3707        1197 :                                 then_exp = exp_rel_update_exp(v->sql, then_exp, false);
    3708        1197 :                                 if (is_single(lsq))
    3709        1194 :                                         single = true;
    3710        1197 :                                 reset_single(lsq);
    3711             :                         }
    3712        1443 :                         exp_set_freevar(v->sql, then_exp, lsq);
    3713        1443 :                         exp_label(v->sql->sa, then_exp, ++v->sql->label);
    3714        1443 :                         lsq = rel_project(v->sql->sa, lsq, append(sa_list(v->sql->sa), then_exp));
    3715        1443 :                         exp_set_freevar(v->sql, cond, lsq);
    3716        1443 :                         set_processed(lsq);
    3717        1443 :                         lsq = rel_select(v->sql->sa, lsq, exp_compare(v->sql->sa, cond, exp_atom_bool(v->sql->sa, 1), cmp_equal));
    3718        1443 :                         set_processed(lsq);
    3719        1443 :                         if (exp_has_rel(else_exp)) {
    3720         246 :                                 rsq = exp_rel_get_rel(v->sql->sa, else_exp);
    3721         246 :                                 else_exp = exp_rel_update_exp(v->sql, else_exp, false);
    3722         246 :                                 if (is_single(rsq))
    3723         246 :                                         single = true;
    3724         246 :                                 reset_single(rsq);
    3725             :                         }
    3726        1443 :                         exp_set_freevar(v->sql, else_exp, rsq);
    3727        1443 :                         exp_label(v->sql->sa, else_exp, ++v->sql->label);
    3728        1443 :                         rsq = rel_project(v->sql->sa, rsq, append(sa_list(v->sql->sa), else_exp));
    3729        1443 :                         cond = exp_copy(v->sql, cond);
    3730        1443 :                         exp_set_freevar(v->sql, cond, rsq);
    3731        1443 :                         not_cond = exp_compare(v->sql->sa, cond, exp_atom_bool(v->sql->sa, 1), cmp_notequal);
    3732        1443 :                         set_semantics(not_cond); /* also compare nulls */
    3733        1443 :                         set_processed(rsq);
    3734        1443 :                         rsq = rel_select(v->sql->sa, rsq, not_cond);
    3735        1443 :                         set_processed(rsq);
    3736        1443 :                         urs = append(urs, lsq);
    3737        1443 :                         urs = append(urs, rsq);
    3738        1443 :                         usq = rel_setop_n_ary(v->sql->sa, urs, op_munion);
    3739        1443 :                         rel_setop_n_ary_set_exps(v->sql, usq, append(sa_list(v->sql->sa), exp_ref(v->sql, e)), false);
    3740        1443 :                         if (single)
    3741        1440 :                                 set_single(usq);
    3742        1443 :                         set_processed(usq);
    3743        1443 :                         e = exp_rel(v->sql, usq);
    3744        1443 :                         v->changes++;
    3745             :                 }
    3746             :         }
    3747             :         return e;
    3748             : }
    3749             : 
    3750             : static list *
    3751      310858 : rewrite_compare_exps(visitor *v, sql_rel *rel, list *exps)
    3752             : {
    3753      310858 :         if (mvc_highwater(v->sql))
    3754           0 :                 return sql_error(v->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
    3755      310858 :         if (list_empty(exps))
    3756             :                 return exps;
    3757             : 
    3758      668356 :         for(node *n = exps->h; n; n = n->next) {
    3759      357498 :                 sql_exp *e = n->data;
    3760             : 
    3761      357498 :                 if (!is_compare(e->type)) {
    3762        5637 :                         sql_subtype bt;
    3763        5637 :                         sql_find_subtype(&bt, "boolean", 0, 0);
    3764        5637 :                         if (!(e = exp_check_type(v->sql, &bt, rel, e, type_equal)))
    3765           0 :                                 return NULL;
    3766        5637 :                         n->data = e = exp_compare(v->sql->sa, e, exp_atom_bool(v->sql->sa, 1), cmp_equal);
    3767        5637 :                         v->changes++;
    3768             :                 }
    3769      357498 :                 if (is_compare(e->type) && e->flag == cmp_or) {
    3770       17136 :                         if (!(e->l = rewrite_compare_exps(v, rel, e->l)))
    3771             :                                 return NULL;
    3772       17136 :                         if (!(e->r = rewrite_compare_exps(v, rel, e->r)))
    3773             :                                 return NULL;
    3774             :                 }
    3775             :         }
    3776             :         return exps;
    3777             : }
    3778             : 
    3779             : /* add an dummy true projection column */
    3780             : static inline sql_rel *
    3781     2322523 : rewrite_compare_exp(visitor *v, sql_rel *rel)
    3782             : {
    3783     2322523 :         if ((is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) && !list_empty(rel->exps))
    3784      276586 :                 if (!(rel->exps = rewrite_compare_exps(v, rel, rel->exps)))
    3785             :                         return NULL;
    3786             :         return rel;
    3787             : }
    3788             : 
    3789             : static inline sql_rel *
    3790     2322526 : rewrite_remove_xp_project(visitor *v, sql_rel *rel)
    3791             : {
    3792     2322526 :         if (rel->op == op_join && list_empty(rel->exps) && !rel_is_ref(rel)) {
    3793       27046 :                 sql_rel *r = rel->r;
    3794             : 
    3795       27046 :                 if (is_simple_project(r->op) && r->l && !project_unsafe(r, 1)) {
    3796        3874 :                         sql_rel *rl = r->l;
    3797             : 
    3798        3874 :                         if (is_simple_project(rl->op) && !rl->l && list_length(rl->exps) == 1) {
    3799         104 :                                 sql_exp *t = rl->exps->h->data;
    3800             : 
    3801         104 :                                 if (is_atom(t->type) && !exp_name(t)) { /* atom with out alias cannot be used later */
    3802           0 :                                         sql_rel *nrel = rel->l;
    3803           0 :                                         rel->l = NULL;
    3804           0 :                                         rel_destroy(rel);
    3805           0 :                                         rel = rel_project(v->sql->sa, nrel, rel_projections(v->sql, nrel, NULL, 1, 1));
    3806           0 :                                         list_merge(rel->exps, r->exps, (fdup)NULL);
    3807           0 :                                         set_processed(rel);
    3808           0 :                                         v->changes++;
    3809             :                                 }
    3810             :                         }
    3811             :                 }
    3812             :         }
    3813     2322526 :         return rel;
    3814             : }
    3815             : 
    3816             : static inline sql_rel *
    3817     2943756 : rewrite_remove_xp(visitor *v, sql_rel *rel)
    3818             : {
    3819     2943756 :         if (rel->op == op_join && list_empty(rel->exps) && !rel_is_ref(rel)) {
    3820       47753 :                 sql_rel *r = rel->r;
    3821             : 
    3822       47753 :                 if (is_simple_project(r->op) && !r->l && list_length(r->exps) == 1) {
    3823         285 :                         sql_exp *t = r->exps->h->data;
    3824             : 
    3825         285 :                         if (is_atom(t->type) && !exp_name(t)) { /* atom with out alias cannot be used later */
    3826           0 :                                 sql_rel *nrel = rel->l;
    3827           0 :                                 rel->l = NULL;
    3828           0 :                                 rel_destroy(rel);
    3829           0 :                                 rel = nrel;
    3830           0 :                                 v->changes++;
    3831             :                         }
    3832             :                 }
    3833             :         }
    3834     2943756 :         return rel;
    3835             : }
    3836             : 
    3837             : /* rel visitor */
    3838             : static sql_rel *
    3839     2932785 : rewrite_fix_count(visitor *v, sql_rel *rel)
    3840             : {
    3841     2932785 :         if (rel->op == op_left && !is_single(rel)) {
    3842       71616 :                 int rel_changes = 0;
    3843       71616 :                 sql_rel *r = rel->r;
    3844             : 
    3845       71616 :                 if (!is_rewrite_fix_count_used(r->used)) {
    3846       66444 :                         list *rexps = r->exps, *exps = NULL;
    3847             : 
    3848       66444 :                         if (!is_project(r->op))
    3849       11865 :                                 rexps = rel_projections(v->sql, r, NULL, 1, 1);
    3850             : 
    3851      220137 :                         for(node *n = rexps->h; n && !rel_changes; n=n->next) {
    3852      153693 :                                 sql_exp *e = n->data;
    3853             : 
    3854      153693 :                                 if (exp_is_count(e, r))
    3855        7340 :                                         rel_changes = 1;
    3856             :                         }
    3857       66444 :                         if (!rel_changes)
    3858             :                                 return rel;
    3859             : 
    3860        7340 :                         if (r->exps == rexps)
    3861        7340 :                                 rexps = rel_projections(v->sql, r, NULL, 1, 1);
    3862       18101 :                         for(node *n = rexps->h; n; n=n->next) {
    3863       10761 :                                 sql_exp *e = n->data, *ne;
    3864             : 
    3865       10761 :                                 if (exp_is_count(e, r)) {
    3866             :                                         /* rewrite count in subquery */
    3867        2362 :                                         list *args, *targs;
    3868        2362 :                                         sql_subfunc *isnil = sql_bind_func(v->sql, "sys", "isnull", exp_subtype(e), NULL, F_FUNC, true, true), *ifthen;
    3869             : 
    3870        2362 :                                         ne = exp_unop(v->sql->sa, e, isnil);
    3871        2362 :                                         set_has_no_nil(ne);
    3872        2362 :                                         targs = sa_list(v->sql->sa);
    3873        2362 :                                         append(targs, sql_bind_localtype("bit"));
    3874        2362 :                                         append(targs, exp_subtype(e));
    3875        2362 :                                         append(targs, exp_subtype(e));
    3876        2362 :                                         ifthen = sql_bind_func_(v->sql, "sys", "ifthenelse", targs, F_FUNC, true, true);
    3877        2362 :                                         args = sa_list(v->sql->sa);
    3878        2362 :                                         append(args, ne);
    3879        2362 :                                         append(args, exp_atom(v->sql->sa, atom_zero_value(v->sql->sa, exp_subtype(e))));
    3880        2362 :                                         append(args, e);
    3881        2362 :                                         ne = exp_op(v->sql->sa, args, ifthen);
    3882        2362 :                                         if (exp_name(e))
    3883        2362 :                                                 exp_prop_alias(v->sql->sa, ne, e);
    3884        2362 :                                         n->data = ne;
    3885             :                                 }
    3886             :                         }
    3887        7340 :                         exps = list_merge(rel_projections(v->sql, rel->l, NULL, 1, 1), rexps, (fdup)NULL);
    3888        7340 :                         rel = rel_project(v->sql->sa, rel, exps);
    3889        7340 :                         set_processed(rel);
    3890        7340 :                         r->used |= rewrite_fix_count_used;
    3891        7340 :                         v->changes++;
    3892             :                 }
    3893             :         }
    3894             :         return rel;
    3895             : }
    3896             : 
    3897             : static inline sql_rel *
    3898     2943755 : rewrite_groupings(visitor *v, sql_rel *rel)
    3899             : {
    3900     2943755 :         prop *found;
    3901             : 
    3902     2943755 :         if (is_groupby(rel->op)) {
    3903             :                 /* ROLLUP, CUBE, GROUPING SETS cases */
    3904       38485 :                 if ((found = find_prop(rel->p, PROP_GROUPINGS))) {
    3905         111 :                         list *sets = (list*) found->value.pval;
    3906         111 :                         list *grpr = sa_list(v->sql->sa);
    3907             : 
    3908         111 :                         rel->p = prop_remove(rel->p, found); /* remove property */
    3909         637 :                         for (node *n = sets->h ; n ; n = n->next) {
    3910         526 :                                 sql_rel *nrel;
    3911         526 :                                 list *l = (list*) n->data, *exps = sa_list(v->sql->sa), *pexps = sa_list(v->sql->sa);
    3912             : 
    3913         526 :                                 l = list_flatten(l);
    3914         526 :                                 nrel = rel_groupby(v->sql, rel_dup(rel->l), l);
    3915             : 
    3916        3377 :                                 for (node *m = rel->exps->h ; m ; m = m->next) {
    3917        2851 :                                         sql_exp *e = (sql_exp*) m->data, *ne = NULL;
    3918        2851 :                                         sql_subfunc *agr = (sql_subfunc*) e->f;
    3919             : 
    3920        3227 :                                         if (e->type == e_aggr && !agr->func->s && !strcmp(agr->func->base.name, "grouping")) {
    3921             :                                                 /* replace grouping aggregate calls with constants */
    3922         376 :                                                 sql_subtype tpe = ((sql_arg*) agr->func->res->h->data)->type;
    3923         376 :                                                 list *groups = (list*) e->l;
    3924         376 :                                                 atom *a = atom_int(v->sql->sa, &tpe, 0);
    3925             : #ifdef HAVE_HGE
    3926         376 :                                                 hge counter = (hge) list_length(groups) - 1;
    3927             : #else
    3928             :                                                 lng counter = (lng) list_length(groups) - 1;
    3929             : #endif
    3930         376 :                                                 assert(groups && list_length(groups) > 0);
    3931             : 
    3932        1196 :                                                 for (node *nn = groups->h ; nn ; nn = nn->next) {
    3933         820 :                                                         sql_exp *exp = (sql_exp*) nn->data;
    3934         820 :                                                         if (!exps_find_exp(l, exp)) {
    3935         415 :                                                                 switch (ATOMstorage(a->data.vtype)) {
    3936         379 :                                                                         case TYPE_bte:
    3937         379 :                                                                                 a->data.val.btval += (bte) (1 << counter);
    3938         379 :                                                                                 break;
    3939          36 :                                                                         case TYPE_sht:
    3940          36 :                                                                                 a->data.val.shval += (sht) (1 << counter);
    3941          36 :                                                                                 break;
    3942           0 :                                                                         case TYPE_int:
    3943           0 :                                                                                 a->data.val.ival += (int) (1 << counter);
    3944           0 :                                                                                 break;
    3945           0 :                                                                         case TYPE_lng:
    3946           0 :                                                                                 a->data.val.lval += (lng) (1 << counter);
    3947           0 :                                                                                 break;
    3948             : #ifdef HAVE_HGE
    3949           0 :                                                                         case TYPE_hge:
    3950           0 :                                                                                 a->data.val.hval += (hge) (1 << counter);
    3951           0 :                                                                                 break;
    3952             : #endif
    3953             :                                                                         default:
    3954           0 :                                                                                 assert(0);
    3955             :                                                                 }
    3956             :                                                         }
    3957         820 :                                                         counter--;
    3958             :                                                 }
    3959             : 
    3960         376 :                                                 ne = exp_atom(v->sql->sa, a);
    3961         376 :                                                 if (exp_name(e))
    3962         376 :                                                         exp_prop_alias(v->sql->sa, ne, e);
    3963        2475 :                                         } else if (e->type == e_column && !exps_find_exp(l, e) && !has_label(e)) {
    3964             :                                                 /* do not include in the output of the group by, but add to the project as null */
    3965         745 :                                                 ne = exp_atom(v->sql->sa, atom_general(v->sql->sa, exp_subtype(e), NULL, 0));
    3966         745 :                                                 if (exp_name(e))
    3967         745 :                                                         exp_prop_alias(v->sql->sa, ne, e);
    3968             :                                         } else {
    3969        1730 :                                                 sql_exp *ec = exp_copy(v->sql, e);
    3970        1730 :                                                 ne = exp_ref(v->sql, ec);
    3971        1730 :                                                 append(exps, ec);
    3972             :                                         }
    3973        2851 :                                         append(pexps, ne);
    3974             :                                 }
    3975         526 :                                 if (list_empty(exps)) {
    3976          24 :                                         sql_exp *e = exp_atom_bool(v->sql->sa, 1);
    3977          24 :                                         exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
    3978          24 :                                         list_append(exps, e);
    3979             :                                 }
    3980         526 :                                 nrel->exps = exps;
    3981         526 :                                 if (!list_empty(rel->r) && !list_empty(nrel->r)) { /* aliases on grouping columns, ugh */
    3982        1290 :                                         for (node *n = ((list*)nrel->r)->h; n; n = n->next) {
    3983         857 :                                                 sql_exp *e = n->data;
    3984         857 :                                                 sql_exp *ne = exps_bind_nid(rel->r, e->alias.label);
    3985         857 :                                                 if (ne)
    3986         857 :                                                         n->data = exp_copy(v->sql, ne);
    3987             :                                         }
    3988         433 :                                         list_hash_clear(nrel->r);
    3989             :                                 }
    3990         526 :                                 set_processed(nrel);
    3991         526 :                                 if (list_empty(pexps)) {
    3992           0 :                                         sql_exp *e = exp_atom_bool(v->sql->sa, 1);
    3993           0 :                                         exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
    3994           0 :                                         list_append(pexps, e);
    3995             :                                 }
    3996         526 :                                 nrel = rel_project(v->sql->sa, nrel, pexps);
    3997         526 :                                 set_processed(nrel);
    3998         526 :                                 grpr = append(grpr, nrel);
    3999             :                         }
    4000             : 
    4001             :                         /* always do relation inplace, so it will be fine when the input group has more than 1 reference */
    4002         111 :                         assert(list_length(grpr) > 0);
    4003         111 :                         if (list_length(grpr) == 0) {
    4004             :                                 return NULL;
    4005         111 :                         } else if (list_length(grpr) == 1) {
    4006           0 :                                 sql_rel *grp = grpr->h->data;
    4007           0 :                                 rel = rel_inplace_project(v->sql->sa, rel, grp, grp->exps);
    4008             :                         } else {
    4009         111 :                                 rel = rel_inplace_setop_n_ary(v->sql, rel, grpr, op_munion, rel_projections(v->sql, rel, NULL, 1, 1));
    4010             :                         }
    4011             : 
    4012         111 :                         v->changes++;
    4013         111 :                         return rel;
    4014             :                 } else {
    4015       38374 :                         bool found_grouping = false;
    4016      108601 :                         for (node *n = rel->exps->h ; n ; n = n->next) {
    4017       70234 :                                 sql_exp *e = (sql_exp*) n->data;
    4018       70234 :                                 sql_subfunc *agr = (sql_subfunc*) e->f;
    4019             : 
    4020       70234 :                                 if (e->type == e_aggr && !agr->func->s && !strcmp(agr->func->base.name, "grouping")) {
    4021             :                                         found_grouping = true;
    4022             :                                         break;
    4023             :                                 }
    4024             :                         }
    4025       38374 :                         if (found_grouping) {
    4026             :                                 /* replace grouping calls with constants of value 0 */
    4027           7 :                                 sql_rel *nrel = rel_groupby(v->sql, rel_dup(rel->l), rel->r);
    4028           7 :                                 list *exps = sa_list(v->sql->sa), *pexps = sa_list(v->sql->sa);
    4029           7 :                                 sql_subtype *bt = sql_bind_localtype("bte");
    4030             : 
    4031          19 :                                 for (node *n = rel->exps->h ; n ; n = n->next) {
    4032          12 :                                         sql_exp *e = (sql_exp*) n->data, *ne;
    4033          12 :                                         sql_subfunc *agr = (sql_subfunc*) e->f;
    4034             : 
    4035          12 :                                         if (e->type == e_aggr && !agr->func->s && !strcmp(agr->func->base.name, "grouping")) {
    4036           7 :                                                 ne = exp_atom(v->sql->sa, atom_int(v->sql->sa, bt, 0));
    4037           7 :                                                 if (exp_name(e))
    4038           7 :                                                         exp_prop_alias(v->sql->sa, ne, e);
    4039             :                                         } else {
    4040           5 :                                                 ne = exp_ref(v->sql, e);
    4041           5 :                                                 append(exps, e);
    4042             :                                         }
    4043          12 :                                         append(pexps, ne);
    4044             :                                 }
    4045           7 :                                 if (list_empty(exps)) {
    4046           4 :                                         sql_exp *e = exp_atom_bool(v->sql->sa, 1);
    4047           4 :                                         exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
    4048           4 :                                         list_append(exps, e);
    4049             :                                 }
    4050           7 :                                 nrel->exps = exps;
    4051           7 :                                 set_processed(nrel);
    4052           7 :                                 if (list_empty(pexps)) {
    4053           0 :                                         sql_exp *e = exp_atom_bool(v->sql->sa, 1);
    4054           0 :                                         exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
    4055           0 :                                         list_append(pexps, e);
    4056             :                                 }
    4057             :                                 /* always do relation inplace, so it will be fine when the input group has more than 1 reference */
    4058           7 :                                 rel = rel_inplace_project(v->sql->sa, rel, nrel, pexps);
    4059           7 :                                 rel->card = exps_card(pexps);
    4060           7 :                                 v->changes++;
    4061           7 :                                 return rel;
    4062             :                         }
    4063             :                 }
    4064             :         }
    4065             :         return rel;
    4066             : }
    4067             : 
    4068             : static int
    4069         122 : include_tid(sql_rel *r)
    4070             : {
    4071         122 :         if (is_basetable(r->op))
    4072          74 :                 r->nrcols = list_length(r->exps);
    4073         122 :         return r->nrcols;
    4074             : }
    4075             : 
    4076             : static sql_rel *
    4077          70 : add_null_projects(visitor *v, sql_rel *prel, sql_rel *irel, bool end)
    4078             : {
    4079          70 :         list *l = NULL;
    4080          70 :         node *n = prel->exps->h;
    4081          70 :         sql_rel *nilrel = rel_project(v->sql->sa, irel, rel_projections(v->sql, irel, NULL, 1, 1));
    4082          70 :         int nr = prel->nrcols - nilrel->nrcols;
    4083          70 :         if (end) {
    4084         115 :                 for(node *m = nilrel->exps->h; n && m; n = n->next, m = m->next)
    4085             :                         ;
    4086             :         } else {
    4087          39 :                 l = sa_list(v->sql->sa);
    4088             :         }
    4089         248 :         for(; nr; n = n->next, nr--) {
    4090         179 :                 sql_exp *e = n->data, *ne;
    4091         179 :                 sql_subtype *tp = exp_subtype(e);
    4092             : 
    4093         179 :                 if (!tp)
    4094           1 :                         return sql_error(v->sql, 10, SQLSTATE(42000) "Cannot rewrite subquery because of parameter with unknown type");
    4095         178 :                 ne = exp_atom(v->sql->sa, atom_general(v->sql->sa, tp, NULL, 0));
    4096         178 :                 assert(e->alias.label);
    4097         178 :                 exp_setalias(ne, e->alias.label, exp_relname(e), exp_name(e));
    4098         178 :                 if (end)
    4099          58 :                         append(nilrel->exps, ne);
    4100             :                 else
    4101         120 :                         append(l, ne);
    4102             :         }
    4103          69 :         if (!end)
    4104          39 :                 nilrel->exps = list_merge(l, nilrel->exps, NULL);
    4105          69 :         nilrel->nrcols = list_length(nilrel->exps);
    4106          69 :         return nilrel;
    4107             : }
    4108             : 
    4109             : static sql_rel *
    4110          61 : rewrite_outer2inner_union(visitor *v, sql_rel *rel)
    4111             : {
    4112          61 :         if (is_outerjoin(rel->op) && rel->flag != MERGE_LEFT) {
    4113          61 :                 int nrcols = rel->nrcols;
    4114             : 
    4115          61 :                 nrcols = include_tid(rel->l);
    4116          61 :                 nrcols += include_tid(rel->r);
    4117          61 :                 rel->nrcols = nrcols;
    4118          61 :                 if (is_left(rel->op)) {
    4119          22 :                         sql_rel *inner = rel_crossproduct(v->sql->sa, rel_dup(rel->l), rel_dup(rel->r),  op_join);
    4120          22 :                         inner->exps = rel->exps;
    4121          22 :                         if(is_dependent(rel))
    4122          16 :                                 set_dependent(inner);
    4123          22 :                         sql_rel *prel = rel_project(v->sql->sa, inner, rel_projections(v->sql, inner, NULL, 1, 1));
    4124          44 :                         sql_rel *except = rel_setop(v->sql->sa,
    4125          22 :                                         rel_project(v->sql->sa, rel_dup(rel->l), rel_projections(v->sql, rel->l, NULL, 1, 1)),
    4126          44 :                                         rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->l, NULL, 1, 1)), op_except);
    4127          22 :                         rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->l, NULL, 1, 1), false);
    4128          22 :                         set_processed(except);
    4129          22 :                         sql_rel *nilrel = add_null_projects(v, prel, except, true);
    4130          22 :                         if (!nilrel)
    4131             :                                 return NULL;
    4132             : 
    4133          21 :                         list *urs = sa_list(v->sql->sa);
    4134          21 :                         urs = append(urs, prel);
    4135          21 :                         urs = append(urs, nilrel);
    4136          21 :                         sql_rel *nrel = rel_setop_n_ary(v->sql->sa, urs, op_munion);
    4137          21 :                         rel_setop_n_ary_set_exps(v->sql, nrel, rel_projections(v->sql, rel, NULL, 1, 1), false);
    4138          21 :                         set_processed(nrel);
    4139          21 :                         if(is_single(rel))
    4140           0 :                                 set_single(nrel);
    4141          21 :                         v->changes++;
    4142          21 :                         rel_destroy(rel);
    4143          21 :                         return nrel;
    4144          39 :                 } else if (is_right(rel->op)) {
    4145          30 :                         sql_rel *inner = rel_crossproduct(v->sql->sa, rel_dup(rel->l), rel_dup(rel->r),  op_join);
    4146          30 :                         inner->exps = rel->exps;
    4147          30 :                         if(is_dependent(rel))
    4148          18 :                                 set_dependent(inner);
    4149          30 :                         sql_rel *prel = rel_project(v->sql->sa, inner, rel_projections(v->sql, inner, NULL, 1, 1));
    4150          60 :                         sql_rel *except = rel_setop(v->sql->sa,
    4151          30 :                                         rel_project(v->sql->sa, rel_dup(rel->r), rel_projections(v->sql, rel->r, NULL, 1, 1)),
    4152          60 :                                         rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->r, NULL, 1, 1)), op_except);
    4153          30 :                         rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->r, NULL, 1, 1), false);
    4154          30 :                         set_processed(except);
    4155          30 :                         sql_rel *nilrel = add_null_projects(v, prel, except, false);
    4156          30 :                         if (!nilrel)
    4157             :                                 return NULL;
    4158             : 
    4159          30 :                         list *urs = sa_list(v->sql->sa);
    4160          30 :                         urs = append(urs, prel);
    4161          30 :                         urs = append(urs, nilrel);
    4162          30 :                         sql_rel *nrel = rel_setop_n_ary(v->sql->sa, urs, op_munion);
    4163          30 :                         rel_setop_n_ary_set_exps(v->sql, nrel, rel_projections(v->sql, rel, NULL, 1, 1), false);
    4164          30 :                         set_processed(nrel);
    4165          30 :                         if(is_single(rel))
    4166           0 :                                 set_single(nrel);
    4167          30 :                         v->changes++;
    4168          30 :                         rel_destroy(rel);
    4169          30 :                         return nrel;
    4170           9 :                 } else if (is_full(rel->op)) {
    4171           9 :                         sql_rel *inner = rel_crossproduct(v->sql->sa, rel_dup(rel->l), rel_dup(rel->r),  op_join);
    4172           9 :                         inner->exps = rel->exps;
    4173           9 :                         if(is_dependent(rel))
    4174           3 :                                 set_dependent(inner);
    4175           9 :                         sql_rel *prel = rel_project(v->sql->sa, inner, rel_projections(v->sql, inner, NULL, 1, 1));
    4176          18 :                         sql_rel *except = rel_setop(v->sql->sa,
    4177           9 :                                         rel_project(v->sql->sa, rel_dup(rel->l), rel_projections(v->sql, rel->l, NULL, 1, 1)),
    4178          18 :                                         rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->l, NULL, 1, 1)), op_except);
    4179           9 :                         rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->l, NULL, 1, 1), false);
    4180           9 :                         set_processed(except);
    4181           9 :                         sql_rel *lrel = add_null_projects(v, prel, except, true);
    4182           9 :                         if (!lrel)
    4183             :                                 return NULL;
    4184             : 
    4185          18 :                         except = rel_setop(v->sql->sa,
    4186           9 :                                         rel_project(v->sql->sa, rel_dup(rel->r), rel_projections(v->sql, rel->r, NULL, 1, 1)),
    4187          18 :                                         rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->r, NULL, 1, 1)), op_except);
    4188           9 :                         rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->r, NULL, 1, 1), false);
    4189           9 :                         set_processed(except);
    4190           9 :                         sql_rel *rrel = add_null_projects(v, prel, except, false);
    4191           9 :                         if (!rrel)
    4192             :                                 return NULL;
    4193             : 
    4194           9 :                         list *urs = sa_list(v->sql->sa);
    4195             :                         /* order matters (see caller logic) */
    4196           9 :                         urs = append(urs, prel);
    4197           9 :                         urs = append(urs, lrel);
    4198           9 :                         urs = append(urs, rrel);
    4199           9 :                         lrel = rel_setop_n_ary(v->sql->sa, urs, op_munion);
    4200           9 :                         rel_setop_n_ary_set_exps(v->sql, lrel, rel_projections(v->sql, rel, NULL, 1, 1), false);
    4201           9 :                         set_processed(lrel);
    4202             : 
    4203           9 :                         if(is_single(rel))
    4204           0 :                                 set_single(lrel);
    4205           9 :                         v->changes++;
    4206           9 :                         rel_destroy(rel);
    4207           9 :                         return lrel;
    4208             :                 }
    4209             :         }
    4210             :         return rel;
    4211             : }
    4212             : 
    4213             : static sql_rel *
    4214     2270603 : rewrite_swap_fullouter(visitor *v, sql_rel *rel)
    4215             : {
    4216     2270603 :         if (is_full(rel->op) && rel_has_freevar(v->sql, rel->r)) { /* swap */
    4217           3 :                 sql_rel *s = rel->r;
    4218           3 :                 rel->r = rel->l;
    4219           3 :                 rel->l = s;
    4220             :         }
    4221     2270603 :         return rel;
    4222             : }
    4223             : 
    4224             : static sql_exp *
    4225    11472150 : rewrite_complex(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    4226             : {
    4227    11472150 :         if (e->type != e_func)
    4228             :                 return e;
    4229             : 
    4230      425926 :         sql_exp *res = rewrite_anyequal(v, rel, e, depth);
    4231      425926 :         if (res == e)
    4232      407721 :                 res = rewrite_exists(v, rel, e, depth);
    4233      425926 :         if (res == e)
    4234      406373 :                 res = rewrite_compare(v, rel, e, depth);
    4235             :         return res;
    4236             : }
    4237             : 
    4238             : static sql_rel *
    4239         103 : flatten_values(visitor *v, sql_rel *rel)
    4240             : {
    4241         103 :         list *exps = sa_list(v->sql->sa);
    4242         103 :         sql_exp *e = rel->exps->h->data;
    4243         103 :         sql_rel *nrel = NULL;
    4244         103 :         list *vals = exp_get_values(e);
    4245         103 :         if (vals) {
    4246         103 :                 list *urs = sa_list(v->sql->sa);
    4247         254 :                 for(int i = 0; i<list_length(vals); i++) {
    4248         151 :                         nrel = rel_project(v->sql->sa, NULL, sa_list(v->sql->sa));
    4249         151 :                         set_processed(nrel);
    4250         344 :                         for(node *n = rel->exps->h; n; n = n->next) {
    4251         193 :                                 sql_exp *e = n->data;
    4252         193 :                                 list *vals = exp_get_values(e);
    4253             : 
    4254         193 :                                 if (vals) {
    4255         193 :                                         if (i == 0)
    4256         127 :                                                 append(exps, exp_ref(v->sql, e));
    4257         193 :                                         sql_exp *val = list_fetch(vals, i);
    4258         193 :                                         exp_setalias(val, e->alias.label, exp_relname(e), exp_name(e));
    4259         193 :                                         append(nrel->exps, val);
    4260         193 :                                         rel_set_exps(nrel, nrel->exps);
    4261             :                                 }
    4262             :                         }
    4263         151 :                         urs = append(urs, nrel);
    4264             :                 }
    4265             : 
    4266         103 :                 if (list_length(urs) == 1) {
    4267          56 :                         if (is_single(rel))
    4268           0 :                                 set_single(nrel);
    4269          56 :                         rel_destroy(rel);
    4270          56 :                         rel = nrel;
    4271             :                 } else {
    4272          47 :                         nrel = rel_setop_n_ary(v->sql->sa, urs, op_munion);
    4273          47 :                         rel_setop_n_ary_set_exps(v->sql, nrel, exps, false);
    4274          47 :                         if (is_single(rel))
    4275           9 :                                 set_single(nrel);
    4276          47 :                         rel_destroy(rel);
    4277          47 :                         rel = nrel;
    4278             :                 }
    4279             : 
    4280         103 :                 v->changes++;
    4281             :         }
    4282         103 :         return rel;
    4283             : }
    4284             : 
    4285             : /* rewrite project [ [multi values], [multi values2] , .. [] ] -> union ) */
    4286             : static inline sql_rel *
    4287     2270608 : rewrite_values(visitor *v, sql_rel *rel)
    4288             : {
    4289     2270608 :         if (!is_simple_project(rel->op) || list_empty(rel->exps) || is_rewrite_values_used(rel->used))
    4290     1529492 :                 return rel;
    4291             : 
    4292      741113 :         sql_exp *e = rel->exps->h->data;
    4293      741113 :         if (!is_values(e) || (!exps_have_rel_exp(rel->exps) && !exps_have_freevar(v->sql, rel->exps)))
    4294      741011 :                 return rel;
    4295         103 :         if (rel_is_ref(rel)) { /* need extra project */
    4296           0 :                 rel->l = rel_project(v->sql->sa, rel->l, rel->exps);
    4297           0 :                 rel->exps = rel_projections(v->sql, rel->l, NULL, 1, 1);
    4298           0 :                 ((sql_rel*)rel->l)->r = rel->r; /* propagate order by exps */
    4299           0 :                 rel->r = NULL;
    4300           0 :                 rel->used |= rewrite_values_used;
    4301           0 :                 v->changes++;
    4302           0 :                 return rel;
    4303             :         }
    4304         103 :         return flatten_values(v, rel);
    4305             : }
    4306             : 
    4307             : static inline sql_rel *
    4308     2270594 : rewrite_rel(visitor *v, sql_rel *rel)
    4309             : {
    4310     2270594 :         if (!is_outerjoin(rel->op) || list_empty(rel->exps) || rel_is_ref(rel))
    4311     2258427 :                 return rel;
    4312       12167 :         sql_rel *l = rel->l, *r = rel->r;
    4313             : 
    4314       12167 :         if ((l && is_project(l->op) && !l->l) ||
    4315       11583 :             (r && is_project(r->op) && !r->l))
    4316             :                 return rel;
    4317             : 
    4318       11534 :         sql_rel *or = rel;
    4319       23399 :         for (node *n = rel->exps->h; n; ) {
    4320       11925 :                 node *next = n->next;
    4321       11925 :                 sql_exp *e = n->data;
    4322             : 
    4323       11925 :                 if (exp_has_rel(e) /*&& exp_has_freevar(v->sql, e)*/) {
    4324          60 :                         list *exps = or->exps;
    4325          60 :                         or->exps = NULL;
    4326          60 :                         sql_rel *ir = exp_rel_get_rel(v->sql->sa, e);
    4327             : 
    4328          60 :                         rel = rewrite_outer2inner_union(v, rel);
    4329          60 :                         if (!rel || or == rel)
    4330             :                                 return rel;
    4331             :                         /* change referenced project into join with outer(ir) */
    4332             :                         /*sql_rel *nr = rel->l;*/
    4333          59 :                         assert(is_munion(rel->op));
    4334          59 :                         sql_rel *nr = ((list*)rel->l)->h->data;
    4335          59 :                         assert(is_project(nr->op));
    4336          59 :                         if (!rel_is_ref(nr))
    4337           0 :                                 nr = nr->l;
    4338          59 :                         sql_rel *s = rel_crossproduct(v->sql->sa, nr->l, ir, op_semi);
    4339          59 :                         s->exps = exps;
    4340          59 :                         set_dependent(s);
    4341          59 :                         nr->l = s;
    4342          59 :                         e = exp_rel_update_exp(v->sql, e, false);
    4343          59 :                         exp_reset_props(nr, e, true);
    4344          59 :                         v->changes++;
    4345          59 :                         break;
    4346             :                 }
    4347             :                 n = next;
    4348             :         }
    4349             :         return rel;
    4350             : }
    4351             : 
    4352             : typedef struct sql_args {
    4353             :         list *args;
    4354             :         list *exps;
    4355             : } sql_args;
    4356             : 
    4357             : static int
    4358         203 : var_name_cmp(sql_arg *v, char *name)
    4359             : {
    4360         203 :         return strcmp(v->name, name);
    4361             : }
    4362             : 
    4363             : static sql_exp *
    4364        3593 : exp_inline_arg(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    4365             : {
    4366        3593 :         (void)rel;
    4367        3593 :         (void)depth;
    4368        3593 :         sql_args *args = v->data;
    4369        3593 :         if (e->type == e_atom && e->r) {
    4370         125 :                 sql_arg *a = e->r;
    4371         125 :                 int level = is_freevar(e);
    4372         125 :                 node *n = list_find(args->args, a->name, (fcmp)&var_name_cmp);
    4373         125 :                 if (n) {
    4374         125 :                         sql_exp *val = list_fetch(args->exps, list_position(args->args, n->data));
    4375         125 :                         val = exp_copy(v->sql, val);
    4376         125 :                         exp_prop_alias(v->sql->sa, val, e);
    4377         125 :                         if (level)
    4378           0 :                                 set_freevar(val, level-1);
    4379         125 :                         return val;
    4380             :                 }
    4381             :         }
    4382             :         return e;
    4383             : }
    4384             : 
    4385             : static sql_rel *
    4386     1720420 : rel_inline_table_func(visitor *v, sql_rel *rel)
    4387             : {
    4388     1720420 :         if (!rel_is_ref(rel) && rel->op == op_table && !rel->l && rel->r) { /* TODO add input relation (rel->l) rewriting */
    4389        2997 :                 sql_exp *opf = rel->r;
    4390        2997 :                 if (opf->type == e_func) {
    4391        2997 :                         sql_subfunc *f = opf->f;
    4392             : 
    4393        2997 :                         if (f->func->vararg || f->func->varres)
    4394             :                                 return rel;
    4395             : 
    4396        1766 :                         if (f->func->lang == FUNC_LANG_SQL && f->func->type == F_UNION) {
    4397         245 :                                 sql_rel *r = rel_parse(v->sql, f->func->s, f->func->query, m_instantiate);
    4398             : 
    4399         245 :                                 if (r && is_ddl(r->op) && list_length(r->exps) == 1) {
    4400         218 :                                         sql_exp *psm = r->exps->h->data;
    4401         218 :                                         if (psm && psm->type == e_psm && psm->flag == PSM_RETURN) {
    4402         216 :                                                 sql_exp *ret = psm->l;
    4403         216 :                                                 if (ret && ret->type == e_psm && ret->flag == PSM_REL) {
    4404         216 :                                                         r = ret->l;
    4405         216 :                                                         list *exps = r->exps;
    4406         216 :                                                         r = rel_project(v->sql->sa, r, sa_list(v->sql->sa));
    4407         693 :                                                         for(node *n = rel->exps->h, *m = exps->h; n && m; n = n->next, m = m->next) {
    4408         477 :                                                                 sql_exp *e = m->data;
    4409         477 :                                                                 sql_exp *pe = n->data;
    4410             : 
    4411         477 :                                                                 if (!e->alias.label)
    4412           6 :                                                                         e = exp_label(v->sql->sa, e, ++v->sql->label);
    4413         477 :                                                                 e = exp_ref(v->sql, e);
    4414         477 :                                                                 exp_setalias(e, pe->alias.label, exp_relname(pe), exp_name(pe));
    4415         477 :                                                                 if (is_freevar(pe))
    4416           0 :                                                                         set_freevar(e, is_freevar(pe)-1);
    4417         477 :                                                                 append(r->exps, e);
    4418             :                                                         }
    4419         216 :                                                         sql_args a;
    4420         216 :                                                         if (f->func->ops) {
    4421         216 :                                                                 a.args = f->func->ops;
    4422         216 :                                                                 a.exps = opf->l;
    4423         216 :                                                                 v->data = &a;
    4424         216 :                                                                 r = rel_exp_visitor_topdown(v, r, &exp_inline_arg, true);
    4425         216 :                                                                 v->data = NULL;
    4426             :                                                         }
    4427         216 :                                                         r = rel_unnest(v->sql, r);
    4428         216 :                                                         return r;
    4429             :                                                 }
    4430             :                                         }
    4431             :                                 }
    4432             :                         }
    4433             :                 }
    4434             :         }
    4435             :         return rel;
    4436             : }
    4437             : 
    4438             : /* add an dummy true projection column */
    4439             : static sql_rel *
    4440     2270604 : rel_unnest_simplify(visitor *v, sql_rel *rel)
    4441             : {
    4442             :         /* at rel_select.c explicit cross-products generate empty selects, if these are not used, they can be removed at rewrite_simplify */
    4443     2270604 :         if (rel && v->sql->emode != m_deps)
    4444     1720418 :                 rel = rel_inline_table_func(v, rel);
    4445     2270603 :         if (rel)
    4446     2270603 :                 rel = rewrite_basetable(v->sql, rel);        /* add proper exps lists */
    4447     2270609 :         if (rel)
    4448     2270609 :                 rel = rewrite_empty_project(v, rel); /* remove empty project/groupby */
    4449     2270602 :         if (rel)
    4450     2270602 :                 rel = rewrite_simplify(v, 0, false, rel);
    4451     2270601 :         if (rel)
    4452     2270601 :                 rel = rewrite_split_select_exps(v, rel); /* has to run before rewrite_complex */
    4453     2270601 :         if (rel)
    4454     2270601 :                 rel = rewrite_swap_fullouter(v, rel);
    4455     2270602 :         if (rel)
    4456     2270602 :                 rel = rewrite_aggregates(v, rel);
    4457     2270597 :         if (rel)
    4458     2270597 :                 rel = rewrite_values(v, rel);
    4459     2270596 :         if (rel)
    4460     2270596 :                 rel = rewrite_rel(v, rel);
    4461     2270591 :         return rel;
    4462             : }
    4463             : 
    4464             : static sql_rel *
    4465     2943754 : rel_unnest_projects(visitor *v, sql_rel *rel)
    4466             : {
    4467     2943754 :         if (rel)
    4468     2943754 :                 rel = rewrite_remove_xp(v, rel);        /* remove crossproducts with project [ atom ] */
    4469     2943753 :         if (rel)
    4470     2943753 :                 rel = rewrite_groupings(v, rel);        /* transform group combinations into union of group relations */
    4471     2943756 :         return rel;
    4472             : }
    4473             : 
    4474             : static sql_rel *
    4475     2322512 : rel_unnest_comparison_rewriters(visitor *v, sql_rel *rel)
    4476             : {
    4477     2322512 :         if (rel)
    4478     2322512 :                 rel = rewrite_join2semi(v, rel);        /* where possible convert anyequal functions into marks */
    4479     2322523 :         if (rel)
    4480     2322523 :                 rel = rewrite_compare_exp(v, rel);      /* only allow for e_cmp in selects and  handling */
    4481     2322523 :         if (rel)
    4482     2322523 :                 rel = rewrite_remove_xp_project(v, rel);        /* remove crossproducts with project ( project [ atom ] ) [ etc ] */
    4483     2322524 :         if (rel)
    4484     2322524 :                 rel = rewrite_simplify(v, 0, false, rel);               /* as expressions got merged before, lets try to simplify again */
    4485     2322524 :         return rel;
    4486             : }
    4487             : 
    4488             : static sql_exp *
    4489     9365043 : rel_simplify_exp_and_rank(visitor *v, sql_rel *rel, sql_exp *e, int depth)
    4490             : {
    4491     9365043 :         if (e)
    4492     9365043 :                 e = rewrite_simplify_exp(v, rel, e, depth);
    4493     9365099 :         if (e)
    4494     9365099 :                 e = rewrite_rank(v, rel, e, depth);
    4495     9365107 :         return e;
    4496             : }
    4497             : 
    4498             : static inline sql_rel *
    4499     3547993 : run_exp_rewriter(visitor *v, sql_rel *rel, exp_rewrite_fptr rewriter, bool direction, const char *name)
    4500             : {
    4501     3547993 :         (void)name;
    4502             :         /*
    4503             : #ifndef NDEBUG
    4504             :         int changes = v->changes;
    4505             :         lng clk = GDKusec();
    4506             :         rel = rel_exp_visitor_bottomup(v, rel, rewriter, direction);
    4507             :         printf("%s %d " LLFMT "\n", name, (v->changes - changes), (GDKusec() - clk));
    4508             :         return rel;
    4509             : #else
    4510             : */
    4511     3547993 :         return rel_exp_visitor_bottomup(v, rel, rewriter, direction);
    4512             : /*#endif*/
    4513             : }
    4514             : 
    4515             : static inline sql_rel *
    4516     3547980 : run_rel_rewriter(visitor *v, sql_rel *rel, rel_rewrite_fptr rewriter, const char *name)
    4517             : {
    4518     3547980 :         (void)name;
    4519             :         /*
    4520             : #ifndef NDEBUG
    4521             :         int changes = v->changes;
    4522             :         lng clk = GDKusec();
    4523             :         rel = rel_visitor_bottomup(v, rel, rewriter);
    4524             :         printf("%s %d " LLFMT "\n", name, (v->changes - changes), (GDKusec() - clk));
    4525             :         return rel;
    4526             : #else
    4527             : */
    4528     3547980 :         return rel_visitor_bottomup(v, rel, rewriter);
    4529             : /*#endif*/
    4530             : }
    4531             : 
    4532             : sql_rel *
    4533      709610 : rel_unnest(mvc *sql, sql_rel *rel)
    4534             : {
    4535      709610 :         visitor v = { .sql = sql };
    4536             : 
    4537      709610 :         rel = run_exp_rewriter(&v, rel, &rel_simplify_exp_and_rank, false, "simplify_exp_and_rank");
    4538      709600 :         rel = run_rel_rewriter(&v, rel, &rel_unnest_simplify, "unnest_simplify");
    4539      709595 :         rel = run_exp_rewriter(&v, rel, &rewrite_complex, true, "rewrite_complex");
    4540      709602 :         rel = run_exp_rewriter(&v, rel, &rewrite_ifthenelse, false, "rewrite_ifthenelse"); /* add isnull handling */
    4541      709603 :         rel = run_exp_rewriter(&v, rel, &rewrite_exp_rel, true, "rewrite_exp_rel");
    4542             : 
    4543      709596 :         rel = run_rel_rewriter(&v, rel, &rel_unnest_comparison_rewriters, "unnest_comparison_rewriters");
    4544      709601 :         rel = run_rel_rewriter(&v, rel, &_rel_unnest, "unnest");
    4545      709591 :         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)) */
    4546      709592 :         rel = run_rel_rewriter(&v, rel, &rel_unnest_projects, "unnest_projects");
    4547      709583 :         rel = run_exp_rewriter(&v, rel, &exp_reset_card_and_freevar_set_physical_type, false, "exp_reset_card_and_freevar_set_physical_type");
    4548      709600 :         rel = rel_visitor_topdown(&v, rel, &rel_set_type);
    4549      709592 :         return rel;
    4550             : }

Generated by: LCOV version 1.14