LCOV - code coverage report
Current view: top level - sql/server - rel_unnest.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2578 2849 90.5 %
Date: 2024-04-26 00:35:57 Functions: 89 90 98.9 %

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

Generated by: LCOV version 1.14