LCOV - code coverage report
Current view: top level - sql/server - rel_optimize_sel.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2169 2336 92.9 %
Date: 2024-12-20 21:24:02 Functions: 107 107 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "rel_optimizer_private.h"
      15             : #include "rel_planner.h"
      16             : #include "rel_exp.h"
      17             : #include "rel_select.h"
      18             : #include "rel_rewriter.h"
      19             : 
      20             : /* Split_select optimizer splits case statements in select expressions. This is a step needed for cse */
      21             : static void select_split_exps(mvc *sql, list *exps, sql_rel *rel);
      22             : 
      23             : static sql_exp *
      24      218387 : select_split_exp(mvc *sql, sql_exp *e, sql_rel *rel)
      25             : {
      26      218387 :         switch(e->type) {
      27             :         case e_column:
      28             :                 return e;
      29        6914 :         case e_convert:
      30        6914 :                 e->l = select_split_exp(sql, e->l, rel);
      31        6914 :                 return e;
      32       24488 :         case e_aggr:
      33             :         case e_func:
      34       24488 :                 if (!is_analytic(e) && !exp_has_sideeffect(e)) {
      35       24484 :                         sql_subfunc *f = e->f;
      36       24484 :                         if (e->type == e_func && !f->func->s && is_caselike_func(f) /*is_ifthenelse_func(f)*/)
      37         283 :                                 return add_exp_too_project(sql, e, rel);
      38             :                 }
      39             :                 return e;
      40       74607 :         case e_cmp:
      41       74607 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
      42       18667 :                         select_split_exps(sql, e->l, rel);
      43       18667 :                         select_split_exps(sql, e->r, rel);
      44       55940 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
      45        3260 :                         e->l = select_split_exp(sql, e->l, rel);
      46        3260 :                         select_split_exps(sql, e->r, rel);
      47             :                 } else {
      48       52680 :                         e->l = select_split_exp(sql, e->l, rel);
      49       52680 :                         e->r = select_split_exp(sql, e->r, rel);
      50       52681 :                         if (e->f)
      51        3591 :                                 e->f = select_split_exp(sql, e->f, rel);
      52             :                 }
      53             :                 return e;
      54             :         case e_atom:
      55             :         case e_psm:
      56             :                 return e;
      57             :         }
      58             :         return e;
      59             : }
      60             : 
      61             : static void
      62       65271 : select_split_exps(mvc *sql, list *exps, sql_rel *rel)
      63             : {
      64       65271 :         node *n;
      65             : 
      66       65271 :         if (!exps)
      67             :                 return;
      68      164534 :         for(n=exps->h; n; n = n->next){
      69       99262 :                 sql_exp *e = n->data;
      70             : 
      71       99262 :                 e = select_split_exp(sql, e, rel);
      72       99263 :                 n->data = e;
      73             :         }
      74             : }
      75             : 
      76             : static sql_rel *
      77     1665722 : rel_split_select_(visitor *v, sql_rel *rel)
      78             : {
      79     1665722 :         if (!rel || !is_select(rel->op) || list_empty(rel->exps) || !rel->l || mvc_highwater(v->sql))
      80     1443116 :                 return rel;
      81             : 
      82      222605 :         bool funcs = false;
      83             : 
      84             :         /* are there functions */
      85      477090 :         for (node *n = rel->exps->h; n && !funcs; n = n->next)
      86      254485 :                 funcs = exp_has_func(n->data);
      87             : 
      88             :         /* introduce extra project */
      89      222605 :         if (funcs) {
      90       24678 :                 sql_rel *nrel = rel_project(v->sql->sa, rel->l,
      91       24677 :                         rel_projections(v->sql, rel->l, NULL, 1, 1));
      92       24678 :                 if (!nrel || !nrel->exps)
      93             :                         return NULL;
      94       24678 :                 rel->l = nrel;
      95             :                 /* recursively split all functions and add those to the projection list */
      96       24678 :                 select_split_exps(v->sql, rel->exps, nrel);
      97       24678 :                 return rel;
      98             :         }
      99             :         return rel;
     100             : }
     101             : 
     102             : static sql_rel *
     103       56876 : rel_split_select(visitor *v, global_props *gp, sql_rel *rel)
     104             : {
     105       56876 :         (void) gp;
     106       56876 :         return rel_visitor_bottomup(v, rel, &rel_split_select_);
     107             : }
     108             : 
     109             : run_optimizer
     110      631194 : bind_split_select(visitor *v, global_props *gp)
     111             : {
     112      631194 :         int flag = v->sql->sql_optimizer;
     113      554182 :         return gp->opt_cycle == 0 && gp->opt_level == 1 && (flag & split_select)
     114     1185368 :                    && gp->cnt[op_select] ? rel_split_select : NULL;
     115             : }
     116             : 
     117             : 
     118             : /*
     119             :  * Remove a redundant join
     120             :  *
     121             :  * join (L, Distinct Project(join(L,P) [ p.key == l.lkey]) [p.key]) [ p.key == l.lkey]
     122             :  * =>
     123             :  * join(L, P) [p.key==l.lkey]
     124             :  */
     125             : static sql_rel *
     126     1479572 : rel_remove_redundant_join_(visitor *v, sql_rel *rel)
     127             : {
     128     1479572 :         if ((is_join(rel->op) || is_semi(rel->op)) && !list_empty(rel->exps)) {
     129      220003 :                 sql_rel *l = rel->l, *r = rel->r, *b, *p = NULL, *j;
     130             : 
     131      220003 :                 if (is_basetable(l->op) && is_simple_project(r->op) && need_distinct(r)) {
     132           8 :                         b = l;
     133           8 :                         p = r;
     134           8 :                         j = p->l;
     135      219995 :                 } else if (is_basetable(r->op) && is_simple_project(l->op) && need_distinct(l)) {
     136        2333 :                         b = r;
     137        2333 :                         p = l;
     138        2333 :                         j = p->l;
     139             :                 }
     140      220003 :                 if (!p || !j || j->op != rel->op)
     141             :                         return rel;
     142             :                 /* j must have b->l (ie table) */
     143          12 :                 sql_rel *jl = j->l, *jr = j->r;
     144          12 :                 if ((is_basetable(jl->op) && jl->l == b->l) ||
     145           8 :                     (is_basetable(jr->op) && jr->l == b->l)) {
     146          11 :                         int left = 0;
     147          11 :                         if (is_basetable(jl->op) && jl->l == b->l)
     148          11 :                                 left = 1;
     149          11 :                         if (!list_empty(p->exps)) {
     150          19 :                                 for (node *n=p->exps->h; n; n = n->next) { /* all exps of 'p' must be bound to the opposite side */
     151          11 :                                         sql_exp *e = n->data;
     152             : 
     153          18 :                                         if (!rel_rebind_exp(v->sql, left ? jr : jl, e))
     154             :                                                 return rel;
     155             :                                 }
     156             :                         }
     157           8 :                         if (exp_match_list(j->exps, rel->exps)) {
     158           0 :                                 p->l = (left)?rel_dup(jr):rel_dup(jl);
     159           0 :                                 rel_destroy(j);
     160           0 :                                 set_nodistinct(p);
     161           0 :                                 v->changes++;
     162           0 :                                 return rel;
     163             :                         }
     164             :                 }
     165             :         }
     166             :         return rel;
     167             : }
     168             : 
     169             : static sql_rel *
     170       49117 : rel_remove_redundant_join(visitor *v, global_props *gp, sql_rel *rel)
     171             : {
     172       49117 :         (void) gp;
     173       49117 :         return rel_visitor_bottomup(v, rel, &rel_remove_redundant_join_); /* this optimizer has to run before rel_first_level_optimizations */
     174             : }
     175             : 
     176             : run_optimizer
     177      631193 : bind_remove_redundant_join(visitor *v, global_props *gp)
     178             : {
     179      631193 :         int flag = v->sql->sql_optimizer;
     180      554219 :         return gp->opt_cycle == 0 && gp->opt_level == 1 && (gp->cnt[op_left] || gp->cnt[op_right]
     181      535721 :                    || gp->cnt[op_full] || gp->cnt[op_join] || gp->cnt[op_semi] || gp->cnt[op_anti]) &&
     182      680073 :                    (flag & remove_redundant_join) ? rel_remove_redundant_join : NULL;
     183             : }
     184             : 
     185             : 
     186             : static list *
     187     1125500 : exp_merge_range(visitor *v, sql_rel *rel, list *exps)
     188             : {
     189     1125500 :         node *n, *m;
     190     2419389 :         for (n=exps->h; n; n = n->next) {
     191     1295785 :                 sql_exp *e = n->data;
     192     1295785 :                 sql_exp *le = e->l;
     193     1295785 :                 sql_exp *re = e->r;
     194             : 
     195             :                 /* handle the and's in the or lists */
     196     1295785 :                 if (e->type == e_cmp && e->flag == cmp_or && !is_anti(e)) {
     197       43163 :                         e->l = exp_merge_range(v, rel, e->l);
     198       43163 :                         e->r = exp_merge_range(v, rel, e->r);
     199             :                 /* only look for gt, gte, lte, lt */
     200     1252622 :                 } else if (n->next &&
     201      166086 :                     e->type == e_cmp && e->flag < cmp_equal && !e->f &&
     202        6823 :                     re->card == CARD_ATOM && !is_anti(e)) {
     203        1275 :                         for (m=n->next; m; m = m->next) {
     204         782 :                                 sql_exp *f = m->data;
     205         782 :                                 sql_exp *lf = f->l;
     206         782 :                                 sql_exp *rf = f->r;
     207         782 :                                 int c_le = is_numeric_upcast(le), c_lf = is_numeric_upcast(lf);
     208             : 
     209         782 :                                 if (f->type == e_cmp && f->flag < cmp_equal && !f->f &&
     210         651 :                                     rf->card == CARD_ATOM && !is_anti(f) &&
     211         325 :                                     exp_match_exp(c_le?le->l:le, c_lf?lf->l:lf)) {
     212         175 :                                         sql_exp *ne;
     213         175 :                                         int swap = 0, lt = 0, gt = 0;
     214         175 :                                         sql_subtype super;
     215             :                                         /* for now only   c1 <[=] x <[=] c2 */
     216             : 
     217         175 :                                         swap = lt = (e->flag == cmp_lt || e->flag == cmp_lte);
     218         175 :                                         gt = !lt;
     219             : 
     220         175 :                                         if (gt &&
     221         151 :                                            (f->flag == cmp_gt ||
     222             :                                             f->flag == cmp_gte))
     223          32 :                                                 continue;
     224          24 :                                         if (lt &&
     225          24 :                                            (f->flag == cmp_lt ||
     226             :                                             f->flag == cmp_lte))
     227           0 :                                                 continue;
     228             : 
     229         143 :                                         cmp_supertype(&super, exp_subtype(le), exp_subtype(lf));
     230         143 :                                         if (!(rf = exp_check_type(v->sql, &super, rel, rf, type_equal)) ||
     231         143 :                                                 !(le = exp_check_type(v->sql, &super, rel, le, type_equal)) ||
     232         143 :                                                 !(re = exp_check_type(v->sql, &super, rel, re, type_equal))) {
     233           0 :                                                         v->sql->session->status = 0;
     234           0 :                                                         v->sql->errstr[0] = 0;
     235           0 :                                                         continue;
     236             :                                                 }
     237         143 :                                         if (!swap)
     238         119 :                                                 ne = exp_compare2(v->sql->sa, le, re, rf, compare2range(e->flag, f->flag), 0);
     239             :                                         else
     240          24 :                                                 ne = exp_compare2(v->sql->sa, le, rf, re, compare2range(f->flag, e->flag), 0);
     241             : 
     242         143 :                                         list_remove_data(exps, NULL, e);
     243         143 :                                         list_remove_data(exps, NULL, f);
     244         143 :                                         list_append(exps, ne);
     245         143 :                                         v->changes++;
     246         143 :                                         return exp_merge_range(v, rel, exps);
     247             :                                 }
     248             :                         }
     249     1251986 :                 } else if (n->next &&
     250      165450 :                            e->type == e_cmp && e->flag < cmp_equal && !e->f &&
     251        6187 :                            re->card > CARD_ATOM && !is_anti(e)) {
     252       11218 :                         for (m=n->next; m; m = m->next) {
     253        6784 :                                 sql_exp *f = m->data;
     254        6784 :                                 sql_exp *lf = f->l;
     255        6784 :                                 sql_exp *rf = f->r;
     256             : 
     257        6784 :                                 if (f->type == e_cmp && f->flag < cmp_equal && !f->f  &&
     258        4979 :                                     rf->card > CARD_ATOM && !is_anti(f)) {
     259        4978 :                                         sql_exp *ne, *t;
     260        4978 :                                         int swap = 0, lt = 0, gt = 0;
     261        4978 :                                         comp_type ef = (comp_type) e->flag, ff = (comp_type) f->flag;
     262        4978 :                                         int c_re = is_numeric_upcast(re), c_rf = is_numeric_upcast(rf);
     263        4978 :                                         int c_le = is_numeric_upcast(le), c_lf = is_numeric_upcast(lf), c;
     264        4978 :                                         sql_subtype super;
     265             : 
     266             :                                         /* both swapped ? */
     267        4978 :                                         if (exp_match_exp(c_re?re->l:re, c_rf?rf->l:rf)) {
     268          19 :                                                 t = re;
     269          19 :                                                 re = le;
     270          19 :                                                 le = t;
     271          19 :                                                 c = c_re; c_re = c_le; c_le = c;
     272          19 :                                                 ef = swap_compare(ef);
     273          19 :                                                 t = rf;
     274          19 :                                                 rf = lf;
     275          19 :                                                 lf = t;
     276          19 :                                                 c = c_rf; c_rf = c_lf; c_lf = c;
     277          19 :                                                 ff = swap_compare(ff);
     278             :                                         }
     279             : 
     280             :                                         /* is left swapped ? */
     281        4978 :                                         if (exp_match_exp(c_re?re->l:re, c_lf?lf->l:lf)) {
     282         104 :                                                 t = re;
     283         104 :                                                 re = le;
     284         104 :                                                 le = t;
     285         104 :                                                 c = c_re; c_re = c_le; c_le = c;
     286         104 :                                                 ef = swap_compare(ef);
     287             :                                         }
     288             : 
     289             :                                         /* is right swapped ? */
     290        4978 :                                         if (exp_match_exp(c_le?le->l:le, c_rf?rf->l:rf)) {
     291         177 :                                                 t = rf;
     292         177 :                                                 rf = lf;
     293         177 :                                                 lf = t;
     294         177 :                                                 c = c_rf; c_rf = c_lf; c_lf = c;
     295         177 :                                                 ff = swap_compare(ff);
     296             :                                         }
     297             : 
     298        4978 :                                         if (!exp_match_exp(c_le?le->l:le, c_lf?lf->l:lf))
     299        3225 :                                                 continue;
     300             : 
     301             :                                         /* for now only   c1 <[=] x <[=] c2 */
     302        1830 :                                         swap = lt = (ef == cmp_lt || ef == cmp_lte);
     303        1830 :                                         gt = !lt;
     304             : 
     305        1830 :                                         if (gt && (ff == cmp_gt || ff == cmp_gte))
     306          73 :                                                 continue;
     307        1757 :                                         if (lt && (ff == cmp_lt || ff == cmp_lte))
     308           4 :                                                 continue;
     309             : 
     310        1753 :                                         cmp_supertype(&super, exp_subtype(le), exp_subtype(lf));
     311        1753 :                                         if (!(rf = exp_check_type(v->sql, &super, rel, rf, type_equal)) ||
     312        1753 :                                                 !(le = exp_check_type(v->sql, &super, rel, le, type_equal)) ||
     313        1753 :                                                 !(re = exp_check_type(v->sql, &super, rel, re, type_equal))) {
     314           0 :                                                         v->sql->session->status = 0;
     315           0 :                                                         v->sql->errstr[0] = 0;
     316           0 :                                                         continue;
     317             :                                                 }
     318        1753 :                                         if (!swap)
     319        1653 :                                                 ne = exp_compare2(v->sql->sa, le, re, rf, compare2range(ef, ff), 0);
     320             :                                         else
     321         100 :                                                 ne = exp_compare2(v->sql->sa, le, rf, re, compare2range(ff, ef), 0);
     322             : 
     323        1753 :                                         list_remove_data(exps, NULL, e);
     324        1753 :                                         list_remove_data(exps, NULL, f);
     325        1753 :                                         list_append(exps, ne);
     326        1753 :                                         v->changes++;
     327        1753 :                                         return exp_merge_range(v, rel, exps);
     328             :                                 }
     329             :                         }
     330             :                 }
     331             :         }
     332             :         return exps;
     333             : }
     334             : 
     335             : static int
     336       39581 : exps_cse( mvc *sql, list *oexps, list *l, list *r )
     337             : {
     338       39581 :         list *nexps;
     339       39581 :         node *n, *m;
     340       39581 :         char *lu, *ru;
     341       39581 :         int lc = 0, rc = 0, match = 0, res = 0;
     342             : 
     343       39581 :         if (list_length(l) == 0 || list_length(r) == 0)
     344           0 :                 return 0;
     345             : 
     346             :         /* first recursive exps_cse */
     347       39581 :         nexps = new_exp_list(sql->sa);
     348       82960 :         for (n = l->h; n; n = n->next) {
     349       43379 :                 sql_exp *e = n->data;
     350             : 
     351       43379 :                 if (e->type == e_cmp && e->flag == cmp_or && !is_anti(e)) {
     352       15107 :                         res = exps_cse(sql, nexps, e->l, e->r);
     353             :                 } else {
     354       28272 :                         append(nexps, e);
     355             :                 }
     356             :         }
     357       39581 :         l = nexps;
     358             : 
     359       39581 :         nexps = new_exp_list(sql->sa);
     360       86145 :         for (n = r->h; n; n = n->next) {
     361       46564 :                 sql_exp *e = n->data;
     362             : 
     363       46564 :                 if (e->type == e_cmp && e->flag == cmp_or && !is_anti(e)) {
     364        2142 :                         res = exps_cse(sql, nexps, e->l, e->r);
     365             :                 } else {
     366       44422 :                         append(nexps, e);
     367             :                 }
     368             :         }
     369       39581 :         r = nexps;
     370             : 
     371             :         /* simplify  true or .. and .. or true */
     372       39581 :         if (list_length(l) == list_length(r) && list_length(l) == 1) {
     373       35051 :                 sql_exp *le = l->h->data, *re = r->h->data;
     374             : 
     375       35051 :                 if (exp_is_true(le)) {
     376          14 :                         append(oexps, le);
     377          14 :                         return 1;
     378             :                 }
     379       35037 :                 if (exp_is_true(re)) {
     380           5 :                         append(oexps, re);
     381           5 :                         return 1;
     382             :                 }
     383             :         }
     384             : 
     385       39562 :         lu = SA_ZNEW_ARRAY(sql->ta, char, list_length(l));
     386       39562 :         ru = SA_ZNEW_ARRAY(sql->ta, char, list_length(r));
     387       82939 :         for (n = l->h, lc = 0; n; n = n->next, lc++) {
     388       43377 :                 sql_exp *le = n->data;
     389             : 
     390       95733 :                 for ( m = r->h, rc = 0; m; m = m->next, rc++) {
     391       52356 :                         sql_exp *re = m->data;
     392             : 
     393       52356 :                         if (!ru[rc] && exp_match_exp(le,re)) {
     394          68 :                                 lu[lc] = 1;
     395          68 :                                 ru[rc] = 1;
     396          68 :                                 match = 1;
     397             :                         }
     398             :                 }
     399             :         }
     400       39562 :         if (match) {
     401          49 :                 list *nl = new_exp_list(sql->sa);
     402          49 :                 list *nr = new_exp_list(sql->sa);
     403             : 
     404         162 :                 for (n = l->h, lc = 0; n; n = n->next, lc++)
     405         113 :                         if (!lu[lc])
     406          49 :                                 append(nl, n->data);
     407         176 :                 for (n = r->h, rc = 0; n; n = n->next, rc++)
     408         127 :                         if (!ru[rc])
     409          59 :                                 append(nr, n->data);
     410             : 
     411          49 :                 if (list_length(nl) && list_length(nr))
     412          23 :                         append(oexps, exp_or(sql->sa, nl, nr, 0));
     413             : 
     414         162 :                 for (n = l->h, lc = 0; n; n = n->next, lc++) {
     415         113 :                         if (lu[lc])
     416          64 :                                 append(oexps, n->data);
     417             :                 }
     418             :                 res = 1;
     419             :         } else {
     420       39513 :                 append(oexps, exp_or(sql->sa, list_dup(l, (fdup)NULL),
     421             :                                      list_dup(r, (fdup)NULL), 0));
     422             :         }
     423             :         return res;
     424             : }
     425             : 
     426             : static inline int
     427       23320 : exp_col_key(sql_exp *e)
     428             : {
     429       17579 :         return e->nid ? e->nid : e->alias.label;
     430             : }
     431             : 
     432             : static inline int
     433        5765 : exp_cmp_eq_unique_id(sql_exp *e)
     434             : {
     435        5765 :         return exp_col_key(e->l);
     436             : }
     437             : 
     438             : static inline int
     439        1768 : exp_multi_col_key(list *l)
     440             : {
     441        1768 :         int k = exp_col_key(l->h->data);
     442        5765 :         for (node *n = l->h->next; n; n = n->next) {
     443        3997 :                 k <<= 4;
     444        7994 :                 k ^= exp_col_key(n->data);
     445             :         }
     446        1768 :         return k;
     447             : }
     448             : 
     449             : typedef struct exp_eq_col_values {
     450             :         /* we need ->first in order to remove it from the list of cmp_eq exps
     451             :          * in case that we find another occurrence (with a different value)
     452             :          */
     453             :         sql_exp* first;
     454             :         sql_exp* col; /* column */
     455             :         list *vs;     /* list of values */
     456             : } eq_cv;
     457             : 
     458             : typedef struct exp_eq_multi_col_values {
     459             :         /* we need ->first in order to remove it from the list of multi col
     460             :          * cmp_eq exps in case that we find another occurrence (with different values)
     461             :          */
     462             :         list *first;
     463             :         list *cols;  /* list of col exps */
     464             :         list *lvs;   /* list of lists of values */
     465             : } eq_mcv;
     466             : 
     467             : static bool
     468        4276 : detect_col_cmp_eqs(mvc *sql, list *eqs, sql_hash *eqh)
     469             : {
     470        4276 :         bool col_multivalue_cmp_eq = false;
     471       16066 :         for (node *n = eqs->h; n; n = n->next ) {
     472       11790 :                 sql_exp *e = n->data;
     473       11790 :                 sql_exp *le = e->l, *re = e->r;
     474             : 
     475             :                 /* find the le in the hash and append the re in the hash value (ea->list) */
     476       11790 :                 bool found = false;
     477             : 
     478       11790 :                 int key = eqh->key(le);
     479       11790 :                 sql_hash_e *he = eqh->buckets[key&(eqh->size-1)];
     480             : 
     481       14686 :                 for (;he && !found; he = he->chain) {
     482        2896 :                         eq_cv *cv = he->value;
     483        2896 :                         if (!exp_equal(le, cv->col)) {
     484        2896 :                                 cv->vs = append(cv->vs, re);
     485        2896 :                                 found = col_multivalue_cmp_eq = true;
     486             :                                 /* remove this and the previous (->first) occurrence (if exists) from eqs */
     487        2896 :                                 if (cv->first) {
     488        1793 :                                         list_remove_data(eqs, NULL, cv->first);
     489        1793 :                                         cv->first = NULL;
     490             :                                 }
     491        2896 :                                 list_remove_node(eqs, NULL, n);
     492             :                         }
     493             :                 }
     494             : 
     495       11790 :                 if (!found) {
     496        8894 :                         eq_cv *cv = SA_NEW(sql->sa, eq_cv);
     497        8894 :                         cv->first = e;
     498        8894 :                         cv->vs = sa_list(sql->sa);
     499        8894 :                         cv->vs = append(cv->vs, re);
     500        8894 :                         cv->col = le;
     501             : 
     502        8894 :                         hash_add(eqh, key, cv);
     503             :                 }
     504             :         }
     505        4276 :         return col_multivalue_cmp_eq;
     506             : }
     507             : 
     508             : static bool
     509         692 : detect_multicol_cmp_eqs(mvc *sql, list *mce_ands, sql_hash *meqh)
     510             : {
     511             :         /* we get as input a list of AND associated expressions (hence the entries are lists themselves)
     512             :          * we need to detect cmp_eq-only AND-associated expressions with the same columns so we can
     513             :          * group together their values
     514             :          * e.g. [[n = 1, m = 10], [m = 20, k = 100, l = 3000], [m = 20, n = 2]] has
     515             :          *      - (m,k,l) group with a single value (20, 100, 3000)
     516             :          *      - (n,k) group with two values (1, 10) and (2, 20)
     517             :          * at the end we return true only if we have at least a group of columns with more than a single value
     518             :          * e.g. in this example (n,k)
     519             :          */
     520         692 :         bool multi_multivalue_cmp_eq = false;
     521        2460 :         for (node *n = mce_ands->h; n; n = n->next) {
     522        1768 :                 list *l = n->data;
     523             : 
     524             :                 /* sort the list of the cmp_eq expressions based on the col exp
     525             :                  * NOTE: from now on we only work with the sorted list, sl */
     526        1768 :                 list *sl = list_sort(l, (fkeyvalue)&exp_cmp_eq_unique_id, NULL);
     527        1768 :                 list_append_before(mce_ands, n, sl);
     528        1768 :                 list_remove_node(mce_ands, NULL, n);
     529             : 
     530             :                 /* find the eq exp in the hash and append the values */
     531        1768 :                 bool found = false;
     532             : 
     533        1768 :                 int key = meqh->key(sl);
     534        1768 :                 sql_hash_e *he = meqh->buckets[key&(meqh->size-1)];
     535             : 
     536        2866 :                 for (;he && !found; he = he->chain) {
     537             :                         /* compare the values of the hash_entry with the cols under cmp_eq from the list */
     538        1098 :                         bool same_cols = true;
     539        1098 :                         eq_mcv *mcv = he->value;
     540        3479 :                         for (node *m = sl->h, *k = mcv->cols->h; m && k && same_cols; m = m->next, k = k->next) {
     541        2381 :                                 sql_exp *col_exp = ((sql_exp*)m->data)->l;
     542        2381 :                                 if (exp_equal(col_exp, k->data))
     543         663 :                                         same_cols = false;
     544             :                         }
     545        1098 :                         if (same_cols) {
     546             :                                 /* we found the same multi cmp_eq exp in mce_ands list multiple times! */
     547         435 :                                 found = multi_multivalue_cmp_eq = true;
     548             :                                 /* gather all the values of the list and add them to the hash entry */
     549         435 :                                 list *atms = sa_list(sql->sa);
     550        1783 :                                 for (node *m = sl->h; m; m = m->next)
     551        1348 :                                         atms = append(atms, ((sql_exp*)m->data)->r);
     552         435 :                                 mcv->lvs = append(mcv->lvs, atms);
     553             :                                 /* remove this and the previous occurrence (which means that's the first time
     554             :                                  * that we found the *same* multi cmp_eq exp)
     555             :                                  */
     556         435 :                                 if (mcv->first) {
     557          80 :                                         list_remove_data(mce_ands, NULL, mcv->first);
     558          80 :                                         mcv->first = NULL;
     559             :                                 }
     560         435 :                                 list_remove_data(mce_ands, NULL, sl);
     561             :                         }
     562             :                 }
     563             : 
     564        1768 :                 if (!found) {
     565        1333 :                         eq_mcv *mcv = SA_NEW(sql->sa, eq_mcv);
     566        1333 :                         mcv->first = sl;
     567        1333 :                         mcv->cols = sa_list(sql->sa);
     568        5750 :                         for (node *m = sl->h; m; m = m->next)
     569        4417 :                                 mcv->cols = append(mcv->cols, ((sql_exp*)m->data)->l);
     570             :                         /* for the list of values (atoms) create a list and append it to the lvs list */
     571        1333 :                         list *atms = sa_list(sql->sa);
     572        5750 :                         for (node *m = sl->h; m; m = m->next)
     573        4417 :                                 atms = append(atms, ((sql_exp*)m->data)->r);
     574        1333 :                         mcv->lvs = sa_list(sql->sa);
     575        1333 :                         mcv->lvs = append(mcv->lvs, atms);
     576             : 
     577        1333 :                         hash_add(meqh, key, mcv);
     578             :                 }
     579             :         }
     580         692 :         return multi_multivalue_cmp_eq;
     581             : }
     582             : 
     583             : static void
     584       65923 : exp_or_chain_groups(mvc *sql, list *exps, list **gen_ands, list **mce_ands, list **eqs, list **noneq)
     585             : {
     586             :         /* identify three different groups
     587             :          * 1. gen_ands: lists of generic expressions (their inner association is AND)
     588             :          * 2. mce_ands: lists of multi_colum cmp_eq ONLY expressions (same^^^)
     589             :          * 3. eqs: equality expressions
     590             :          * 4. neq: non equality col expressions
     591             :          *
     592             :          * return true if there is an exp with more than one cmp_eq
     593             :          */
     594       85316 :     bool eq_only = true;
     595      182137 :     for (node *n = exps->h; n && eq_only; n = n->next) {
     596       96821 :         sql_exp *e = n->data;
     597       96821 :         sql_exp *le = e->l, *re = e->r;
     598      193391 :         eq_only &= (e->type == e_cmp && e->flag == cmp_equal &&
     599       34408 :                     le->card != CARD_ATOM && is_column(le->type) &&
     600      130075 :                     re->card == CARD_ATOM && !is_semantics(e));
     601             :     }
     602             : 
     603       85316 :         if (list_length(exps) > 1) {
     604        5401 :                 if (eq_only)
     605        4520 :                         *mce_ands = append(*mce_ands, exps);
     606             :                 else
     607         881 :                         *gen_ands = append(*gen_ands, exps);
     608       79915 :         } else if (list_length(exps) == 1) {
     609       79915 :                 sql_exp *se = exps->h->data;
     610       79915 :                 sql_exp *le = se->l, *re = se->r;
     611             : 
     612       79915 :                 if (se->type == e_cmp && se->flag == cmp_or && !is_anti(se)) {
     613             :                         /* for a cmp_or expression go down the tree */
     614       19393 :                         exp_or_chain_groups(sql, (list*)le, gen_ands, mce_ands, eqs, noneq);
     615       19393 :                         exp_or_chain_groups(sql, (list*)re, gen_ands, mce_ands, eqs, noneq);
     616             : 
     617       60522 :                 } else if (eq_only) {
     618       15426 :                         *eqs = append(*eqs, se);
     619             :                 } else {
     620       45096 :                         *noneq = append(*noneq, se);
     621             :                 }
     622             :         }
     623       65923 : }
     624             : 
     625             : static list *
     626        1686 : generate_single_col_cmp_in(mvc *sql, sql_hash *eqh)
     627             : {
     628             :         /* from single col cmp_eq with multiple atoms in the hash generate
     629             :          * "e_col in (val0, val1, ...)" (see detect_col_cmp_eqs())
     630             :          */
     631        1686 :         list *ins = new_exp_list(sql->sa);
     632       55638 :         for (int i = 0; i < eqh->size; i++) {
     633       53952 :                 sql_hash_e *he = eqh->buckets[i];
     634             : 
     635       56592 :                 while (he) {
     636        2640 :                         eq_cv *cv = he->value;
     637             :                         /* NOTE: cmp_eq expressions with a single entry are still in eqs */
     638        2640 :                         if (list_length(cv->vs) > 1)
     639        1793 :                                 ins = append(ins, exp_in(sql->sa, cv->col, cv->vs, cmp_in));
     640        2640 :                         he = he->chain;
     641             :                 }
     642             :         }
     643        1686 :         return ins;
     644             : }
     645             : 
     646             : static list *
     647          80 : generate_multi_col_cmp_in(mvc *sql, sql_hash *meqh)
     648             : {
     649             :         /* from multivalue cmp_eq with multiple lists of atoms in the hash generate
     650             :          * "(col1, col2, ...) in [(val10, val20, ...), (val11, val21, ...), ... ]"
     651             :          * (see detect_multicol_cmp_eqs())
     652             :          */
     653          80 :         list *ins = new_exp_list(sql->sa);
     654        2640 :         for (int i = 0; i < meqh->size; i++) {
     655        2560 :                 sql_hash_e *he = meqh->buckets[i];
     656        2654 :                 while (he) {
     657          94 :                         eq_mcv *mcv = he->value;
     658             :                         /* NOTE: multivalue cmp_eq expressions with a single entry are still in mce_ands */
     659          94 :                         if (list_length(mcv->lvs) > 1) {
     660          80 :                                 sql_exp *mc = exp_label(sql->sa, exp_values(sql->sa, mcv->cols), ++sql->label);
     661         595 :                                 for (node *a = mcv->lvs->h; a; a = a->next)
     662         515 :                                         a->data = exp_values(sql->sa, a->data);
     663          80 :                                 ins = append(ins, exp_in(sql->sa, mc, mcv->lvs, cmp_in));
     664             :                         }
     665          94 :                         he = he->chain;
     666             :                 }
     667             :         }
     668          80 :         return ins;
     669             : }
     670             : 
     671             : static list *
     672      522199 : merge_ors(mvc *sql, list *exps, int *changes)
     673             : {
     674      522199 :         sql_hash *eqh = NULL, *meqh = NULL;
     675      522199 :         list *eqs = NULL, *neq = NULL, *gen_ands = NULL, *mce_ands = NULL, *ins = NULL, *mins = NULL;
     676     1123890 :         for (node *n = exps->h; n; n = n->next) {
     677      601691 :                 sql_exp *e = n->data;
     678             : 
     679      601691 :                 if (e->type == e_cmp && e->flag == cmp_or && !is_anti(e)) {
     680             :                         /* NOTE: gen_ands and mce_ands are both a list of lists since the AND association
     681             :                          *       between expressions is expressed with a list
     682             :                          *       e.g. [[e1, e2], [e3, e4, e5]] semantically translates
     683             :                          *         to [(e1 AND e2), (e3 AND  e4 AND e5)]
     684             :                          *       those (internal) AND list can be then used to
     685             :                          *       reconstructed an OR tree [[e1, e2], [e3, e4, e5]] =>
     686             :                          *       (([e1, e2] OR [e3, e4, e5]) OR <whatever-else> )
     687             :                          *       gen_ands includes general expressions associated with AND
     688             :                          *       mce_ands includes only cmp_eq expressions associated with AND
     689             :                          */
     690       23265 :                         gen_ands = new_exp_list(sql->sa);
     691       23265 :                         mce_ands = new_exp_list(sql->sa);
     692       23265 :                         eqs = new_exp_list(sql->sa);
     693       23265 :                         neq = new_exp_list(sql->sa);
     694             : 
     695             :                         /* walk the OR tree */
     696       23265 :                         exp_or_chain_groups(sql, e->l, &gen_ands, &mce_ands, &eqs, &neq);
     697       23265 :                         exp_or_chain_groups(sql, e->r, &gen_ands, &mce_ands, &eqs, &neq);
     698             : 
     699             :                         /* detect col cmp_eq exps with multiple values */
     700       23265 :                         bool col_multival = false;
     701       23265 :                         if (list_length(eqs) > 1) {
     702        4276 :                                 eqh = hash_new(sql->sa, 32, (fkeyvalue)&exp_col_key);
     703        4276 :                                 col_multival = detect_col_cmp_eqs(sql, eqs, eqh);
     704             :                         }
     705             : 
     706             :                         /* detect mutli-col cmp_eq exps with multiple (lists of) values */
     707       23265 :                         bool multicol_multival = false;
     708       23265 :                         if (list_length(mce_ands) > 1) {
     709         692 :                                 meqh = hash_new(sql->sa, 32, (fkeyvalue)&exp_multi_col_key);
     710         692 :                                 multicol_multival = detect_multicol_cmp_eqs(sql, mce_ands, meqh);
     711             :                         }
     712             : 
     713       23265 :                         if (!col_multival && !multicol_multival)
     714       21508 :                                 continue;
     715             : 
     716        1757 :                         if (col_multival)
     717        1686 :                                 ins = generate_single_col_cmp_in(sql, eqh);
     718             : 
     719        1757 :                         if (multicol_multival)
     720          80 :                                 mins = generate_multi_col_cmp_in(sql, meqh);
     721             : 
     722             :                         /* create the new OR tree */
     723        1757 :                         sql_exp *new = (ins) ? ins->h->data : mins->h->data;
     724             : 
     725          71 :                         if (ins) {
     726        1793 :                                 for (node *i = ins->h->next; i; i = i->next) {
     727         107 :                                         list *l = new_exp_list(sql->sa);
     728         107 :                                         list *r = new_exp_list(sql->sa);
     729         107 :                                         l = append(l, new);
     730         107 :                                         r = append(r, (sql_exp*)i->data);
     731         107 :                                         new = exp_or(sql->sa, l, r, 0);
     732             : 
     733         107 :                                         (*changes)++;
     734             :                                 }
     735             :                         }
     736             : 
     737        1757 :                         if (list_length(eqs)) {
     738        1448 :                                 for (node *i = eqs->h; i; i = i->next) {
     739         872 :                                         list *l = new_exp_list(sql->sa);
     740         872 :                                         list *r = new_exp_list(sql->sa);
     741         872 :                                         l = append(l, new);
     742         872 :                                         r = append(r, (sql_exp*)i->data);
     743         872 :                                         new = exp_or(sql->sa, l, r, 0);
     744             :                                 }
     745             :                         }
     746             : 
     747        1757 :                         if (mins) {
     748         169 :                                 for (node *i = ((ins) ? mins->h : mins->h->next); i; i = i->next) {
     749           9 :                                         list *l = new_exp_list(sql->sa);
     750           9 :                                         list *r = new_exp_list(sql->sa);
     751           9 :                                         l = append(l, new);
     752           9 :                                         r = append(r, (sql_exp*)i->data);
     753           9 :                                         new = exp_or(sql->sa, l, r, 0);
     754             : 
     755           9 :                                         (*changes)++;
     756             :                                 }
     757             :                         }
     758             : 
     759        1757 :                         if (list_length(mce_ands)) {
     760         523 :                                 for (node *i = mce_ands->h; i; i = i->next) {
     761         273 :                                         list *l = new_exp_list(sql->sa);
     762         273 :                                         l = append(l, new);
     763         273 :                                         new = exp_or(sql->sa, l, i->data, 0);
     764             :                                 }
     765             :                         }
     766             : 
     767        1760 :                         for (node *a = gen_ands->h; a; a = a->next){
     768           3 :                                 list *l = new_exp_list(sql->sa);
     769           3 :                                 l = append(l, new);
     770           3 :                                 new = exp_or(sql->sa, l, a->data, 0);
     771             :                         }
     772             : 
     773        2075 :                         for (node *o = neq->h; o; o = o->next){
     774         318 :                                 list *l = new_exp_list(sql->sa);
     775         318 :                                 list *r = new_exp_list(sql->sa);
     776         318 :                                 l = append(l, new);
     777         318 :                                 r = append(r, (sql_exp*)o->data);
     778         318 :                                 new = exp_or(sql->sa, l, r, 0);
     779             :                         }
     780             : 
     781        1757 :                         list_remove_node(exps, NULL, n);
     782        1757 :                         exps = append(exps, new);
     783             :                 }
     784             :         }
     785      522199 :         return exps;
     786             : }
     787             : 
     788             : #define TRIVIAL_NOT_EQUAL_CMP(e) \
     789             :         ((e)->type == e_cmp && (e)->flag == cmp_notequal && !is_anti((e)) && !is_semantics((e)) && ((sql_exp*)(e)->l)->card != CARD_ATOM && ((sql_exp*)(e)->r)->card == CARD_ATOM)
     790             : 
     791             : static list *
     792      601343 : merge_notequal(mvc *sql, list *exps, int *changes)
     793             : {
     794      601343 :         list *inequality_groups = NULL, *nexps = NULL;
     795      601343 :         int needed = 0;
     796             : 
     797     1292527 :         for (node *n = exps->h; n; n = n->next) {
     798      691184 :                 sql_exp *e = n->data;
     799             : 
     800      691184 :                 if (TRIVIAL_NOT_EQUAL_CMP(e)) {
     801       82810 :                         bool appended = false;
     802             : 
     803       82810 :                         if (inequality_groups) {
     804        9095 :                                 for (node *m = inequality_groups->h; m && !appended; m = m->next) {
     805        5212 :                                         list *next = m->data;
     806        5212 :                                         sql_exp *first = (sql_exp*) next->h->data;
     807             : 
     808        5212 :                                         if (exp_match(first->l, e->l)) {
     809        1166 :                                                 list_append(next, e);
     810        1166 :                                                 appended = true;
     811             :                                         }
     812             :                                 }
     813             :                         }
     814        3883 :                         if (!appended) {
     815       81644 :                                 if (!inequality_groups)
     816       78927 :                                         inequality_groups = new_exp_list(sql->sa);
     817       81644 :                                 list_append(inequality_groups, list_append(new_exp_list(sql->sa), e));
     818             :                         }
     819             :                 }
     820             :         }
     821             : 
     822      601343 :         if (inequality_groups) { /* if one list of inequalities has more than one entry, then the re-write is needed */
     823      160571 :                 for (node *n = inequality_groups->h; n; n = n->next) {
     824       81644 :                         list *next = n->data;
     825             : 
     826       81644 :                         if (list_length(next) > 1)
     827        1081 :                                 needed = 1;
     828             :                 }
     829             :         }
     830             : 
     831       78927 :         if (needed) {
     832         999 :                 nexps = new_exp_list(sql->sa);
     833        2614 :                 for (node *n = inequality_groups->h; n; n = n->next) {
     834        1615 :                         list *next = n->data;
     835        1615 :                         sql_exp *first = (sql_exp*) next->h->data;
     836             : 
     837        1615 :                         if (list_length(next) > 1) {
     838        1081 :                                 list *notin = new_exp_list(sql->sa);
     839             : 
     840        3328 :                                 for (node *m = next->h; m; m = m->next) {
     841        2247 :                                         sql_exp *e = m->data;
     842        2247 :                                         list_append(notin, e->r);
     843             :                                 }
     844        1081 :                                 list_append(nexps, exp_in(sql->sa, first->l, notin, cmp_notin));
     845             :                         } else {
     846         534 :                                 list_append(nexps, first);
     847             :                         }
     848             :                 }
     849             : 
     850        4138 :                 for (node *n = exps->h; n; n = n->next) {
     851        3139 :                         sql_exp *e = n->data;
     852             : 
     853        3139 :                         if (!TRIVIAL_NOT_EQUAL_CMP(e))
     854         358 :                                 list_append(nexps, e);
     855             :                 }
     856         999 :                 (*changes)++;
     857             :         } else {
     858             :                 nexps = exps;
     859             :         }
     860             : 
     861     1291361 :         for (node *n = nexps->h; n ; n = n->next) {
     862      690018 :                 sql_exp *e = n->data;
     863             : 
     864      690018 :                 if (e->type == e_cmp && e->flag == cmp_or) {
     865       39572 :                         e->l = merge_notequal(sql, e->l, changes);
     866       39572 :                         e->r = merge_notequal(sql, e->r, changes);
     867             :                 }
     868             :         }
     869             : 
     870      601343 :         return nexps;
     871             : }
     872             : 
     873             : int
     874      175249 : is_numeric_upcast(sql_exp *e)
     875             : {
     876      175249 :         if (is_convert(e->type)) {
     877        4698 :                 sql_subtype *f = exp_fromtype(e);
     878        4698 :                 sql_subtype *t = exp_totype(e);
     879             : 
     880        4698 :                 if (f->type->eclass == t->type->eclass && EC_COMPUTE(f->type->eclass)) {
     881        1638 :                         if (f->type->localtype < t->type->localtype)
     882        1618 :                                 return 1;
     883             :                 }
     884             :         }
     885             :         return 0;
     886             : }
     887             : 
     888             : /* optimize (a = b) or (a is null and b is null) -> a = b with null semantics */
     889             : static sql_exp *
     890       44706 : try_rewrite_equal_or_is_null(mvc *sql, sql_rel *rel, sql_exp *or, list *l1, list *l2)
     891             : {
     892       44706 :         if (list_length(l1) == 1) {
     893       41344 :                 bool valid = true, first_is_null_found = false, second_is_null_found = false;
     894       41344 :                 sql_exp *cmp = l1->h->data;
     895       41344 :                 sql_exp *first = cmp->l, *second = cmp->r;
     896             : 
     897       41344 :                 if (is_compare(cmp->type) && !is_anti(cmp) && !cmp->f && cmp->flag == cmp_equal) {
     898        7200 :                         int fupcast = is_numeric_upcast(first), supcast = is_numeric_upcast(second);
     899       14424 :                         for(node *n = l2->h ; n && valid; n = n->next) {
     900        7224 :                                 sql_exp *e = n->data, *l = e->l, *r = e->r;
     901             : 
     902        7224 :                                 if (is_compare(e->type) && e->flag == cmp_equal && !e->f &&
     903        4190 :                                         !is_anti(e) && is_semantics(e)) {
     904        1379 :                                         int lupcast = is_numeric_upcast(l);
     905        1379 :                                         int rupcast = is_numeric_upcast(r);
     906        1379 :                                         sql_exp *rr = rupcast ? r->l : r;
     907             : 
     908        1379 :                                         if (rr->type == e_atom && rr->l && atom_null(rr->l)) {
     909        1379 :                                                 if (exp_match_exp(fupcast?first->l:first, lupcast?l->l:l))
     910             :                                                         first_is_null_found = true;
     911         121 :                                                 else if (exp_match_exp(supcast?second->l:second, lupcast?l->l:l))
     912             :                                                         second_is_null_found = true;
     913             :                                                 else
     914        5942 :                                                         valid = false;
     915             :                                         } else {
     916             :                                                 valid = false;
     917             :                                         }
     918             :                                 } else {
     919             :                                         valid = false;
     920             :                                 }
     921             :                         }
     922        7200 :                         if (valid && first_is_null_found && second_is_null_found) {
     923          21 :                                 sql_subtype super;
     924             : 
     925          21 :                                 cmp_supertype(&super, exp_subtype(first), exp_subtype(second)); /* first and second must have the same type */
     926          21 :                                 if (!(first = exp_check_type(sql, &super, rel, first, type_equal)) ||
     927          21 :                                         !(second = exp_check_type(sql, &super, rel, second, type_equal))) {
     928           0 :                                                 sql->session->status = 0;
     929           0 :                                                 sql->errstr[0] = 0;
     930           0 :                                                 return or;
     931             :                                         }
     932          21 :                                 sql_exp *res = exp_compare(sql->sa, first, second, cmp->flag);
     933          21 :                                 set_semantics(res);
     934          21 :                                 if (exp_name(or))
     935           0 :                                         exp_prop_alias(sql->sa, res, or);
     936          21 :                                 return res;
     937             :                         }
     938             :                 }
     939             :         }
     940             :         return or;
     941             : }
     942             : 
     943             : static list *
     944     1037278 : merge_cmp_or_null(mvc *sql, sql_rel *rel, list *exps, int *changes)
     945             : {
     946     2231173 :         for (node *n = exps->h; n ; n = n->next) {
     947     1193895 :                 sql_exp *e = n->data;
     948             : 
     949     1193895 :                 if (is_compare(e->type) && e->flag == cmp_or && !is_anti(e)) {
     950       22353 :                         sql_exp *ne = try_rewrite_equal_or_is_null(sql, rel, e, e->l, e->r);
     951       22353 :                         if (ne != e) {
     952          19 :                                 (*changes)++;
     953          19 :                                 n->data = ne;
     954             :                         }
     955       22353 :                         ne = try_rewrite_equal_or_is_null(sql, rel, e, e->r, e->l);
     956       22353 :                         if (ne != e) {
     957           2 :                                 (*changes)++;
     958           2 :                                 n->data = ne;
     959             :                         }
     960             :                 }
     961             :         }
     962     1037278 :         return exps;
     963             : }
     964             : 
     965             : static list *
     966     1037278 : cleanup_equal_exps(mvc *sql, sql_rel *rel, list *exps, int *changes)
     967             : {
     968     1037278 :         if (list_length(exps) <= 1)
     969             :                 return exps;
     970      142380 :         if (is_join(rel->op)) {
     971      212811 :                 for(node *n = exps->h; n; n = n->next) {
     972      143111 :                         sql_exp *e = n->data;
     973      286053 :                         if (e->type == e_cmp && !e->f && e->flag <= cmp_notequal &&
     974      185277 :                                 !rel_find_exp(rel->l, e->l) && !rel_find_exp(rel->r, e->r) &&
     975       42161 :                                 !find_prop(e->p, PROP_HASHCOL) && !find_prop(e->p, PROP_JOINIDX)) {
     976       21000 :                                 exp_swap(e);
     977             :                         }
     978             :                 }
     979             :         }
     980      142380 :         bool needed = false;
     981      442435 :         for(node *n = exps->h; !needed && n; n = n->next) {
     982      593989 :                 for (node *m = n->next; !needed && m; m = m->next) {
     983      293934 :                         if (exp_match_exp_semantics(n->data, m->data, true))
     984          89 :                                 needed = true;
     985             :                 }
     986             :         }
     987      142380 :         if (needed) {
     988          89 :                 list *nexps = sa_list(sql->sa);
     989             : 
     990         293 :                 for(node *n = exps->h; n; n = n->next) {
     991         204 :                         bool done = false;
     992         629 :                         for (node *m = exps->h; m && !done; m = m->next) {
     993         425 :                                 if (n != m && exp_match_exp_semantics(n->data, m->data, false)) {
     994         179 :                                         sql_exp *e1 = n->data, *e2 = m->data;
     995         179 :                                         if ((is_any(e1) || is_semantics(e1)) || (!is_any(e2) && !is_semantics(e2))) {
     996         179 :                                                 append(nexps, e1);
     997         179 :                                                 if ((!is_any(e2) && !is_semantics(e2)) && is_left(rel->op) && list_length(rel->attr) == 1) {
     998             :                                                         /* nil is false */
     999           0 :                                                         sql_exp *m = rel->attr->h->data;
    1000           0 :                                                         if (exp_is_atom(m))
    1001           0 :                                                                 set_no_nil(m);
    1002             :                                                 }
    1003             :                                         }
    1004             :                                         done = true;
    1005             :                                 }
    1006             :                         }
    1007         204 :                         if (!done)
    1008          25 :                                 append(nexps, n->data);
    1009             :                 }
    1010             :                 return nexps;
    1011             :         }
    1012             :         (void)changes;
    1013             :         return exps;
    1014             : }
    1015             : 
    1016             : static inline sql_rel *
    1017     1037277 : rel_select_cse(visitor *v, sql_rel *rel)
    1018             : {
    1019     1037277 :         if ((is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) && rel->exps) /* cleanup equal expressions */
    1020     1037278 :                 rel->exps = cleanup_equal_exps(v->sql, rel, rel->exps, &v->changes); /* (a = b) and (a += b) */
    1021             : 
    1022     1037276 :         if (is_select(rel->op) && rel->exps)
    1023      522199 :                 rel->exps = merge_ors(v->sql, rel->exps, &v->changes);
    1024             : 
    1025     1037276 :         if (is_select(rel->op) && rel->exps)
    1026      522199 :                 rel->exps = merge_notequal(v->sql, rel->exps, &v->changes); /* x <> 1 and x <> 2 => x not in (1, 2)*/
    1027             : 
    1028     1037276 :         if ((is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) && rel->exps)
    1029     1037278 :                 rel->exps = merge_cmp_or_null(v->sql, rel, rel->exps, &v->changes); /* (a = b) or (a is null and b is null) -> a = b with null semantics */
    1030             : 
    1031     1037275 :         if ((is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) && rel->exps) {
    1032     1037277 :                 node *n;
    1033     1037277 :                 list *nexps;
    1034     1037277 :                 int needed = 0;
    1035             : 
    1036     2224553 :                 for (n=rel->exps->h; n && !needed; n = n->next) {
    1037     1187276 :                         sql_exp *e = n->data;
    1038             : 
    1039     1187276 :                         if (e->type == e_cmp && e->flag == cmp_or && !is_anti(e))
    1040     1187276 :                                 needed = 1;
    1041             :                 }
    1042     1037277 :                 if (!needed)
    1043             :                         return rel;
    1044       21523 :                 nexps = new_exp_list(v->sql->sa);
    1045       50992 :                 for (n=rel->exps->h; n; n = n->next) {
    1046       29469 :                         sql_exp *e = n->data;
    1047             : 
    1048       29469 :                         if (e->type == e_cmp && e->flag == cmp_or && !is_anti(e)) {
    1049             :                                 /* split the common expressions */
    1050       22332 :                                 v->changes += exps_cse(v->sql, nexps, e->l, e->r);
    1051             :                         } else {
    1052        7137 :                                 append(nexps, e);
    1053             :                         }
    1054             :                 }
    1055       21523 :                 rel->exps = nexps;
    1056             :         }
    1057             :         return rel;
    1058             : }
    1059             : 
    1060             : static list *
    1061       13611 : exps_merge_select_rse( mvc *sql, list *l, list *r, bool *merged)
    1062             : {
    1063       13611 :         node *n, *m, *o;
    1064       13611 :         list *nexps = NULL, *lexps, *rexps;
    1065       13611 :         bool lmerged = true, rmerged = true;
    1066             : 
    1067       13611 :         lexps = new_exp_list(sql->sa);
    1068       28599 :         for (n = l->h; n; n = n->next) {
    1069       14988 :                 sql_exp *e = n->data;
    1070             : 
    1071       14988 :                 if (e->type == e_cmp && e->flag == cmp_or && !is_anti(e) && !is_semantics(e)) {
    1072        5242 :                         lmerged = false;
    1073        5242 :                         list *nexps = exps_merge_select_rse(sql, e->l, e->r, &lmerged);
    1074        5644 :                         for (o = nexps->h; o; o = o->next)
    1075         402 :                                 append(lexps, o->data);
    1076             :                 } else {
    1077        9746 :                         append(lexps, e);
    1078             :                 }
    1079             :         }
    1080       13611 :         if (lmerged)
    1081        8418 :                 lmerged = (list_length(lexps) == 1);
    1082       13611 :         rexps = new_exp_list(sql->sa);
    1083       29618 :         for (n = r->h; n; n = n->next) {
    1084       16007 :                 sql_exp *e = n->data;
    1085             : 
    1086       16007 :                 if (e->type == e_cmp && e->flag == cmp_or && !is_anti(e) && !is_semantics(e)) {
    1087         699 :                         rmerged = false;
    1088         699 :                         list *nexps = exps_merge_select_rse(sql, e->l, e->r, &rmerged);
    1089         724 :                         for (o = nexps->h; o; o = o->next)
    1090          25 :                                 append(rexps, o->data);
    1091             :                 } else {
    1092       15308 :                         append(rexps, e);
    1093             :                 }
    1094             :         }
    1095       13611 :         if (rmerged)
    1096       12933 :                 rmerged = (list_length(r) == 1);
    1097             : 
    1098       13611 :         nexps = new_exp_list(sql->sa);
    1099             : 
    1100             :         /* merge merged lists first ? */
    1101       23759 :         for (n = lexps->h; n; n = n->next) {
    1102       10148 :                 sql_exp *le = n->data, *re, *fnd = NULL;
    1103             : 
    1104       10148 :                 if (le->type != e_cmp || le->flag == cmp_or || is_anti(le) || is_semantics(le) || is_symmetric(le))
    1105         622 :                         continue;
    1106       19650 :                 for (m = rexps->h; !fnd && m; m = m->next) {
    1107       10124 :                         re = m->data;
    1108       10124 :                         if (exps_match_col_exps(le, re))
    1109        1548 :                                 fnd = re;
    1110             :                 }
    1111        9526 :                 if (fnd && (is_anti(fnd) || is_semantics(fnd)))
    1112          50 :                         continue;
    1113             :                 /* cases
    1114             :                  * 1) 2 values (cmp_equal)
    1115             :                  * 2) 1 value (cmp_equal), and cmp_in
    1116             :                  *      (also cmp_in, cmp_equal)
    1117             :                  * 3) 2 cmp_in
    1118             :                  * 4) ranges
    1119             :                  */
    1120        1498 :                 if (fnd) {
    1121        1498 :                         re = fnd;
    1122        1498 :                         fnd = NULL;
    1123        1498 :                         if (is_anti(le) || is_anti(re) || is_symmetric(re))
    1124           0 :                                 continue;
    1125        1935 :                         if (le->flag == cmp_equal && re->flag == cmp_equal) {
    1126         437 :                                 list *exps = new_exp_list(sql->sa);
    1127             : 
    1128         437 :                                 append(exps, le->r);
    1129         437 :                                 append(exps, re->r);
    1130         437 :                                 fnd = exp_in(sql->sa, le->l, exps, cmp_in);
    1131        1204 :                         } else if (le->flag == cmp_equal && re->flag == cmp_in){
    1132         143 :                                 list *exps = new_exp_list(sql->sa);
    1133             : 
    1134         143 :                                 append(exps, le->r);
    1135         143 :                                 list_merge(exps, re->r, NULL);
    1136         143 :                                 fnd = exp_in(sql->sa, le->l, exps, cmp_in);
    1137        1213 :                         } else if (le->flag == cmp_in && re->flag == cmp_equal){
    1138         295 :                                 list *exps = new_exp_list(sql->sa);
    1139             : 
    1140         295 :                                 append(exps, re->r);
    1141         295 :                                 list_merge(exps, le->r, NULL);
    1142         295 :                                 fnd = exp_in(sql->sa, le->l, exps, cmp_in);
    1143         738 :                         } else if (le->flag == cmp_in && re->flag == cmp_in){
    1144         115 :                                 list *exps = new_exp_list(sql->sa);
    1145             : 
    1146         115 :                                 list_merge(exps, le->r, NULL);
    1147         115 :                                 list_merge(exps, re->r, NULL);
    1148         115 :                                 fnd = exp_in(sql->sa, le->l, exps, cmp_in);
    1149         508 :                         } else if (le->f && re->f && /* merge ranges */
    1150          20 :                                    le->flag == re->flag && le->flag <= cmp_lt) {
    1151          20 :                                 sql_exp *mine = NULL, *maxe = NULL;
    1152             : 
    1153          20 :                                 if (!(mine = rel_binop_(sql, NULL, exp_copy(sql, le->r), exp_copy(sql, re->r), "sys", "sql_min", card_value, true))) {
    1154           0 :                                         sql->session->status = 0;
    1155           0 :                                         sql->errstr[0] = '\0';
    1156           0 :                                         continue;
    1157             :                                 }
    1158          20 :                                 if (!(maxe = rel_binop_(sql, NULL, exp_copy(sql, le->f), exp_copy(sql, re->f), "sys", "sql_max", card_value, true))) {
    1159           0 :                                         sql->session->status = 0;
    1160           0 :                                         sql->errstr[0] = '\0';
    1161           0 :                                         continue;
    1162             :                                 }
    1163          20 :                                 fnd = exp_compare2(sql->sa, exp_copy(sql, le->l), mine, maxe, le->flag, 0);
    1164          20 :                                 lmerged = false;
    1165             :                         }
    1166        1010 :                         if (fnd) {
    1167        1010 :                                 append(nexps, fnd);
    1168        1864 :                                 *merged = (fnd && lmerged && rmerged);
    1169             :                         }
    1170             :                 }
    1171             :         }
    1172       13611 :         return nexps;
    1173             : }
    1174             : 
    1175             : /* merge related sub expressions
    1176             :  *
    1177             :  * ie   (x = a and y > 1 and y < 5) or
    1178             :  *      (x = c and y > 1 and y < 10) or
    1179             :  *      (x = e and y > 1 and y < 20)
    1180             :  * ->
    1181             :  *     ((x = a and y > 1 and y < 5) or
    1182             :  *      (x = c and y > 1 and y < 10) or
    1183             :  *      (x = e and y > 1 and y < 20)) and
    1184             :  *       x in (a,c,e) and
    1185             :  *       y > 1 and y < 20
    1186             :  *
    1187             :  * for single expression or's we can do better
    1188             :  *              x in (a, b, c) or x in (d, e, f)
    1189             :  *              ->
    1190             :  *              x in (a, b, c, d, e, f)
    1191             :  * */
    1192             : static inline sql_rel *
    1193      398265 : rel_merge_select_rse(visitor *v, sql_rel *rel)
    1194             : {
    1195             :         /* only execute once per select */
    1196      398265 :         if ((is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) && rel->exps && !is_rel_merge_select_rse_used(rel->used)) {
    1197      142620 :                 node *n, *o;
    1198      142620 :                 list *nexps = new_exp_list(v->sql->sa);
    1199             : 
    1200      304980 :                 for (n=rel->exps->h; n; n = n->next) {
    1201      162361 :                         sql_exp *e = n->data;
    1202             : 
    1203      170031 :                         if (e->type == e_cmp && e->flag == cmp_or && !is_anti(e) && !is_semantics(e)) {
    1204             :                                 /* possibly merge related expressions */
    1205        7670 :                                 bool merged = false;
    1206             : 
    1207        7670 :                                 list *ps = exps_merge_select_rse(v->sql, e->l, e->r, &merged);
    1208        8253 :                                 for (o = ps->h; o; o = o->next)
    1209         583 :                                         append(nexps, o->data);
    1210        7670 :                                 if (merged)
    1211          87 :                                         v->changes++;
    1212             :                                 else
    1213        7583 :                                         append(nexps, e);
    1214             :                         } else {
    1215      154691 :                                 append(nexps, e);
    1216             :                         }
    1217             :                 }
    1218      142619 :                 rel->exps = nexps;
    1219      142619 :                 rel->used |= rel_merge_select_rse_used;
    1220             :         }
    1221      398264 :         return rel;
    1222             : }
    1223             : 
    1224             : /* pack optimizers into a single function call to avoid iterations in the AST */
    1225             : static sql_rel *
    1226     3667407 : rel_optimize_select_and_joins_bottomup_(visitor *v, sql_rel *rel)
    1227             : {
    1228     3667407 :         if (!rel || (!is_join(rel->op) && !is_semi(rel->op) && !is_select(rel->op)) || list_empty(rel->exps))
    1229     2630130 :                 return rel;
    1230     1037278 :         uint8_t cycle = *(uint8_t*) v->data;
    1231             : 
    1232     1037278 :         rel->exps = exp_merge_range(v, rel, rel->exps);
    1233     1037278 :         rel = rel_select_cse(v, rel);
    1234     1037277 :         if (cycle == 1)
    1235      398266 :                 rel = rel_merge_select_rse(v, rel);
    1236     1037276 :         rel = rewrite_simplify(v, cycle, v->value_based_opt, rel);
    1237     1037276 :         return rel;
    1238             : }
    1239             : 
    1240             : static sql_rel *
    1241      129212 : rel_optimize_select_and_joins_bottomup(visitor *v, global_props *gp, sql_rel *rel)
    1242             : {
    1243      129212 :         v->data = &gp->opt_cycle;
    1244      129212 :         rel = rel_visitor_bottomup(v, rel, &rel_optimize_select_and_joins_bottomup_);
    1245      129213 :         v->data = gp;
    1246      129213 :         return rel;
    1247             : }
    1248             : 
    1249             : run_optimizer
    1250      631096 : bind_optimize_select_and_joins_bottomup(visitor *v, global_props *gp)
    1251             : {
    1252      631096 :         int flag = v->sql->sql_optimizer;
    1253      630888 :         return gp->opt_level == 1 && (gp->cnt[op_join] || gp->cnt[op_left] || gp->cnt[op_right] ||
    1254      545226 :                    gp->cnt[op_full] || gp->cnt[op_semi] || gp->cnt[op_anti] ||
    1255     1261984 :                    gp->cnt[op_select]) && (flag & optimize_select_and_joins_bottomup) ? rel_optimize_select_and_joins_bottomup : NULL;
    1256             : }
    1257             : 
    1258             : 
    1259             : static inline sql_rel *
    1260     3464030 : rel_push_join_exps_down(visitor *v, sql_rel *rel)
    1261             : {
    1262             :         /* push select exps part of join expressions down */
    1263             :         /* TODO CHECK WHY not semi enabled */
    1264     3464030 :         if ((is_innerjoin(rel->op) || is_left(rel->op) || is_right(rel->op) /*|| is_semi(rel->op)*/) && !list_empty(rel->exps)) {
    1265      486954 :                 int left = is_innerjoin(rel->op) || is_right(rel->op) || rel->op == op_semi;
    1266      486954 :                 int right = is_innerjoin(rel->op) || is_left(rel->op) || is_semi(rel->op);
    1267      486954 :                 sql_rel *jl = rel->l, *ojl = jl, *jr = rel->r, *ojr = jr;
    1268             : 
    1269      486954 :                 set_processed(jl);
    1270      486954 :                 set_processed(jr);
    1271     1047235 :                 for (node *n = rel->exps->h; n;) {
    1272      560281 :                         node *next = n->next;
    1273      560281 :                         sql_exp *e = n->data;
    1274             : 
    1275      560281 :                         if (left && rel_rebind_exp(v->sql, jl, e) && !is_any(e)) { /* select expressions on left */
    1276        1330 :                                 if (!is_select(jl->op) || rel_is_ref(jl))
    1277        1319 :                                         rel->l = jl = rel_select(v->sql->sa, jl, NULL);
    1278        1330 :                                 rel_select_add_exp(v->sql->sa, jl, e);
    1279        1330 :                                 list_remove_node(rel->exps, NULL, n);
    1280        1330 :                                 v->changes++;
    1281      558951 :                         } else if (right && rel_rebind_exp(v->sql, jr, e) && !is_any(e)) { /* select expressions on right */
    1282          43 :                                 if (!is_select(jr->op) || rel_is_ref(jr))
    1283          40 :                                         rel->r = jr = rel_select(v->sql->sa, jr, NULL);
    1284          43 :                                 rel_select_add_exp(v->sql->sa, jr, e);
    1285          43 :                                 list_remove_node(rel->exps, NULL, n);
    1286          43 :                                 v->changes++;
    1287             :                         }
    1288             :                         n = next;
    1289             :                 }
    1290      486954 :                 if (ojl != jl)
    1291        1319 :                         set_processed(jl);
    1292      486954 :                 if (ojr != jr)
    1293          40 :                         set_processed(jr);
    1294             :         }
    1295     3464030 :         return rel;
    1296             : }
    1297             : 
    1298             : static inline bool
    1299     3464030 : is_non_trivial_select_applied_to_outer_join(sql_rel *rel)
    1300             : {
    1301     3464030 :         return is_select(rel->op) && rel->exps && is_outerjoin(((sql_rel*) rel->l)->op);
    1302             : }
    1303             : 
    1304             : extern list *list_append_before(list *l, node *n, void *data);
    1305             : 
    1306             : static void
    1307             : replace_column_references_with_nulls_2(mvc *sql, sql_rel *inner_join_side, sql_exp* e);
    1308             : 
    1309             : static void
    1310        5831 : replace_column_references_with_nulls_1(mvc *sql, sql_rel *inner_join_side, list* exps) {
    1311        5831 :         if (list_empty(exps))
    1312             :                 return;
    1313       14865 :         for(node* n = exps->h; n; n=n->next) {
    1314        9034 :                 sql_exp* e = n->data;
    1315        9034 :                 replace_column_references_with_nulls_2(sql, inner_join_side, e);
    1316             :         }
    1317             : }
    1318             : 
    1319             : static void
    1320       28796 : replace_column_references_with_nulls_2(mvc *sql, sql_rel *inner_join_side, sql_exp* e) {
    1321       36670 :         if (e == NULL) {
    1322             :                 return;
    1323             :         }
    1324             : 
    1325       30398 :         switch (e->type) {
    1326        9134 :         case e_column:
    1327        9134 :                 if (rel_find_exp_and_corresponding_rel(inner_join_side, e, true, NULL, NULL)) {
    1328        2559 :                         e->type = e_atom;
    1329        2559 :                         e->l = atom_general(sql->sa, &e->tpe, NULL, 0);
    1330        2559 :                         e->r = e->f = NULL;
    1331             :                 }
    1332             :                 break;
    1333        9415 :         case e_cmp:
    1334        9415 :                 switch (e->flag) {
    1335        6702 :                 case cmp_gt:
    1336             :                 case cmp_gte:
    1337             :                 case cmp_lte:
    1338             :                 case cmp_lt:
    1339             :                 case cmp_equal:
    1340             :                 case cmp_notequal:
    1341             :                 {
    1342        6702 :                         sql_exp* l = e->l;
    1343        6702 :                         sql_exp* r = e->r;
    1344        6702 :                         sql_exp* f = e->f;
    1345             : 
    1346        6702 :                         replace_column_references_with_nulls_2(sql, inner_join_side, l);
    1347        6702 :                         replace_column_references_with_nulls_2(sql, inner_join_side, r);
    1348        6702 :                         replace_column_references_with_nulls_2(sql, inner_join_side, f);
    1349        6702 :                         break;
    1350             :                 }
    1351        1953 :                 case cmp_filter:
    1352             :                 case cmp_or:
    1353             :                 {
    1354        1953 :                         list* l = e->l;
    1355        1953 :                         list* r = e->r;
    1356        1953 :                         replace_column_references_with_nulls_1(sql, inner_join_side, l);
    1357        1953 :                         replace_column_references_with_nulls_1(sql, inner_join_side, r);
    1358        1953 :                         break;
    1359             :                 }
    1360         760 :                 case cmp_in:
    1361             :                 case cmp_notin:
    1362             :                 {
    1363         760 :                         sql_exp* l = e->l;
    1364         760 :                         list* r = e->r;
    1365         760 :                         replace_column_references_with_nulls_2(sql, inner_join_side, l);
    1366         760 :                         replace_column_references_with_nulls_1(sql, inner_join_side, r);
    1367         760 :                         break;
    1368             :                 }
    1369             :                 default:
    1370             :                         break;
    1371             :                 }
    1372             :                 break;
    1373        1165 :         case e_func:
    1374             :         {
    1375        1165 :                 list* l = e->l;
    1376        1165 :                 replace_column_references_with_nulls_1(sql, inner_join_side, l);
    1377        1165 :                 break;
    1378             :         }
    1379        1172 :         case e_convert:
    1380             :         {
    1381        1172 :                 sql_exp* l = e->l;
    1382        1172 :                 replace_column_references_with_nulls_2(sql, inner_join_side, l);
    1383        1172 :                 break;
    1384             :         }
    1385             :         default:
    1386             :                 break;
    1387             :         }
    1388             : }
    1389             : 
    1390             : static sql_rel *
    1391        4962 : out2inner(visitor *v, sql_rel* sel, sql_rel* join, sql_rel* inner_join_side, operator_type new_type) {
    1392             : 
    1393             :         /* handle inner_join relations with a simple select */
    1394        4962 :         if (is_select(inner_join_side->op) && inner_join_side->l)
    1395        4962 :                 inner_join_side = inner_join_side->l;
    1396             : 
    1397        4962 :         list* select_predicates = exps_copy(v->sql, sel->exps);
    1398             : 
    1399       10466 :         for(node* n = select_predicates->h; n; n=n->next) {
    1400        5598 :                 sql_exp* e = n->data;
    1401        5598 :                 replace_column_references_with_nulls_2(v->sql, inner_join_side, e);
    1402             : 
    1403        5598 :                 if (exp_is_false(e)) {
    1404          94 :                         join->op = new_type;
    1405          94 :                         v->changes++;
    1406          94 :                         break;
    1407             :                 }
    1408             :         }
    1409             : 
    1410        4962 :         return sel;
    1411             : }
    1412             : 
    1413             : static inline sql_rel *
    1414     3464030 : rel_out2inner(visitor *v, sql_rel *rel) {
    1415             : 
    1416     3464030 :         if (!is_non_trivial_select_applied_to_outer_join(rel)) {
    1417             :                 // Nothing to do here.
    1418             :                 return rel;
    1419             :         }
    1420             : 
    1421        4940 :         sql_rel* join = (sql_rel*) rel->l;
    1422             : 
    1423        4940 :         if (rel_is_ref(join)) {
    1424             :                 /* Do not alter a multi-referenced join relation.
    1425             :                         * This is problematic (e.g. in the case of the plan of a merge statement)
    1426             :                         * basically because there are no guarantees on the other container relations.
    1427             :                         * In particular there is no guarantee that the other referencing relations are
    1428             :                         * select relations with null-rejacting predicates on the inner join side.
    1429             :                         */
    1430             :                 return rel;
    1431             :         }
    1432             : 
    1433        4940 :         sql_rel* inner_join_side;
    1434        4940 :         if (is_left(join->op)) {
    1435        4892 :                 inner_join_side = join->r;
    1436        4892 :                 return out2inner(v, rel, join, inner_join_side, op_join);
    1437             :         }
    1438          48 :         else if (is_right(join->op)) {
    1439          26 :                 inner_join_side = join->l;
    1440          26 :                 return out2inner(v, rel, join, inner_join_side, op_join);
    1441             :         }
    1442             :         else /*full outer join*/ {
    1443             :                 // First check if left side can degenerate from full outer join to just right outer join.
    1444          22 :                 inner_join_side = join->r;
    1445          22 :                 rel = out2inner(v, rel, join, inner_join_side, op_right);
    1446             :                 /* Now test if the right side can degenerate to
    1447             :                         * a normal inner join or a left outer join
    1448             :                         * depending on the result of previous call to out2inner.
    1449             :                         */
    1450             : 
    1451          22 :                 inner_join_side = join->l;
    1452          35 :                 return out2inner(v, rel, join, inner_join_side, is_right(join->op)? op_join: op_left);
    1453             :         }
    1454             : }
    1455             : 
    1456             : static bool
    1457        4284 : exps_uses_any(list *exps, list *l)
    1458             : {
    1459        4284 :         bool uses_any = false;
    1460             : 
    1461        4284 :         if (list_empty(exps) || list_empty(l))
    1462          14 :                 return false;
    1463        8546 :         for (node *n = l->h; n && !uses_any; n = n->next) {
    1464        4276 :                 sql_exp *e = n->data;
    1465        4276 :                 uses_any |= list_exps_uses_exp(exps, exp_relname(e), exp_name(e)) != NULL;
    1466             :         }
    1467             : 
    1468             :         return uses_any;
    1469             : }
    1470             : 
    1471             : /* TODO At the moment I have to disable the new join2semi because the join order optimizer doesn't take semi-joins into account,
    1472             : so plans get deteriorated if more joins are optimized into semi-joins. Later I will review the join order with semi-joins and hopefully,
    1473             : I will be able to re-enable the new join2semi. */
    1474             : #if 0
    1475             : #define NO_EXP_FOUND 0
    1476             : #define FOUND_WITH_DUPLICATES 1
    1477             : #define MAY_HAVE_DUPLICATE_NULLS 2
    1478             : #define ALL_VALUES_DISTINCT 3
    1479             : 
    1480             : static int
    1481             : find_projection_for_join2semi(sql_rel *rel, sql_exp *jc)
    1482             : {
    1483             :         sql_rel *res = NULL;
    1484             :         sql_exp *e = NULL;
    1485             :         bool underjoin = false;
    1486             : 
    1487             :         if ((e = rel_find_exp_and_corresponding_rel(rel, jc, &res, &underjoin))) {
    1488             :                 if (underjoin || e->type != e_column)
    1489             :                         return FOUND_WITH_DUPLICATES;
    1490             :                 /* if just one groupby column is projected or the relation needs distinct values and one column is projected or is a primary key, it will be distinct */
    1491             :                 if (is_unique(e) ||
    1492             :                         (is_groupby(res->op) && list_length(res->r) == 1 && exps_find_exp(res->r, e)) ||
    1493             :                         ((is_project(res->op) || is_base(res->op)) && ((need_distinct(res) && list_length(res->exps) == 1) || res->card < CARD_AGGR)))
    1494             :                         return has_nil(e) ? MAY_HAVE_DUPLICATE_NULLS : ALL_VALUES_DISTINCT;
    1495             :                 return FOUND_WITH_DUPLICATES;
    1496             :         }
    1497             :         return NO_EXP_FOUND;
    1498             : }
    1499             : 
    1500             : static int
    1501             : subrel_uses_exp_outside_subrel(visitor *v, sql_rel *rel, list *l, sql_rel *j)
    1502             : {
    1503             :         if (rel == j)
    1504             :                 return 0;
    1505             :         if (mvc_highwater(v->sql))
    1506             :                 return 1;
    1507             :         switch(rel->op){
    1508             :         case op_join:
    1509             :         case op_left:
    1510             :         case op_right:
    1511             :         case op_full:
    1512             :                 return exps_uses_any(rel->exps, l) ||
    1513             :                         subrel_uses_exp_outside_subrel(v, rel->l, l, j) || subrel_uses_exp_outside_subrel(v, rel->r, l, j);
    1514             :         case op_semi:
    1515             :         case op_anti:
    1516             :         case op_select:
    1517             :                 return exps_uses_any(rel->exps, l) ||
    1518             :                         subrel_uses_exp_outside_subrel(v, rel->l, l, j);
    1519             :         case op_project:
    1520             :         case op_groupby:
    1521             :                 return exps_uses_any(rel->exps, l) || exps_uses_any(rel->r, l);
    1522             :         case op_basetable:
    1523             :         case op_table:
    1524             :         case op_union:
    1525             :         case op_except:
    1526             :         case op_inter:
    1527             :                 return exps_uses_any(rel->exps, l);
    1528             :         case op_topn:
    1529             :         case op_sample:
    1530             :                 return subrel_uses_exp_outside_subrel(v, rel->l, l, j);
    1531             :         default:
    1532             :                 return 1;
    1533             :         }
    1534             : }
    1535             : 
    1536             : static int
    1537             : projrel_uses_exp_outside_subrel(visitor *v, sql_rel *rel, list *l, sql_rel *j)
    1538             : {
    1539             :         /* test if projecting relation uses any of the join expressions */
    1540             :         assert((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->l);
    1541             :         return exps_uses_any(rel->exps, l) || exps_uses_any(rel->r, l) || subrel_uses_exp_outside_subrel(v, rel->l, l, j);
    1542             : }
    1543             : 
    1544             : static sql_rel *
    1545             : rewrite_joins2semi(visitor *v, sql_rel *proj, sql_rel *rel)
    1546             : {
    1547             :         /* generalize possibility : we need the visitor 'step' here */
    1548             :         if (rel_is_ref(rel) || mvc_highwater(v->sql)) /* if the join has multiple references, it's dangerous to convert it into a semijoin */
    1549             :                 return rel;
    1550             :         if (is_innerjoin(rel->op) && !list_empty(rel->exps)) {
    1551             :                 sql_rel *l = rel->l, *r = rel->r;
    1552             :                 bool left_unique = true, right_unique = true;
    1553             : 
    1554             :                 /* these relations don't project anything, so skip them */
    1555             :                 while (is_topn(l->op) || is_sample(l->op) || is_select(l->op) || is_semi(l->op))
    1556             :                         l = l->l;
    1557             :                 /* joins will expand values, so don't search on those */
    1558             :                 if (!is_base(l->op) && !is_project(l->op))
    1559             :                         left_unique = false;
    1560             :                 while (is_topn(r->op) || is_sample(r->op) || is_select(r->op) || is_semi(r->op))
    1561             :                         r = r->l;
    1562             :                 if (!is_base(r->op) && !is_project(r->op))
    1563             :                         right_unique = false;
    1564             :                 /* if all columns used in equi-joins from one of the sides are unique, the join can be rewritten into a semijoin */
    1565             :                 for (node *n=rel->exps->h; n && (left_unique || right_unique); n = n->next) {
    1566             :                         sql_exp *e = n->data, *el = e->l, *er = e->r;
    1567             : 
    1568             :                         if (!is_compare(e->type) || e->flag != cmp_equal || exp_has_func(el) || exp_has_func(er)) {
    1569             :                                 left_unique = right_unique = false;
    1570             :                         } else {
    1571             :                                 int found = 0;
    1572             : 
    1573             :                                 if (left_unique && (found = find_projection_for_join2semi(l, el)) > NO_EXP_FOUND)
    1574             :                                         left_unique &= (found == ALL_VALUES_DISTINCT || (found == MAY_HAVE_DUPLICATE_NULLS && (!is_semantics(e) || !has_nil(er))));
    1575             :                                 if (left_unique && (found = find_projection_for_join2semi(l, er)) > NO_EXP_FOUND)
    1576             :                                         left_unique &= (found == ALL_VALUES_DISTINCT || (found == MAY_HAVE_DUPLICATE_NULLS && (!is_semantics(e) || !has_nil(el))));
    1577             :                                 if (right_unique && (found = find_projection_for_join2semi(r, el)) > NO_EXP_FOUND)
    1578             :                                         right_unique &= (found == ALL_VALUES_DISTINCT || (found == MAY_HAVE_DUPLICATE_NULLS && (!is_semantics(e) || !has_nil(er))));
    1579             :                                 if (right_unique && (found = find_projection_for_join2semi(r, er)) > NO_EXP_FOUND)
    1580             :                                         right_unique &= (found == ALL_VALUES_DISTINCT || (found == MAY_HAVE_DUPLICATE_NULLS && (!is_semantics(e) || !has_nil(el))));
    1581             :                         }
    1582             :                 }
    1583             : 
    1584             :                 /* now we need to check relation's expressions are not used */
    1585             :                 if (left_unique && !projrel_uses_exp_outside_subrel(v, proj, l->exps, rel)) {
    1586             :                         sql_rel *tmp = rel->r;
    1587             :                         rel->r = rel->l;
    1588             :                         rel->l = tmp;
    1589             :                         rel->op = op_semi;
    1590             :                         v->changes++;
    1591             :                 } else if (right_unique && !projrel_uses_exp_outside_subrel(v, proj, r->exps, rel)) {
    1592             :                         rel->op = op_semi;
    1593             :                         v->changes++;
    1594             :                 }
    1595             :         }
    1596             :         if (is_join(rel->op)) {
    1597             :                 rel->l = rewrite_joins2semi(v, proj, rel->l);
    1598             :                 rel->r = rewrite_joins2semi(v, proj, rel->r);
    1599             :         } else if (is_topn(rel->op) || is_sample(rel->op) || is_select(rel->op) || is_semi(rel->op)) {
    1600             :                 rel->l = rewrite_joins2semi(v, proj, rel->l);
    1601             :         }
    1602             :         return rel;
    1603             : }
    1604             : 
    1605             : static inline sql_rel *
    1606             : rel_join2semijoin(visitor *v, sql_rel *rel)
    1607             : {
    1608             :         if ((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->l)
    1609             :                 rel->l = rewrite_joins2semi(v, rel, rel->l);
    1610             :         return rel;
    1611             : }
    1612             : #endif
    1613             : 
    1614             : #define NO_PROJECTION_FOUND 0
    1615             : #define MAY_HAVE_DUPLICATE_NULLS 1
    1616             : #define ALL_VALUES_DISTINCT 2
    1617             : 
    1618             : static int
    1619      713475 : find_projection_for_join2semi(sql_rel *rel)
    1620             : {
    1621      713475 :         if (is_simple_project(rel->op) || is_groupby(rel->op) || is_inter(rel->op) || is_except(rel->op) || is_base(rel->op) || (is_union(rel->op) && need_distinct(rel))) {
    1622      379149 :                 if (rel->card < CARD_AGGR) /* const or groupby without group by exps */
    1623             :                         return ALL_VALUES_DISTINCT;
    1624      377988 :                 if (list_length(rel->exps) == 1) {
    1625        6757 :                         sql_exp *e = rel->exps->h->data;
    1626             :                         /* a single group by column in the projection list from a group by relation is guaranteed to be unique, but not an aggregate */
    1627        6757 :                         if (e->type == e_column) {
    1628        6727 :                                 sql_rel *res = NULL;
    1629        6727 :                                 sql_exp *found = NULL;
    1630        6727 :                                 bool underjoin = false;
    1631             : 
    1632             :                                 /* if just one groupby column is projected or the relation needs distinct values and one column is projected or is a primary key, it will be distinct */
    1633        6727 :                                 if ((is_groupby(rel->op) && list_length(rel->r) == 1 && exps_find_exp(rel->r, e)) || (need_distinct(rel) && list_length(rel->exps) == 1))
    1634        9616 :                                         return ALL_VALUES_DISTINCT;
    1635        3049 :                                 if (is_unique(e))
    1636        2259 :                                         return has_nil(e) ? MAY_HAVE_DUPLICATE_NULLS : ALL_VALUES_DISTINCT;
    1637             : 
    1638         790 :                                 if ((is_simple_project(rel->op) || is_groupby(rel->op) || is_inter(rel->op) || is_except(rel->op)) &&
    1639         146 :                                         (found = rel_find_exp_and_corresponding_rel(rel->l, e, false, &res, &underjoin)) && !underjoin) { /* grouping column on inner relation */
    1640         130 :                                         if (need_distinct(res) && list_length(res->exps) == 1)
    1641             :                                                 return ALL_VALUES_DISTINCT;
    1642         130 :                                         if (is_unique(found))
    1643           0 :                                                 return has_nil(e) ? MAY_HAVE_DUPLICATE_NULLS : ALL_VALUES_DISTINCT;
    1644         130 :                                         if (found->type == e_column && found->card <= CARD_AGGR) {
    1645           1 :                                                 if (!is_groupby(res->op) && list_length(res->exps) != 1)
    1646             :                                                         return NO_PROJECTION_FOUND;
    1647           0 :                                                 for (node *n = res->exps->h ; n ; n = n->next) { /* must be the single column in the group by expression list */
    1648           0 :                                                         sql_exp *e = n->data;
    1649           0 :                                                         if (e != found && e->type == e_column)
    1650             :                                                                 return NO_PROJECTION_FOUND;
    1651             :                                                 }
    1652             :                                                 return ALL_VALUES_DISTINCT;
    1653             :                                         }
    1654             :                                 }
    1655             :                         }
    1656             :                 }
    1657             :         }
    1658             :         return NO_PROJECTION_FOUND;
    1659             : }
    1660             : 
    1661             : static sql_rel *
    1662     2269393 : find_candidate_join2semi(visitor *v, sql_rel *rel, bool *swap)
    1663             : {
    1664             :         /* generalize possibility : we need the visitor 'step' here */
    1665     2269991 :         if (rel_is_ref(rel)) /* if the join has multiple references, it's dangerous to convert it into a semijoin */
    1666             :                 return NULL;
    1667     2153145 :         if (rel->op == op_join && !list_empty(rel->exps) && list_empty(rel->attr)) {
    1668      358923 :                 sql_rel *l = rel->l, *r = rel->r;
    1669      358923 :                 int foundr = NO_PROJECTION_FOUND, foundl = NO_PROJECTION_FOUND, found = NO_PROJECTION_FOUND;
    1670      358923 :                 bool ok = false;
    1671             : 
    1672      358923 :                 foundr = find_projection_for_join2semi(r);
    1673      358923 :                 if (foundr < ALL_VALUES_DISTINCT)
    1674      354552 :                         foundl = find_projection_for_join2semi(l);
    1675      358923 :                 if (foundr && foundr > foundl) {
    1676        4381 :                         *swap = false;
    1677        4381 :                         found = foundr;
    1678      354542 :                 } else if (foundl) {
    1679        2710 :                         *swap = true;
    1680        2710 :                         found = foundl;
    1681             :                 }
    1682             : 
    1683        7091 :                 if (found > NO_PROJECTION_FOUND) {
    1684             :                         /* if all join expressions can be pushed down or have function calls, then it cannot be rewritten into a semijoin */
    1685       14186 :                         for (node *n=rel->exps->h; n && !ok; n = n->next) {
    1686        7095 :                                 sql_exp *e = n->data;
    1687             : 
    1688       10870 :                                 ok |= e->type == e_cmp && e->flag == cmp_equal && !exp_has_func(e) && !rel_rebind_exp(v->sql, l, e) && !rel_rebind_exp(v->sql, r, e) &&
    1689          11 :                                         (found == ALL_VALUES_DISTINCT || !is_semantics(e) || !has_nil((sql_exp *)e->l) || !has_nil((sql_exp *)e->r));
    1690             :                         }
    1691             :                 }
    1692             : 
    1693      358923 :                 if (ok)
    1694             :                         return rel;
    1695             :         }
    1696     2149814 :         if (is_join(rel->op) || is_semi(rel->op)) {
    1697      539916 :                 sql_rel *c;
    1698             : 
    1699      539916 :                 if ((c=find_candidate_join2semi(v, rel->l, swap)) != NULL ||
    1700      539515 :                     (c=find_candidate_join2semi(v, rel->r, swap)) != NULL)
    1701         423 :                         if (list_empty(c->attr))
    1702             :                                 return c;
    1703             :         }
    1704     2149391 :         if (is_topn(rel->op) || is_sample(rel->op))
    1705         598 :                 return find_candidate_join2semi(v, rel->l, swap);
    1706             :         return NULL;
    1707             : }
    1708             : 
    1709             : static int
    1710        2542 : subrel_uses_exp_outside_subrel(sql_rel *rel, list *l, sql_rel *c)
    1711             : {
    1712        2543 :         if (rel == c)
    1713             :                 return 0;
    1714             :         /* for subrel only expect joins (later possibly selects) */
    1715         843 :         if (is_join(rel->op) || is_semi(rel->op)) {
    1716         427 :                 if (exps_uses_any(rel->exps, l))
    1717             :                         return 1;
    1718         836 :                 if (subrel_uses_exp_outside_subrel(rel->l, l, c) ||
    1719         417 :                     subrel_uses_exp_outside_subrel(rel->r, l, c))
    1720           5 :                         return 1;
    1721             :         }
    1722         830 :         if (is_topn(rel->op) || is_sample(rel->op))
    1723           1 :                 return subrel_uses_exp_outside_subrel(rel->l, l, c);
    1724             :         return 0;
    1725             : }
    1726             : 
    1727             : static int
    1728        3331 : rel_uses_exp_outside_subrel(sql_rel *rel, list *l, sql_rel *c)
    1729             : {
    1730             :         /* for now we only expect sub relations of type project, selects (rel) or join/semi */
    1731        3331 :         if (is_simple_project(rel->op) || is_groupby(rel->op) || is_select(rel->op)) {
    1732        3331 :                 if (!list_empty(rel->exps) && exps_uses_any(rel->exps, l))
    1733             :                         return 1;
    1734        1706 :                 if ((is_simple_project(rel->op) || is_groupby(rel->op)) && !list_empty(rel->r) && exps_uses_any(rel->r, l))
    1735             :                         return 1;
    1736        1706 :                 if (rel->l)
    1737        1706 :                         return subrel_uses_exp_outside_subrel(rel->l, l, c);
    1738             :         }
    1739           0 :         if (is_topn(rel->op) || is_sample(rel->op))
    1740           0 :                 return subrel_uses_exp_outside_subrel(rel->l, l, c);
    1741             :         return 1;
    1742             : }
    1743             : 
    1744             : static inline sql_rel *
    1745     3464030 : rel_join2semijoin(visitor *v, sql_rel *rel)
    1746             : {
    1747     3464030 :         if ((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->l) {
    1748     1189962 :                 bool swap = false;
    1749     1189962 :                 sql_rel *l = rel->l;
    1750     1189962 :                 sql_rel *c = find_candidate_join2semi(v, l, &swap);
    1751             : 
    1752     1189962 :                 if (c) {
    1753             :                         /* 'p' is a project */
    1754        3331 :                         sql_rel *p = swap ? c->l : c->r;
    1755             : 
    1756             :                         /* now we need to check if ce is only used at the level of c */
    1757        3331 :                         if (!rel_uses_exp_outside_subrel(rel, p->exps, c)) {
    1758        1698 :                                 c->op = op_semi;
    1759        1698 :                                 if (swap) {
    1760         521 :                                         sql_rel *tmp = c->r;
    1761         521 :                                         c->r = c->l;
    1762         521 :                                         c->l = tmp;
    1763             :                                 }
    1764        1698 :                                 v->changes++;
    1765             :                         }
    1766             :                 }
    1767             :         }
    1768     3464030 :         return rel;
    1769             : }
    1770             : 
    1771             : static inline sql_rel *
    1772     3464030 : rel_push_join_down_outer(visitor *v, sql_rel *rel)
    1773             : {
    1774     3464030 :         if (is_join(rel->op) && !is_outerjoin(rel->op) && !is_single(rel) && !list_empty(rel->exps) && !rel_is_ref(rel)) {
    1775      369222 :                 sql_rel *l = rel->l, *r = rel->r;
    1776             : 
    1777      369222 :                 if (is_left(r->op) && (is_select(l->op) || (is_join(l->op) && !is_outerjoin(l->op))) && !rel_is_ref(l) &&
    1778         648 :                                 !rel_is_ref(r)) {
    1779         648 :                         sql_rel *rl = r->l;
    1780         648 :                         sql_rel *rr = r->r;
    1781         648 :                         if (rel_is_ref(rl) || rel_is_ref(rr))
    1782             :                                 return rel;
    1783             :                         /* join exps should only include l and r.l */
    1784         648 :                         list *njexps = sa_list(v->sql->sa);
    1785        1304 :                         for(node *n = rel->exps->h; n; n = n->next) {
    1786         656 :                                 sql_exp *je = n->data;
    1787             : 
    1788         656 :                                 assert(je->type == e_cmp);
    1789         656 :                                 if (je->f)
    1790             :                                         return rel;
    1791         656 :                                 if ((rel_find_exp(l, je->l) && rel_find_exp(rl, je->r)) || (rel_find_exp(l, je->r) && rel_find_exp(rl, je->l))) {
    1792         656 :                                         list_append(njexps, je);
    1793             :                                 } else {
    1794           0 :                                         return rel;
    1795             :                                 }
    1796             :                         }
    1797         648 :                         sql_rel *nl = rel_crossproduct(v->sql->sa, rel_dup(l), rl, rel->op);
    1798         648 :                         r->l = nl;
    1799         648 :                         nl->exps = njexps;
    1800         648 :                         nl->attr = rel->attr;
    1801         648 :                         rel->attr = NULL;
    1802         648 :                         set_processed(nl);
    1803         648 :                         rel_dup(r);
    1804         648 :                         rel_destroy(rel);
    1805         648 :                         rel = r;
    1806         648 :                         v->changes++;
    1807             :                 }
    1808             :         }
    1809             :         return rel;
    1810             : }
    1811             : 
    1812             : static sql_rel *
    1813     3464030 : rel_optimize_joins_(visitor *v, sql_rel *rel)
    1814             : {
    1815     3464030 :         rel = rel_push_join_exps_down(v, rel);
    1816     3464030 :         rel = rel_out2inner(v, rel);
    1817     3464030 :         rel = rel_join2semijoin(v, rel);
    1818     3464030 :         rel = rel_push_join_down_outer(v, rel);
    1819     3464030 :         return rel;
    1820             : }
    1821             : 
    1822             : static sql_rel *
    1823       91310 : rel_optimize_joins(visitor *v, global_props *gp, sql_rel *rel)
    1824             : {
    1825       91310 :         (void) gp;
    1826       91310 :         return rel_visitor_topdown(v, rel, &rel_optimize_joins_);
    1827             : }
    1828             : 
    1829             : run_optimizer
    1830      631180 : bind_optimize_joins(visitor *v, global_props *gp)
    1831             : {
    1832      631180 :         int flag = v->sql->sql_optimizer;
    1833      630983 :         return gp->opt_level == 1 && (gp->cnt[op_join] || gp->cnt[op_left] || gp->cnt[op_right]
    1834     1262163 :                    || gp->cnt[op_full] || gp->cnt[op_semi] || gp->cnt[op_anti]) && (flag & optimize_joins) ? rel_optimize_joins : NULL;
    1835             : }
    1836             : 
    1837             : 
    1838             : static sql_rel *rel_join_order_(visitor *v, sql_rel *rel);
    1839             : 
    1840             : static void
    1841      711026 : get_relations(visitor *v, sql_rel *rel, list *rels)
    1842             : {
    1843      988955 :         if (list_empty(rel->attr) && !rel_is_ref(rel) && rel->op == op_join && rel->exps == NULL) {
    1844      277929 :                 sql_rel *l = rel->l;
    1845      277929 :                 sql_rel *r = rel->r;
    1846             : 
    1847      277929 :                 get_relations(v, l, rels);
    1848      277929 :                 get_relations(v, r, rels);
    1849      277929 :                 rel->l = NULL;
    1850      277929 :                 rel->r = NULL;
    1851      277929 :                 rel_destroy(rel);
    1852             :         } else {
    1853      433097 :                 rel = rel_join_order_(v, rel);
    1854      433097 :                 append(rels, rel);
    1855             :         }
    1856      711026 : }
    1857             : 
    1858             : static void
    1859      184913 : get_inner_relations(mvc *sql, sql_rel *rel, list *rels)
    1860             : {
    1861      292512 :         if (!rel_is_ref(rel) && is_join(rel->op)) {
    1862      107599 :                 sql_rel *l = rel->l;
    1863      107599 :                 sql_rel *r = rel->r;
    1864             : 
    1865      107599 :                 get_inner_relations(sql, l, rels);
    1866      107599 :                 get_inner_relations(sql, r, rels);
    1867             :         } else {
    1868      184913 :                 append(rels, rel);
    1869             :         }
    1870      184913 : }
    1871             : 
    1872             : static int
    1873     1071519 : exp_count(int *cnt, sql_exp *e)
    1874             : {
    1875     1071519 :         int flag;
    1876     1071519 :         if (!e)
    1877             :                 return 0;
    1878     1071519 :         if (find_prop(e->p, PROP_JOINIDX))
    1879        3541 :                 *cnt += 100;
    1880     1071519 :         if (find_prop(e->p, PROP_HASHCOL))
    1881       34379 :                 *cnt += 100;
    1882     1071519 :         if (find_prop(e->p, PROP_HASHIDX))
    1883           0 :                 *cnt += 100;
    1884     1071519 :         switch(e->type) {
    1885      395443 :         case e_cmp:
    1886      395443 :                 if (!is_complex_exp(e->flag)) {
    1887      336509 :                         exp_count(cnt, e->l);
    1888      336509 :                         exp_count(cnt, e->r);
    1889      336509 :                         if (e->f)
    1890        3052 :                                 exp_count(cnt, e->f);
    1891             :                 }
    1892      395443 :                 flag = e->flag;
    1893      395443 :                 switch (flag) {
    1894      312511 :                 case cmp_equal:
    1895      312511 :                         *cnt += 90;
    1896      312511 :                         return 90;
    1897       17493 :                 case cmp_notequal:
    1898       17493 :                         *cnt += 7;
    1899       17493 :                         return 7;
    1900        6505 :                 case cmp_gt:
    1901             :                 case cmp_gte:
    1902             :                 case cmp_lt:
    1903             :                 case cmp_lte:
    1904        6505 :                         *cnt += 6;
    1905        6505 :                         if (e->l) {
    1906        6505 :                                 sql_exp *l = e->l;
    1907        6505 :                                 sql_subtype *t = exp_subtype(l);
    1908        6505 :                                 if (EC_TEMP(t->type->eclass)) /* give preference to temporal ranges */
    1909         172 :                                         *cnt += 90;
    1910             :                         }
    1911        6505 :                         if (e->f){ /* range */
    1912        3052 :                                 *cnt += 6;
    1913        3052 :                                 return 12;
    1914             :                         }
    1915             :                         return 6;
    1916        1042 :                 case cmp_filter:
    1917        1042 :                         if (exps_card(e->r) > CARD_AGGR) {
    1918             :                                 /* filters for joins are special */
    1919           3 :                                 *cnt += 1000;
    1920           3 :                                 return 1000;
    1921             :                         }
    1922        1039 :                         *cnt += 2;
    1923        1039 :                         return 2;
    1924       53140 :                 case cmp_in:
    1925             :                 case cmp_notin: {
    1926       53140 :                         list *l = e->r;
    1927       53140 :                         int c = 9 - 10*list_length(l);
    1928       53140 :                         *cnt += c;
    1929       53140 :                         return c;
    1930             :                 }
    1931        4752 :                 case cmp_or: /* prefer or over functions */
    1932        4752 :                         *cnt += 3;
    1933        4752 :                         return 3;
    1934             :                 default:
    1935             :                         return 0;
    1936             :                 }
    1937      533273 :         case e_column:
    1938      533273 :                 *cnt += 20;
    1939      533273 :                 return 20;
    1940      123956 :         case e_atom:
    1941      123956 :                 *cnt += 10;
    1942      123956 :                 return 10;
    1943        2862 :         case e_func:
    1944             :                 /* functions are more expensive, depending on the number of columns involved. */
    1945        2862 :                 if (e->card == CARD_ATOM)
    1946             :                         return 0;
    1947        2571 :                 *cnt -= 5*list_length(e->l);
    1948        2571 :                 return 5*list_length(e->l);
    1949       15985 :         case e_convert:
    1950             :                 /* functions are more expensive, depending on the number of columns involved. */
    1951       15985 :                 if (e->card == CARD_ATOM)
    1952             :                         return 0;
    1953             :                 /* fall through */
    1954             :         default:
    1955       15321 :                 *cnt -= 5;
    1956       15321 :                 return -5;
    1957             :         }
    1958             : }
    1959             : 
    1960             : int
    1961      269678 : exp_keyvalue(sql_exp *e)
    1962             : {
    1963      269678 :         int cnt = 0;
    1964       60453 :         exp_count(&cnt, e);
    1965      269678 :         return cnt;
    1966             : }
    1967             : 
    1968             : static sql_exp *
    1969      746774 : joinexp_col(sql_exp *e, sql_rel *r)
    1970             : {
    1971      746774 :         if (e->type == e_cmp) {
    1972      746774 :                 if (rel_has_exp(r, e->l, false) >= 0)
    1973      399250 :                         return e->l;
    1974      347524 :                 return e->r;
    1975             :         }
    1976           0 :         assert(0);
    1977             :         return NULL;
    1978             : }
    1979             : 
    1980             : static sql_column *
    1981      494114 : table_colexp(sql_exp *e, sql_rel *r)
    1982             : {
    1983      494114 :         sql_table *t = r->l;
    1984             : 
    1985      494114 :         if (e->type == e_column) {
    1986      479670 :                 const char *name = exp_name(e);
    1987      479670 :                 node *cn;
    1988             : 
    1989      479670 :                 if (r->exps) { /* use alias */
    1990      887561 :                         for (cn = r->exps->h; cn; cn = cn->next) {
    1991      883249 :                                 sql_exp *ce = cn->data;
    1992      883249 :                                 if (strcmp(exp_name(ce), name) == 0) {
    1993      475358 :                                         name = ce->r;
    1994      475358 :                                         break;
    1995             :                                 }
    1996             :                         }
    1997             :                 }
    1998     1056541 :                 for (cn = ol_first_node(t->columns); cn; cn = cn->next) {
    1999     1052229 :                         sql_column *c = cn->data;
    2000     1052229 :                         if (strcmp(c->base.name, name) == 0)
    2001      475358 :                                 return c;
    2002             :                 }
    2003             :         }
    2004             :         return NULL;
    2005             : }
    2006             : 
    2007             : static list *
    2008      359615 : matching_joins(allocator *sa, list *rels, list *exps, sql_exp *je)
    2009             : {
    2010      359615 :         sql_rel *l, *r;
    2011             : 
    2012      359615 :         assert (je->type == e_cmp);
    2013             : 
    2014      359615 :         l = find_rel(rels, je->l);
    2015      359615 :         r = find_rel(rels, je->r);
    2016      359615 :         if (l && r) {
    2017      359474 :                 list *res;
    2018      359474 :                 list *n_rels = sa_list(sa);
    2019             : 
    2020      359474 :                 append(n_rels, l);
    2021      359474 :                 append(n_rels, r);
    2022      359474 :                 res = list_select(exps, n_rels, (fcmp) &exp_joins_rels, (fdup)NULL);
    2023      359474 :                 return res;
    2024             :         }
    2025         141 :         return sa_list(sa);
    2026             : }
    2027             : 
    2028             : static int
    2029        6373 : sql_column_kc_cmp(sql_column *c, sql_kc *kc)
    2030             : {
    2031             :         /* return on equality */
    2032        6373 :         return (c->colnr - kc->c->colnr);
    2033             : }
    2034             : 
    2035             : static sql_idx *
    2036      463767 : find_fk_index(mvc *sql, sql_table *l, list *lcols, sql_table *r, list *rcols)
    2037             : {
    2038      463767 :         sql_trans *tr = sql->session->tr;
    2039             : 
    2040      463767 :         if (l->idxs) {
    2041      463767 :                 node *in;
    2042      551398 :                 for (in = ol_first_node(l->idxs); in; in = in->next){
    2043       88471 :                         sql_idx *li = in->data;
    2044       88471 :                         if (li->type == join_idx) {
    2045        8717 :                                 sql_key *rk = (sql_key*)os_find_id(tr->cat->objects, tr, ((sql_fkey*)li->key)->rkey);
    2046        8717 :                                 fcmp cmp = (fcmp)&sql_column_kc_cmp;
    2047             : 
    2048        9666 :                                 if (rk->t == r &&
    2049        1789 :                                         list_match(lcols, li->columns, cmp) == 0 &&
    2050         840 :                                         list_match(rcols, rk->columns, cmp) == 0) {
    2051         840 :                                         return li;
    2052             :                                 }
    2053             :                         }
    2054             :                 }
    2055             :         }
    2056             :         return NULL;
    2057             : }
    2058             : 
    2059             : static sql_rel *
    2060      719230 : find_basetable( sql_rel *r)
    2061             : {
    2062     1062473 :         if (!r)
    2063             :                 return NULL;
    2064     1054811 :         switch(r->op) {
    2065      579163 :         case op_basetable:
    2066      579163 :                 if (!r->l)
    2067           0 :                         return NULL;
    2068             :                 return r;
    2069      343243 :         case op_semi:
    2070             :         case op_anti:
    2071             :         case op_project:
    2072             :         case op_select:
    2073             :         case op_topn:
    2074             :         case op_sample:
    2075      343243 :                 return find_basetable(r->l);
    2076             :         default:
    2077             :                 return NULL;
    2078             :         }
    2079             : }
    2080             : 
    2081             : static int
    2082       99909 : exps_count(list *exps)
    2083             : {
    2084       99909 :         node *n;
    2085       99909 :         int cnt = 0;
    2086             : 
    2087       99909 :         if (!exps)
    2088             :                 return 0;
    2089      225680 :         for (n = exps->h; n; n=n->next)
    2090      125771 :                 exp_count(&cnt, n->data);
    2091       99909 :         return cnt;
    2092             : }
    2093             : 
    2094             : static list *
    2095      255589 : order_join_expressions(mvc *sql, list *dje, list *rels)
    2096             : {
    2097      255589 :         node *n;
    2098      255589 :         int cnt = list_length(dje);
    2099             : 
    2100      255589 :         if (cnt <= 1)
    2101             :                 return dje;
    2102             : 
    2103       66397 :         list *res = sa_list(sql->sa);
    2104       66397 :         int i, *keys = SA_NEW_ARRAY(sql->ta, int, cnt);
    2105       66397 :         void **data = SA_NEW_ARRAY(sql->ta, void*, cnt);
    2106             : 
    2107      275622 :         for (n = dje->h, i = 0; n; n = n->next, i++) {
    2108      209225 :                 sql_exp *e = n->data;
    2109             : 
    2110      209225 :                 keys[i] = exp_keyvalue(e);
    2111             :                 /* add some weight for the selections */
    2112      209225 :                 if (e->type == e_cmp && !is_complex_exp(e->flag)) {
    2113      209201 :                         sql_rel *l = find_rel(rels, e->l);
    2114      209201 :                         sql_rel *r = find_rel(rels, e->r);
    2115             : 
    2116      209201 :                         if (l && is_select(l->op) && l->exps)
    2117       53478 :                                 keys[i] += list_length(l->exps)*10 + exps_count(l->exps);
    2118      209201 :                         if (r && is_select(r->op) && r->exps)
    2119       46431 :                                 keys[i] += list_length(r->exps)*10 + exps_count(r->exps);
    2120             :                 }
    2121      209225 :                 data[i] = n->data;
    2122             :         }
    2123             :         /* sort descending */
    2124       66397 :         GDKqsort(keys, data, NULL, cnt, sizeof(int), sizeof(void *), TYPE_int, true, true);
    2125      342019 :         for(i=0; i<cnt; i++) {
    2126      209225 :                 list_append(res, data[i]);
    2127             :         }
    2128             :         return res;
    2129             : }
    2130             : 
    2131             : static int
    2132      239086 : find_join_rels(list **L, list **R, list *exps, list *rels)
    2133             : {
    2134      239086 :         node *n;
    2135             : 
    2136      239086 :         *L = sa_list(exps->sa);
    2137      239086 :         *R = sa_list(exps->sa);
    2138      239086 :         if (!exps || list_length(exps) <= 1)
    2139             :                 return -1;
    2140      292337 :         for(n = exps->h; n; n = n->next) {
    2141      220776 :                 sql_exp *e = n->data;
    2142      220776 :                 sql_rel *l = NULL, *r = NULL;
    2143             : 
    2144      220776 :                 if (!is_complex_exp(e->flag)){
    2145      220771 :                         l = find_rel(rels, e->l);
    2146      220771 :                         r = find_rel(rels, e->r);
    2147             :                 }
    2148      220771 :                 if (l<r) {
    2149      142998 :                         list_append(*L, l);
    2150      142998 :                         list_append(*R, r);
    2151             :                 } else {
    2152       77778 :                         list_append(*L, r);
    2153       77778 :                         list_append(*R, l);
    2154             :                 }
    2155             :         }
    2156             :         return 0;
    2157             : }
    2158             : 
    2159             : static list *
    2160       71561 : distinct_join_exps(list *aje, list *lrels, list *rrels)
    2161             : {
    2162       71561 :         node *n, *m, *o, *p;
    2163       71561 :         int len = list_length(aje), i, j;
    2164       71561 :         char *used = SA_ZNEW_ARRAY(aje->sa, char, len);
    2165       71561 :         list *res = sa_list(aje->sa);
    2166             : 
    2167       71561 :         assert(len == list_length(lrels));
    2168      292337 :         for(n = lrels->h, m = rrels->h, j = 0; n && m;
    2169      220776 :             n = n->next, m = m->next, j++) {
    2170      220776 :                 if (n->data && m->data)
    2171      953759 :                 for(o = n->next, p = m->next, i = j+1; o && p;
    2172      733033 :                     o = o->next, p = p->next, i++) {
    2173      733033 :                         if (o->data == n->data && p->data == m->data)
    2174       29947 :                                 used[i] = 1;
    2175             :                 }
    2176             :         }
    2177      292337 :         for (i = 0, n = aje->h; i < len; n = n->next, i++) {
    2178      220776 :                 if (!used[i])
    2179      195957 :                         list_append(res, n->data);
    2180             :         }
    2181       71561 :         return res;
    2182             : }
    2183             : 
    2184             : static list *
    2185      239086 : find_fk( mvc *sql, list *rels, list *exps)
    2186             : {
    2187      239086 :         node *djn;
    2188      239086 :         list *sdje, *aje, *dje;
    2189      239086 :         list *lrels, *rrels;
    2190             : 
    2191             :         /* first find the distinct join expressions */
    2192      239086 :         aje = list_select(exps, rels, (fcmp) &exp_is_join, (fdup)NULL);
    2193             :         /* add left/right relation */
    2194      239086 :         if (find_join_rels(&lrels, &rrels, aje, rels) < 0)
    2195             :                 dje = aje;
    2196             :         else
    2197       71561 :                 dje = distinct_join_exps(aje, lrels, rrels);
    2198      602201 :         for(djn=dje->h; djn; djn = djn->next) {
    2199             :                 /* equal join expressions */
    2200      363195 :                 sql_idx *idx = NULL;
    2201      363195 :                 sql_exp *je = djn->data, *le = je->l, *re = je->r;
    2202             : 
    2203      363195 :                 if (is_complex_exp(je->flag))
    2204             :                         break;
    2205      363115 :                 if (!find_prop(je->p, PROP_JOINIDX)) {
    2206      359615 :                         int swapped = 0;
    2207      359615 :                         list *aaje = matching_joins(sql->sa, rels, aje, je);
    2208      359615 :                         list *eje = list_select(aaje, (void*)1, (fcmp) &exp_is_eqjoin, (fdup)NULL);
    2209      359615 :                         sql_rel *lr = find_rel(rels, le), *olr = lr;
    2210      359615 :                         sql_rel *rr = find_rel(rels, re), *orr = rr;
    2211      359615 :                         sql_rel *bt = NULL;
    2212      359615 :                         char *iname;
    2213             : 
    2214      359615 :                         sql_table *l, *r;
    2215      359615 :                         list *lexps = list_map(eje, lr, (fmap) &joinexp_col);
    2216      359615 :                         list *rexps = list_map(eje, rr, (fmap) &joinexp_col);
    2217      359615 :                         list *lcols, *rcols;
    2218             : 
    2219      359615 :                         lr = find_basetable(lr);
    2220      359615 :                         rr = find_basetable(rr);
    2221      359615 :                         if (!lr || !rr)
    2222      236297 :                                 continue;
    2223      250717 :                         l = lr->l;
    2224      250717 :                         r = rr->l;
    2225      250717 :                         lcols = list_map(lexps, lr, (fmap) &table_colexp);
    2226      250717 :                         rcols = list_map(rexps, rr, (fmap) &table_colexp);
    2227      250717 :                         lcols->destroy = NULL;
    2228      250717 :                         rcols->destroy = NULL;
    2229      250717 :                         if (list_length(lcols) != list_length(rcols))
    2230       18500 :                                 continue;
    2231             : 
    2232      232217 :                         idx = find_fk_index(sql, l, lcols, r, rcols);
    2233      232217 :                         if (!idx) {
    2234      231550 :                                 idx = find_fk_index(sql, r, rcols, l, lcols);
    2235      231550 :                                 swapped = 1;
    2236             :                         }
    2237             : 
    2238      232217 :                         if (idx && (iname = sa_strconcat( sql->sa, "%", idx->base.name)) != NULL &&
    2239         667 :                                    ((!swapped && name_find_column(olr, NULL, iname, -2, &bt) == NULL) ||
    2240         173 :                                     ( swapped && name_find_column(orr, NULL, iname, -2, &bt) == NULL)))
    2241             :                                 idx = NULL;
    2242             : 
    2243             :                         if (idx) {
    2244         751 :                                 prop *p;
    2245         751 :                                 node *n;
    2246         751 :                                 sql_exp *t = NULL, *i = NULL;
    2247             : 
    2248         751 :                                 if (list_length(lcols) > 1 || !mvc_debug_on(sql, 512)) {
    2249             : 
    2250             :                                         /* Add join between idx and TID */
    2251         751 :                                         if (swapped) {
    2252         155 :                                                 sql_exp *s = je->l, *l = je->r;
    2253             : 
    2254         155 :                                                 t = rel_find_column(sql, olr, s->l, TID);
    2255         155 :                                                 i = rel_find_column(sql, orr, l->l, iname);
    2256         155 :                                                 if (!t || !i)
    2257           1 :                                                         continue;
    2258         154 :                                                 t->p = NULL;
    2259         154 :                                                 i->p = NULL;
    2260         154 :                                                 je = exp_compare(sql->sa, i, t, cmp_equal);
    2261             :                                         } else {
    2262         596 :                                                 sql_exp *s = je->r, *l = je->l;
    2263             : 
    2264         596 :                                                 t = rel_find_column(sql, orr, s->l, TID);
    2265         596 :                                                 i = rel_find_column(sql, olr, l->l, iname);
    2266         596 :                                                 if (!t || !i)
    2267           0 :                                                         continue;
    2268         596 :                                                 t->p = NULL;
    2269         596 :                                                 i->p = NULL;
    2270         596 :                                                 je = exp_compare(sql->sa, i, t, cmp_equal);
    2271             :                                         }
    2272             : 
    2273             :                                         /* Remove all join expressions */
    2274        1502 :                                         for (n = eje->h; n; n = n->next)
    2275         752 :                                                 list_remove_data(exps, NULL, n->data);
    2276         750 :                                         append(exps, je);
    2277         750 :                                         djn->data = je;
    2278           0 :                                 } else if (swapped) { /* else keep je for single column expressions */
    2279           0 :                                         je = exp_compare(sql->sa, je->r, je->l, cmp_equal);
    2280             :                                         /* Remove all join expressions */
    2281           0 :                                         for (n = eje->h; n; n = n->next)
    2282           0 :                                                 list_remove_data(exps, NULL, n->data);
    2283           0 :                                         append(exps, je);
    2284           0 :                                         djn->data = je;
    2285             :                                 }
    2286         750 :                                 je->p = p = prop_create(sql->sa, PROP_JOINIDX, je->p);
    2287         750 :                                 p->value.pval = idx;
    2288             :                         }
    2289             :                 }
    2290             :         }
    2291             : 
    2292             :         /* sort expressions on weighted number of reducing operators */
    2293      239086 :         sdje = order_join_expressions(sql, dje, rels);
    2294      239086 :         return sdje;
    2295             : }
    2296             : 
    2297             : static int
    2298      557601 : rels_find_one_rel( sql_rel **rels, int nr, sql_exp *e)
    2299             : {
    2300      557601 :         int fnd = 0;
    2301             : 
    2302     4449196 :         for(int i = 1; i<=nr; i++) {
    2303     3891659 :                 if (rel_has_exp(rels[i], e, false) == 0) {
    2304      557399 :                         if (fnd)
    2305             :                                 return 0;
    2306             :                         fnd = i;
    2307             :                 }
    2308             :         }
    2309             :         return fnd;
    2310             : }
    2311             : 
    2312             : /* TODO move popcount and popcount64 into gdk_*.h, used in gdk_cand, strimps and here */
    2313             : static inline int
    2314             : popcount64(uint64_t x)
    2315             : {
    2316             : #ifdef __has_builtin
    2317             : #if __has_builtin(__builtin_popcountll)
    2318             :         return (uint32_t) __builtin_popcountll(x);
    2319             : #define BUILTIN_USED
    2320             : #endif
    2321             : #endif
    2322             : #ifndef BUILTIN_USED
    2323             : #if defined(_MSC_VER)
    2324             : #if SIZEOF_OID == 4
    2325             :         /* no __popcnt64 on 32 bit Windows */
    2326             :         return (int) (__popcnt((uint32_t) x) + __popcnt((uint32_t) (x >> 32)));
    2327             : #else
    2328             :         return (uint32_t) __popcnt64(x);
    2329             : #endif
    2330             : #else
    2331             :         x = (x & UINT64_C(0x5555555555555555)) + ((x >> 1) & UINT64_C(0x5555555555555555));
    2332             :         x = (x & UINT64_C(0x3333333333333333)) + ((x >> 2) & UINT64_C(0x3333333333333333));
    2333             :         x = (x & UINT64_C(0x0F0F0F0F0F0F0F0F)) + ((x >> 4) & UINT64_C(0x0F0F0F0F0F0F0F0F));
    2334             :         return (x * UINT64_C(0x0101010101010101)) >> 56;
    2335             : #endif
    2336             : #endif
    2337             : #undef BUILTIN_USED
    2338             : }
    2339             : 
    2340             : static sql_rel *
    2341      155168 : order_joins(visitor *v, list *rels, list *exps)
    2342             : {
    2343      155168 :         sql_rel *top = NULL, *l = NULL, *r = NULL;
    2344      155168 :         sql_exp *cje;
    2345      155168 :         node *djn;
    2346      155168 :         list *sdje, *n_rels = NULL;
    2347      155168 :         int fnd = 0;
    2348      155168 :         unsigned int rsingle;
    2349      155168 :         int direct = 1;
    2350             : 
    2351             :         /* find foreign keys and reorder the expressions on reducing quality */
    2352      155168 :         sdje = find_fk(v->sql, rels, exps);
    2353             : 
    2354      433870 :         for(djn = sdje->h; djn; djn = djn->next ) {
    2355      278702 :                 sql_exp *e = djn->data;
    2356      278702 :                 list_remove_data(exps, NULL, e);
    2357             :         }
    2358      155168 :         if (list_length(rels) > 2 && mvc_debug_on(v->sql, 256)) {
    2359           0 :                 top =  rel_planner(v->sql, rels, sdje, exps);
    2360           0 :                 return top;
    2361             :         }
    2362             : 
    2363      155168 :         int nr_exps = list_length(sdje), nr_rels = list_length(rels), ci = 1;
    2364      155168 :         if (nr_rels > 64) {
    2365           1 :                 direct = 0;
    2366           1 :                 n_rels = sa_list(v->sql->ta);
    2367             :         }
    2368      155168 :         sql_rel **rels_a = SA_NEW_ARRAY(v->sql->ta, sql_rel*, nr_rels+1); /* don't use slot 0 */
    2369      155168 :         rels_a[0] = NULL;
    2370      588265 :         for (node *n = rels->h; n; n = n->next, ci++) {
    2371      433097 :                 rels_a[ci] = n->data;
    2372             :         }
    2373      155168 :         ulng *h = SA_NEW_ARRAY(v->sql->ta, ulng, nr_exps), rel_mask = 0;  /* bit field (for > 64 its an imprint) */
    2374      155168 :         uint16_t *r1 = SA_NEW_ARRAY(v->sql->ta, uint16_t, nr_exps);
    2375      155168 :         uint16_t *r2 = SA_NEW_ARRAY(v->sql->ta, uint16_t, nr_exps);
    2376             :         /* change r3 into rest list's */
    2377      155168 :         int *r3 = SA_NEW_ARRAY(v->sql->ta, int, nr_exps);
    2378             : 
    2379      155168 :         ci = 0;
    2380      433870 :         for (node *n = sdje->h; n; n = n->next, ci++) {
    2381      278702 :                 sql_exp *cje = n->data;
    2382             : 
    2383      278702 :                 h[ci] = r1[ci] = r2[ci] = 0;
    2384      278702 :                 r3[ci] = 0;
    2385             :                 /* h[ci] = exp_find_rels(cje, rels) */
    2386      278702 :                 if (cje->type != e_cmp || !is_complex_exp(cje->flag) || !find_prop(cje->p, PROP_HASHCOL) ||
    2387           0 :                    (cje->type == e_cmp && cje->f == NULL)) {
    2388      278702 :                         cje->tmp = ci;
    2389      278702 :                         r1[ci] = rels_find_one_rel(rels_a, nr_rels, cje->l);
    2390      278702 :                         r2[ci] = rels_find_one_rel(rels_a, nr_rels, cje->r);
    2391      278702 :                         if (r1[ci])
    2392      278583 :                                 h[ci] |= ((ulng)1)<<((r1[ci]-1)%64);
    2393      278702 :                         if (r2[ci])
    2394      278564 :                                 h[ci] |= ((ulng)1)<<((r2[ci]-1)%64);
    2395      278702 :                         if (cje->f) {
    2396         197 :                                 r3[ci] = rels_find_one_rel(rels_a, nr_rels, cje->f);
    2397         197 :                                 if (r3[ci] == r2[ci])
    2398         177 :                                         r3[ci] = 0;
    2399         197 :                                 if (r3[ci])
    2400          10 :                                         h[ci] |= ((ulng)1)<<((r3[ci]-1)%64);
    2401             :                         }
    2402             :                 }
    2403             :         }
    2404             :         /* open problem, some expressions use more than 2 relations */
    2405             :         /* For example a.x = b.y * c.z; */
    2406      155168 :         if (list_length(rels) >= 2 && sdje->h) {
    2407      310294 :                 for (node *n = sdje->h; n && !l && !r; n = n->next, ci++) {
    2408      155151 :                         cje = n->data;
    2409             : 
    2410             :                         /* find the involved relations */
    2411             : 
    2412             :                         /* complex expressions may touch multiple base tables
    2413             :                          * Should be pushed up to extra selection.
    2414             :                          * */
    2415      155151 :                         if (0 && popcount64(h[cje->tmp]) > 2)
    2416             :                                 assert(0);
    2417      155151 :                         if (cje->type != e_cmp || !is_complex_exp(cje->flag) || !find_prop(cje->p, PROP_HASHCOL) ||
    2418           0 :                                 (cje->type == e_cmp && cje->f == NULL)) {
    2419      155151 :                                 l = rels_a[r1[cje->tmp]];
    2420      155151 :                                 r = rels_a[r2[cje->tmp]];
    2421      155151 :                                 if (l && r)
    2422      155031 :                                         rel_mask |= h[cje->tmp];
    2423             :                         }
    2424             :                 }
    2425      155143 :                 cje->tmp = 0;
    2426             : 
    2427      155143 :                 if (l && r && l != r)
    2428      155031 :                         list_remove_data(sdje, NULL, cje);
    2429             :         }
    2430             : 
    2431      155168 :         if (l && r && l != r) {
    2432      155031 :                 list_remove_data(rels, NULL, l);
    2433      155031 :                 list_remove_data(rels, NULL, r);
    2434      155031 :                 if (!direct) {
    2435           1 :                         list_append(n_rels, l);
    2436           1 :                         list_append(n_rels, r);
    2437             :                 }
    2438             : 
    2439             :                 /* Create a relation between l and r. Since the calling
    2440             :                    functions rewrote the join tree, into a list of expressions
    2441             :                    and a list of (simple) relations, there are no outer joins
    2442             :                    involved, we can simply do a crossproduct here.
    2443             :                  */
    2444      155031 :                 rsingle = is_single(r);
    2445      155031 :                 reset_single(r);
    2446      155031 :                 top = rel_crossproduct(v->sql->sa, l, r, op_join);
    2447      155031 :                 if (rsingle)
    2448        5108 :                         set_single(r);
    2449      155031 :                 rel_join_add_exp(v->sql->sa, top, cje);
    2450             : 
    2451             :                 /* all other join expressions on these 2 relations */
    2452      158834 :                 for (node *en = exps->h; en; ) {
    2453        3803 :                         node *next = en->next;
    2454        3803 :                         sql_exp *e = en->data;
    2455        3803 :                         if (rel_rebind_exp(v->sql, top, e)) {
    2456        3631 :                                 rel_join_add_exp(v->sql->sa, top, e);
    2457        3631 :                                 list_remove_data(exps, NULL, e);
    2458             :                         }
    2459             :                         en = next;
    2460             :                 }
    2461             :                 fnd = 1;
    2462             :         }
    2463             :         /* build join tree using the ordered list */
    2464      275404 :         while(list_length(sdje) && fnd) {
    2465      120236 :                 fnd = 0;
    2466             :                 /* find the first expression which could be added */
    2467      880146 :                 for(djn = sdje->h; djn && !fnd && rels->h; djn = (!fnd)?djn->next:NULL) {
    2468      379955 :                         node *en;
    2469      379955 :                         l = r = NULL;
    2470             : 
    2471      379955 :                         cje = djn->data;
    2472      379955 :                         if ((h[cje->tmp] & rel_mask) > 0) {
    2473      120154 :                                 if (rel_mask & (((ulng)1)<<((r1[cje->tmp]-1)%64)))
    2474       67737 :                                         l = rels_a[r1[cje->tmp]];
    2475      120154 :                                 if (rel_mask & (((ulng)1)<<((r2[cje->tmp]-1)%64)))
    2476       52418 :                                         r = rels_a[r2[cje->tmp]];
    2477             :                         }
    2478      379955 :                         if (!direct) { /* check if at least one side in n_rels */
    2479        1040 :                                 if (l && !list_find(n_rels, l, NULL))
    2480        1007 :                                         l = NULL;
    2481        1040 :                                 if (r && !list_find(n_rels, r, NULL))
    2482           1 :                                         r = NULL;
    2483             :                         }
    2484             : 
    2485      379955 :                         if (l && r) {
    2486           0 :                                 assert(0);
    2487             :                                 /* create a selection on the current */
    2488             :                                 rel_join_add_exp(v->sql->sa, top, cje);
    2489             :                                 fnd = 1;
    2490      379955 :                         } else if (l || r) {
    2491             :                                 /* TODO: handle case for joins which need > 2 relations, ie where the current 'top' of the
    2492             :                                  * join tree needs to add more then one relation */
    2493      120154 :                                 rel_mask |= h[cje->tmp];
    2494      120154 :                                 if (l) {
    2495       67737 :                                         r = rels_a[r2[cje->tmp]];
    2496             :                                 } else {
    2497       52417 :                                         l = r;
    2498       52417 :                                         r = rels_a[r1[cje->tmp]];
    2499             :                                 }
    2500      120154 :                                 if (!r) {
    2501           0 :                                         fnd = 1; /* not really, but this bails out */
    2502           0 :                                         list_remove_data(sdje, NULL, cje); /* handle later as select */
    2503           0 :                                         continue;
    2504             :                                 }
    2505             : 
    2506             :                                 /* remove the expression from the lists */
    2507      120154 :                                 list_remove_data(sdje, NULL, cje);
    2508             : 
    2509      120154 :                                 list_remove_data(rels, NULL, r);
    2510      120154 :                                 if (!direct)
    2511          63 :                                         append(n_rels, r);
    2512             : 
    2513             :                                 /* create a join using the current expression */
    2514      120154 :                                 rsingle = is_single(r);
    2515      120154 :                                 reset_single(r);
    2516      120154 :                                 top = rel_crossproduct(v->sql->sa, top, r, op_join);
    2517      120154 :                                 if (rsingle)
    2518           0 :                                         set_single(r);
    2519      120154 :                                 rel_join_add_exp(v->sql->sa, top, cje);
    2520             : 
    2521             :                                 /* all join expressions on these tables */
    2522      120543 :                                 for (en = exps->h; en; ) {
    2523         389 :                                         node *next = en->next;
    2524         389 :                                         sql_exp *e = en->data;
    2525         389 :                                         if (rel_rebind_exp(v->sql, top, e)) {
    2526         170 :                                                 rel_join_add_exp(v->sql->sa, top, e);
    2527         170 :                                                 list_remove_data(exps, NULL, e);
    2528             :                                         }
    2529             :                                         en = next;
    2530             :                                 }
    2531             :                                 /* Remove other joins on the current 'n_rels'
    2532             :                                    set in the distinct list too */
    2533      695621 :                                 for (en = sdje->h; en; ) {
    2534      575467 :                                         node *next = en->next;
    2535      575467 :                                         sql_exp *e = en->data;
    2536      575467 :                                         if ((direct && ((e->flag <= cmp_notequal && (h[e->tmp] & rel_mask) == h[e->tmp] && h[e->tmp]) || (e->flag > cmp_notequal && rel_rebind_exp(v->sql, top, e))))  ||
    2537        1953 :                                             (!direct && rel_rebind_exp(v->sql, top, e))) {
    2538        3318 :                                                 rel_join_add_exp(v->sql->sa, top, e);
    2539        3318 :                                                 list_remove_data(sdje, NULL, en->data);
    2540             :                                         }
    2541             :                                         en = next;
    2542             :                                 }
    2543             :                                 fnd = 1;
    2544             :                         }
    2545             :                 }
    2546             :         }
    2547      155168 :         if (list_length(rels)) { /* more relations */
    2548        1182 :                 node *n;
    2549        4063 :                 for(n=rels->h; n; n = n->next) {
    2550        2881 :                         sql_rel *nr = n->data;
    2551             : 
    2552        2881 :                         if (top) {
    2553        2744 :                                 rsingle = is_single(nr);
    2554        2744 :                                 reset_single(nr);
    2555        2744 :                                 top = rel_crossproduct(v->sql->sa, top, nr, op_join);
    2556        2744 :                                 if (rsingle)
    2557           0 :                                         set_single(nr);
    2558             :                         } else
    2559             :                                 top = nr;
    2560             :                 }
    2561             :         }
    2562      155168 :         if (list_length(sdje)) {
    2563         194 :                 if (list_empty(exps))
    2564             :                         exps = sdje;
    2565             :                 else
    2566           0 :                         exps = list_merge(exps, sdje, (fdup)NULL);
    2567             :         }
    2568      155168 :         if (list_length(exps)) { /* more expressions (add selects) */
    2569         221 :                 top = rel_select(v->sql->sa, top, NULL);
    2570         447 :                 for(node *n=exps->h; n; n = n->next) {
    2571         226 :                         sql_exp *e = n->data;
    2572             : 
    2573         226 :                         if (exp_is_join_exp(e) == 0) {
    2574         211 :                                 sql_rel *nr = NULL;
    2575         211 :                                 if (is_theta_exp(e->flag)) {
    2576         136 :                                         nr = rel_push_join(v->sql, top->l, e->l, e->r, e->f, e, 0);
    2577          75 :                                 } else if (e->flag == cmp_filter || e->flag == cmp_or) {
    2578          75 :                                         sql_exp *l = exps_find_one_multi_exp(e->l), *r = exps_find_one_multi_exp(e->r);
    2579          75 :                                         if (l && r)
    2580          69 :                                                 nr = rel_push_join(v->sql, top->l, l, r, NULL, e, 0);
    2581             :                                 }
    2582         205 :                                 if (!nr)
    2583           6 :                                         rel_join_add_exp(v->sql->sa, top->l, e);
    2584             :                         } else
    2585          15 :                                 rel_select_add_exp(v->sql->sa, top, e);
    2586             :                 }
    2587         221 :                 if (list_empty(top->exps)) { /* empty select */
    2588         206 :                         sql_rel *l = top->l;
    2589         206 :                         top->l = NULL;
    2590         206 :                         rel_destroy(top);
    2591         206 :                         top = l;
    2592             :                 }
    2593             :         }
    2594             :         return top;
    2595             : }
    2596             : 
    2597             : static int
    2598      433097 : rel_neg_in_size(sql_rel *r)
    2599             : {
    2600      433097 :         if ((is_union(r->op) /*|| is_munion(r->op)*/) && r->nrcols == 0)
    2601           0 :                 return -1 + rel_neg_in_size(r->l);
    2602      433097 :         if (is_project(r->op) && r->nrcols == 0)
    2603           0 :                 return -1;
    2604             :         return 0;
    2605             : }
    2606             : 
    2607      433097 : static void _rel_destroy(void *dummy, sql_rel *rel)
    2608             : {
    2609      433097 :         (void)dummy;
    2610      433097 :         rel_destroy(rel);
    2611      433097 : }
    2612             : 
    2613             : static list *
    2614      155168 : push_in_join_down(mvc *sql, list *rels, list *exps)
    2615             : {
    2616      155168 :         node *n;
    2617      155168 :         int restart = 1;
    2618      155168 :         list *nrels;
    2619             : 
    2620             :         /* we should sort these first, ie small in's before large one's */
    2621      155168 :         nrels = list_sort(rels, (fkeyvalue)&rel_neg_in_size, (fdup)&rel_dup);
    2622             : 
    2623             :         /* we need to cleanup, the new refs ! */
    2624      155168 :         rels->destroy = (fdestroy)_rel_destroy;
    2625      155168 :         list_destroy(rels);
    2626      155168 :         rels = nrels;
    2627             : 
    2628             :         /* one of the rels should be a op_union with nrcols == 0 */
    2629      465504 :         while (restart) {
    2630      588265 :                 for (n = rels->h; n; n = n->next) {
    2631      433097 :                         sql_rel *r = n->data;
    2632             : 
    2633      433097 :                         restart = 0;
    2634      433097 :                         if (is_project(r->op) && r->nrcols == 0) {
    2635             :                                 /* next step find expression on this relation */
    2636           0 :                                 node *m;
    2637           0 :                                 sql_rel *l = NULL;
    2638           0 :                                 sql_exp *je = NULL;
    2639             : 
    2640           0 :                                 for(m = exps->h; !je && m; m = m->next) {
    2641           0 :                                         sql_exp *e = m->data;
    2642             : 
    2643           0 :                                         if (e->type == e_cmp && e->flag == cmp_equal) {
    2644             :                                                 /* in values are on
    2645             :                                                         the right of the join */
    2646           0 :                                                 if (rel_has_exp(r, e->r, false) >= 0)
    2647           0 :                                                         je = e;
    2648             :                                         }
    2649             :                                 }
    2650             :                                 /* with this expression find other relation */
    2651           0 :                                 if (je && (l = find_rel(rels, je->l)) != NULL) {
    2652           0 :                                         unsigned int rsingle = is_single(r);
    2653           0 :                                         reset_single(r);
    2654           0 :                                         sql_rel *nr = rel_crossproduct(sql->sa, l, r, op_join);
    2655           0 :                                         if (rsingle)
    2656           0 :                                                 set_single(r);
    2657           0 :                                         rel_join_add_exp(sql->sa, nr, je);
    2658           0 :                                         list_append(rels, nr);
    2659           0 :                                         list_remove_data(rels, NULL, l);
    2660           0 :                                         list_remove_data(rels, NULL, r);
    2661           0 :                                         list_remove_data(exps, NULL, je);
    2662           0 :                                         restart = 1;
    2663           0 :                                         break;
    2664             :                                 }
    2665             : 
    2666             :                         }
    2667             :                 }
    2668             :         }
    2669      155168 :         return rels;
    2670             : }
    2671             : 
    2672             : static list *
    2673      739644 : push_up_join_exps( mvc *sql, sql_rel *rel)
    2674             : {
    2675      739644 :         if (rel_is_ref(rel))
    2676             :                 return NULL;
    2677             : 
    2678      698883 :         switch(rel->op) {
    2679      290226 :         case op_join: {
    2680      290226 :                 sql_rel *rl = rel->l;
    2681      290226 :                 sql_rel *rr = rel->r;
    2682      290226 :                 list *l, *r;
    2683             : 
    2684      290226 :                 if (rel_is_ref(rl) && rel_is_ref(rr)) {
    2685          16 :                         l = rel->exps;
    2686          16 :                         rel->exps = NULL;
    2687          16 :                         return l;
    2688             :                 }
    2689      290210 :                 l = push_up_join_exps(sql, rl);
    2690      290210 :                 r = push_up_join_exps(sql, rr);
    2691      290210 :                 if (l && r) {
    2692          34 :                         l = list_merge(l, r, (fdup)NULL);
    2693          34 :                         r = NULL;
    2694      290176 :                 } else if (!l) {
    2695      176639 :                         l = r;
    2696      176639 :                         r = NULL;
    2697             :                 }
    2698      290210 :                 if (rel->exps) {
    2699      258414 :                         if (l && !r)
    2700      103188 :                                 r = l;
    2701      258414 :                         l = list_merge(rel->exps, r, (fdup)NULL);
    2702             :                 }
    2703      290210 :                 rel->exps = NULL;
    2704      290210 :                 return l;
    2705             :         }
    2706             :         default:
    2707             :                 return NULL;
    2708             :         }
    2709             : }
    2710             : 
    2711             : static sql_rel *
    2712      286693 : reorder_join(visitor *v, sql_rel *rel)
    2713             : {
    2714      286693 :         list *exps, *rels;
    2715             : 
    2716      286693 :         if (is_innerjoin(rel->op) && !is_single(rel) && !rel_is_ref(rel) && list_empty(rel->attr)) {
    2717      176712 :                 if (list_empty(rel->exps)) {
    2718       22352 :                         sql_rel *l = rel->l, *r = rel->r;
    2719       22352 :                         if (!is_innerjoin(l->op) && !is_innerjoin(r->op))
    2720             :                                 return rel;
    2721             :                 }
    2722      159224 :                 rel->exps = push_up_join_exps(v->sql, rel);
    2723             :         }
    2724             : 
    2725      269205 :         if (!is_innerjoin(rel->op) || is_single(rel) || rel_is_ref(rel) || list_empty(rel->exps) || !list_empty(rel->attr)) {
    2726      114037 :                 if (!list_empty(rel->exps)) { /* cannot add join idxs to cross products */
    2727       77314 :                         exps = rel->exps;
    2728       77314 :                         rel->exps = NULL; /* should be all crosstables by now */
    2729       77314 :                         rels = sa_list(v->sql->ta);
    2730             :                         /* try to use an join index also for outer joins */
    2731       77314 :                         get_inner_relations(v->sql, rel, rels);
    2732       77314 :                         int cnt = list_length(exps);
    2733       77314 :                         rel->exps = find_fk(v->sql, rels, exps);
    2734       77314 :                         if (list_length(rel->exps) != cnt)
    2735       16503 :                                 rel->exps = order_join_expressions(v->sql, exps, rels);
    2736             :                 }
    2737      114037 :                 rel->l = rel_join_order_(v, rel->l);
    2738      114037 :                 rel->r = rel_join_order_(v, rel->r);
    2739             :         } else {
    2740      155168 :                 exps = rel->exps;
    2741      155168 :                 rel->exps = NULL; /* should be all crosstables by now */
    2742      155168 :                 rels = sa_list(v->sql->ta);
    2743      155168 :                 get_relations(v, rel, rels);
    2744      155168 :                 if (list_length(rels) > 1) {
    2745      155168 :                         rels = push_in_join_down(v->sql, rels, exps);
    2746      155168 :                         rel = order_joins(v, rels, exps);
    2747             :                 } else {
    2748           0 :                         rel->exps = exps;
    2749             :                 }
    2750             :         }
    2751             :         return rel;
    2752             : }
    2753             : 
    2754             : static sql_rel *
    2755     2425458 : rel_join_order_(visitor *v, sql_rel *rel)
    2756             : {
    2757     2425458 :         if (!rel)
    2758             :                 return rel;
    2759             : 
    2760     2409503 :         switch (rel->op) {
    2761             :         case op_basetable:
    2762             :                 break;
    2763        3878 :         case op_table:
    2764        3878 :                 if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION)
    2765        3878 :                         rel->l = rel_join_order_(v, rel->l);
    2766             :                 break;
    2767             :         case op_join:
    2768             :         case op_left:
    2769             :         case op_right:
    2770             :         case op_full:
    2771             :                 break;
    2772             : 
    2773       12397 :         case op_semi:
    2774             :         case op_anti:
    2775             : 
    2776             :         case op_union:
    2777             :         case op_inter:
    2778             :         case op_except:
    2779             :         case op_merge:
    2780       12397 :                 rel->l = rel_join_order_(v, rel->l);
    2781       12397 :                 rel->r = rel_join_order_(v, rel->r);
    2782       12397 :                 break;
    2783      118224 :         case op_munion:
    2784      118224 :                 assert(rel->l);
    2785      475311 :                 for (node *n = ((list*)rel->l)->h; n; n = n->next)
    2786      357087 :                         n->data = rel_join_order_(v, n->data);
    2787             :                 break;
    2788     1282376 :         case op_project:
    2789             :         case op_select:
    2790             :         case op_groupby:
    2791             :         case op_topn:
    2792             :         case op_sample:
    2793     1282376 :                 rel->l = rel_join_order_(v, rel->l);
    2794     1282376 :                 break;
    2795          52 :         case op_ddl:
    2796          52 :                 if (rel->flag == ddl_output || rel->flag == ddl_create_seq || rel->flag == ddl_alter_seq || rel->flag == ddl_alter_table || rel->flag == ddl_create_table || rel->flag == ddl_create_view) {
    2797           0 :                         rel->l = rel_join_order_(v, rel->l);
    2798             :                 } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
    2799          52 :                         rel->l = rel_join_order_(v, rel->l);
    2800          52 :                         rel->r = rel_join_order_(v, rel->r);
    2801             :                 }
    2802             :                 break;
    2803       11879 :         case op_insert:
    2804             :         case op_update:
    2805             :         case op_delete:
    2806       11879 :                 rel->r = rel_join_order_(v, rel->r);
    2807       11879 :                 break;
    2808             :         case op_truncate:
    2809             :                 break;
    2810             :         }
    2811     2409503 :         if (is_join(rel->op))
    2812      286693 :                 rel = reorder_join(v, rel);
    2813             :         return rel;
    2814             : }
    2815             : 
    2816             : static sql_rel *
    2817       84169 : rel_join_order(visitor *v, global_props *gp, sql_rel *rel)
    2818             : {
    2819       84169 :         (void) gp;
    2820       84169 :         sql_rel *r = rel_join_order_(v, rel);
    2821       84169 :         sa_reset(v->sql->ta);
    2822       84169 :         return r;
    2823             : }
    2824             : 
    2825             : run_optimizer
    2826      631250 : bind_join_order(visitor *v, global_props *gp)
    2827             : {
    2828      631250 :         int flag = v->sql->sql_optimizer;
    2829      631054 :         return gp->opt_level == 1 && gp->opt_cycle < 10 && !gp->cnt[op_update] && (gp->cnt[op_join] || gp->cnt[op_left] ||
    2830     1256041 :                    gp->cnt[op_right] || gp->cnt[op_full]) && (flag & join_order) ? rel_join_order : NULL;
    2831             : }
    2832             : 
    2833             : /* this join order is to be done once after statistics are gathered */
    2834             : run_optimizer
    2835      722134 : bind_join_order2(visitor *v, global_props *gp)
    2836             : {
    2837             :         /*int flag = v->sql->sql_optimizer;
    2838             :         return gp->opt_level == 1 && !gp->has_special_modify && !gp->cnt[op_update] && (gp->cnt[op_join] || gp->cnt[op_left] ||
    2839             :                    gp->cnt[op_right] || gp->cnt[op_full]) && (flag & join_order) ? rel_join_order : NULL;*/
    2840             :         /* TODO we have to propagate count statistics here */
    2841      722134 :         (void) v;
    2842      722134 :         (void) gp;
    2843      722134 :         return NULL;
    2844             : }
    2845             : 
    2846             : 
    2847             : static int
    2848       14678 : is_identity_of(sql_exp *e, sql_rel *l)
    2849             : {
    2850       14678 :         if (e->type != e_cmp)
    2851             :                 return 0;
    2852       14651 :         if (!is_identity(e->l, l) || !is_identity(e->r, l) || (e->f && !is_identity(e->f, l)))
    2853       14651 :                 return 0;
    2854             :         return 1;
    2855             : }
    2856             : 
    2857             : static inline sql_rel *
    2858       18919 : rel_rewrite_semijoin(visitor *v, sql_rel *rel)
    2859             : {
    2860       18919 :         assert(is_semi(rel->op));
    2861             :         {
    2862       18919 :                 sql_rel *l = rel->l;
    2863       18919 :                 sql_rel *r = rel->r;
    2864       18919 :                 sql_rel *rl = (r->l)?r->l:NULL;
    2865       18919 :                 int on_identity = 1;
    2866             : 
    2867       18919 :                 if (!rel->exps || list_length(rel->exps) != 1 || !is_identity_of(rel->exps->h->data, l))
    2868             :                         on_identity = 0;
    2869             : 
    2870             :                 /* rewrite {semi,anti}join (A, join(A,B)) into {semi,anti}join (A,B)
    2871             :                  * and     {semi,anti}join (A, join(B,A)) into {semi,anti}join (A,B)
    2872             :                  * Where the semi/anti join is done using the identity */
    2873           0 :                 if (on_identity && l->ref.refcnt == 2 && ((is_join(r->op) && (l == r->l || l == r->r)) ||
    2874           0 :                    (is_project(r->op) && rl && is_join(rl->op) && (l == rl->l || l == rl->r)))){
    2875           0 :                         sql_rel *or = r;
    2876             : 
    2877           0 :                         if (is_project(r->op))
    2878           0 :                                 r = rl;
    2879             : 
    2880           0 :                         if (l == r->r)
    2881           0 :                                 rel->r = rel_dup(r->l);
    2882             :                         else
    2883           0 :                                 rel->r = rel_dup(r->r);
    2884             : 
    2885           0 :                         rel->exps = r->exps;
    2886           0 :                         r->exps = NULL;
    2887           0 :                         rel->attr = r->attr;
    2888           0 :                         r->attr = NULL;
    2889           0 :                         rel_destroy(or);
    2890           0 :                         v->changes++;
    2891             :                 }
    2892             :         }
    2893             :         {
    2894       18919 :                 sql_rel *l = rel->l, *rl = NULL;
    2895       18919 :                 sql_rel *r = rel->r, *or = r;
    2896             : 
    2897       18919 :                 if (r)
    2898       18919 :                         rl = r->l;
    2899       18919 :                 if (r && is_project(r->op)) {
    2900       15786 :                         r = rl;
    2901       15786 :                         if (r)
    2902       15539 :                                 rl = r->l;
    2903             :                 }
    2904             : 
    2905             :                 /* More general case is (join reduction)
    2906             :                    {semi,anti}join (A, join(A,B) [A.c1 == B.c1]) [ A.c1 == B.c1 ]
    2907             :                    into {semi,anti}join (A,B) [ A.c1 == B.c1 ]
    2908             : 
    2909             :                    for semijoin also A.c1 == B.k1 ] [ A.c1 == B.k2 ] could be rewritten
    2910             :                  */
    2911       18919 :                 if (l && r && rl &&
    2912       17530 :                     is_basetable(l->op) && is_basetable(rl->op) &&
    2913        4032 :                     is_join(r->op) && l->l == rl->l)
    2914             :                 {
    2915          25 :                         node *n, *m;
    2916          25 :                         list *exps;
    2917             : 
    2918          49 :                         if (!rel->exps || !r->exps ||
    2919          24 :                             list_length(rel->exps) != list_length(r->exps))
    2920           1 :                                 return rel;
    2921          24 :                         exps = new_exp_list(v->sql->sa);
    2922             : 
    2923             :                         /* are the join conditions equal */
    2924          24 :                         for (n = rel->exps->h, m = r->exps->h;
    2925          24 :                              n && m; n = n->next, m = m->next)
    2926             :                         {
    2927          24 :                                 sql_exp *le = NULL, *oe = n->data;
    2928          24 :                                 sql_exp *re = NULL, *ne = m->data;
    2929          24 :                                 sql_column *cl;
    2930          24 :                                 int equal = 0;
    2931             : 
    2932          24 :                                 if (oe->type != e_cmp || ne->type != e_cmp ||
    2933          24 :                                     oe->flag != cmp_equal ||
    2934          24 :                                     ne->flag != cmp_equal || is_anti(oe) || is_anti(ne))
    2935             :                                         return rel;
    2936             : 
    2937          24 :                                 if ((cl = exp_find_column(rel->l, oe->l, -2)) != NULL) {
    2938          24 :                                         le = oe->l;
    2939          24 :                                         re = oe->r;
    2940           0 :                                 } else if ((cl = exp_find_column(rel->l, oe->r, -2)) != NULL) {
    2941           0 :                                         le = oe->r;
    2942           0 :                                         re = oe->l;
    2943             :                                 } else
    2944             :                                         return rel;
    2945             : 
    2946          24 :                                 if (exp_find_column(rl, ne->l, -2) == cl) {
    2947          24 :                                         sql_exp *e = (or != r)?rel_find_exp(or, re):re;
    2948             : 
    2949          24 :                                         if (e)
    2950          24 :                                                 equal = exp_match_exp(ne->r, e);
    2951          24 :                                         if (!e || !equal)
    2952             :                                                 return rel;
    2953           0 :                                         re = ne->r;
    2954           0 :                                 } else if (exp_find_column(rl, ne->r, -2) == cl) {
    2955           0 :                                         sql_exp *e = (or != r)?rel_find_exp(or, re):re;
    2956             : 
    2957           0 :                                         if (e)
    2958           0 :                                                 equal = exp_match_exp(ne->l, e);
    2959           0 :                                         if (!e || !equal)
    2960             :                                                 return rel;
    2961           0 :                                         re = ne->l;
    2962             :                                 } else
    2963             :                                         return rel;
    2964             : 
    2965           0 :                                 ne = exp_compare(v->sql->sa, le, re, cmp_equal);
    2966           0 :                                 append(exps, ne);
    2967             :                         }
    2968             : 
    2969           0 :                         rel->r = rel_dup(r->r);
    2970           0 :                         rel->exps = exps;
    2971           0 :                         rel_destroy(or);
    2972           0 :                         v->changes++;
    2973             :                 }
    2974             :         }
    2975             :         return rel;
    2976             : }
    2977             : 
    2978             : /*
    2979             :  * Push semijoins down, pushes the semijoin through a join.
    2980             :  *
    2981             :  * semijoin( join(A, B) [ A.x == B.y ], C ) [ A.z == C.c ]
    2982             :  * ->
    2983             :  * join( semijoin(A, C) [ A.z == C.c ], B ) [ A.x == B.y ]
    2984             :  *
    2985             :  * also push simple expressions of a semijoin down if they only
    2986             :  * involve the left sided of the semijoin.
    2987             :  *
    2988             :  * in some cases the other way is useful, ie push join down
    2989             :  * semijoin. When the join reduces (ie when there are selects on it).
    2990             :  *
    2991             :  * At the moment, we only flag changes by this optimizer on the first level of optimization
    2992             :  */
    2993             : static inline sql_rel *
    2994      467828 : rel_push_semijoin_down_or_up(visitor *v, sql_rel *rel)
    2995             : {
    2996      467828 :         uint8_t cycle = *(uint8_t*) v->data;
    2997             : 
    2998      467828 :         if (rel->op == op_join && rel->exps && rel->l) {
    2999      430453 :                 sql_rel *l = rel->l, *r = rel->r;
    3000             : 
    3001      430453 :                 if (is_semi(l->op) && !rel_is_ref(l) && is_select(r->op) && !rel_is_ref(r)) {
    3002          22 :                         rel->l = l->l;
    3003          22 :                         l->l = rel;
    3004          22 :                         if (cycle <= 0)
    3005           0 :                                 v->changes++;
    3006          22 :                         return l;
    3007             :                 }
    3008             :         }
    3009             :         /* also case with 2 joins */
    3010             :         /* join ( join ( semijoin(), table), select (table)); */
    3011      467806 :         if (rel->op == op_join && rel->exps && rel->l) {
    3012      430431 :                 sql_rel *l = rel->l, *r = rel->r;
    3013      430431 :                 sql_rel *ll;
    3014             : 
    3015      430431 :                 if (is_join(l->op) && !rel_is_ref(l) && is_select(r->op) && !rel_is_ref(r)) {
    3016        8164 :                         ll = l->l;
    3017        8164 :                         if (is_semi(ll->op) && !rel_is_ref(ll)) {
    3018          51 :                                 l->l = ll->l;
    3019          51 :                                 ll->l = rel;
    3020          51 :                                 if (cycle <= 0)
    3021          12 :                                         v->changes++;
    3022          51 :                                 return ll;
    3023             :                         }
    3024             :                 }
    3025             :         }
    3026             :         /* first push down the expressions involving only A */
    3027      467755 :         if (rel->op == op_semi && rel->exps && rel->l) {
    3028       12300 :                 sql_rel *jl = rel->l, *ojl = jl;
    3029             : 
    3030       12300 :                 set_processed(jl);
    3031       28174 :                 for (node *n = rel->exps->h; n;) {
    3032       15874 :                         node *next = n->next;
    3033       15874 :                         sql_exp *e = n->data;
    3034             : 
    3035       15874 :                         if (n != rel->exps->h && e->type == e_cmp && rel_rebind_exp(v->sql, jl, e)) {
    3036          16 :                                 if (!is_select(jl->op) || rel_is_ref(jl))
    3037          14 :                                         rel->l = jl = rel_select(v->sql->sa, jl, NULL);
    3038          16 :                                 rel_select_add_exp(v->sql->sa, jl, e);
    3039          16 :                                 list_remove_node(rel->exps, NULL, n);
    3040          16 :                                 if (cycle <= 0)
    3041          16 :                                         v->changes++;
    3042             :                         }
    3043             :                         n = next;
    3044             :                 }
    3045       12300 :                 if (ojl != jl)
    3046          14 :                         set_processed(jl);
    3047             :         }
    3048      467755 :         if (rel->op == op_semi && rel->exps && rel->l) {
    3049       12300 :                 operator_type op = rel->op, lop;
    3050       12300 :                 node *n;
    3051       12300 :                 sql_rel *l = rel->l, *ll = NULL, *lr = NULL;
    3052       12300 :                 sql_rel *r = rel->r;
    3053       12300 :                 list *exps = rel->exps, *nsexps, *njexps, *nsattr, *njattr;
    3054       12300 :                 int left = 1, right = 1;
    3055             : 
    3056             :                 /* handle project
    3057             :                 if (l->op == op_project && !need_distinct(l))
    3058             :                         l = l->l;
    3059             :                 */
    3060             : 
    3061       12300 :                 if (!is_join(l->op) || is_full(l->op) || rel_is_ref(l) || is_single(l))
    3062             :                         return rel;
    3063             : 
    3064        1219 :                 lop = l->op;
    3065        1219 :                 ll = l->l;
    3066        1219 :                 lr = l->r;
    3067             : 
    3068             :                 /* check which side is used and other exps are atoms or from right of semijoin */
    3069        2348 :                 for(n = exps->h; n; n = n->next) {
    3070        1346 :                         sql_exp *sje = n->data;
    3071             : 
    3072        1346 :                         if (sje->type != e_cmp || is_complex_exp(sje->flag))
    3073             :                                 return rel;
    3074             :                         /* sje->l from ll and sje->r/f from semijoin r ||
    3075             :                          * sje->l from semijoin r and sje->r/f from ll ||
    3076             :                          * sje->l from lr and sje->r/f from semijoin r ||
    3077             :                          * sje->l from semijoin r and sje->r/f from lr */
    3078        2628 :                         if (left &&
    3079        2628 :                            ((rel_rebind_exp(v->sql, ll, sje->l) && rel_rebind_exp(v->sql, rel->r, sje->r) && (!sje->f || rel_rebind_exp(v->sql, rel->r, sje->f))) ||
    3080        1282 :                             (rel_rebind_exp(v->sql, rel->r, sje->l) && rel_rebind_exp(v->sql, ll, sje->r) && (!sje->f || rel_rebind_exp(v->sql, ll, sje->f)))))
    3081             :                                 right = 0;
    3082             :                         else
    3083         955 :                                 left = 0;
    3084        1785 :                         if (right &&
    3085        1660 :                            ((rel_rebind_exp(v->sql, lr, sje->l) && rel_rebind_exp(v->sql, rel->r, sje->r) && (!sje->f || rel_rebind_exp(v->sql, rel->r, sje->f))) ||
    3086         566 :                             (rel_rebind_exp(v->sql, rel->r, sje->l) && rel_rebind_exp(v->sql, lr, sje->r) && (!sje->f || rel_rebind_exp(v->sql, lr, sje->f)))))
    3087             :                                 left = 0;
    3088             :                         else
    3089             :                                 right = 0;
    3090        1314 :                         if (!right && !left)
    3091             :                                 return rel;
    3092             :                 }
    3093        1002 :                 if (left && is_right(lop))
    3094             :                         return rel;
    3095        1001 :                 if (right && is_left(lop))
    3096             :                         return rel;
    3097         999 :                 nsexps = exps_copy(v->sql, rel->exps);
    3098         999 :                 nsattr = exps_copy(v->sql, rel->attr);
    3099         999 :                 njexps = exps_copy(v->sql, l->exps);
    3100         999 :                 njattr = exps_copy(v->sql, l->attr);
    3101         999 :                 if (left)
    3102         231 :                         l = rel_crossproduct(v->sql->sa, rel_dup(ll), rel_dup(r), op);
    3103             :                 else
    3104         768 :                         l = rel_crossproduct(v->sql->sa, rel_dup(lr), rel_dup(r), op);
    3105         999 :                 l->exps = nsexps;
    3106         999 :                 l->attr = nsattr;
    3107         999 :                 set_processed(l);
    3108         999 :                 if (left)
    3109         231 :                         l = rel_crossproduct(v->sql->sa, l, rel_dup(lr), lop);
    3110             :                 else
    3111         768 :                         l = rel_crossproduct(v->sql->sa, rel_dup(ll), l, lop);
    3112         999 :                 l->exps = njexps;
    3113         999 :                 l->attr = njattr;
    3114         999 :                 set_processed(l);
    3115         999 :                 rel_destroy(rel);
    3116         999 :                 rel = l;
    3117         999 :                 if (cycle <= 0)
    3118         587 :                         v->changes++;
    3119             :         }
    3120             :         return rel;
    3121             : }
    3122             : 
    3123             : /* antijoin(a, union(b,c)) -> antijoin(antijoin(a,b), c) */
    3124             : static inline sql_rel *
    3125        6563 : rel_rewrite_antijoin(visitor *v, sql_rel *rel)
    3126             : {
    3127        6563 :         sql_rel *l = rel->l;
    3128        6563 :         sql_rel *r = rel->r;
    3129             : 
    3130        6563 :         assert(rel->op == op_anti);
    3131        6563 :         if (l && !rel_is_ref(l) && r && !rel_is_ref(r) && is_union(r->op) && !is_single(r)) {
    3132           0 :                 sql_rel *rl = rel_dup(r->l), *nl;
    3133           0 :                 sql_rel *rr = rel_dup(r->r);
    3134             : 
    3135           0 :                 if (!is_project(rl->op))
    3136           0 :                         rl = rel_project(v->sql->sa, rl,
    3137             :                                 rel_projections(v->sql, rl, NULL, 1, 1));
    3138           0 :                 if (!is_project(rr->op))
    3139           0 :                         rr = rel_project(v->sql->sa, rr,
    3140             :                                 rel_projections(v->sql, rr, NULL, 1, 1));
    3141           0 :                 rel_rename_exps(v->sql, r->exps, rl->exps);
    3142           0 :                 rel_rename_exps(v->sql, r->exps, rr->exps);
    3143             : 
    3144           0 :                 nl = rel_crossproduct(v->sql->sa, rel->l, rl, op_anti);
    3145           0 :                 nl->exps = exps_copy(v->sql, rel->exps);
    3146           0 :                 nl->attr = exps_copy(v->sql, rel->attr);
    3147           0 :                 set_processed(nl);
    3148           0 :                 rel->l = nl;
    3149           0 :                 rel->r = rr;
    3150           0 :                 rel_destroy(r);
    3151           0 :                 v->changes++;
    3152           0 :                 return rel;
    3153             :         }
    3154             :         return rel;
    3155             : }
    3156             : 
    3157             : static sql_rel *
    3158     3464048 : rel_optimize_semi_and_anti_(visitor *v, sql_rel *rel)
    3159             : {
    3160             :         /* rewrite semijoin (A, join(A,B)) into semijoin (A,B) */
    3161     3464048 :         if (rel && is_semi(rel->op))
    3162       18919 :                 rel = rel_rewrite_semijoin(v, rel);
    3163             :         /* push semijoin through join */
    3164     3464048 :         if (rel && (is_semi(rel->op) || is_innerjoin(rel->op)))
    3165      467828 :                 rel = rel_push_semijoin_down_or_up(v, rel);
    3166             :         /* antijoin(a, union(b,c)) -> antijoin(antijoin(a,b), c) */
    3167     3464048 :         if (rel && rel->op == op_anti)
    3168        6563 :                 rel = rel_rewrite_antijoin(v, rel);
    3169     3464048 :         return rel;
    3170             : }
    3171             : 
    3172             : static sql_rel *
    3173       91310 : rel_optimize_semi_and_anti(visitor *v, global_props *gp, sql_rel *rel)
    3174             : {
    3175       91310 :         v->data = &gp->opt_cycle;
    3176       91310 :         rel = rel_visitor_bottomup(v, rel, &rel_optimize_semi_and_anti_);
    3177       91310 :         v->data = gp;
    3178       91310 :         return rel;
    3179             : }
    3180             : 
    3181             : run_optimizer
    3182      631283 : bind_optimize_semi_and_anti(visitor *v, global_props *gp)
    3183             : {
    3184             :         /* Important -> Re-write semijoins after rel_join_order */
    3185      631283 :         int flag = v->sql->sql_optimizer;
    3186      631110 :         return gp->opt_level == 1 && (gp->cnt[op_join] || gp->cnt[op_left] || gp->cnt[op_right]
    3187     1262393 :                    || gp->cnt[op_full] || gp->cnt[op_semi] || gp->cnt[op_anti]) && (flag & optimize_semi_and_anti) ? rel_optimize_semi_and_anti : NULL;
    3188             : }
    3189             : 
    3190             : 
    3191             : static sql_rel *
    3192     1610221 : rel_semijoin_use_fk(visitor *v, sql_rel *rel)
    3193             : {
    3194     1610221 :         if (is_semi(rel->op) && rel->exps) {
    3195        6604 :                 list *exps = rel->exps;
    3196        6604 :                 list *rels = sa_list(v->sql->sa);
    3197             : 
    3198        6604 :                 rel->exps = NULL;
    3199        6604 :                 append(rels, rel->l);
    3200        6604 :                 append(rels, rel->r);
    3201        6604 :                 (void) find_fk( v->sql, rels, exps);
    3202             : 
    3203        6604 :                 rel->exps = exps;
    3204             :         }
    3205     1610221 :         return rel;
    3206             : }
    3207             : 
    3208             : /*
    3209             :  * Push {semi}joins down, pushes the joins through group by expressions.
    3210             :  * When the join is on the group by columns, we can push the joins left
    3211             :  * under the group by. This should only be done, iff the new semijoin would
    3212             :  * reduce the input table to the groupby. So there should be a reduction
    3213             :  * (selection) on the table A and this should be propagated to the groupby via
    3214             :  * for example a primary key.
    3215             :  *
    3216             :  * {semi}join( A, groupby( B ) [gbe][aggrs] ) [ gbe == A.x ]
    3217             :  * ->
    3218             :  * {semi}join( A, groupby( semijoin(B,A) [gbe == A.x] ) [gbe][aggrs] ) [ gbe == A.x ]
    3219             :  */
    3220             : static inline sql_rel *
    3221     1610221 : rel_push_join_down(visitor *v, sql_rel *rel)
    3222             : {
    3223     1610221 :         if (!rel_is_ref(rel) && ((is_left(rel->op) || rel->op == op_join || is_semi(rel->op)) && rel->l && rel->exps)) {
    3224      233672 :                 sql_rel *gb = rel->r, *ogb = gb, *l = NULL, *rell = rel->l;
    3225             : 
    3226      233672 :                 if (is_simple_project(gb->op) && !rel_is_ref(gb))
    3227       46134 :                         gb = gb->l;
    3228             : 
    3229      233672 :                 if (rel_is_ref(rell) || !gb || rel_is_ref(gb))
    3230             :                         return rel;
    3231             : 
    3232      223762 :                 if (is_groupby(gb->op) && gb->r && list_length(gb->r)) {
    3233         190 :                         list *exps = rel->exps, *jes = new_exp_list(v->sql->sa), *gbes = gb->r;
    3234         190 :                         node *n, *m;
    3235             :                         /* find out if all group by expressions are used in the join */
    3236         195 :                         for(n = gbes->h; n; n = n->next) {
    3237         190 :                                 sql_exp *gbe = n->data;
    3238         190 :                                 int fnd = 0;
    3239         190 :                                 const char *rname = NULL, *name = NULL;
    3240             : 
    3241             :                                 /* project in between, ie find alias */
    3242             :                                 /* first find expression in expression list */
    3243         190 :                                 gbe = exps_uses_exp( gb->exps, gbe);
    3244         190 :                                 if (!gbe)
    3245           0 :                                         continue;
    3246         190 :                                 if (ogb != gb)
    3247         167 :                                         gbe = exps_uses_exp( ogb->exps, gbe);
    3248         190 :                                 if (gbe) {
    3249         149 :                                         rname = exp_find_rel_name(gbe);
    3250         149 :                                         name = exp_name(gbe);
    3251             :                                 }
    3252             : 
    3253         149 :                                 if (!name)
    3254          41 :                                         return rel;
    3255             : 
    3256         370 :                                 for (m = exps->h; m && !fnd; m = m->next) {
    3257         221 :                                         sql_exp *je = m->data;
    3258             : 
    3259         221 :                                         if (je->card >= CARD_ATOM && je->type == e_cmp &&
    3260         221 :                                             !is_complex_exp(je->flag)) {
    3261             :                                                 /* expect right expression to match */
    3262         221 :                                                 sql_exp *r = je->r;
    3263             : 
    3264         221 :                                                 if (r == 0 || r->type != e_column)
    3265          10 :                                                         continue;
    3266         211 :                                                 if (r->l && rname && strcmp(r->l, rname) == 0 && strcmp(r->r, name)==0) {
    3267             :                                                         fnd = 1;
    3268          83 :                                                 } else if (!r->l && !rname  && strcmp(r->r, name)==0) {
    3269             :                                                         fnd = 1;
    3270             :                                                 }
    3271             :                                                 if (fnd) {
    3272         128 :                                                         sql_exp *le = je->l;
    3273         128 :                                                         sql_exp *re = exp_push_down_prj(v->sql, r, gb, gb->l);
    3274         128 :                                                         if (!re || (list_length(jes) == 0 && !find_prop(le->p, PROP_HASHCOL))) {
    3275             :                                                                 fnd = 0;
    3276             :                                                         } else {
    3277           5 :                                                                 int anti = is_anti(je), semantics = is_semantics(je);
    3278             : 
    3279           5 :                                                                 je = exp_compare(v->sql->sa, le, re, je->flag);
    3280           5 :                                                                 if (anti) set_anti(je);
    3281           5 :                                                                 if (semantics) set_semantics(je);
    3282           5 :                                                                 list_append(jes, je);
    3283             :                                                         }
    3284             :                                                 }
    3285             :                                         }
    3286             :                                 }
    3287         149 :                                 if (!fnd)
    3288             :                                         return rel;
    3289             :                         }
    3290           5 :                         l = rel_dup(rel->l);
    3291             : 
    3292             :                         /* push join's left side (as semijoin) down group by */
    3293           5 :                         l = gb->l = rel_crossproduct(v->sql->sa, gb->l, l, op_semi);
    3294           5 :                         l->exps = jes;
    3295           5 :                         set_processed(l);
    3296           5 :                         v->changes++;
    3297           5 :                         return rel;
    3298             :                 }
    3299             :         }
    3300             :         return rel;
    3301             : }
    3302             : 
    3303             : static bool
    3304         728 : check_projection_on_foreignside(sql_rel *r, list *pexps, int fk_left)
    3305             : {
    3306             :         /* projection columns from the foreign side */
    3307         728 :         if (list_empty(pexps))
    3308             :                 return true;
    3309        3156 :         for (node *n = pexps->h; n; n = n->next) {
    3310        3091 :                 sql_exp *pe = n->data;
    3311             : 
    3312        3091 :                 if (pe && is_atom(pe->type))
    3313          23 :                         continue;
    3314        3068 :                 if (pe && !is_alias(pe->type))
    3315             :                         return false;
    3316             :                 /* check for columns from the pk side, then keep the join with the pk */
    3317        3047 :                 if ((fk_left && rel_find_exp(r->r, pe)) || (!fk_left && rel_find_exp(r->l, pe)))
    3318         594 :                         return false;
    3319             :         }
    3320             :         return true;
    3321             : }
    3322             : 
    3323             : static sql_rel *
    3324      240153 : rel_simplify_project_fk_join(mvc *sql, sql_rel *r, list *pexps, list *orderexps, int *changes)
    3325             : {
    3326      240153 :         sql_rel *rl = r->l, *rr = r->r, *nr = NULL;
    3327      240153 :         sql_exp *je, *le, *nje, *re;
    3328      240153 :         int fk_left = 1;
    3329             : 
    3330             :         /* check for foreign key join */
    3331      240153 :         if (list_length(r->exps) != 1 || !list_empty(r->attr))
    3332        7516 :                 return r;
    3333      232637 :         if (!(je = exps_find_prop(r->exps, PROP_JOINIDX)) || je->flag != cmp_equal)
    3334             :                 return r;
    3335             :         /* je->l == foreign expression, je->r == primary expression */
    3336        1204 :         if (rel_find_exp(r->l, je->l)) {
    3337             :                 fk_left = 1;
    3338          34 :         } else if (rel_find_exp(r->r, je->l)) {
    3339             :                 fk_left = 0;
    3340             :         } else { /* not found */
    3341             :                 return r;
    3342             :         }
    3343             : 
    3344             :         /* primary side must be a full table */
    3345        1170 :         if ((fk_left && (!is_left(r->op) && !is_full(r->op)) && !is_basetable(rr->op)) ||
    3346          34 :                 (!fk_left && (!is_right(r->op) && !is_full(r->op)) && !is_basetable(rl->op)))
    3347         554 :                 return r;
    3348             : 
    3349         650 :         if (!check_projection_on_foreignside(r, pexps, fk_left) || !check_projection_on_foreignside(r, orderexps, fk_left))
    3350         613 :                 return r;
    3351             : 
    3352             :         /* rewrite, ie remove pkey side if possible */
    3353          37 :         le = (sql_exp*)je->l, re = (sql_exp*)je->l;
    3354             : 
    3355             :         /* both have NULL and there are semantics, the join cannot be removed */
    3356          37 :         if (is_semantics(je) && has_nil(le) && has_nil(re))
    3357             :                 return r;
    3358             : 
    3359          37 :         (*changes)++;
    3360             :         /* if the foreign key column doesn't have NULL values, then return it */
    3361          37 :         if (!has_nil(le) || is_full(r->op) || (fk_left && is_left(r->op)) || (!fk_left && is_right(r->op))) {
    3362             :                 /* if ->attr, introduce group by on index */
    3363          31 :                 if (fk_left) {
    3364          23 :                         nr = rel_dup(r->l);
    3365             :                 } else {
    3366           8 :                         nr = rel_dup(r->r);
    3367             :                 }
    3368          31 :                 if (!list_empty(r->attr)) {
    3369           0 :                         nr = rel_groupby(sql, nr, NULL);
    3370           0 :                         if (nr) {
    3371             :                                 // printf("# introduced groupby  \n");
    3372           0 :                                 nr->r = append(sa_list(sql->sa), le);
    3373           0 :                                 nr->exps = r->attr;
    3374             :                         }
    3375             :                 }
    3376          31 :                 return nr;
    3377             :         }
    3378             : 
    3379             :         /* remove NULL values, ie generate a select not null */
    3380           6 :         nje = exp_compare(sql->sa, exp_ref(sql, le), exp_atom(sql->sa, atom_general(sql->sa, exp_subtype(le), NULL, 0)), cmp_equal);
    3381           6 :         set_anti(nje);
    3382           6 :         set_has_no_nil(nje);
    3383           6 :         set_semantics(nje);
    3384           6 :         if (fk_left) {
    3385           6 :                 nr = rel_dup(r->l);
    3386             :         } else {
    3387           0 :                 nr = rel_dup(r->r);
    3388             :         }
    3389           6 :         nr = rel_select(sql->sa, nr, nje);
    3390           6 :         set_processed(nr);
    3391           6 :         return nr;
    3392             : }
    3393             : 
    3394             : static sql_rel *
    3395        1853 : rel_simplify_count_fk_join(mvc *sql, sql_rel *r, list *gexps, list *gcols, int *changes)
    3396             : {
    3397        1853 :         sql_rel *rl = r->l, *rr = r->r, *nr = NULL;
    3398        1853 :         sql_exp *je, *le, *nje, *re, *oce;
    3399        1853 :         int fk_left = 1;
    3400             : 
    3401             :         /* check for foreign key join */
    3402        1853 :         if (list_length(r->exps) != 1)
    3403             :                 return r;
    3404        1852 :         if (!(je = exps_find_prop(r->exps, PROP_JOINIDX)) || je->flag != cmp_equal)
    3405             :                 return r;
    3406             :         /* je->l == foreign expression, je->r == primary expression */
    3407          63 :         if (rel_find_exp(r->l, je->l)) {
    3408             :                 fk_left = 1;
    3409           7 :         } else if (rel_find_exp(r->r, je->l)) {
    3410             :                 fk_left = 0;
    3411             :         } else { /* not found */
    3412             :                 return r;
    3413             :         }
    3414             : 
    3415          63 :         oce = gexps->h->data;
    3416          63 :         if (oce->l) /* we only handle COUNT(*) */
    3417             :                 return r;
    3418             : 
    3419             :         /* primary side must be a full table */
    3420          62 :         if ((fk_left && (!is_left(r->op) && !is_full(r->op)) && !is_basetable(rr->op)) ||
    3421           6 :                 (!fk_left && (!is_right(r->op) && !is_full(r->op)) && !is_basetable(rl->op)))
    3422             :                 return r;
    3423             : 
    3424          33 :         if (fk_left && is_join(rl->op) && !rel_is_ref(rl)) {
    3425          12 :                 r->l = rel_simplify_count_fk_join(sql, rl, gexps, gcols, changes);
    3426          12 :                 if (rl != r->l)
    3427           9 :                         rel_destroy(rl);
    3428             :         }
    3429          39 :         if (!fk_left && is_join(rr->op) && !rel_is_ref(rr)) {
    3430           2 :                 r->r = rel_simplify_count_fk_join(sql, rr, gexps, gcols, changes);
    3431           2 :                 if (rr != r->r)
    3432           2 :                         rel_destroy(rr);
    3433             :         }
    3434             : 
    3435          39 :         if (!check_projection_on_foreignside(r, gcols, fk_left))
    3436             :                 return r;
    3437             : 
    3438             :         /* rewrite, ie remove pkey side if possible */
    3439          37 :         le = (sql_exp*)je->l, re = (sql_exp*)je->l;
    3440             : 
    3441             :         /* both have NULL and there are semantics, the join cannot be removed */
    3442          37 :         if (is_semantics(je) && has_nil(le) && has_nil(re))
    3443             :                 return r;
    3444             : 
    3445          37 :         (*changes)++;
    3446             :         /* if the foreign key column doesn't have NULL values, then return it */
    3447          37 :         if (!has_nil(le) || is_full(r->op) || (fk_left && is_left(r->op)) || (!fk_left && is_right(r->op))) {
    3448          31 :                 if (fk_left) {
    3449          25 :                         nr = rel_dup(r->l);
    3450             :                 } else {
    3451           6 :                         nr = rel_dup(r->r);
    3452             :                 }
    3453          31 :                 return nr;
    3454             :         }
    3455             : 
    3456             :         /* remove NULL values, ie generate a select not null */
    3457           6 :         nje = exp_compare(sql->sa, exp_ref(sql, le), exp_atom(sql->sa, atom_general(sql->sa, exp_subtype(le), NULL, 0)), cmp_equal);
    3458           6 :         set_anti(nje);
    3459           6 :         set_has_no_nil(nje);
    3460           6 :         set_semantics(nje);
    3461           6 :         if (fk_left) {
    3462           6 :                 nr = rel_dup(r->l);
    3463             :         } else {
    3464           0 :                 nr = rel_dup(r->r);
    3465             :         }
    3466           6 :         nr = rel_select(sql->sa, nr, nje);
    3467           6 :         set_processed(nr);
    3468           6 :         return nr;
    3469             : }
    3470             : 
    3471             : /*
    3472             :  * Handle (left/right/outer/natural) join fk-pk rewrites
    3473             :  *   1 group by ( fk-pk-join () ) [ count(*) ] -> group by ( fk )
    3474             :  *   2 project ( fk-pk-join () ) [ fk-column ] -> project (fk table)[ fk-column ]
    3475             :  *   3 project ( fk1-pk1-join( fk2-pk2-join()) [ fk-column, pk1 column ] -> project (fk1-pk1-join)[ fk-column, pk1 column ]
    3476             :  */
    3477             : static inline sql_rel *
    3478     3689693 : rel_simplify_fk_joins(visitor *v, sql_rel *rel)
    3479             : {
    3480     3689693 :         sql_rel *r = NULL;
    3481             : 
    3482     3689693 :         if (is_simple_project(rel->op))
    3483     1204891 :                 r = rel->l;
    3484             : 
    3485     3689730 :         while (is_simple_project(rel->op) && r && list_length(r->exps) == 1 && (is_join(r->op) || r->op == op_semi) && !(rel_is_ref(r))) {
    3486      240153 :                 sql_rel *or = r;
    3487             : 
    3488      240153 :                 r = rel_simplify_project_fk_join(v->sql, r, rel->exps, rel->r, &v->changes);
    3489      240153 :                 if (r == or)
    3490             :                         return rel;
    3491          37 :                 rel_destroy(rel->l);
    3492          37 :                 rel->l = r;
    3493             :         }
    3494             : 
    3495     3449576 :         if (!is_groupby(rel->op))
    3496             :                 return rel;
    3497             : 
    3498       90678 :         r = rel->l;
    3499      134945 :         while(r && is_simple_project(r->op))
    3500       44267 :                 r = r->l;
    3501             : 
    3502      105179 :         while (is_groupby(rel->op) && !rel_is_ref(rel) && r && (is_join(r->op) || r->op == op_semi) && list_length(r->exps) == 1 && !(rel_is_ref(r)) &&
    3503             :                    /* currently only single count aggregation is handled, no other projects or aggregation */
    3504      109214 :                    list_length(rel->exps) == 1 && exp_aggr_is_count(rel->exps->h->data)) {
    3505        1839 :                 sql_rel *or = r;
    3506             : 
    3507        1839 :                 r = rel_simplify_count_fk_join(v->sql, r, rel->exps, rel->r, &v->changes);
    3508        1839 :                 if (r == or)
    3509             :                         return rel;
    3510          26 :                 rel_destroy(rel->l);
    3511          26 :                 rel->l = r;
    3512             :         }
    3513             :         return rel;
    3514             : }
    3515             : 
    3516             : /*
    3517             :  * Gets the column expressions of a diff function and adds them to "columns".
    3518             :  * The diff function has two possible argument types: either a sql_exp representing a column
    3519             :  * or a sql_exp representing another diff function, therefore this function is recursive.
    3520             :  */
    3521             : static void
    3522         168 : get_diff_function_columns(sql_exp *diffExp, list *columns) {
    3523         168 :         list *args = diffExp->l;
    3524             : 
    3525         370 :         for (node *arg = args->h; arg; arg = arg->next) {
    3526         202 :                 sql_exp *exp = arg->data;
    3527             : 
    3528             :                 // diff function
    3529         202 :                 if (exp->type == e_func) {
    3530          34 :                         get_diff_function_columns(exp, columns);
    3531             :                 }
    3532             :                 // column
    3533             :                 else {
    3534         168 :                         list_append(columns, exp);
    3535             :                 }
    3536             :         }
    3537         168 : }
    3538             : 
    3539             : /*
    3540             :  * Builds a list of aggregation key columns to be used by the select push down algorithm, namely for
    3541             :  * window functions. Returns NULL if the window function does not partition by any column
    3542             :  */
    3543             : static list *
    3544        1735 : get_partition_by_key_columns(allocator *sa, sql_rel *r) {
    3545       18832 :         for (node* n = r->exps->h; n; n = n->next) {
    3546       17321 :                 sql_exp *e = n->data;
    3547             : 
    3548       17321 :                 if (e->type == e_func) {
    3549        6035 :                         sql_subfunc *f = e->f;
    3550             : 
    3551             :                         // aggregation function
    3552        6035 :                         if (!strcmp(f->func->base.name, "rank")) {
    3553         224 :                                 list* rankArguments = e->l;
    3554             :                                 // the partition key is the second argument
    3555         224 :                                 sql_exp *partitionExp = rankArguments->h->next->data;
    3556             : 
    3557             :                                 // check if the key contains any columns, i.e., is a diff function
    3558         224 :                                 if (partitionExp->type == e_func) {
    3559             :                                         // get columns to list
    3560         134 :                                         list *aggColumns = sa_list(sa);
    3561         134 :                                         get_diff_function_columns(partitionExp, aggColumns);
    3562         134 :                                         return aggColumns;
    3563             :                                 }
    3564             :                                 // the function has no aggregation columns (e_atom of boolean)
    3565             :                                 else {
    3566             :                                         return NULL;
    3567             :                                 }
    3568             : 
    3569             :                         }
    3570             :                 }
    3571             :         }
    3572             :         return NULL;
    3573             : }
    3574             : 
    3575             : /*
    3576             : static bool
    3577             : rank_exp_has_partition_key(sql_exp *e)
    3578             : {
    3579             :         if (e->type == e_func) {
    3580             :                 sql_subfunc *f = e->f;
    3581             : 
    3582             :                 if (f->func->type == F_ANALYTIC) {
    3583             :                         list *args = e->l;
    3584             : 
    3585             :                         if (list_length(args) >= 2) { // the partition key is the second argument
    3586             :                                 return true;
    3587             :                         }
    3588             :                 }
    3589             :         }
    3590             :         return false;
    3591             : }
    3592             : */
    3593             : 
    3594             : /*
    3595             :  * Checks if a filter column is also used as an aggregation key, so it can be later safely pushed down.
    3596             :  */
    3597             : static int
    3598         187 : filter_column_in_partition_by_columns(sql_exp *column, list *keyColumns)
    3599             : {
    3600             :         /* check if it is a column or an e_convert, and get the actual column if it is the latter */
    3601         187 :         if (column->type == e_convert) {
    3602           1 :                 column = column->l;
    3603             :         }
    3604             : 
    3605         187 :         char *tableName = column->l;
    3606         187 :         char *columnName = column->r;
    3607             : 
    3608         404 :         for (node *n = keyColumns->h; n; n = n->next) {
    3609         226 :                 sql_exp *keyCol = n->data;
    3610         226 :                 char *keyColTableName = keyCol->l;
    3611         226 :                 char *keyColColumnName = keyCol->r;
    3612             : 
    3613         226 :                 if (!strcmp(tableName, keyColTableName) && !strcmp(columnName, keyColColumnName)) {
    3614             :                         /* match */
    3615             :                         return 1;
    3616             :                 }
    3617             :         }
    3618             : 
    3619             :         /* no matches found */
    3620             :         return 0;
    3621             : }
    3622             : 
    3623             : /*
    3624             :  * Push select down, pushes the selects through (simple) projections. Also
    3625             :  * it cleans up the projections which become useless.
    3626             :  *
    3627             :  * WARNING - Make sure to call try_remove_empty_select macro before returning so we ensure
    3628             :  * possible generated empty selects won't never be generated
    3629             :  */
    3630             : static sql_rel *
    3631     7303985 : rel_push_select_down(visitor *v, sql_rel *rel)
    3632             : {
    3633     7303985 :         list *exps = NULL;
    3634     7303985 :         sql_rel *r = NULL;
    3635     7303985 :         node *n;
    3636             : 
    3637     7303985 :         if (rel_is_ref(rel)) {
    3638      375278 :                 if (is_select(rel->op) && !list_empty(rel->exps)) {
    3639             :                         /* add inplace empty select */
    3640        1741 :                         sql_rel *l = rel_select(v->sql->sa, rel->l, NULL);
    3641             : 
    3642        1741 :                         l->exps = rel->exps;
    3643        1741 :                         set_processed(l);
    3644        1741 :                         rel->exps = NULL;
    3645        1741 :                         rel->l = l;
    3646        1741 :                         v->changes++;
    3647             :                 }
    3648      375278 :                 return rel;
    3649             :         }
    3650             : 
    3651             :         /* don't make changes for empty selects */
    3652     6928707 :         if (is_select(rel->op) && list_empty(rel->exps))
    3653          10 :                 return try_remove_empty_select(v, rel);
    3654             : 
    3655             :         /* merge 2 selects */
    3656     6928699 :         r = rel->l;
    3657     6928699 :         if (is_select(rel->op) && r && r->exps && is_select(r->op) && !(rel_is_ref(r)) && !exps_have_func(rel->exps)) {
    3658          27 :                 (void)list_merge(r->exps, rel->exps, (fdup)NULL);
    3659          27 :                 rel->l = NULL;
    3660          27 :                 rel_destroy(rel);
    3661          27 :                 v->changes++;
    3662          27 :                 return try_remove_empty_select(v, r);
    3663             :         }
    3664             :         /*
    3665             :          * Push select through semi/anti join
    3666             :          *      select (semi(A,B)) == semi(select(A), B)
    3667             :          */
    3668     6928672 :         if (is_select(rel->op) && r && is_semi(r->op) && !(rel_is_ref(r))) {
    3669         328 :                 rel->l = r->l;
    3670         328 :                 r->l = rel;
    3671         328 :                 v->changes++;
    3672             :                 /*
    3673             :                  * if A has 2 references (ie used on both sides of
    3674             :                  * the semi join), we also push the select into A.
    3675             :                  */
    3676         328 :                 if (rel_is_ref(rel->l) && rel->l == rel_find_ref(r->r)){
    3677           0 :                         sql_rel *lx = rel->l;
    3678           0 :                         sql_rel *rx = r->r;
    3679           0 :                         if (lx->ref.refcnt == 2 && !rel_is_ref(rx)) {
    3680           0 :                                 while (rx->l && !rel_is_ref(rx->l) &&
    3681           0 :                                        (is_project(rx->op) ||
    3682             :                                         is_select(rx->op) ||
    3683             :                                         is_join(rx->op)))
    3684             :                                                 rx = rx->l;
    3685             :                                 /* probably we need to introduce a project */
    3686           0 :                                 rel_destroy(rel->l);
    3687           0 :                                 lx = rel_project(v->sql->sa, rel, rel_projections(v->sql, rel, NULL, 1, 1));
    3688           0 :                                 r->l = lx;
    3689           0 :                                 rx->l = rel_dup(lx);
    3690             :                         }
    3691             :                 }
    3692         328 :                 return r;
    3693             :         }
    3694     6928344 :         exps = rel->exps;
    3695             : 
    3696             :         /* push select through join */
    3697     6928344 :         if (is_select(rel->op) && r && is_join(r->op) && !rel_is_ref(r) && !is_single(r)){
    3698       22277 :                 sql_rel *jl = r->l, *ojl = jl, *jr = r->r, *ojr = jr;
    3699       22277 :                 int left = r->op == op_join || r->op == op_left;
    3700       22277 :                 int right = r->op == op_join || r->op == op_right;
    3701             : 
    3702       22277 :                 if (r->op == op_full)
    3703             :                         return rel;
    3704             : 
    3705             :                 /* introduce selects under the join (if needed) */
    3706       22255 :                 set_processed(jl);
    3707       22255 :                 set_processed(jr);
    3708       48966 :                 for (n = exps->h; n;) {
    3709       26711 :                         node *next = n->next;
    3710       26711 :                         sql_exp *e = n->data;
    3711             : 
    3712       26711 :                         if (!exp_unsafe(e, false, true)) {
    3713       26501 :                                 if (left && rel_rebind_exp(v->sql, jl, e)) {
    3714       13532 :                                         if (!is_select(jl->op) || rel_is_ref(jl))
    3715       11296 :                                                 r->l = jl = rel_select(v->sql->sa, jl, NULL);
    3716       13532 :                                         rel_select_add_exp(v->sql->sa, jl, e);
    3717       13532 :                                         list_remove_node(exps, NULL, n);
    3718       13532 :                                         v->changes++;
    3719       12969 :                                 } else if (right && rel_rebind_exp(v->sql, jr, e)) {
    3720        5224 :                                         if (!is_select(jr->op) || rel_is_ref(jr))
    3721        4257 :                                                 r->r = jr = rel_select(v->sql->sa, jr, NULL);
    3722        5224 :                                         rel_select_add_exp(v->sql->sa, jr, e);
    3723        5224 :                                         list_remove_node(exps, NULL, n);
    3724        5224 :                                         v->changes++;
    3725             :                                 }
    3726             :                         }
    3727             :                         n = next;
    3728             :                 }
    3729       22255 :                 if (ojl != jl)
    3730       11296 :                         set_processed(jl);
    3731       22255 :                 if (ojr != jr)
    3732        4257 :                         set_processed(jr);
    3733             :         }
    3734             : 
    3735             :         /* merge select and cross product ? */
    3736     6928322 :         if (is_select(rel->op) && r && r->op == op_join && !rel_is_ref(r) && !is_single(r) && !exps_have_unsafe(exps, false, true)) {
    3737       14502 :                 for (n = exps->h; n;) {
    3738        1834 :                         node *next = n->next;
    3739        1834 :                         sql_exp *e = n->data;
    3740             : 
    3741        1834 :                         if (exp_is_join(e, NULL) == 0) {
    3742         498 :                                 if (!r->exps)
    3743         151 :                                         r->exps = sa_list(v->sql->sa);
    3744         498 :                                 append(r->exps, e);
    3745         498 :                                 list_remove_node(exps, NULL, n);
    3746         498 :                                 v->changes++;
    3747             :                         }
    3748             :                         n = next;
    3749             :                 }
    3750             :         }
    3751             : 
    3752     6928322 :         if (is_select(rel->op) && r && (is_simple_project(r->op) || (is_groupby(r->op) && !list_empty(r->r))) && !rel_is_ref(r) && !is_single(r)){
    3753       78434 :                 sql_rel *pl = r->l, *opl = pl;
    3754             :                 /* we cannot push through window functions (for safety I disabled projects over DDL too) */
    3755       78434 :                 if (pl && pl->op != op_ddl && !exps_have_unsafe(r->exps, false, false)) {
    3756             :                         /* introduce selects under the project (if needed) */
    3757       58786 :                         set_processed(pl);
    3758       58786 :                         if (!pl->exps)
    3759         417 :                                 pl->exps = sa_list(v->sql->sa);
    3760      125304 :                         for (n = exps->h; n;) {
    3761       66518 :                                 node *next = n->next;
    3762       66518 :                                 sql_exp *e = n->data, *ne = NULL;
    3763             : 
    3764             :                                 /* can we move it down */
    3765       66518 :                                 if (e->type == e_cmp && (ne = exp_push_down_prj(v->sql, e, r, pl)) && ne != e) {
    3766       36967 :                                         if (!(is_select(pl->op) && is_join(pl->op) && is_semi(pl->op)) || rel_is_ref(pl))
    3767       36967 :                                                 r->l = pl = rel_select(v->sql->sa, pl, NULL);
    3768       36967 :                                         rel_select_add_exp(v->sql->sa, pl, ne);
    3769       36967 :                                         list_remove_node(exps, NULL, n);
    3770       36967 :                                         v->changes++;
    3771             :                                 }
    3772             :                                 n = next;
    3773             :                         }
    3774       58786 :                         if (opl != pl)
    3775       28399 :                                 set_processed(pl);
    3776             :                 }
    3777             : 
    3778             :                 /* push filters if they match the partition by key on a window function */
    3779        1735 :                 else if (pl && pl->op != op_ddl && exps_have_unsafe(r->exps, false, false)) {
    3780        1735 :                         set_processed(pl);
    3781             :                         /* list of partition by key columns */
    3782        1735 :                         list *keyColumns = get_partition_by_key_columns(v->sql->sa, r);
    3783             : 
    3784             :                         /* partition by keys found, check if any filter matches them */
    3785        1735 :                         if (keyColumns) {
    3786         325 :                                 for (n = exps->h; n;) {
    3787         191 :                                         node *next = n->next;
    3788         191 :                                         sql_exp *e = n->data, *ne = NULL;
    3789             : 
    3790         191 :                                         if (e->type == e_cmp) {
    3791             :                                                 /* simple comparison filter */
    3792         191 :                                                 if (e->flag == cmp_gt || e->flag == cmp_gte || e->flag == cmp_lte || e->flag == cmp_lt
    3793         191 :                                                         || e->flag == cmp_equal || e->flag == cmp_notequal || e->flag == cmp_in || e->flag == cmp_notin
    3794           5 :                                                         || (e->flag == cmp_filter && ((list*)e->l)->cnt == 1)) {
    3795         187 :                                                         sql_exp* column;
    3796             :                                                         /* the column in 'like' filters is stored inside a list */
    3797         187 :                                                         if (e->flag == cmp_filter) {
    3798           1 :                                                                 column = ((list*)e->l)->h->data;
    3799             :                                                         } else {
    3800         186 :                                                                 column = e->l;
    3801             :                                                         }
    3802             : 
    3803             :                                                         /* check if the expression matches any partition by key, meaning we can
    3804             :                                                            try to safely push it down */
    3805         187 :                                                         if (filter_column_in_partition_by_columns(column, keyColumns)) {
    3806           9 :                                                                 ne = exp_push_down_prj(v->sql, e, r, pl);
    3807             : 
    3808             :                                                                 /* can we move it down */
    3809           9 :                                                                 if (ne && ne != e && pl->exps) {
    3810           9 :                                                                         if (!is_select(pl->op) || rel_is_ref(pl))
    3811           8 :                                                                                 r->l = pl = rel_select(v->sql->sa, pl, NULL);
    3812           9 :                                                                         rel_select_add_exp(v->sql->sa, pl, ne);
    3813           9 :                                                                         list_remove_node(exps, NULL, n);
    3814           9 :                                                                         v->changes++;
    3815             :                                                                 }
    3816             :                                                         }
    3817             :                                                 }
    3818             :                                         }
    3819             :                                         n = next;
    3820             :                                 }
    3821             : 
    3822             :                                 /* cleanup list */
    3823         134 :                                 list_destroy(keyColumns);
    3824             :                         }
    3825             :                         /* also push (rewrite) limits on output of row_number/(*)rank like window functions */
    3826        1735 :                         if (is_simple_project(r->op) /*&& is_simple_project(pl->op)*/) { /* possible window functions */
    3827        3653 :                                 for (n = exps->h; n; n = n->next) {
    3828        1926 :                                         sql_exp *e = n->data;
    3829             : 
    3830        1926 :                                         if (e->type == e_cmp && (e->flag == cmp_lt || e->flag == cmp_lte) && exp_is_atom(e->r)) { /* simple limit */
    3831          80 :                                                 sql_exp *ranke = rel_find_exp(r, e->l);
    3832             : 
    3833          80 :                                                 if (ranke && ranke->type == e_func) {
    3834          75 :                                                         sql_subfunc *rankf = ranke->f;
    3835          75 :                                                         if (rankf->func->type == F_ANALYTIC) { /* rank functions cannot have a frame */
    3836             :                                                                 // For now only for rank/row_number without partition by
    3837          74 :                                                                 sql_rel *tn = NULL;
    3838          74 :                                                                 if (strcmp(rankf->func->base.name, "rank") == 0 && is_simple_project(pl->op) && pl->r /* &&
    3839             :                                                                                 !rank_exp_has_partition_key(ranke)*/) {
    3840           6 :                                                                         tn = r->l = rel_topn(v->sql->sa, r->l, append(sa_list(v->sql->sa), e->r));
    3841           6 :                                                                         tn->grouped = 1;
    3842           6 :                                                                         v->changes++;
    3843           6 :                                                                         break;
    3844             :                                                                 }
    3845          68 :                                                                 if (strcmp(rankf->func->base.name, "row_number") == 0 && list_empty(r->r) && !is_topn(pl->op) /*&&
    3846             :                                                                                 !rank_exp_has_partition_key(ranke)*/) {
    3847           2 :                                                                         tn = r->l = rel_topn(v->sql->sa, r->l, append(sa_list(v->sql->sa), e->r));
    3848           2 :                                                                         tn->grouped = 1;
    3849           2 :                                                                         v->changes++;
    3850           2 :                                                                         break;
    3851             :                                                                 }
    3852             :                                                         }
    3853             :                                                 }
    3854             :                                         }
    3855             :                                 }
    3856             :                         }
    3857             :                 }
    3858             :         }
    3859             : 
    3860             :         /* try push select under set relation */
    3861     6928322 :         if (is_select(rel->op) && r && is_set(r->op) && !list_empty(r->exps) && !rel_is_ref(r) && !is_single(r) && !list_empty(exps)) {
    3862          19 :                 sql_rel *u = r, *ul = u->l, *ur = u->r;
    3863             : 
    3864          19 :                 ul = rel_dup(ul);
    3865          19 :                 ur = rel_dup(ur);
    3866          19 :                 if (!is_project(ul->op))
    3867           0 :                         ul = rel_project(v->sql->sa, ul,
    3868             :                                 rel_projections(v->sql, ul, NULL, 1, 1));
    3869          19 :                 if (!is_project(ur->op))
    3870           0 :                         ur = rel_project(v->sql->sa, ur,
    3871             :                                 rel_projections(v->sql, ur, NULL, 1, 1));
    3872          19 :                 rel_rename_exps(v->sql, u->exps, ul->exps);
    3873          19 :                 rel_rename_exps(v->sql, u->exps, ur->exps);
    3874             : 
    3875             :                 /* introduce selects under the set */
    3876          19 :                 ul = rel_select(v->sql->sa, ul, NULL);
    3877          19 :                 ul->exps = exps_copy(v->sql, exps);
    3878          19 :                 set_processed(ul);
    3879          19 :                 ur = rel_select(v->sql->sa, ur, NULL);
    3880          19 :                 ur->exps = exps_copy(v->sql, exps);
    3881          19 :                 set_processed(ur);
    3882             : 
    3883          19 :                 rel = rel_inplace_setop(v->sql, rel, ul, ur, u->op, rel_projections(v->sql, rel, NULL, 1, 1));
    3884          19 :                 if (need_distinct(u))
    3885           0 :                         set_distinct(rel);
    3886          19 :                 v->changes++;
    3887             :         }
    3888     6928322 :         if (is_select(rel->op) && r && is_munion(r->op) && !is_recursive(r) && !list_empty(r->exps) && !rel_is_ref(r) && !is_single(r) && !list_empty(exps)) {
    3889        4953 :                 sql_rel *u = r;
    3890        4953 :                 list *rels = u->l, *nrels = sa_list(v->sql->sa);
    3891       14867 :                 for(node *n = rels->h; n; n = n->next) {
    3892        9914 :                         sql_rel *ul = n->data;
    3893        9914 :                         ul = rel_dup(ul);
    3894        9914 :                         if (!is_project(ul->op) || rel_is_ref(ul))
    3895        9914 :                                 ul = rel_project(v->sql->sa, ul,
    3896             :                                         rel_projections(v->sql, ul, NULL, 1, 1));
    3897        9914 :                         rel_rename_exps(v->sql, u->exps, ul->exps);
    3898             : 
    3899             :                         /* introduce selects under the set */
    3900        9914 :                         ul = rel_select(v->sql->sa, ul, NULL);
    3901        9914 :                         ul->exps = exps_copy(v->sql, exps);
    3902        9914 :                         set_processed(ul);
    3903        9914 :                         nrels = append(nrels, ul);
    3904             :                 }
    3905             : 
    3906        4953 :                 rel = rel_inplace_setop_n_ary(v->sql, rel, nrels, u->op, rel_projections(v->sql, rel, NULL, 1, 1));
    3907        4953 :                 if (need_distinct(u))
    3908           8 :                         set_distinct(rel);
    3909        4953 :                 if (is_recursive(u))
    3910           0 :                         set_recursive(rel);
    3911        4953 :                 v->changes++;
    3912             :         }
    3913             : 
    3914     6928322 :         return try_remove_empty_select(v, rel);
    3915             : }
    3916             : 
    3917             : static int
    3918       12033 : index_exp(sql_exp *e, sql_idx *i)
    3919             : {
    3920       12033 :         if (e->type == e_cmp && !is_complex_exp(e->flag)) {
    3921        6776 :                 switch(i->type) {
    3922        6776 :                 case hash_idx:
    3923             :                 case oph_idx:
    3924        6776 :                         if (e->flag == cmp_equal)
    3925             :                                 return 0;
    3926             :                         /* fall through */
    3927             :                 case join_idx:
    3928             :                 default:
    3929        1252 :                         return -1;
    3930             :                 }
    3931             :         }
    3932             :         return -1;
    3933             : }
    3934             : 
    3935             : /* find column for the select/join expression */
    3936             : static sql_column *
    3937        5524 : sjexp_col(sql_exp *e, sql_rel *r)
    3938             : {
    3939        5524 :         sql_column *res = NULL;
    3940             : 
    3941        5524 :         if (e->type == e_cmp && !is_complex_exp(e->flag)) {
    3942        5524 :                 res = exp_find_column(r, e->l, -2);
    3943        5524 :                 if (!res)
    3944         466 :                         res = exp_find_column(r, e->r, -2);
    3945             :         }
    3946        5524 :         return res;
    3947             : }
    3948             : 
    3949             : static sql_idx *
    3950     1783018 : find_index(allocator *sa, sql_rel *rel, sql_rel *sub, list **EXPS)
    3951             : {
    3952     1783018 :         node *n;
    3953             : 
    3954             :         /* any (partial) match of the expressions with the index columns */
    3955             :         /* Depending on the index type we may need full matches and only
    3956             :            limited number of cmp types (hash only equality etc) */
    3957             :         /* Depending on the index type we should (in the rel_bin) generate
    3958             :            more code, ie for spatial index add post filter etc, for hash
    3959             :            compute hash value and use index */
    3960             : 
    3961     1783018 :         if (sub->exps && rel->exps)
    3962     7118892 :         for(n = sub->exps->h; n; n = n->next) {
    3963     5521439 :                 prop *p;
    3964     5521439 :                 sql_exp *e = n->data;
    3965             : 
    3966     5521439 :                 if ((p = find_prop(e->p, PROP_HASHIDX)) != NULL) {
    3967        9409 :                         list *exps, *cols;
    3968        9409 :                         sql_idx *i = p->value.pval;
    3969        9409 :                         fcmp cmp = (fcmp)&sql_column_kc_cmp;
    3970             : 
    3971             :                         /* join indices are only interesting for joins */
    3972        9409 :                         if (i->type == join_idx || list_length(i->columns) <= 1)
    3973           0 :                                 continue;
    3974             :                         /* based on the index type, find qualifying exps */
    3975        9409 :                         exps = list_select(rel->exps, i, (fcmp) &index_exp, (fdup)NULL);
    3976        9409 :                         if (list_empty(exps))
    3977        4849 :                                 continue;
    3978             :                         /* now we obtain the columns, move into sql_column_kc_cmp! */
    3979        4560 :                         cols = list_map(exps, sub, (fmap) &sjexp_col);
    3980             : 
    3981             :                         /* TODO check that at most 2 relations are involved */
    3982             : 
    3983             :                         /* Match the index columns with the expression columns.
    3984             :                            TODO, Allow partial matches ! */
    3985        4560 :                         if (list_match(cols, i->columns, cmp) == 0) {
    3986             :                                 /* re-order exps in index order */
    3987         286 :                                 node *n, *m;
    3988         286 :                                 list *es = sa_list(sa);
    3989             : 
    3990         958 :                                 for(n = i->columns->h; n; n = n->next) {
    3991         672 :                                         int i = 0;
    3992        2152 :                                         for(m = cols->h; m; m = m->next, i++) {
    3993        2152 :                                                 if (cmp(m->data, n->data) == 0){
    3994         672 :                                                         sql_exp *e = list_fetch(exps, i);
    3995         672 :                                                         list_append(es, e);
    3996         672 :                                                         break;
    3997             :                                                 }
    3998             :                                         }
    3999             :                                 }
    4000             :                                 /* fix the destroy function */
    4001         286 :                                 cols->destroy = NULL;
    4002         286 :                                 *EXPS = es;
    4003         286 :                                 e->used = 1;
    4004         286 :                                 return i;
    4005             :                         }
    4006        4274 :                         cols->destroy = NULL;
    4007             :                 }
    4008             :         }
    4009             :         return NULL;
    4010             : }
    4011             : 
    4012             : static inline sql_rel *
    4013     1163403 : rel_use_index(visitor *v, sql_rel *rel)
    4014             : {
    4015     1163403 :         list *exps = NULL;
    4016     1163403 :         sql_idx *i = find_index(v->sql->sa, rel, rel->l, &exps);
    4017     1163403 :         int left = 1;
    4018             : 
    4019     1163403 :         assert(is_select(rel->op) || is_join(rel->op));
    4020     1163403 :         if (!i && is_join(rel->op)) {
    4021      619615 :                 left = 0;
    4022      619615 :                 i = find_index(v->sql->sa, rel, rel->r, &exps);
    4023             :         }
    4024             : 
    4025     1163223 :         if (i) {
    4026         286 :                 prop *p;
    4027         286 :                 node *n;
    4028         286 :                 int single_table = 1;
    4029         286 :                 sql_exp *re = NULL;
    4030             : 
    4031         956 :                 for( n = exps->h; n && single_table; n = n->next) {
    4032         670 :                         sql_exp *e = n->data, *nre = e->l;
    4033             : 
    4034         670 :                         if (!is_compare(e->type) || is_anti(e) || e->flag != cmp_equal)
    4035             :                                 return rel;
    4036         670 :                         if (is_join(rel->op) && ((left && !rel_find_exp(rel->l, nre)) || (!left && rel_find_exp(rel->r, nre))))
    4037         111 :                                 nre = e->r;
    4038         670 :                         single_table = (!re || (exp_relname(nre) && exp_relname(re) && strcmp(exp_relname(nre), exp_relname(re)) == 0));
    4039         670 :                         re = nre;
    4040             :                 }
    4041         286 :                 if (single_table) { /* add PROP_HASHCOL to all column exps */
    4042         932 :                         for( n = exps->h; n; n = n->next) {
    4043         654 :                                 sql_exp *e = n->data;
    4044             : 
    4045             :                                 /* swapped ? */
    4046         654 :                                 if (is_join(rel->op) && ((left && !rel_find_exp(rel->l, e->l)) || (!left && !rel_find_exp(rel->r, e->l)))) {
    4047         165 :                                         exp_swap(e);
    4048             :                                 }
    4049         654 :                                 p = find_prop(e->p, PROP_HASHCOL);
    4050         654 :                                 if (!p)
    4051         285 :                                         e->p = p = prop_create(v->sql->sa, PROP_HASHCOL, e->p);
    4052         654 :                                 p->value.pval = i;
    4053             :                         }
    4054             :                 }
    4055             :                 /* add the remaining exps to the new exp list */
    4056         286 :                 if (list_length(rel->exps) > list_length(exps)) {
    4057         108 :                         for( n = rel->exps->h; n; n = n->next) {
    4058          81 :                                 sql_exp *e = n->data;
    4059          81 :                                 if (!list_find(exps, e, (fcmp)&exp_cmp))
    4060          27 :                                         list_append(exps, e);
    4061             :                         }
    4062             :                 }
    4063         286 :                 rel->exps = exps;
    4064             :         }
    4065             :         return rel;
    4066             : }
    4067             : 
    4068             : static sql_rel *
    4069     3689692 : rel_select_leftgroup_2_semi(visitor *v, sql_rel *rel)
    4070             : {
    4071     3689692 :         if (rel_is_ref(rel) || !is_select(rel->op) || list_empty(rel->exps))
    4072     3156228 :                 return rel;
    4073      533464 :         sql_rel *l = rel->l;
    4074             : 
    4075      533464 :         if (!l || rel_is_ref(l) || !is_left(l->op) || list_empty(l->attr))
    4076      532478 :                 return rel;
    4077             : 
    4078        1964 :         for(node *n = rel->exps->h; n; n = n->next) {
    4079         986 :                 sql_exp *e = n->data;
    4080             : 
    4081         986 :                 if (e->type == e_cmp && !is_semantics(e) && !e->f) {
    4082         973 :                         list *attrs = l->attr;
    4083         973 :                         sql_exp *a = attrs->h->data;
    4084             : 
    4085         973 :                         if (exps_find_exp(l->attr, e->l) && exp_is_true(e->r) && e->flag == cmp_equal /*&& exp_is_true(a)*/) {
    4086             :                                 // printf("# optimize select leftgroup -> semi\n");
    4087           8 :                                 if (!list_empty(l->exps)) {
    4088          13 :                                         for(node *m = l->exps->h; m; m = m->next) {
    4089           7 :                                                 sql_exp *j = m->data;
    4090           7 :                                                 reset_any(j);
    4091             :                                         }
    4092             :                                 }
    4093           8 :                                 l->attr = NULL;
    4094           8 :                                 l->op = exp_is_true(a)?op_semi:op_anti;
    4095           8 :                                 list_remove_node(rel->exps, NULL, n);
    4096           8 :                                 rel = rel_project(v->sql->sa, rel, rel_projections(v->sql, rel, NULL, 1, 1));
    4097           8 :                                 list_append(rel->exps, attrs->h->data);
    4098           8 :                                 v->changes++;
    4099           8 :                                 return rel;
    4100             :                         }
    4101             :                 }
    4102             :         }
    4103             :         return rel;
    4104             : }
    4105             : 
    4106             : static sql_rel *
    4107     3689692 : rel_optimize_select_and_joins_topdown_(visitor *v, sql_rel *rel)
    4108             : {
    4109             :         /* push_join_down introduces semijoins */
    4110     3689692 :         uint8_t cycle = *(uint8_t*) v->data;
    4111     3689692 :         if (cycle <= 0) {
    4112     1610221 :                 rel = rel_semijoin_use_fk(v, rel);
    4113     1610221 :                 rel = rel_push_join_down(v, rel);
    4114             :         }
    4115             : 
    4116     3689692 :         rel = rel_simplify_fk_joins(v, rel);
    4117     3689692 :         rel = rel_push_select_down(v, rel);
    4118     3689692 :         rel = rel_select_leftgroup_2_semi(v, rel);
    4119     3689692 :         if (rel && rel->l && (is_select(rel->op) || is_join(rel->op)))
    4120     1163403 :                 rel = rel_use_index(v, rel);
    4121     3689692 :         return rel;
    4122             : }
    4123             : 
    4124             : static sql_rel *
    4125      129212 : rel_optimize_select_and_joins_topdown(visitor *v, global_props *gp, sql_rel *rel)
    4126             : {
    4127      129212 :         v->data = &gp->opt_cycle;
    4128      129212 :         rel = rel_visitor_topdown(v, rel, &rel_optimize_select_and_joins_topdown_);
    4129      129213 :         v->data = gp;
    4130      129213 :         return rel;
    4131             : }
    4132             : 
    4133             : run_optimizer
    4134      631321 : bind_optimize_select_and_joins_topdown(visitor *v, global_props *gp)
    4135             : {
    4136      631321 :         int flag = v->sql->sql_optimizer;
    4137      631129 :         return gp->opt_level == 1 && (gp->cnt[op_join] || gp->cnt[op_left] || gp->cnt[op_right]
    4138      545245 :                    || gp->cnt[op_full] || gp->cnt[op_semi] || gp->cnt[op_anti] ||
    4139     1262450 :                    gp->cnt[op_select]) && (flag & optimize_select_and_joins_topdown) ? rel_optimize_select_and_joins_topdown : NULL;
    4140             : }
    4141             : 
    4142             : 
    4143             : static int
    4144     1255666 : can_push_func(sql_exp *e, sql_rel *rel, int *must, int depth)
    4145             : {
    4146     1300967 :         switch(e->type) {
    4147     1099036 :         case e_cmp: {
    4148     1099036 :                 sql_exp *l = e->l, *r = e->r, *f = e->f;
    4149             : 
    4150             :                 /* don't push down functions inside attribute joins */
    4151     1099036 :                 if (e->flag == cmp_or || e->flag == cmp_in || e->flag == cmp_notin || e->flag == cmp_filter || (is_join(rel->op) && is_any(e)))
    4152             :                         return 0;
    4153     1042944 :                 if (depth > 0) { /* for comparisons under the top ones, they become functions */
    4154          62 :                         int lmust = 0;
    4155          62 :                         int res = can_push_func(l, rel, &lmust, depth + 1) && can_push_func(r, rel, &lmust, depth + 1) &&
    4156          22 :                                         (!f || can_push_func(f, rel, &lmust, depth + 1));
    4157          12 :                         if (res && !lmust)
    4158             :                                 return 1;
    4159          58 :                         (*must) |= lmust;
    4160          58 :                         return res;
    4161             :                 } else {
    4162     1042882 :                         int mustl = 0, mustr = 0, mustf = 0;
    4163     1042882 :                         return ((l->type == e_column || can_push_func(l, rel, &mustl, depth + 1)) && (*must = mustl)) ||
    4164     2078615 :                                         ((r->type == e_column || can_push_func(r, rel, &mustr, depth + 1)) && (*must = mustr)) ||
    4165        3648 :                                         ((f && (f->type == e_column || can_push_func(f, rel, &mustf, depth + 1)) && (*must = mustf)));
    4166             :                 }
    4167             :         }
    4168       45301 :         case e_convert:
    4169       45301 :                 return can_push_func(e->l, rel, must, depth + 1);
    4170        9470 :         case e_aggr:
    4171             :         case e_func: {
    4172        9470 :                 list *l = e->l;
    4173        9470 :                 int res = 1, lmust = 0;
    4174             : 
    4175        9470 :                 if (exp_unsafe(e, false, false))
    4176             :                         return 0;
    4177       26982 :                 if (l) for (node *n = l->h; n && res; n = n->next)
    4178       17520 :                         res &= can_push_func(n->data, rel, &lmust, depth + 1);
    4179        9462 :                 if (res && !lmust)
    4180             :                         return 1;
    4181        8607 :                 (*must) |= lmust;
    4182        8607 :                 return res;
    4183             :         }
    4184       51578 :         case e_column:
    4185       51578 :                 if (rel && !rel_find_exp(rel, e))
    4186             :                         return 0;
    4187       30302 :                 (*must) = 1;
    4188             :                 /* fall through */
    4189             :         default:
    4190             :                 return 1;
    4191             :         }
    4192             : }
    4193             : 
    4194             : static int
    4195      911523 : exps_can_push_func(list *exps, sql_rel *rel)
    4196             : {
    4197     3918452 :         for(node *n = exps->h; n; n = n->next) {
    4198     3031368 :                 sql_exp *e = n->data;
    4199     3031368 :                 int mustl = 0, mustr = 0;
    4200             : 
    4201     3031368 :                 if ((is_joinop(rel->op) || is_select(rel->op)) && ((can_push_func(e, rel->l, &mustl, 0) && mustl)))
    4202       24439 :                         return 1;
    4203     3027046 :                 if (is_joinop(rel->op) && can_push_func(e, rel->r, &mustr, 0) && mustr)
    4204             :                         return 1;
    4205             :         }
    4206             :         return 0;
    4207             : }
    4208             : 
    4209             : static int
    4210       84226 : exp_needs_push_down(sql_rel *rel, sql_exp *e)
    4211             : {
    4212      109386 :         switch(e->type) {
    4213       28266 :         case e_cmp:
    4214             :                 /* don't push down functions inside attribute joins */
    4215       28266 :                 if (e->flag == cmp_or || e->flag == cmp_in || e->flag == cmp_notin || e->flag == cmp_filter || (is_join(rel->op) && is_any(e)))
    4216             :                         return 0;
    4217       27330 :                 return exp_needs_push_down(rel, e->l) || exp_needs_push_down(rel, e->r) || (e->f && exp_needs_push_down(rel, e->f));
    4218       25160 :         case e_convert:
    4219       25160 :                 return exp_needs_push_down(rel, e->l);
    4220        1917 :         case e_aggr:
    4221             :         case e_func:
    4222        1917 :                 if (!e->l || exps_are_atoms(e->l))
    4223          20 :                         return 0;
    4224             :                 return 1;
    4225        1452 :         case e_atom:
    4226        1452 :                 if (!e->f || exps_are_atoms(e->f))
    4227        1452 :                         return 0;
    4228             :                 return 1;
    4229             :         case e_column:
    4230             :         default:
    4231             :                 return 0;
    4232             :         }
    4233             : }
    4234             : 
    4235             : static int
    4236       24439 : exps_need_push_down(sql_rel *rel, list *exps )
    4237             : {
    4238       50800 :         for(node *n = exps->h; n; n = n->next)
    4239       28258 :                 if (exp_needs_push_down(rel, n->data))
    4240             :                         return 1;
    4241             :         return 0;
    4242             : }
    4243             : 
    4244             : static sql_exp *exp_push_single_func_down(visitor *v, sql_rel *rel, sql_rel *ol, sql_rel *or, sql_exp *e, int depth);
    4245             : 
    4246             : static list *
    4247        2409 : exps_push_single_func_down(visitor *v, sql_rel *rel, sql_rel *ol, sql_rel *or, list *exps, int depth)
    4248             : {
    4249        4818 :         if (mvc_highwater(v->sql))
    4250             :                 return exps;
    4251             : 
    4252        6707 :         for (node *n = exps->h; n; n = n->next)
    4253        4298 :                 if ((n->data = exp_push_single_func_down(v, rel, ol, or, n->data, depth)) == NULL)
    4254             :                         return NULL;
    4255             :         return exps;
    4256             : }
    4257             : 
    4258             : static sql_exp *
    4259       15696 : exp_push_single_func_down(visitor *v, sql_rel *rel, sql_rel *ol, sql_rel *or, sql_exp *e, int depth)
    4260             : {
    4261       27437 :         if (mvc_highwater(v->sql))
    4262             :                 return e;
    4263             : 
    4264       15696 :         switch(e->type) {
    4265        4235 :         case e_cmp: {
    4266        4235 :                 if (e->flag == cmp_or || e->flag == cmp_filter) {
    4267         247 :                         if ((e->l = exps_push_single_func_down(v, rel, ol, or, e->l, depth + 1)) == NULL)
    4268             :                                 return NULL;
    4269         247 :                         if ((e->r = exps_push_single_func_down(v, rel, ol, or, e->r, depth + 1)) == NULL)
    4270             :                                 return NULL;
    4271        3988 :                 } else if (e->flag == cmp_in || e->flag == cmp_notin) {
    4272          18 :                         if ((e->l = exp_push_single_func_down(v, rel, ol, or, e->l, depth + 1)) == NULL)
    4273             :                                 return NULL;
    4274          18 :                         if ((e->r = exps_push_single_func_down(v, rel, ol, or, e->r, depth + 1)) == NULL)
    4275             :                                 return NULL;
    4276             :                 } else {
    4277        3970 :                         if ((e->l = exp_push_single_func_down(v, rel, ol, or, e->l, depth + 1)) == NULL)
    4278             :                                 return NULL;
    4279        3970 :                         if ((e->r = exp_push_single_func_down(v, rel, ol, or, e->r, depth + 1)) == NULL)
    4280             :                                 return NULL;
    4281        3970 :                         if (e->f && (e->f = exp_push_single_func_down(v, rel, ol, or, e->f, depth + 1)) == NULL)
    4282             :                                 return NULL;
    4283             :                 }
    4284             :         } break;
    4285        2005 :         case e_convert:
    4286        2005 :                 if ((e->l = exp_push_single_func_down(v, rel, ol, or, e->l, depth + 1)) == NULL)
    4287             :                         return NULL;
    4288             :                 break;
    4289        3978 :         case e_aggr:
    4290             :         case e_func: {
    4291        3978 :                 sql_rel *l = rel->l, *r = rel->r;
    4292        3978 :                 int must = 0, mustl = 0, mustr = 0;
    4293             : 
    4294        3978 :                 if (exp_unsafe(e, false, false))
    4295          23 :                         return e;
    4296        3978 :                 if (!e->l || exps_are_atoms(e->l))
    4297          23 :                         return e;
    4298        3955 :                 if ((is_joinop(rel->op) && ((can_push_func(e, l, &mustl, depth + 1) && mustl) || (can_push_func(e, r, &mustr, depth + 1) && mustr))) ||
    4299        2970 :                         (is_select(rel->op) && can_push_func(e, l, &must, depth + 1) && must)) {
    4300        3942 :                         exp_label(v->sql->sa, e, ++v->sql->label);
    4301             :                         /* we need a full projection, group by's and unions cannot be extended with more expressions */
    4302        3942 :                         if (mustr) {
    4303         353 :                                 if (r == or) /* don't project twice */
    4304         330 :                                         rel->r = r = rel_project(v->sql->sa, r, rel_projections(v->sql, r, NULL, 1, 1));
    4305         353 :                                 list_append(r->exps, e);
    4306             :                         } else {
    4307        3589 :                                 if (l == ol) /* don't project twice */
    4308        1833 :                                         rel->l = l = rel_project(v->sql->sa, l, rel_projections(v->sql, l, NULL, 1, 1));
    4309        3589 :                                 list_append(l->exps, e);
    4310             :                         }
    4311        3942 :                         e = exp_ref(v->sql, e);
    4312        3942 :                         v->changes++;
    4313             :                 }
    4314        3955 :         } break;
    4315        1142 :         case e_atom: {
    4316        1142 :                 if (e->f && (e->f = exps_push_single_func_down(v, rel, ol, or, e->f, depth + 1)) == NULL)
    4317             :                         return NULL;
    4318             :         } break;
    4319             :         case e_column:
    4320             :         case e_psm:
    4321             :                 break;
    4322             :         }
    4323             :         return e;
    4324             : }
    4325             : 
    4326             : static inline sql_rel *
    4327     3614294 : rel_push_func_down(visitor *v, sql_rel *rel)
    4328             : {
    4329     3614294 :         if ((is_select(rel->op) || is_joinop(rel->op)) && rel->l && rel->exps && !(rel_is_ref(rel))) {
    4330     1089117 :                 int changes = v->changes;
    4331     1089117 :                 sql_rel *l = rel->l, *r = rel->r;
    4332             : 
    4333             :                 /* only push down when is useful */
    4334     1089117 :                 if ((is_select(rel->op) && list_length(rel->exps) <= 1) || rel_is_ref(l) || (is_joinop(rel->op) && rel_is_ref(r)))
    4335      533250 :                         return rel;
    4336      555867 :                 if (exps_can_push_func(rel->exps, rel) && exps_need_push_down(rel, rel->exps) && !exps_push_single_func_down(v, rel, l, r, rel->exps, 0))
    4337             :                         return NULL;
    4338      555867 :                 if (v->changes > changes) /* once we get a better join order, we can try to remove this projection */
    4339        1897 :                         return rel_project(v->sql->sa, rel, rel_projections(v->sql, rel, NULL, 1, 1));
    4340             :         }
    4341     3079147 :         if (is_simple_project(rel->op) && rel->l && rel->exps) {
    4342     1143878 :                 sql_rel *pl = rel->l;
    4343             : 
    4344     1143878 :                 if (is_joinop(pl->op) && exps_can_push_func(rel->exps, rel)) {
    4345           0 :                         sql_rel *l = pl->l, *r = pl->r, *ol = l, *or = r;
    4346             : 
    4347           0 :                         for (node *n = rel->exps->h; n; ) {
    4348           0 :                                 node *next = n->next;
    4349           0 :                                 sql_exp *e = n->data;
    4350           0 :                                 int mustl = 0, mustr = 0;
    4351             : 
    4352           0 :                                 if ((can_push_func(e, l, &mustl, 0) && mustl) || (can_push_func(e, r, &mustr, 0) && mustr)) {
    4353           0 :                                         if (mustl) {
    4354           0 :                                                 if (l == ol) /* don't project twice */
    4355           0 :                                                         pl->l = l = rel_project(v->sql->sa, l, rel_projections(v->sql, l, NULL, 1, 1));
    4356           0 :                                                 list_append(l->exps, e);
    4357           0 :                                                 list_remove_node(rel->exps, NULL, n);
    4358           0 :                                                 v->changes++;
    4359             :                                         } else {
    4360           0 :                                                 if (r == or) /* don't project twice */
    4361           0 :                                                         pl->r = r = rel_project(v->sql->sa, r, rel_projections(v->sql, r, NULL, 1, 1));
    4362           0 :                                                 list_append(r->exps, e);
    4363           0 :                                                 list_remove_node(rel->exps, NULL, n);
    4364           0 :                                                 v->changes++;
    4365             :                                         }
    4366             :                                 }
    4367           0 :                                 n = next;
    4368             :                         }
    4369             :                 }
    4370             :         }
    4371             :         return rel;
    4372             : }
    4373             : 
    4374             : static sql_rel *
    4375     3614295 : rel_push_func_and_select_down_(visitor *v, sql_rel *rel)
    4376             : {
    4377     3614295 :         if (rel)
    4378     3614295 :                 rel = rel_push_func_down(v, rel);
    4379     3614294 :         if (rel)
    4380     3614294 :                 rel = rel_push_select_down(v, rel);
    4381     3614295 :         return rel;
    4382             : }
    4383             : 
    4384             : static sql_rel *
    4385      129212 : rel_push_func_and_select_down(visitor *v, global_props *gp, sql_rel *rel)
    4386             : {
    4387      129212 :         (void) gp;
    4388      129212 :         return rel_visitor_topdown(v, rel, &rel_push_func_and_select_down_);
    4389             : }
    4390             : 
    4391             : run_optimizer
    4392      631114 : bind_push_func_and_select_down(visitor *v, global_props *gp)
    4393             : {
    4394      631114 :         int flag = v->sql->sql_optimizer;
    4395      630855 :         return gp->opt_level == 1 && (gp->cnt[op_join] || gp->cnt[op_left] || gp->cnt[op_right]
    4396      545062 :                         || gp->cnt[op_full] || gp->cnt[op_semi] || gp->cnt[op_anti] || gp->cnt[op_select])
    4397      759983 :                         && (flag & push_func_and_select_down) ? rel_push_func_and_select_down : NULL;
    4398             : }

Generated by: LCOV version 1.14