LCOV - code coverage report
Current view: top level - sql/server - rel_unnest.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2456 2706 90.8 %
Date: 2024-04-25 20:03:45 Functions: 85 86 98.8 %

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

Generated by: LCOV version 1.14