LCOV - code coverage report
Current view: top level - sql/server - rel_optimize_exps.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 458 563 81.3 %
Date: 2024-04-25 20:03:45 Functions: 12 12 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_select.h"
      16             : #include "rel_exp.h"
      17             : #include "rel_rewriter.h"
      18             : 
      19             : static inline int
      20       50673 : str_ends_with(const char *s, const char *suffix)
      21             : {
      22       50673 :         size_t slen = strlen(s), suflen = strlen(suffix);
      23       50673 :         if (suflen > slen)
      24             :                 return 1;
      25        1103 :         return strncmp(s + slen - suflen, suffix, suflen);
      26             : }
      27             : 
      28             : static sql_exp *
      29      460176 : exp_simplify_math( mvc *sql, sql_exp *e, int *changes)
      30             : {
      31      460176 :         if (e->type == e_func || e->type == e_aggr) {
      32       93996 :                 list *l = e->l;
      33       93996 :                 sql_subfunc *f = e->f;
      34       93996 :                 node *n;
      35       93996 :                 sql_exp *le;
      36             : 
      37       93996 :                 if (list_length(l) < 1)
      38             :                         return e;
      39             : 
      40             :                 /* if the function has no null semantics we can return NULL if one of the arguments is NULL */
      41       93463 :                 if (!f->func->semantics && f->func->type != F_PROC) {
      42      154286 :                         for (node *n = l->h ; n ; n = n->next) {
      43      101620 :                                 sql_exp *arg = n->data;
      44             : 
      45      101620 :                                 if (exp_is_atom(arg) && exp_is_null(arg)) {
      46          60 :                                         sql_exp *ne = exp_null(sql->sa, exp_subtype(e));
      47          60 :                                         (*changes)++;
      48          60 :                                         if (exp_name(e))
      49          15 :                                                 exp_prop_alias(sql->sa, ne, e);
      50          60 :                                         return ne;
      51             :                                 }
      52             :                         }
      53             :                 }
      54       93403 :                 if (!f->func->s && list_length(l) == 2 && str_ends_with(sql_func_imp(f->func), "_no_nil") == 0) {
      55         120 :                         sql_exp *le = l->h->data;
      56         120 :                         sql_exp *re = l->h->next->data;
      57             : 
      58             :                         /* if "_no_nil" is in the name of the
      59             :                          * implementation function (currently either
      60             :                          * min_no_nil or max_no_nil), in which case we
      61             :                          * ignore the NULL and return the other value */
      62             : 
      63         120 :                         if (exp_is_atom(le) && exp_is_null(le)) {
      64           1 :                                 (*changes)++;
      65           1 :                                 if (exp_name(e))
      66           1 :                                         exp_prop_alias(sql->sa, re, e);
      67           1 :                                 return re;
      68             :                         }
      69         119 :                         if (exp_is_atom(re) && exp_is_null(re)) {
      70           2 :                                 (*changes)++;
      71           2 :                                 if (exp_name(e))
      72           2 :                                         exp_prop_alias(sql->sa, le, e);
      73           2 :                                 return le;
      74             :                         }
      75             :                 }
      76             : 
      77       93400 :                 le = l->h->data;
      78       93400 :                 if (!EC_COMPUTE(exp_subtype(le)->type->eclass) && exp_subtype(le)->type->eclass != EC_DEC)
      79             :                         return e;
      80             : 
      81       64073 :                 if (!f->func->s && !strcmp(f->func->base.name, "sql_mul") && list_length(l) == 2) {
      82       11109 :                         sql_exp *le = l->h->data;
      83       11109 :                         sql_exp *re = l->h->next->data;
      84       11109 :                         sql_subtype *et = exp_subtype(e);
      85             : 
      86             :                         /* 0*a = 0 */
      87       11109 :                         if (exp_is_atom(le) && exp_is_zero(le) && exp_is_atom(re) && !has_nil(re)) {
      88           0 :                                 (*changes)++;
      89           0 :                                 le = exp_zero(sql->sa, et);
      90           0 :                                 if (subtype_cmp(exp_subtype(e), exp_subtype(le)) != 0)
      91           0 :                                         le = exp_convert(sql->sa, le, exp_subtype(le), exp_subtype(e));
      92           0 :                                 if (exp_name(e))
      93           0 :                                         exp_prop_alias(sql->sa, le, e);
      94           0 :                                 return le;
      95             :                         }
      96             :                         /* a*0 = 0 */
      97       11109 :                         if (exp_is_atom(re) && exp_is_zero(re) && exp_is_atom(le) && !has_nil(le)) {
      98           2 :                                 (*changes)++;
      99           2 :                                 re = exp_zero(sql->sa, et);
     100           2 :                                 if (subtype_cmp(exp_subtype(e), exp_subtype(re)) != 0)
     101           0 :                                         re = exp_convert(sql->sa, re, exp_subtype(re), exp_subtype(e));
     102           2 :                                 if (exp_name(e))
     103           1 :                                         exp_prop_alias(sql->sa, re, e);
     104           2 :                                 return re;
     105             :                         }
     106       11107 :                         if (exp_is_atom(le) && exp_is_atom(re)) {
     107          96 :                                 atom *la = exp_flatten(sql, true, le);
     108          96 :                                 atom *ra = exp_flatten(sql, true, re);
     109             : 
     110          96 :                                 if (la && ra && subtype_cmp(atom_type(la), atom_type(ra)) == 0 && subtype_cmp(atom_type(la), exp_subtype(e)) == 0) {
     111           5 :                                         atom *a = atom_mul(sql->sa, la, ra);
     112             : 
     113           5 :                                         if (a && (a = atom_cast(sql->sa, a, exp_subtype(e)))) {
     114           4 :                                                 sql_exp *ne = exp_atom(sql->sa, a);
     115           4 :                                                 if (subtype_cmp(exp_subtype(e), exp_subtype(ne)) != 0)
     116           0 :                                                         ne = exp_convert(sql->sa, ne, exp_subtype(ne), exp_subtype(e));
     117           4 :                                                 (*changes)++;
     118           4 :                                                 if (exp_name(e))
     119           0 :                                                         exp_prop_alias(sql->sa, ne, e);
     120           4 :                                                 return ne;
     121             :                                         }
     122             :                                 }
     123             :                         }
     124             :                         /* change a*pow(a,n) or pow(a,n)*a into pow(a,n+1) */
     125       11103 :                         if (is_func(le->type)) {
     126          98 :                                 list *l = le->l;
     127          98 :                                 sql_subfunc *f = le->f;
     128             : 
     129          98 :                                 if (!f->func->s && !strcmp(f->func->base.name, "power") && list_length(l) == 2) {
     130           0 :                                         sql_exp *lle = l->h->data;
     131           0 :                                         sql_exp *lre = l->h->next->data;
     132           0 :                                         if (exp_equal(re, lle)==0) {
     133           0 :                                                 atom *a = exp_value(sql, lre);
     134           0 :                                                 if (a && (a = atom_inc(sql->sa, a))) {
     135           0 :                                                         lre->l = a;
     136           0 :                                                         lre->r = NULL;
     137           0 :                                                         if (subtype_cmp(exp_subtype(e), exp_subtype(le)) != 0)
     138           0 :                                                                 le = exp_convert(sql->sa, le, exp_subtype(le), exp_subtype(e));
     139           0 :                                                         (*changes)++;
     140           0 :                                                         if (exp_name(e))
     141           0 :                                                                 exp_prop_alias(sql->sa, le, e);
     142           0 :                                                         return le;
     143             :                                                 }
     144             :                                         }
     145             :                                 }
     146          98 :                                 if (!f->func->s && !strcmp(f->func->base.name, "sql_mul") && list_length(l) == 2) {
     147          30 :                                         sql_exp *lle = l->h->data;
     148          30 :                                         sql_exp *lre = l->h->next->data;
     149          30 :                                         if (!exp_is_atom(lle) && exp_is_atom(lre) && exp_is_atom(re)) {
     150             :                                                 /* (x*c1)*c2 -> x * (c1*c2) */
     151          13 :                                                 sql_exp *ne = NULL;
     152             : 
     153          13 :                                                 if (!(le = rel_binop_(sql, NULL, lre, re, "sys", "sql_mul", card_value))) {
     154           0 :                                                         sql->session->status = 0;
     155           0 :                                                         sql->errstr[0] = '\0';
     156           0 :                                                         return e; /* error, fallback to original expression */
     157             :                                                 }
     158          13 :                                                 if (!(ne = rel_binop_(sql, NULL, lle, le, "sys", "sql_mul", card_value))) {
     159           0 :                                                         sql->session->status = 0;
     160           0 :                                                         sql->errstr[0] = '\0';
     161           0 :                                                         return e; /* error, fallback to original expression */
     162             :                                                 }
     163          13 :                                                 if (subtype_cmp(exp_subtype(e), exp_subtype(ne)) != 0)
     164           2 :                                                         ne = exp_convert(sql->sa, ne, exp_subtype(ne), exp_subtype(e));
     165          13 :                                                 (*changes)++;
     166          13 :                                                 if (exp_name(e))
     167           8 :                                                         exp_prop_alias(sql->sa, ne, e);
     168          13 :                                                 return ne;
     169             :                                         }
     170             :                                 }
     171             :                         }
     172             :                 }
     173       64054 :                 if (!f->func->s && !strcmp(f->func->base.name, "sql_add") && list_length(l) == 2) {
     174       23068 :                         sql_exp *le = l->h->data;
     175       23068 :                         sql_exp *re = l->h->next->data;
     176       23068 :                         if (exp_is_atom(le) && exp_is_zero(le)) {
     177           1 :                                 if (subtype_cmp(exp_subtype(e), exp_subtype(re)) != 0)
     178           0 :                                         re = exp_convert(sql->sa, re, exp_subtype(re), exp_subtype(e));
     179           1 :                                 (*changes)++;
     180           1 :                                 if (exp_name(e))
     181           1 :                                         exp_prop_alias(sql->sa, re, e);
     182           1 :                                 return re;
     183             :                         }
     184       23067 :                         if (exp_is_atom(re) && exp_is_zero(re)) {
     185           4 :                                 if (subtype_cmp(exp_subtype(e), exp_subtype(le)) != 0)
     186           0 :                                         le = exp_convert(sql->sa, le, exp_subtype(le), exp_subtype(e));
     187           4 :                                 (*changes)++;
     188           4 :                                 if (exp_name(e))
     189           4 :                                         exp_prop_alias(sql->sa, le, e);
     190           4 :                                 return le;
     191             :                         }
     192       23063 :                         if (exp_is_atom(le) && exp_is_atom(re)) {
     193          83 :                                 atom *la = exp_flatten(sql, true, le);
     194          83 :                                 atom *ra = exp_flatten(sql, true, re);
     195             : 
     196          83 :                                 if (la && ra) {
     197          18 :                                         atom *a = atom_add(sql->sa, la, ra);
     198             : 
     199          18 :                                         if (a) {
     200          17 :                                                 sql_exp *ne = exp_atom(sql->sa, a);
     201          17 :                                                 if (subtype_cmp(exp_subtype(e), exp_subtype(ne)) != 0)
     202           2 :                                                         ne = exp_convert(sql->sa, ne, exp_subtype(ne), exp_subtype(e));
     203          17 :                                                 (*changes)++;
     204          17 :                                                 if (exp_name(e))
     205           2 :                                                         exp_prop_alias(sql->sa, ne, e);
     206          17 :                                                 return ne;
     207             :                                         }
     208             :                                 }
     209             :                         }
     210       23046 :                         if (is_func(le->type)) {
     211        2925 :                                 list *ll = le->l;
     212        2925 :                                 sql_subfunc *f = le->f;
     213        2925 :                                 if (!f->func->s && !strcmp(f->func->base.name, "sql_add") && list_length(ll) == 2) {
     214        2503 :                                         sql_exp *lle = ll->h->data;
     215        2503 :                                         sql_exp *lre = ll->h->next->data;
     216             : 
     217        2503 :                                         if (exp_is_atom(lle) && exp_is_atom(lre))
     218             :                                                 return e;
     219        2491 :                                         if (!exp_is_atom(re) && exp_is_atom(lre)) {
     220             :                                                 /* (x+c1)+y -> (x+y) + c1 */
     221           1 :                                                 ll->h->next->data = re;
     222           1 :                                                 l->h->next->data = lre;
     223           1 :                                                 if (!(l->h->data = exp_simplify_math(sql, le, changes)))
     224             :                                                         return NULL;
     225           1 :                                                 (*changes)++;
     226           1 :                                                 return e;
     227             :                                         }
     228        2490 :                                         if (exp_is_atom(re) && exp_is_atom(lre)) {
     229             :                                                 /* (x+c1)+c2 -> (c2+c1) + x */
     230           3 :                                                 ll->h->data = re;
     231           3 :                                                 l->h->next->data = lle;
     232           3 :                                                 if (!(l->h->data = exp_simplify_math(sql, le, changes)))
     233             :                                                         return NULL;
     234           3 :                                                 (*changes)++;
     235           3 :                                                 return e;
     236             :                                         }
     237             :                                 }
     238             :                         }
     239             :                 }
     240       64016 :                 if (!f->func->s && !strcmp(f->func->base.name, "sql_sub") && list_length(l) == 2) {
     241        5490 :                         sql_exp *le = l->h->data;
     242        5490 :                         sql_exp *re = l->h->next->data;
     243             : 
     244        5490 :                         if (exp_is_atom(le) && exp_is_atom(re)) {
     245          29 :                                 atom *la = exp_flatten(sql, true, le);
     246          29 :                                 atom *ra = exp_flatten(sql, true, re);
     247             : 
     248          29 :                                 if (la && ra) {
     249           7 :                                         atom *a = atom_sub(sql->sa, la, ra);
     250             : 
     251           7 :                                         if (a) {
     252           7 :                                                 sql_exp *ne = exp_atom(sql->sa, a);
     253           7 :                                                 if (subtype_cmp(exp_subtype(e), exp_subtype(ne)) != 0)
     254           4 :                                                         ne = exp_convert(sql->sa, ne, exp_subtype(ne), exp_subtype(e));
     255           7 :                                                 (*changes)++;
     256           7 :                                                 if (exp_name(e))
     257           3 :                                                         exp_prop_alias(sql->sa, ne, e);
     258           7 :                                                 return ne;
     259             :                                         }
     260             :                                 }
     261             :                         }
     262        5483 :                         if (!has_nil(le) && !has_nil(re) && exp_equal(le,re) == 0) { /* a - a = 0 */
     263           0 :                                 atom *a;
     264           0 :                                 sql_exp *ne;
     265             : 
     266           0 :                                 if (exp_subtype(le)->type->eclass == EC_NUM) {
     267           0 :                                         a = atom_int(sql->sa, exp_subtype(le), 0);
     268           0 :                                 } else if (exp_subtype(le)->type->eclass == EC_FLT) {
     269           0 :                                         a = atom_float(sql->sa, exp_subtype(le), 0);
     270             :                                 } else {
     271             :                                         return e;
     272             :                                 }
     273           0 :                                 ne = exp_atom(sql->sa, a);
     274           0 :                                 if (subtype_cmp(exp_subtype(e), exp_subtype(ne)) != 0)
     275           0 :                                         ne = exp_convert(sql->sa, ne, exp_subtype(ne), exp_subtype(e));
     276           0 :                                 (*changes)++;
     277           0 :                                 if (exp_name(e))
     278           0 :                                         exp_prop_alias(sql->sa, ne, e);
     279           0 :                                 return ne;
     280             :                         }
     281        5483 :                         if (is_func(le->type)) {
     282          49 :                                 list *ll = le->l;
     283          49 :                                 sql_subfunc *f = le->f;
     284          49 :                                 if (!f->func->s && !strcmp(f->func->base.name, "sql_add") && list_length(ll) == 2) {
     285           7 :                                         sql_exp *lle = ll->h->data;
     286           7 :                                         sql_exp *lre = ll->h->next->data;
     287           7 :                                         if (exp_equal(re, lre) == 0) {
     288             :                                                 /* (x+a)-a = x*/
     289           0 :                                                 if (subtype_cmp(exp_subtype(e), exp_subtype(lle)) != 0)
     290           0 :                                                         lle = exp_convert(sql->sa, lle, exp_subtype(lle), exp_subtype(e));
     291           0 :                                                 if (exp_name(e))
     292           0 :                                                         exp_prop_alias(sql->sa, lle, e);
     293           0 :                                                 (*changes)++;
     294           0 :                                                 return lle;
     295             :                                         }
     296           7 :                                         if (exp_is_atom(lle) && exp_is_atom(lre))
     297             :                                                 return e;
     298           7 :                                         if (!exp_is_atom(re) && exp_is_atom(lre)) {
     299             :                                                 /* (x+c1)-y -> (x-y) + c1 */
     300           3 :                                                 ll->h->next->data = re;
     301           3 :                                                 l->h->next->data = lre;
     302           3 :                                                 le->f = e->f;
     303           3 :                                                 e->f = f;
     304           3 :                                                 if (!(l->h->data = exp_simplify_math(sql, le, changes)))
     305             :                                                         return NULL;
     306           3 :                                                 (*changes)++;
     307           3 :                                                 return e;
     308             :                                         }
     309           4 :                                         if (exp_is_atom(re) && exp_is_atom(lre)) {
     310             :                                                 /* (x+c1)-c2 -> (c1-c2) + x */
     311           0 :                                                 ll->h->data = lre;
     312           0 :                                                 ll->h->next->data = re;
     313           0 :                                                 l->h->next->data = lle;
     314           0 :                                                 le->f = e->f;
     315           0 :                                                 e->f = f;
     316           0 :                                                 if (!(l->h->data = exp_simplify_math(sql, le, changes)))
     317             :                                                         return NULL;
     318           0 :                                                 (*changes)++;
     319           0 :                                                 return e;
     320             :                                         }
     321             :                                 }
     322             :                         }
     323             :                 }
     324       64006 :                 if (l)
     325      200304 :                         for (n = l->h; n; n = n->next)
     326      136298 :                                 if (!(n->data = exp_simplify_math(sql, n->data, changes)))
     327             :                                         return NULL;
     328             :         }
     329      430186 :         if (e->type == e_convert)
     330       66570 :                 if (!(e->l = exp_simplify_math(sql, e->l, changes)))
     331             :                         return NULL;
     332             :         return e;
     333             : }
     334             : 
     335             : static inline sql_rel *
     336     1187686 : rel_simplify_math_(visitor *v, sql_rel *rel)
     337             : {
     338     1187686 :         if ((is_simple_project(rel->op) || (rel->op == op_ddl && rel->flag == ddl_psm)) && rel->exps) {
     339      304298 :                 int needed = 0, ochanges = 0;
     340             : 
     341     1596520 :                 for (node *n = rel->exps->h; n && !needed; n = n->next) {
     342     1292222 :                         sql_exp *e = n->data;
     343             : 
     344     1292222 :                         if (e->type == e_func || e->type == e_convert || e->type == e_aggr || e->type == e_psm)
     345       51450 :                                 needed = 1;
     346             :                 }
     347      304298 :                 if (!needed)
     348      252848 :                         return rel;
     349             : 
     350      308751 :                 for (node *n = rel->exps->h; n; n = n->next) {
     351      257301 :                         sql_exp *ne = exp_simplify_math(v->sql, n->data, &ochanges);
     352             : 
     353      257301 :                         if (!ne)
     354             :                                 return NULL;
     355      257301 :                         n->data = ne;
     356             :                 }
     357       51450 :                 v->changes += ochanges;
     358             :         }
     359             :         return rel;
     360             : }
     361             : 
     362             : static sql_rel *
     363      351484 : rel_simplify_math(visitor *v, global_props *gp, sql_rel *rel)
     364             : {
     365      351484 :         (void) gp;
     366      351484 :         return rel_visitor_bottomup(v, rel, &rel_simplify_math_);
     367             : }
     368             : 
     369             : run_optimizer
     370      596798 : bind_simplify_math(visitor *v, global_props *gp)
     371             : {
     372      596798 :         int flag = v->sql->sql_optimizer;
     373      530869 :         return gp->opt_cycle == 0 && gp->opt_level == 1 && v->value_based_opt && (gp->cnt[op_project]
     374      990521 :                    || gp->cnt[op_ddl] || gp->cnt[ddl_psm]) && (flag & simplify_math) ? rel_simplify_math : NULL;
     375             : }
     376             : 
     377             : 
     378             : /*
     379             :  * Casting decimal values on both sides of a compare expression is expensive,
     380             :  * both in preformance (cpu cost) and memory requirements (need for large
     381             :  * types).
     382             :  */
     383             : 
     384             : #define reduce_scale_tpe(tpe, uval) \
     385             :         do { \
     386             :                 tpe v = uval; \
     387             :                 if (v != 0) { \
     388             :                         while( (v/10)*10 == v ) { \
     389             :                                 i++; \
     390             :                                 v /= 10; \
     391             :                         } \
     392             :                         nval = v; \
     393             :                 } \
     394             :         } while (0)
     395             : 
     396             : atom *
     397           5 : reduce_scale(mvc *sql, atom *a)
     398             : {
     399           5 :         int i = 0;
     400           5 :         atom *na = a;
     401             : #ifdef HAVE_HGE
     402           5 :         hge nval = 0;
     403             : #else
     404             :         lng nval = 0;
     405             : #endif
     406             : 
     407             : #ifdef HAVE_HGE
     408           5 :         if (a->data.vtype == TYPE_hge) {
     409           0 :                 reduce_scale_tpe(hge, a->data.val.hval);
     410             :         } else
     411             : #endif
     412             :         if (a->data.vtype == TYPE_lng) {
     413           0 :                 reduce_scale_tpe(lng, a->data.val.lval);
     414             :         } else if (a->data.vtype == TYPE_int) {
     415           8 :                 reduce_scale_tpe(int, a->data.val.ival);
     416             :         } else if (a->data.vtype == TYPE_sht) {
     417          10 :                 reduce_scale_tpe(sht, a->data.val.shval);
     418             :         } else if (a->data.vtype == TYPE_bte) {
     419           0 :                 reduce_scale_tpe(bte, a->data.val.btval);
     420             :         }
     421           5 :         if (i) {
     422           3 :                 na = atom_int(sql->sa, &a->tpe, nval);
     423           3 :                 if (na->tpe.scale)
     424           3 :                         na->tpe.scale -= i;
     425             :         }
     426           5 :         return na;
     427             : }
     428             : 
     429             : static inline sql_exp *
     430     7051097 : rel_simplify_predicates(visitor *v, sql_rel *rel, sql_exp *e)
     431             : {
     432     7051097 :         if (is_func(e->type) && list_length(e->l) == 3 && is_case_func((sql_subfunc*)e->f)) {
     433       33305 :                 list *args = e->l;
     434       33305 :                 sql_exp *ie = args->h->data;
     435             : 
     436       33305 :                 if (exp_is_true(ie)) { /* ifthenelse(true, x, y) -> x */
     437          14 :                         sql_exp *res = args->h->next->data;
     438          14 :                         if (exp_name(e))
     439           6 :                                 exp_prop_alias(v->sql->sa, res, e);
     440          14 :                         v->changes++;
     441          14 :                         return res;
     442       33291 :                 } else if (exp_is_false(ie) || exp_is_null(ie)) { /* ifthenelse(false or null, x, y) -> y */
     443          12 :                         sql_exp *res = args->h->next->next->data;
     444          12 :                         if (exp_name(e))
     445           6 :                                 exp_prop_alias(v->sql->sa, res, e);
     446          12 :                         v->changes++;
     447          12 :                         return res;
     448             :                 }
     449             :         }
     450     7051071 :         if (is_func(e->type) && list_length(e->l) == 4 && is_casewhen_func((sql_subfunc*)e->f)) {
     451             :                 /* case x when y then a else b */
     452         507 :                 list *args = e->l;
     453         507 :                 node *n = args->h;
     454         507 :                 sql_exp *le = n->data;
     455         507 :                 sql_exp *re = n->next->data;
     456             : 
     457         507 :                 if (exp_is_atom(le) && !exp_is_null(le) && exp_is_atom(re) && le->type == e_atom && le->l && re->type == e_atom && re->l) {
     458          57 :                         n = n->next->next;
     459          57 :                         if (exp_match_exp(le, re)) { /* x==y -> a */
     460           9 :                                 sql_exp *res = n->data;
     461           9 :                                 if (exp_name(e))
     462           7 :                                         exp_prop_alias(v->sql->sa, res, e);
     463           9 :                                 v->changes++;
     464           9 :                                 return res;
     465             :                         } else { /*  -> b */
     466          48 :                                 sql_exp *res = n->next->data;
     467          48 :                                 if (exp_name(e))
     468          12 :                                         exp_prop_alias(v->sql->sa, res, e);
     469          48 :                                 v->changes++;
     470          48 :                                 return res;
     471             :                         }
     472             :                 }
     473             :         }
     474     7051014 :         if (is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) {
     475             :                 /* simplify like expressions */
     476     1660270 :                 if (is_compare(e->type) && e->flag == cmp_filter && !((sql_subfunc*)e->f)->func->s && strcmp(((sql_subfunc*)e->f)->func->base.name, "like") == 0 &&
     477       13360 :                         list_length((list *)e->l) == 1 && list_length((list *)e->r) == 3) {
     478        6680 :                         list *r = e->r;
     479        6680 :                         sql_exp *fmt = r->h->data;
     480        6680 :                         sql_exp *esc = r->h->next->data;
     481        6680 :                         sql_exp *isen = r->h->next->next->data;
     482        6680 :                         int rewrite = 0, isnull = 0;
     483             : 
     484        6680 :                         if (fmt->type == e_convert)
     485          97 :                                 fmt = fmt->l;
     486             :                         /* check for simple like expression */
     487        6680 :                         if (exp_is_null(fmt)) {
     488             :                                 isnull = 1;
     489        6677 :                         } else if (is_atom(fmt->type)) {
     490        6558 :                                 atom *fa = NULL;
     491             : 
     492        6558 :                                 if (fmt->l)
     493        6558 :                                         fa = fmt->l;
     494        6558 :                                 if (fa && fa->data.vtype == TYPE_str && !strchr(fa->data.val.sval, '%') && !strchr(fa->data.val.sval, '_'))
     495        6680 :                                         rewrite = 1;
     496             :                         }
     497        6680 :                         if (rewrite && !isnull) { /* check escape flag */
     498         131 :                                 if (exp_is_null(esc)) {
     499             :                                         isnull = 1;
     500             :                                 } else {
     501         131 :                                         atom *ea = esc->l;
     502             : 
     503         131 :                                         if (!is_atom(esc->type) || !ea)
     504             :                                                 rewrite = 0;
     505         131 :                                         else if (ea->data.vtype != TYPE_str || strlen(ea->data.val.sval) != 0)
     506          69 :                                                 rewrite = 0;
     507             :                                 }
     508             :                         }
     509        6680 :                         if (rewrite && !isnull) { /* check insensitive flag */
     510          62 :                                 if (exp_is_null(isen)) {
     511             :                                         isnull = 1;
     512             :                                 } else {
     513          62 :                                         atom *ia = isen->l;
     514             : 
     515          62 :                                         if (!is_atom(isen->type) || !ia)
     516             :                                                 rewrite = 0;
     517          62 :                                         else if (ia->data.vtype != TYPE_bit || ia->data.val.btval == 1)
     518           9 :                                                 rewrite = 0;
     519             :                                 }
     520             :                         }
     521        6680 :                         if (isnull) {
     522           3 :                                 e = exp_null(v->sql->sa, sql_bind_localtype("bit"));
     523           3 :                                 v->changes++;
     524           3 :                                 return e;
     525        6677 :                         } else if (rewrite) { /* rewrite to cmp_equal ! */
     526          53 :                                 list *l = e->l;
     527          53 :                                 list *r = e->r;
     528         103 :                                 e = exp_compare(v->sql->sa, l->h->data, r->h->data, is_anti(e) ? cmp_notequal : cmp_equal);
     529          53 :                                 v->changes++;
     530             :                         }
     531             :                 }
     532             :                 /* rewrite e if left or right is a cast */
     533     1653587 :                 if (is_compare(e->type) && !e->f && is_theta_exp(e->flag) && (((sql_exp*)e->l)->type == e_convert || ((sql_exp*)e->r)->type == e_convert)) {
     534       42097 :                         sql_rel *r = rel->r;
     535       42097 :                         sql_exp *le = e->l, *re = e->r;
     536             : 
     537             :                         /* if convert on left then find mul or div on right which increased scale! */
     538       42097 :                         if (le->type == e_convert && re->type == e_column && (e->flag == cmp_lt || e->flag == cmp_gt) && r && is_project(r->op)) {
     539          79 :                                 sql_exp *nre = rel_find_exp(r, re);
     540          79 :                                 sql_subtype *tt = exp_totype(le), *ft = exp_fromtype(le);
     541             : 
     542          79 :                                 if (nre && nre->type == e_func) {
     543           4 :                                         sql_subfunc *f = nre->f;
     544             : 
     545           4 :                                         if (!f->func->s && !strcmp(f->func->base.name, "sql_mul")) {
     546           4 :                                                 list *args = nre->l;
     547           4 :                                                 sql_exp *ce = args->t->data;
     548           4 :                                                 sql_subtype *fst = exp_subtype(args->h->data);
     549             : 
     550           4 :                                                 if (fst->scale && fst->scale == ft->scale && is_atom(ce->type) && ce->l) {
     551           1 :                                                         atom *a = ce->l;
     552           1 :                                                         int anti = is_anti(e);
     553           1 :                                                         sql_exp *arg1, *arg2;
     554           1 :                                                         sql_subfunc *f;
     555             : #ifdef HAVE_HGE
     556           1 :                                                         hge val = 1;
     557             : #else
     558             :                                                         lng val = 1;
     559             : #endif
     560             :                                                         /* multiply with smallest value, then scale and (round) */
     561           1 :                                                         int scale = (int) tt->scale - (int) ft->scale, rs = 0;
     562           1 :                                                         atom *na = reduce_scale(v->sql, a);
     563             : 
     564           1 :                                                         if (na != a) {
     565           1 :                                                                 rs = a->tpe.scale - na->tpe.scale;
     566           1 :                                                                 ce->l = na;
     567             :                                                         }
     568           1 :                                                         scale -= rs;
     569             : 
     570           3 :                                                         while (scale > 0) {
     571           2 :                                                                 scale--;
     572           2 :                                                                 val *= 10;
     573             :                                                         }
     574           1 :                                                         arg1 = re;
     575             : #ifdef HAVE_HGE
     576           1 :                                                         arg2 = exp_atom_hge(v->sql->sa, val);
     577             : #else
     578             :                                                         arg2 = exp_atom_lng(v->sql->sa, val);
     579             : #endif
     580           1 :                                                         if ((f = sql_bind_func(v->sql, "sys", "scale_down", exp_subtype(arg1), exp_subtype(arg2), F_FUNC, true))) {
     581           1 :                                                                 e = exp_compare(v->sql->sa, le->l, exp_binop(v->sql->sa, arg1, arg2, f), e->flag);
     582           1 :                                                                 if (anti) set_anti(e);
     583           1 :                                                                 v->changes++;
     584             :                                                         } else {
     585           0 :                                                                 v->sql->session->status = 0;
     586           0 :                                                                 v->sql->errstr[0] = '\0';
     587             :                                                         }
     588             :                                                 }
     589             :                                         }
     590             :                                 }
     591             :                         }
     592             :                 }
     593     1653587 :                 if (is_compare(e->type) && is_semantics(e) && (e->flag == cmp_equal || e->flag == cmp_notequal) && exp_is_null(e->r)) {
     594             :                         /* simplify 'is null' predicates on constants */
     595       11133 :                         if (exp_is_null(e->l)) {
     596          29 :                                 int nval = e->flag == cmp_equal;
     597          29 :                                 if (is_anti(e)) nval = !nval;
     598          29 :                                 e = exp_atom_bool(v->sql->sa, nval);
     599          29 :                                 v->changes++;
     600          29 :                                 return e;
     601       11104 :                         } else if (exp_is_not_null(e->l)) {
     602         396 :                                 int nval = e->flag == cmp_notequal;
     603         396 :                                 if (is_anti(e)) nval = !nval;
     604         396 :                                 e = exp_atom_bool(v->sql->sa, nval);
     605         396 :                                 v->changes++;
     606         396 :                                 return e;
     607             :                         }
     608             :                 }
     609     1653162 :                 if (is_atom(e->type) && ((!e->l && !e->r && !e->f) || e->r)) /* prepared statement parameter or argument */
     610             :                         return e;
     611     1652796 :                 if (is_atom(e->type) && e->l) { /* direct literal */
     612      415438 :                         atom *a = e->l;
     613      415438 :                         int flag = a->data.val.bval;
     614             : 
     615             :                         /* remove simple select true expressions */
     616      415438 :                         if (flag)
     617             :                                 return e;
     618             :                 }
     619     1268306 :                 if (is_compare(e->type) && is_theta_exp(e->flag)) {
     620      412964 :                         sql_exp *l = e->l;
     621      412964 :                         sql_exp *r = e->r;
     622             : 
     623      412964 :                         if (is_func(l->type) && (e->flag == cmp_equal || e->flag == cmp_notequal)) {
     624        5369 :                                 sql_subfunc *f = l->f;
     625             : 
     626             :                                 /* rewrite isnull(x) = TRUE/FALSE => x =/<> NULL */
     627        5369 :                                 if (!f->func->s && is_isnull_func(f)) {
     628         943 :                                         list *args = l->l;
     629         943 :                                         sql_exp *ie = args->h->data;
     630             : 
     631         943 :                                         if (!has_nil(ie) || exp_is_not_null(ie)) { /* is null on something that is never null, is always false */
     632          98 :                                                 ie = exp_atom_bool(v->sql->sa, 0);
     633          98 :                                                 v->changes++;
     634          98 :                                                 e->l = ie;
     635         845 :                                         } else if (exp_is_null(ie)) { /* is null on something that is always null, is always true */
     636           0 :                                                 ie = exp_atom_bool(v->sql->sa, 1);
     637           0 :                                                 v->changes++;
     638           0 :                                                 e->l = ie;
     639         845 :                                         } else if (is_atom(r->type) && r->l) { /* direct literal */
     640         829 :                                                 atom *a = r->l;
     641             : 
     642         829 :                                                 if (a->isnull) {
     643           0 :                                                         if (is_semantics(e)) { /* isnull(x) = NULL -> false, isnull(x) <> NULL -> true */
     644           0 :                                                                 int flag = e->flag == cmp_notequal;
     645           0 :                                                                 if (is_anti(e))
     646           0 :                                                                         flag = !flag;
     647           0 :                                                                 e = exp_atom_bool(v->sql->sa, flag);
     648             :                                                         } else /* always NULL */
     649           0 :                                                                 e = exp_null(v->sql->sa, sql_bind_localtype("bit"));
     650           0 :                                                         v->changes++;
     651             :                                                 } else {
     652         829 :                                                         int flag = a->data.val.bval;
     653             : 
     654         829 :                                                         assert(list_length(args) == 1);
     655         829 :                                                         l = args->h->data;
     656         829 :                                                         if (exp_subtype(l)) {
     657         829 :                                                                 r = exp_atom(v->sql->sa, atom_general(v->sql->sa, exp_subtype(l), NULL));
     658         829 :                                                                 e = exp_compare(v->sql->sa, l, r, e->flag);
     659         829 :                                                                 if (e && !flag)
     660         284 :                                                                         set_anti(e);
     661         829 :                                                                 if (e)
     662         829 :                                                                         set_semantics(e);
     663         829 :                                                                 v->changes++;
     664             :                                                         }
     665             :                                                 }
     666             :                                         }
     667        4426 :                                 } else if (!f->func->s && is_not_func(f)) {
     668           2 :                                         if (is_atom(r->type) && r->l) { /* direct literal */
     669           2 :                                                 atom *a = r->l;
     670           2 :                                                 list *args = l->l;
     671           2 :                                                 sql_exp *inner = args->h->data;
     672           2 :                                                 sql_subfunc *inf = inner->f;
     673             : 
     674           2 :                                                 assert(list_length(args) == 1);
     675             : 
     676             :                                                 /* not(not(x)) = TRUE/FALSE => x = TRUE/FALSE */
     677           2 :                                                 if (is_func(inner->type) &&
     678           0 :                                                         !inf->func->s &&
     679           0 :                                                         is_not_func(inf)) {
     680           0 :                                                         int anti = is_anti(e), is_semantics = is_semantics(e);
     681             : 
     682           0 :                                                         args = inner->l;
     683           0 :                                                         assert(list_length(args) == 1);
     684           0 :                                                         l = args->h->data;
     685           0 :                                                         e = exp_compare(v->sql->sa, l, r, e->flag);
     686           0 :                                                         if (anti) set_anti(e);
     687           0 :                                                         if (is_semantics) set_semantics(e);
     688           0 :                                                         v->changes++;
     689             :                                                 /* rewrite not(=/<>(a,b)) = TRUE/FALSE => a=b / a<>b */
     690           2 :                                                 } else if (is_func(inner->type) &&
     691           0 :                                                         !inf->func->s &&
     692           0 :                                                         (!strcmp(inf->func->base.name, "=") ||
     693           0 :                                                          !strcmp(inf->func->base.name, "<>"))) {
     694           0 :                                                         int flag = a->data.val.bval;
     695           0 :                                                         sql_exp *ne;
     696           0 :                                                         args = inner->l;
     697             : 
     698           0 :                                                         if (!strcmp(inf->func->base.name, "<>"))
     699           0 :                                                                 flag = !flag;
     700           0 :                                                         if (e->flag == cmp_notequal)
     701           0 :                                                                 flag = !flag;
     702           0 :                                                         assert(list_length(args) == 2);
     703           0 :                                                         l = args->h->data;
     704           0 :                                                         r = args->h->next->data;
     705           0 :                                                         ne = exp_compare(v->sql->sa, l, r, (!flag)?cmp_equal:cmp_notequal);
     706           0 :                                                         if (a->isnull)
     707           0 :                                                                 e->l = ne;
     708             :                                                         else
     709             :                                                                 e = ne;
     710           0 :                                                         v->changes++;
     711           2 :                                                 } else if (a && a->data.vtype == TYPE_bit) {
     712           2 :                                                         int anti = is_anti(e), is_semantics = is_semantics(e);
     713             : 
     714             :                                                         /* change atom's value on right */
     715           2 :                                                         l = args->h->data;
     716           2 :                                                         if (!a->isnull)
     717           2 :                                                                 r = exp_atom_bool(v->sql->sa, !a->data.val.bval);
     718           2 :                                                         e = exp_compare(v->sql->sa, l, r, e->flag);
     719           2 :                                                         if (anti) set_anti(e);
     720           2 :                                                         if (is_semantics) set_semantics(e);
     721           2 :                                                         v->changes++;
     722             :                                                 }
     723             :                                         }
     724             :                                 }
     725      407595 :                         } else if (is_atom(l->type) && is_atom(r->type) && !is_semantics(e) && !is_any(e) && !e->f) {
     726             :                                 /* compute comparisons on atoms */
     727         456 :                                 if (exp_is_null(l) || exp_is_null(r)) {
     728          39 :                                         e = exp_null(v->sql->sa, sql_bind_localtype("bit"));
     729          39 :                                         v->changes++;
     730         417 :                                 } else if (l->l && r->l) {
     731         417 :                                         int res = atom_cmp(l->l, r->l);
     732         417 :                                         bool flag = !is_anti(e);
     733             : 
     734         417 :                                         if (res == 0)
     735          53 :                                                 e = exp_atom_bool(v->sql->sa, (e->flag == cmp_equal || e->flag == cmp_gte || e->flag == cmp_lte) ? flag : !flag);
     736         364 :                                         else if (res > 0)
     737          58 :                                                 e = exp_atom_bool(v->sql->sa, (e->flag == cmp_gt || e->flag == cmp_gte || e->flag == cmp_notequal) ? flag : !flag);
     738             :                                         else
     739         306 :                                                 e = exp_atom_bool(v->sql->sa, (e->flag == cmp_lt || e->flag == cmp_lte || e->flag == cmp_notequal) ? flag : !flag);
     740         417 :                                         v->changes++;
     741             :                                 }
     742             :                         }
     743             :                 }
     744             :         }
     745             :         return e;
     746             : }
     747             : 
     748             : static inline sql_exp *
     749    15231359 : rel_remove_alias(visitor *v, sql_rel *rel, sql_exp *e)
     750             : {
     751    15231359 :         if (e->type != e_column)
     752             :                 return e;
     753    10919904 :         if (!rel_is_ref(rel) && rel->op == op_project && rel->l && list_length(rel->exps) > 1) {
     754     4830727 :                 sql_rel *l = rel->l;
     755     4830727 :                 if (l->op == op_project) {
     756     1245506 :                         sql_exp *ne = rel_find_exp(l, e);
     757     1245506 :                         if (ne && ne->type == e_column && is_selfref(ne)) {
     758        2103 :                                 sql_exp *nne = NULL;
     759             :                                 /* found ne in projection, try to find reference in the same list */
     760        2103 :                                 if (ne->l)
     761        1603 :                                         nne = exps_bind_column2(l->exps, ne->l, ne->r, NULL);
     762             :                                 else
     763         500 :                                         nne = exps_bind_column(l->exps, ne->r, NULL, NULL, 1);
     764        2103 :                                 if (nne && nne != ne && list_position(l->exps, nne) < list_position(l->exps, ne)) {
     765        1918 :                                         e->l = (char*)exp_relname(nne);
     766        1918 :                                         e->r = (char*)exp_name(nne);
     767        1918 :                                         v->changes++;
     768             :                                 }
     769             :                         }
     770             :                 }
     771             :         }
     772    10919898 :         if (!rel_is_ref(rel) && rel->op != op_project) {
     773     5494795 :                 bool found = false;
     774     5494795 :                 if ((is_select(rel->op) || is_join(rel->op)) && rel->l && list_length(rel->exps) > 1) {
     775      333093 :                         sql_rel *l = rel->l;
     776      333093 :                         if (l->op == op_project) {
     777       17864 :                                 sql_exp *ne = rel_find_exp(l, e);
     778       17864 :                                 found = true;
     779       17864 :                                 if (ne && ne->type == e_column && is_selfref(ne)) {
     780           6 :                                         sql_exp *nne = NULL;
     781           6 :                                         if (ne->l)
     782           1 :                                                 nne = exps_bind_column2(l->exps, ne->l, ne->r, NULL);
     783             :                                         else
     784           5 :                                                 nne = exps_bind_column(l->exps, ne->r, NULL, NULL, 1);
     785           6 :                                         if (nne && nne != ne && list_position(l->exps, nne) < list_position(l->exps, ne)) {
     786           6 :                                                 e->l = (char*)exp_relname(nne);
     787           6 :                                                 e->r = (char*)exp_name(nne);
     788           6 :                                                 v->changes++;
     789             :                                         }
     790             :                                 }
     791             :                         }
     792             :                 }
     793     5476937 :                 if (!found && is_join(rel->op) && rel->r && list_length(rel->exps) > 1 && !is_semi(rel->op)) {
     794      175101 :                         sql_rel *l = rel->r;
     795      175101 :                         if (l->op == op_project) {
     796       11769 :                                 sql_exp *ne = rel_find_exp(l, e);
     797       11769 :                                 found = true;
     798       11769 :                                 if (ne && ne->type == e_column && is_selfref(ne)) {
     799          31 :                                         sql_exp *nne = NULL;
     800          31 :                                         if (ne->l)
     801          31 :                                                 nne = exps_bind_column2(l->exps, ne->l, ne->r, NULL);
     802             :                                         else
     803           0 :                                                 nne = exps_bind_column(l->exps, ne->r, NULL, NULL, 1);
     804          31 :                                         if (nne && nne != ne && list_position(l->exps, nne) < list_position(l->exps, ne)) {
     805          31 :                                                 e->l = (char*)exp_relname(nne);
     806          31 :                                                 e->r = (char*)exp_name(nne);
     807          31 :                                                 v->changes++;
     808             :                                         }
     809             :                                 }
     810             :                         }
     811             :                 }
     812             :         }
     813             :         return e;
     814             : }
     815             : 
     816             : static inline sql_exp *
     817    15231357 : rel_merge_project_rse(visitor *v, sql_rel *rel, sql_exp *e)
     818             : {
     819    15231357 :         if (is_simple_project(rel->op) && is_func(e->type) && e->l) {
     820      734945 :                 list *fexps = e->l;
     821      734945 :                 sql_subfunc *f = e->f;
     822             : 
     823             :                 /* is and function */
     824      734945 :                 if (!f->func->s && strcmp(f->func->base.name, "and") == 0 && list_length(fexps) == 2) {
     825       17951 :                         sql_exp *l = list_fetch(fexps, 0), *r = list_fetch(fexps, 1);
     826             : 
     827             :                         /* check merge into single between */
     828       17951 :                         if (is_func(l->type) && is_func(r->type)) {
     829       14662 :                                 list *lfexps = l->l, *rfexps = r->l;
     830       14662 :                                 sql_subfunc *lff = l->f, *rff = r->f;
     831             : 
     832       14662 :                                 if (((strcmp(lff->func->base.name, ">=") == 0 || strcmp(lff->func->base.name, ">") == 0) && list_length(lfexps) == 2) &&
     833        1034 :                                         ((strcmp(rff->func->base.name, "<=") == 0 || strcmp(rff->func->base.name, "<") == 0) && list_length(rfexps) == 2)) {
     834         129 :                                         sql_exp *le = list_fetch(lfexps, 0), *lf = list_fetch(rfexps, 0);
     835         129 :                                         int c_le = is_numeric_upcast(le), c_lf = is_numeric_upcast(lf);
     836             : 
     837         129 :                                         if (exp_equal(c_le?le->l:le, c_lf?lf->l:lf) == 0) {
     838         108 :                                                 sql_exp *re = list_fetch(lfexps, 1), *rf = list_fetch(rfexps, 1), *ne = NULL;
     839         108 :                                                 sql_subtype super;
     840             : 
     841         108 :                                                 supertype(&super, exp_subtype(le), exp_subtype(lf)); /* le/re and lf/rf must have the same type */
     842         108 :                                                 if (!(le = exp_check_type(v->sql, &super, rel, le, type_equal)) ||
     843         108 :                                                         !(re = exp_check_type(v->sql, &super, rel, re, type_equal)) ||
     844         108 :                                                         !(rf = exp_check_type(v->sql, &super, rel, rf, type_equal))) {
     845           0 :                                                                 v->sql->session->status = 0;
     846           0 :                                                                 v->sql->errstr[0] = 0;
     847           0 :                                                                 return e;
     848             :                                                         }
     849         108 :                                                 if ((ne = exp_compare2(v->sql->sa, le, re, rf, compare_funcs2range(lff->func->base.name, rff->func->base.name), 0))) {
     850         108 :                                                         if (exp_name(e))
     851           0 :                                                                 exp_prop_alias(v->sql->sa, ne, e);
     852         108 :                                                         e = ne;
     853         108 :                                                         v->changes++;
     854             :                                                 }
     855             :                                         }
     856             :                                 }
     857             :                         }
     858             :                 }
     859             :         }
     860             :         return e;
     861             : }
     862             : 
     863             : static sql_exp *
     864    15231353 : rel_optimize_exps_(visitor *v, sql_rel *rel, sql_exp *e, int depth)
     865             : {
     866    15231353 :         (void) depth;
     867    15231353 :         if (v->value_based_opt)
     868     7051095 :                 e = rel_simplify_predicates(v, rel, e);
     869    15231352 :         e = rel_merge_project_rse(v, rel, e);
     870    15231352 :         e = rel_remove_alias(v, rel, e);
     871    15231346 :         return e;
     872             : }
     873             : 
     874             : static sql_rel *
     875      152874 : rel_optimize_exps(visitor *v, global_props *gp, sql_rel *rel)
     876             : {
     877      152874 :         (void) gp;
     878      152874 :         return rel_exp_visitor_bottomup(v, rel, &rel_optimize_exps_, false);
     879             : }
     880             : 
     881             : run_optimizer
     882      596796 : bind_optimize_exps(visitor *v, global_props *gp)
     883             : {
     884      596796 :         int flag = v->sql->sql_optimizer;
     885      583258 :         return gp->opt_cycle < 2 && gp->opt_level == 1 && (gp->cnt[op_project] || gp->cnt[op_join]
     886      430627 :                    || gp->cnt[op_left] || gp->cnt[op_right] || gp->cnt[op_full] || gp->cnt[op_semi]
     887     1179866 :                    || gp->cnt[op_anti] || gp->cnt[op_select]) && (flag & optimize_exps) ? rel_optimize_exps : NULL;
     888             : }

Generated by: LCOV version 1.14