LCOV - code coverage report
Current view: top level - sql/server - rel_unnest.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2595 2905 89.3 %
Date: 2024-12-20 21:24:02 Functions: 89 90 98.9 %

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

Generated by: LCOV version 1.14