LCOV - code coverage report
Current view: top level - sql/server - rel_optimize_exps.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 450 556 80.9 %
Date: 2024-10-03 20:03:20 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       50830 : str_ends_with(const char *s, const char *suffix)
      21             : {
      22       50830 :         size_t slen = strlen(s), suflen = strlen(suffix);
      23       50830 :         if (suflen > slen)
      24             :                 return 1;
      25         549 :         return strncmp(s + slen - suflen, suffix, suflen);
      26             : }
      27             : 
      28             : static sql_exp *
      29      398322 : exp_simplify_math( mvc *sql, sql_exp *e, int *changes)
      30             : {
      31      398322 :         if (e->type == e_func || e->type == e_aggr) {
      32       86044 :                 list *l = e->l;
      33       86044 :                 sql_subfunc *f = e->f;
      34       86044 :                 node *n;
      35       86044 :                 sql_exp *le;
      36             : 
      37       86044 :                 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       85972 :                 if (!f->func->semantics && f->func->type != F_PROC) {
      42      154413 :                         for (node *n = l->h ; n ; n = n->next) {
      43      101662 :                                 sql_exp *arg = n->data;
      44             : 
      45      101662 :                                 if (exp_is_atom(arg) && exp_is_null(arg)) {
      46          48 :                                         sql_exp *ne = exp_null(sql->sa, exp_subtype(e));
      47          48 :                                         (*changes)++;
      48          48 :                                         if (exp_name(e))
      49          19 :                                                 exp_prop_alias(sql->sa, ne, e);
      50          48 :                                         return ne;
      51             :                                 }
      52             :                         }
      53             :                 }
      54       85924 :                 if (!f->func->s && list_length(l) == 2 && str_ends_with(sql_func_imp(f->func), "_no_nil") == 0) {
      55         106 :                         sql_exp *le = l->h->data;
      56         106 :                         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         106 :                         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         105 :                         if (exp_is_atom(re) && exp_is_null(re)) {
      70           0 :                                 (*changes)++;
      71           0 :                                 if (exp_name(e))
      72           0 :                                         exp_prop_alias(sql->sa, le, e);
      73           0 :                                 return le;
      74             :                         }
      75             :                 }
      76             : 
      77       85923 :                 le = l->h->data;
      78       85923 :                 if (!EC_COMPUTE(exp_subtype(le)->type->eclass) && exp_subtype(le)->type->eclass != EC_DEC)
      79             :                         return e;
      80             : 
      81       56163 :                 if (!f->func->s && !strcmp(f->func->base.name, "sql_mul") && list_length(l) == 2) {
      82       11106 :                         sql_exp *le = l->h->data;
      83       11106 :                         sql_exp *re = l->h->next->data;
      84       11106 :                         sql_subtype *et = exp_subtype(e);
      85             : 
      86             :                         /* 0*a = 0 */
      87       11106 :                         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, 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       11106 :                         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, 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       11104 :                         if (exp_is_atom(le) && exp_is_atom(re)) {
     107          83 :                                 atom *la = exp_flatten(sql, true, le);
     108          83 :                                 atom *ra = exp_flatten(sql, true, re);
     109             : 
     110          83 :                                 if (la && ra && subtype_cmp(atom_type(la), atom_type(ra)) == 0 && subtype_cmp(atom_type(la), exp_subtype(e)) == 0) {
     111          10 :                                         atom *a = atom_mul(sql->sa, la, ra);
     112             : 
     113          10 :                                         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, 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       11100 :                         if (is_func(le->type)) {
     126         101 :                                 list *l = le->l;
     127         101 :                                 sql_subfunc *f = le->f;
     128             : 
     129         101 :                                 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, 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         101 :                                 if (!f->func->s && !strcmp(f->func->base.name, "sql_mul") && list_length(l) == 2) {
     147          31 :                                         sql_exp *lle = l->h->data;
     148          31 :                                         sql_exp *lre = l->h->next->data;
     149          31 :                                         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, true))) {
     154           2 :                                                         sql->session->status = 0;
     155           2 :                                                         sql->errstr[0] = '\0';
     156           2 :                                                         return e; /* error, fallback to original expression */
     157             :                                                 }
     158          11 :                                                 if (!(ne = rel_binop_(sql, NULL, lle, le, "sys", "sql_mul", card_value, true))) {
     159           0 :                                                         sql->session->status = 0;
     160           0 :                                                         sql->errstr[0] = '\0';
     161           0 :                                                         return e; /* error, fallback to original expression */
     162             :                                                 }
     163          11 :                                                 if (subtype_cmp(exp_subtype(e), exp_subtype(ne)) != 0)
     164           0 :                                                         ne = exp_convert(sql, ne, exp_subtype(ne), exp_subtype(e));
     165          11 :                                                 (*changes)++;
     166          11 :                                                 if (exp_name(e))
     167           6 :                                                         exp_prop_alias(sql->sa, ne, e);
     168          11 :                                                 return ne;
     169             :                                         }
     170             :                                 }
     171             :                         }
     172             :                 }
     173       56144 :                 if (!f->func->s && !strcmp(f->func->base.name, "sql_add") && list_length(l) == 2) {
     174       23142 :                         sql_exp *le = l->h->data;
     175       23142 :                         sql_exp *re = l->h->next->data;
     176       23142 :                         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, 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       23141 :                         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, 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       23137 :                         if (exp_is_atom(le) && exp_is_atom(re)) {
     193          57 :                                 atom *la = exp_flatten(sql, true, le);
     194          57 :                                 atom *ra = exp_flatten(sql, true, re);
     195             : 
     196          57 :                                 if (la && ra) {
     197          20 :                                         atom *a = atom_add(sql->sa, la, ra);
     198             : 
     199          20 :                                         if (a) {
     200           9 :                                                 sql_exp *ne = exp_atom(sql->sa, a);
     201           9 :                                                 if (subtype_cmp(exp_subtype(e), exp_subtype(ne)) != 0)
     202           3 :                                                         ne = exp_convert(sql, ne, exp_subtype(ne), exp_subtype(e));
     203           9 :                                                 (*changes)++;
     204           9 :                                                 if (exp_name(e))
     205           1 :                                                         exp_prop_alias(sql->sa, ne, e);
     206           9 :                                                 return ne;
     207             :                                         }
     208             :                                 }
     209             :                         }
     210       23128 :                         if (is_func(le->type)) {
     211        5355 :                                 list *ll = le->l;
     212        5355 :                                 sql_subfunc *f = le->f;
     213        5355 :                                 if (!f->func->s && !strcmp(f->func->base.name, "sql_add") && list_length(ll) == 2) {
     214        4906 :                                         sql_exp *lle = ll->h->data;
     215        4906 :                                         sql_exp *lre = ll->h->next->data;
     216             : 
     217        4906 :                                         if (exp_is_atom(lle) && exp_is_atom(lre))
     218             :                                                 return e;
     219        4889 :                                         if (!exp_is_atom(re) && exp_is_atom(lre)) {
     220             :                                                 /* (x+c1)+y -> (x+y) + c1 */
     221         390 :                                                 ll->h->next->data = re;
     222         390 :                                                 l->h->next->data = lre;
     223         390 :                                                 if (!(l->h->data = exp_simplify_math(sql, le, changes)))
     224             :                                                         return NULL;
     225         390 :                                                 (*changes)++;
     226         390 :                                                 return e;
     227             :                                         }
     228        4499 :                                         if (exp_is_atom(re) && exp_is_atom(lre)) {
     229             :                                                 /* (x+c1)+c2 -> (c2+c1) + x */
     230           4 :                                                 ll->h->data = re;
     231           4 :                                                 l->h->next->data = lle;
     232           4 :                                                 if (!(l->h->data = exp_simplify_math(sql, le, changes)))
     233             :                                                         return NULL;
     234           4 :                                                 (*changes)++;
     235           4 :                                                 return e;
     236             :                                         }
     237             :                                 }
     238             :                         }
     239             :                 }
     240       55719 :                 if (!f->func->s && !strcmp(f->func->base.name, "sql_sub") && list_length(l) == 2) {
     241        5471 :                         sql_exp *le = l->h->data;
     242        5471 :                         sql_exp *re = l->h->next->data;
     243             : 
     244        5471 :                         if (exp_is_atom(le) && exp_is_atom(re)) {
     245          22 :                                 atom *la = exp_flatten(sql, true, le);
     246          22 :                                 atom *ra = exp_flatten(sql, true, re);
     247             : 
     248          22 :                                 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           5 :                                                         ne = exp_convert(sql, 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        5464 :                         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, 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        5464 :                         if (is_func(le->type)) {
     282          53 :                                 list *ll = le->l;
     283          53 :                                 sql_subfunc *f = le->f;
     284          53 :                                 if (!f->func->s && !strcmp(f->func->base.name, "sql_add") && list_length(ll) == 2) {
     285           8 :                                         sql_exp *lle = ll->h->data;
     286           8 :                                         sql_exp *lre = ll->h->next->data;
     287           8 :                                         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, 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           8 :                                         if (exp_is_atom(lle) && exp_is_atom(lre))
     297             :                                                 return e;
     298           8 :                                         if (!exp_is_atom(re) && exp_is_atom(lre)) {
     299             :                                                 /* (x+c1)-y -> (x-y) + c1 */
     300           4 :                                                 ll->h->next->data = re;
     301           4 :                                                 l->h->next->data = lre;
     302           4 :                                                 le->f = e->f;
     303           4 :                                                 e->f = f;
     304           4 :                                                 if (!(l->h->data = exp_simplify_math(sql, le, changes)))
     305             :                                                         return NULL;
     306           4 :                                                 (*changes)++;
     307           4 :                                                 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       55708 :                 if (l)
     325      176029 :                         for (n = l->h; n; n = n->next)
     326      120321 :                                 if (!(n->data = exp_simplify_math(sql, n->data, changes)))
     327             :                                         return NULL;
     328             :         }
     329      367986 :         if (e->type == e_convert)
     330       27611 :                 if (!(e->l = exp_simplify_math(sql, e->l, changes)))
     331             :                         return NULL;
     332             :         return e;
     333             : }
     334             : 
     335             : static inline sql_rel *
     336     1174227 : rel_simplify_math_(visitor *v, sql_rel *rel)
     337             : {
     338     1174227 :         if ((is_simple_project(rel->op) || (rel->op == op_ddl && rel->flag == ddl_psm)) && rel->exps) {
     339      283475 :                 int needed = 0, ochanges = 0;
     340             : 
     341     1596827 :                 for (node *n = rel->exps->h; n && !needed; n = n->next) {
     342     1313352 :                         sql_exp *e = n->data;
     343             : 
     344     1313352 :                         if (e->type == e_func || e->type == e_convert || e->type == e_aggr || e->type == e_psm)
     345       38590 :                                 needed = 1;
     346             :                 }
     347      283475 :                 if (!needed)
     348      244886 :                         return rel;
     349             : 
     350      288581 :                 for (node *n = rel->exps->h; n; n = n->next) {
     351      249991 :                         sql_exp *ne = exp_simplify_math(v->sql, n->data, &ochanges);
     352             : 
     353      249992 :                         if (!ne)
     354             :                                 return NULL;
     355      249992 :                         n->data = ne;
     356             :                 }
     357       38590 :                 v->changes += ochanges;
     358             :         }
     359             :         return rel;
     360             : }
     361             : 
     362             : static sql_rel *
     363      357074 : rel_simplify_math(visitor *v, global_props *gp, sql_rel *rel)
     364             : {
     365      357074 :         (void) gp;
     366      357074 :         return rel_visitor_bottomup(v, rel, &rel_simplify_math_);
     367             : }
     368             : 
     369             : run_optimizer
     370      622729 : bind_simplify_math(visitor *v, global_props *gp)
     371             : {
     372      622729 :         int flag = v->sql->sql_optimizer;
     373      547455 :         return gp->opt_cycle == 0 && gp->opt_level == 1 && v->value_based_opt && (gp->cnt[op_project]
     374     1022095 :                    || 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 performance (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           4 : reduce_scale(mvc *sql, atom *a)
     398             : {
     399           4 :         int i = 0;
     400           4 :         atom *na = a;
     401             : #ifdef HAVE_HGE
     402           4 :         hge nval = 0;
     403             : #else
     404             :         lng nval = 0;
     405             : #endif
     406             : 
     407             : #ifdef HAVE_HGE
     408           4 :         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           7 :                 reduce_scale_tpe(int, a->data.val.ival);
     416             :         } else if (a->data.vtype == TYPE_sht) {
     417           0 :                 reduce_scale_tpe(sht, a->data.val.shval);
     418             :         } else if (a->data.vtype == TYPE_bte) {
     419           5 :                 reduce_scale_tpe(bte, a->data.val.btval);
     420             :         }
     421           4 :         if (i) {
     422           2 :                 na = atom_int(sql->sa, &a->tpe, nval);
     423           2 :                 if (na->tpe.scale)
     424           1 :                         na->tpe.scale -= i;
     425             :                 else
     426             :                         return NULL;
     427             :         }
     428             :         return na;
     429             : }
     430             : 
     431             : static inline sql_exp *
     432     7061110 : rel_simplify_predicates(visitor *v, sql_rel *rel, sql_exp *e)
     433             : {
     434     7061110 :         if (is_func(e->type) && list_length(e->l) == 3 && is_case_func((sql_subfunc*)e->f)) {
     435       35230 :                 list *args = e->l;
     436       35230 :                 sql_exp *ie = args->h->data;
     437             : 
     438       35230 :                 if (exp_is_true(ie)) { /* ifthenelse(true, x, y) -> x */
     439          14 :                         sql_exp *res = args->h->next->data;
     440          14 :                         if (exp_name(e))
     441           6 :                                 exp_prop_alias(v->sql->sa, res, e);
     442          14 :                         v->changes++;
     443          14 :                         return res;
     444       35216 :                 } else if (exp_is_false(ie) || exp_is_null(ie)) { /* ifthenelse(false or null, x, y) -> y */
     445          12 :                         sql_exp *res = args->h->next->next->data;
     446          12 :                         if (exp_name(e))
     447           6 :                                 exp_prop_alias(v->sql->sa, res, e);
     448          12 :                         v->changes++;
     449          12 :                         return res;
     450             :                 }
     451             :         }
     452     7061084 :         if (is_func(e->type) && list_length(e->l) == 4 && is_casewhen_func((sql_subfunc*)e->f)) {
     453             :                 /* case x when y then a else b */
     454         420 :                 list *args = e->l;
     455         420 :                 node *n = args->h;
     456         420 :                 sql_exp *le = n->data;
     457         420 :                 sql_exp *re = n->next->data;
     458             : 
     459         420 :                 if (exp_is_atom(le) && exp_is_not_null(le) && exp_is_atom(re) && le->type == e_atom && le->l && re->type == e_atom && re->l) {
     460          53 :                         n = n->next->next;
     461          53 :                         if (exp_match_exp(le, re)) { /* x==y -> a */
     462           9 :                                 sql_exp *res = n->data;
     463           9 :                                 if (exp_name(e))
     464           7 :                                         exp_prop_alias(v->sql->sa, res, e);
     465           9 :                                 v->changes++;
     466           9 :                                 return res;
     467             :                         } else { /*  -> b */
     468          44 :                                 sql_exp *res = n->next->data;
     469          44 :                                 if (exp_name(e))
     470           9 :                                         exp_prop_alias(v->sql->sa, res, e);
     471          44 :                                 v->changes++;
     472          44 :                                 return res;
     473             :                         }
     474             :                 }
     475             :         }
     476     7061031 :         if (is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) {
     477             :                 /* simplify like expressions */
     478     1626444 :                 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 &&
     479       12768 :                         list_length((list *)e->l) == 1 && list_length((list *)e->r) == 3) {
     480        6384 :                         list *r = e->r;
     481        6384 :                         sql_exp *fmt = r->h->data;
     482        6384 :                         sql_exp *esc = r->h->next->data;
     483        6384 :                         sql_exp *isen = r->h->next->next->data;
     484        6384 :                         int rewrite = 0, isnull = 0;
     485             : 
     486        6384 :                         if (fmt->type == e_convert)
     487          97 :                                 fmt = fmt->l;
     488             :                         /* check for simple like expression */
     489        6384 :                         if (exp_is_null(fmt)) {
     490             :                                 isnull = 1;
     491        6381 :                         } else if (is_atom(fmt->type)) {
     492        6256 :                                 atom *fa = NULL;
     493             : 
     494        6256 :                                 if (fmt->l)
     495        6256 :                                         fa = fmt->l;
     496        6256 :                                 if (fa && fa->data.vtype == TYPE_str && !strchr(fa->data.val.sval, '%') && !strchr(fa->data.val.sval, '_'))
     497        6384 :                                         rewrite = 1;
     498             :                         }
     499        6384 :                         if (rewrite && !isnull) { /* check escape flag */
     500         141 :                                 if (exp_is_null(esc)) {
     501             :                                         isnull = 1;
     502             :                                 } else {
     503         141 :                                         atom *ea = esc->l;
     504             : 
     505         141 :                                         if (!is_atom(esc->type) || !ea)
     506             :                                                 rewrite = 0;
     507         141 :                                         else if (ea->data.vtype != TYPE_str || strlen(ea->data.val.sval) != 0)
     508          69 :                                                 rewrite = 0;
     509             :                                 }
     510             :                         }
     511        6384 :                         if (rewrite && !isnull) { /* check insensitive flag */
     512          72 :                                 if (exp_is_null(isen)) {
     513             :                                         isnull = 1;
     514             :                                 } else {
     515          72 :                                         atom *ia = isen->l;
     516             : 
     517          72 :                                         if (!is_atom(isen->type) || !ia)
     518             :                                                 rewrite = 0;
     519          72 :                                         else if (ia->data.vtype != TYPE_bit || ia->data.val.btval == 1)
     520          17 :                                                 rewrite = 0;
     521             :                                 }
     522             :                         }
     523        6384 :                         if (isnull) {
     524           3 :                                 e = exp_null(v->sql->sa, sql_bind_localtype("bit"));
     525           3 :                                 v->changes++;
     526           3 :                                 return e;
     527        6381 :                         } else if (rewrite) { /* rewrite to cmp_equal ! */
     528          55 :                                 list *l = e->l;
     529          55 :                                 list *r = e->r;
     530         107 :                                 e = exp_compare(v->sql->sa, l->h->data, r->h->data, is_anti(e) ? cmp_notequal : cmp_equal);
     531          55 :                                 v->changes++;
     532             :                         }
     533             :                 }
     534             :                 /* rewrite e if left or right is a cast */
     535     1620057 :                 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)) {
     536       11209 :                         sql_rel *r = rel->r;
     537       11209 :                         sql_exp *le = e->l, *re = e->r;
     538             : 
     539             :                         /* if convert on left then find mul or div on right which increased scale! */
     540       11209 :                         if (le->type == e_convert && re->type == e_column && (e->flag == cmp_lt || e->flag == cmp_gt) && r && is_project(r->op)) {
     541          73 :                                 sql_exp *nre = rel_find_exp(r, re);
     542          73 :                                 sql_subtype *tt = exp_totype(le), *ft = exp_fromtype(le);
     543             : 
     544          73 :                                 if (nre && nre->type == e_func) {
     545           3 :                                         sql_subfunc *f = nre->f;
     546             : 
     547           3 :                                         if (!f->func->s && !strcmp(f->func->base.name, "sql_mul")) {
     548           3 :                                                 list *args = nre->l;
     549           3 :                                                 sql_exp *ce = args->t->data;
     550           3 :                                                 sql_subtype *fst = exp_subtype(args->h->data);
     551             : 
     552           3 :                                                 if (fst->scale && fst->scale == ft->scale && is_atom(ce->type) && ce->l) {
     553           1 :                                                         atom *a = ce->l;
     554           1 :                                                         int anti = is_anti(e);
     555           1 :                                                         sql_exp *arg1, *arg2;
     556           1 :                                                         sql_subfunc *f;
     557             : #ifdef HAVE_HGE
     558           1 :                                                         hge val = 1;
     559             : #else
     560             :                                                         lng val = 1;
     561             : #endif
     562             :                                                         /* multiply with smallest value, then scale and (round) */
     563           1 :                                                         int scale = (int) tt->scale - (int) ft->scale, rs = 0;
     564           1 :                                                         atom *na = reduce_scale(v->sql, a);
     565             : 
     566           1 :                                                         if (na != a) {
     567           1 :                                                                 rs = a->tpe.scale - na->tpe.scale;
     568           1 :                                                                 ce->l = na;
     569             :                                                         }
     570           1 :                                                         scale -= rs;
     571             : 
     572           3 :                                                         while (scale > 0) {
     573           2 :                                                                 scale--;
     574           2 :                                                                 val *= 10;
     575             :                                                         }
     576           1 :                                                         arg1 = re;
     577             : #ifdef HAVE_HGE
     578           1 :                                                         arg2 = exp_atom_hge(v->sql->sa, val);
     579             : #else
     580             :                                                         arg2 = exp_atom_lng(v->sql->sa, val);
     581             : #endif
     582           1 :                                                         if ((f = sql_bind_func(v->sql, "sys", "scale_down", exp_subtype(arg1), exp_subtype(arg2), F_FUNC, true, true))) {
     583           1 :                                                                 e = exp_compare(v->sql->sa, le->l, exp_binop(v->sql->sa, arg1, arg2, f), e->flag);
     584           1 :                                                                 if (anti) set_anti(e);
     585           1 :                                                                 v->changes++;
     586             :                                                         } else {
     587           0 :                                                                 v->sql->session->status = 0;
     588           0 :                                                                 v->sql->errstr[0] = '\0';
     589             :                                                         }
     590             :                                                 }
     591             :                                         }
     592             :                                 }
     593             :                         }
     594             :                 }
     595     1620057 :                 if (is_compare(e->type) && is_semantics(e) && (e->flag == cmp_equal || e->flag == cmp_notequal) && exp_is_null(e->r)) {
     596             :                         /* simplify 'is null' predicates on constants */
     597        7320 :                         if (exp_is_null(e->l)) {
     598          29 :                                 int nval = e->flag == cmp_equal;
     599          29 :                                 if (is_anti(e)) nval = !nval;
     600          29 :                                 e = exp_atom_bool(v->sql->sa, nval);
     601          29 :                                 v->changes++;
     602          29 :                                 return e;
     603        7291 :                         } else if (exp_is_not_null(e->l)) {
     604        2318 :                                 int nval = e->flag == cmp_notequal;
     605        2318 :                                 if (is_anti(e)) nval = !nval;
     606        2318 :                                 e = exp_atom_bool(v->sql->sa, nval);
     607        2318 :                                 v->changes++;
     608        2318 :                                 return e;
     609             :                         }
     610             :                 }
     611     1617710 :                 if (is_atom(e->type) && ((!e->l && !e->r && !e->f) || e->r)) /* prepared statement parameter or argument */
     612             :                         return e;
     613     1617341 :                 if (is_atom(e->type) && e->l) { /* direct literal */
     614      426392 :                         atom *a = e->l;
     615      426392 :                         int flag = a->data.val.bval;
     616             : 
     617             :                         /* remove simple select true expressions */
     618      426392 :                         if (flag)
     619             :                                 return e;
     620             :                 }
     621     1226580 :                 if (is_compare(e->type) && is_theta_exp(e->flag)) {
     622      415307 :                         sql_exp *l = e->l;
     623      415307 :                         sql_exp *r = e->r;
     624             : 
     625      415307 :                         if (is_func(l->type) && (e->flag == cmp_equal || e->flag == cmp_notequal)) {
     626        5392 :                                 sql_subfunc *f = l->f;
     627             : 
     628             :                                 /* rewrite isnull(x) = TRUE/FALSE => x =/<> NULL */
     629        5392 :                                 if (!f->func->s && is_isnull_func(f)) {
     630         964 :                                         list *args = l->l;
     631         964 :                                         sql_exp *ie = args->h->data;
     632             : 
     633         964 :                                         if (!has_nil(ie) || exp_is_not_null(ie)) { /* is null on something that is never null, is always false */
     634         306 :                                                 ie = exp_atom_bool(v->sql->sa, 0);
     635         306 :                                                 v->changes++;
     636         306 :                                                 e->l = ie;
     637         658 :                                         } else if (exp_is_null(ie)) { /* is null on something that is always null, is always true */
     638           0 :                                                 ie = exp_atom_bool(v->sql->sa, 1);
     639           0 :                                                 v->changes++;
     640           0 :                                                 e->l = ie;
     641         658 :                                         } else if (is_atom(r->type) && r->l) { /* direct literal */
     642         642 :                                                 atom *a = r->l;
     643             : 
     644         642 :                                                 if (a->isnull) {
     645           0 :                                                         if (is_semantics(e)) { /* isnull(x) = NULL -> false, isnull(x) <> NULL -> true */
     646           0 :                                                                 int flag = e->flag == cmp_notequal;
     647           0 :                                                                 if (is_anti(e))
     648           0 :                                                                         flag = !flag;
     649           0 :                                                                 e = exp_atom_bool(v->sql->sa, flag);
     650             :                                                         } else /* always NULL */
     651           0 :                                                                 e = exp_null(v->sql->sa, sql_bind_localtype("bit"));
     652           0 :                                                         v->changes++;
     653             :                                                 } else {
     654         642 :                                                         int flag = a->data.val.bval;
     655             : 
     656         642 :                                                         assert(list_length(args) == 1);
     657         642 :                                                         l = args->h->data;
     658         642 :                                                         if (exp_subtype(l)) {
     659         642 :                                                                 r = exp_atom(v->sql->sa, atom_general(v->sql->sa, exp_subtype(l), NULL, 0));
     660         642 :                                                                 e = exp_compare(v->sql->sa, l, r, e->flag);
     661         642 :                                                                 if (e && !flag)
     662         272 :                                                                         set_anti(e);
     663         642 :                                                                 if (e)
     664         642 :                                                                         set_semantics(e);
     665         642 :                                                                 v->changes++;
     666             :                                                         }
     667             :                                                 }
     668             :                                         }
     669        4428 :                                 } else if (!f->func->s && is_not_func(f)) {
     670           2 :                                         if (is_atom(r->type) && r->l) { /* direct literal */
     671           2 :                                                 atom *a = r->l;
     672           2 :                                                 list *args = l->l;
     673           2 :                                                 sql_exp *inner = args->h->data;
     674           2 :                                                 sql_subfunc *inf = inner->f;
     675             : 
     676           2 :                                                 assert(list_length(args) == 1);
     677             : 
     678             :                                                 /* not(not(x)) = TRUE/FALSE => x = TRUE/FALSE */
     679           2 :                                                 if (is_func(inner->type) &&
     680           0 :                                                         !inf->func->s &&
     681           0 :                                                         is_not_func(inf)) {
     682           0 :                                                         int anti = is_anti(e), is_semantics = is_semantics(e);
     683             : 
     684           0 :                                                         args = inner->l;
     685           0 :                                                         assert(list_length(args) == 1);
     686           0 :                                                         l = args->h->data;
     687           0 :                                                         e = exp_compare(v->sql->sa, l, r, e->flag);
     688           0 :                                                         if (anti) set_anti(e);
     689           0 :                                                         if (is_semantics) set_semantics(e);
     690           0 :                                                         v->changes++;
     691             :                                                 /* rewrite not(=/<>(a,b)) = TRUE/FALSE => a=b / a<>b */
     692           2 :                                                 } else if (is_func(inner->type) &&
     693           0 :                                                         !inf->func->s &&
     694           0 :                                                         (!strcmp(inf->func->base.name, "=") ||
     695           0 :                                                          !strcmp(inf->func->base.name, "<>"))) {
     696           0 :                                                         int flag = a->data.val.bval;
     697           0 :                                                         sql_exp *ne;
     698           0 :                                                         args = inner->l;
     699             : 
     700           0 :                                                         if (!strcmp(inf->func->base.name, "<>"))
     701           0 :                                                                 flag = !flag;
     702           0 :                                                         if (e->flag == cmp_notequal)
     703           0 :                                                                 flag = !flag;
     704           0 :                                                         assert(list_length(args) == 2);
     705           0 :                                                         l = args->h->data;
     706           0 :                                                         r = args->h->next->data;
     707           0 :                                                         ne = exp_compare(v->sql->sa, l, r, (!flag)?cmp_equal:cmp_notequal);
     708           0 :                                                         if (a->isnull)
     709           0 :                                                                 e->l = ne;
     710             :                                                         else
     711             :                                                                 e = ne;
     712           0 :                                                         v->changes++;
     713           2 :                                                 } else if (a && a->data.vtype == TYPE_bit) {
     714           2 :                                                         int anti = is_anti(e), is_semantics = is_semantics(e);
     715             : 
     716             :                                                         /* change atom's value on right */
     717           2 :                                                         l = args->h->data;
     718           2 :                                                         if (!a->isnull)
     719           2 :                                                                 r = exp_atom_bool(v->sql->sa, !a->data.val.bval);
     720           2 :                                                         e = exp_compare(v->sql->sa, l, r, e->flag);
     721           2 :                                                         if (anti) set_anti(e);
     722           2 :                                                         if (is_semantics) set_semantics(e);
     723           2 :                                                         v->changes++;
     724             :                                                 }
     725             :                                         }
     726             :                                 }
     727      409915 :                         } else if (is_atom(l->type) && is_atom(r->type) && !is_semantics(e) && !is_any(e) && !e->f) {
     728             :                                 /* compute comparisons on atoms */
     729         646 :                                 if (exp_is_null(l) || exp_is_null(r)) {
     730          41 :                                         e = exp_null(v->sql->sa, sql_bind_localtype("bit"));
     731          41 :                                         v->changes++;
     732         605 :                                 } else if (l->l && r->l) {
     733         605 :                                         int res = atom_cmp(l->l, r->l);
     734         605 :                                         bool flag = !is_anti(e);
     735             : 
     736         605 :                                         if (res == 0)
     737          67 :                                                 e = exp_atom_bool(v->sql->sa, (e->flag == cmp_equal || e->flag == cmp_gte || e->flag == cmp_lte) ? flag : !flag);
     738         538 :                                         else if (res > 0)
     739          54 :                                                 e = exp_atom_bool(v->sql->sa, (e->flag == cmp_gt || e->flag == cmp_gte || e->flag == cmp_notequal) ? flag : !flag);
     740             :                                         else
     741         484 :                                                 e = exp_atom_bool(v->sql->sa, (e->flag == cmp_lt || e->flag == cmp_lte || e->flag == cmp_notequal) ? flag : !flag);
     742         605 :                                         v->changes++;
     743             :                                 }
     744             :                         }
     745             :                 }
     746             :         }
     747             :         return e;
     748             : }
     749             : 
     750             : static inline sql_exp *
     751    14805981 : rel_remove_alias(visitor *v, sql_rel *rel, sql_exp *e)
     752             : {
     753    14805981 :         if (e->type != e_column)
     754             :                 return e;
     755    10906808 :         if (!rel_is_ref(rel) && rel->op == op_project && rel->l && list_length(rel->exps) > 1) {
     756     4807585 :                 sql_rel *l = rel->l;
     757     4807585 :                 if (l->op == op_project) {
     758     1272792 :                         sql_exp *ne = rel_find_exp(l, e);
     759     1272792 :                         if (ne && ne->type == e_column && is_selfref(ne)) {
     760             :                                 /* found ne in projection, try to find reference in the same list */
     761         983 :                                 sql_exp *nne = exps_bind_nid(l->exps, ne->nid);
     762         983 :                                 if (nne && nne != ne && list_position(l->exps, nne) < list_position(l->exps, ne)) {
     763         983 :                                         e->l = (char*)exp_relname(nne);
     764         983 :                                         e->r = (char*)exp_name(nne);
     765         983 :                                         e->nid = nne->alias.label;
     766         983 :                                         v->changes++;
     767             :                                 }
     768             :                         }
     769             :                 }
     770             :         }
     771    10906805 :         if (!rel_is_ref(rel) && rel->op != op_project) {
     772     5448497 :                 bool found = false;
     773     5448497 :                 if ((is_select(rel->op) || is_join(rel->op)) && rel->l && list_length(rel->exps) > 1) {
     774      333375 :                         sql_rel *l = rel->l;
     775      333375 :                         if (l->op == op_project) {
     776       17991 :                                 sql_exp *ne = rel_find_exp(l, e);
     777       17991 :                                 found = true;
     778       17991 :                                 if (ne && ne->type == e_column && is_selfref(ne)) {
     779           3 :                                         sql_exp *nne = exps_bind_nid(l->exps, ne->nid);
     780           3 :                                         if (nne && nne != ne && list_position(l->exps, nne) < list_position(l->exps, ne)) {
     781           3 :                                                 e->l = (char*)exp_relname(nne);
     782           3 :                                                 e->r = (char*)exp_name(nne);
     783           3 :                                                 e->nid = nne->alias.label;
     784           3 :                                                 v->changes++;
     785             :                                         }
     786             :                                 }
     787             :                         }
     788             :                 }
     789     5430509 :                 if (!found && is_join(rel->op) && rel->r && list_length(rel->exps) > 1 && !is_semi(rel->op)) {
     790      176654 :                         sql_rel *l = rel->r;
     791      176654 :                         if (l->op == op_project) {
     792       11785 :                                 sql_exp *ne = rel_find_exp(l, e);
     793       11785 :                                 found = true;
     794       11785 :                                 if (ne && ne->type == e_column && is_selfref(ne)) {
     795          29 :                                         sql_exp *nne = exps_bind_nid(l->exps, ne->nid);
     796          29 :                                         if (nne && nne != ne && list_position(l->exps, nne) < list_position(l->exps, ne)) {
     797          29 :                                                 e->l = (char*)exp_relname(nne);
     798          29 :                                                 e->r = (char*)exp_name(nne);
     799          29 :                                                 e->nid = nne->alias.label;
     800          29 :                                                 v->changes++;
     801             :                                         }
     802             :                                 }
     803             :                         }
     804             :                 }
     805             :         }
     806             :         return e;
     807             : }
     808             : 
     809             : static inline sql_exp *
     810    14805977 : rel_merge_project_rse(visitor *v, sql_rel *rel, sql_exp *e)
     811             : {
     812    14805977 :         if (is_simple_project(rel->op) && is_func(e->type) && e->l) {
     813      709906 :                 list *fexps = e->l;
     814      709906 :                 sql_subfunc *f = e->f;
     815             : 
     816             :                 /* is and function */
     817      709906 :                 if (!f->func->s && strcmp(f->func->base.name, "and") == 0 && list_length(fexps) == 2) {
     818       17713 :                         sql_exp *l = list_fetch(fexps, 0), *r = list_fetch(fexps, 1);
     819             : 
     820             :                         /* check merge into single between */
     821       17713 :                         if (is_func(l->type) && is_func(r->type)) {
     822       14319 :                                 list *lfexps = l->l, *rfexps = r->l;
     823       14319 :                                 sql_subfunc *lff = l->f, *rff = r->f;
     824             : 
     825       14319 :                                 if (((strcmp(lff->func->base.name, ">=") == 0 || strcmp(lff->func->base.name, ">") == 0) && list_length(lfexps) == 2) &&
     826         593 :                                         ((strcmp(rff->func->base.name, "<=") == 0 || strcmp(rff->func->base.name, "<") == 0) && list_length(rfexps) == 2)) {
     827         130 :                                         sql_exp *le = list_fetch(lfexps, 0), *lf = list_fetch(rfexps, 0);
     828         130 :                                         int c_le = is_numeric_upcast(le), c_lf = is_numeric_upcast(lf);
     829             : 
     830         130 :                                         if (exp_equal(c_le?le->l:le, c_lf?lf->l:lf) == 0) {
     831          95 :                                                 sql_exp *re = list_fetch(lfexps, 1), *rf = list_fetch(rfexps, 1), *ne = NULL;
     832          95 :                                                 sql_subtype super;
     833             : 
     834          95 :                                                 supertype(&super, exp_subtype(le), exp_subtype(lf)); /* le/re and lf/rf must have the same type */
     835          95 :                                                 if (!(le = exp_check_type(v->sql, &super, rel, le, type_equal)) ||
     836          95 :                                                         !(re = exp_check_type(v->sql, &super, rel, re, type_equal)) ||
     837          95 :                                                         !(rf = exp_check_type(v->sql, &super, rel, rf, type_equal))) {
     838           0 :                                                                 v->sql->session->status = 0;
     839           0 :                                                                 v->sql->errstr[0] = 0;
     840           0 :                                                                 return e;
     841             :                                                         }
     842          95 :                                                 if ((ne = exp_compare2(v->sql->sa, le, re, rf, compare_funcs2range(lff->func->base.name, rff->func->base.name), 0))) {
     843          95 :                                                         if (exp_name(e))
     844           0 :                                                                 exp_prop_alias(v->sql->sa, ne, e);
     845          95 :                                                         e = ne;
     846          95 :                                                         v->changes++;
     847             :                                                 }
     848             :                                         }
     849             :                                 }
     850             :                         }
     851             :                 }
     852             :         }
     853             :         return e;
     854             : }
     855             : 
     856             : static sql_exp *
     857    14805968 : rel_optimize_exps_(visitor *v, sql_rel *rel, sql_exp *e, int depth)
     858             : {
     859    14805968 :         (void) depth;
     860    14805968 :         if (v->value_based_opt)
     861     7061107 :                 e = rel_simplify_predicates(v, rel, e);
     862    14805972 :         e = rel_merge_project_rse(v, rel, e);
     863    14805973 :         e = rel_remove_alias(v, rel, e);
     864    14805962 :         return e;
     865             : }
     866             : 
     867             : static sql_rel *
     868      167267 : rel_optimize_exps(visitor *v, global_props *gp, sql_rel *rel)
     869             : {
     870      167267 :         (void) gp;
     871      167267 :         return rel_exp_visitor_bottomup(v, rel, &rel_optimize_exps_, false);
     872             : }
     873             : 
     874             : run_optimizer
     875      622730 : bind_optimize_exps(visitor *v, global_props *gp)
     876             : {
     877      622730 :         int flag = v->sql->sql_optimizer;
     878      607619 :         return gp->opt_cycle < 2 && gp->opt_level == 1 && (gp->cnt[op_project] || gp->cnt[op_join]
     879      440620 :                    || gp->cnt[op_left] || gp->cnt[op_right] || gp->cnt[op_full] || gp->cnt[op_semi]
     880     1230153 :                    || gp->cnt[op_anti] || gp->cnt[op_select]) && (flag & optimize_exps) ? rel_optimize_exps : NULL;
     881             : }

Generated by: LCOV version 1.14