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 : }
|