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

Generated by: LCOV version 1.14