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

Generated by: LCOV version 1.14