LCOV - code coverage report
Current view: top level - sql/server - rel_unnest.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2608 2917 89.4 %
Date: 2025-03-24 23:16:36 Functions: 89 90 98.9 %

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

Generated by: LCOV version 1.14