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 50832 : str_ends_with(const char *s, const char *suffix)
21 : {
22 50832 : size_t slen = strlen(s), suflen = strlen(suffix);
23 50832 : if (suflen > slen)
24 : return 1;
25 549 : return strncmp(s + slen - suflen, suffix, suflen);
26 : }
27 :
28 : static sql_exp *
29 398517 : exp_simplify_math( mvc *sql, sql_exp *e, int *changes)
30 : {
31 398517 : if (e->type == e_func || e->type == e_aggr) {
32 86083 : list *l = e->l;
33 86083 : sql_subfunc *f = e->f;
34 86083 : node *n;
35 86083 : sql_exp *le;
36 :
37 86083 : 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 86011 : if (!f->func->semantics && f->func->type != F_PROC) {
42 154423 : for (node *n = l->h ; n ; n = n->next) {
43 101669 : sql_exp *arg = n->data;
44 :
45 101669 : 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 18 : exp_prop_alias(sql->sa, ne, e);
50 48 : return ne;
51 : }
52 : }
53 : }
54 85963 : 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 85962 : le = l->h->data;
78 85962 : if (!EC_COMPUTE(exp_subtype(le)->type->eclass) && exp_subtype(le)->type->eclass != EC_DEC)
79 : return e;
80 :
81 56165 : 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 56146 : if (!f->func->s && !strcmp(f->func->base.name, "sql_add") && list_length(l) == 2) {
174 23144 : sql_exp *le = l->h->data;
175 23144 : sql_exp *re = l->h->next->data;
176 23144 : 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 23143 : 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 23139 : 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 23130 : 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 55721 : 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 55710 : if (l)
325 176035 : for (n = l->h; n; n = n->next)
326 120325 : if (!(n->data = exp_simplify_math(sql, n->data, changes)))
327 : return NULL;
328 : }
329 368144 : if (e->type == e_convert)
330 27621 : if (!(e->l = exp_simplify_math(sql, e->l, changes)))
331 : return NULL;
332 : return e;
333 : }
334 :
335 : static inline sql_rel *
336 1176861 : rel_simplify_math_(visitor *v, sql_rel *rel)
337 : {
338 1176861 : if ((is_simple_project(rel->op) || (rel->op == op_ddl && rel->flag == ddl_psm)) && rel->exps) {
339 283963 : int needed = 0, ochanges = 0;
340 :
341 1600016 : for (node *n = rel->exps->h; n && !needed; n = n->next) {
342 1316053 : sql_exp *e = n->data;
343 :
344 1316053 : if (e->type == e_func || e->type == e_convert || e->type == e_aggr || e->type == e_psm)
345 38628 : needed = 1;
346 : }
347 283963 : if (!needed)
348 245335 : return rel;
349 :
350 288801 : for (node *n = rel->exps->h; n; n = n->next) {
351 250173 : sql_exp *ne = exp_simplify_math(v->sql, n->data, &ochanges);
352 :
353 250173 : if (!ne)
354 : return NULL;
355 250173 : n->data = ne;
356 : }
357 38628 : v->changes += ochanges;
358 : }
359 : return rel;
360 : }
361 :
362 : static sql_rel *
363 357319 : rel_simplify_math(visitor *v, global_props *gp, sql_rel *rel)
364 : {
365 357319 : (void) gp;
366 357319 : return rel_visitor_bottomup(v, rel, &rel_simplify_math_);
367 : }
368 :
369 : run_optimizer
370 622961 : bind_simplify_math(visitor *v, global_props *gp)
371 : {
372 622961 : int flag = v->sql->sql_optimizer;
373 547301 : return gp->opt_cycle == 0 && gp->opt_level == 1 && v->value_based_opt && (gp->cnt[op_project]
374 1022167 : || 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 7077303 : rel_simplify_predicates(visitor *v, sql_rel *rel, sql_exp *e)
433 : {
434 7077303 : if (is_func(e->type) && list_length(e->l) == 3 && is_case_func((sql_subfunc*)e->f)) {
435 35229 : list *args = e->l;
436 35229 : sql_exp *ie = args->h->data;
437 :
438 35229 : 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 35215 : } 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 7077277 : 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 7077224 : if (is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) {
477 : /* simplify like expressions */
478 1633061 : 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 12792 : list_length((list *)e->l) == 1 && list_length((list *)e->r) == 3) {
480 6396 : list *r = e->r;
481 6396 : sql_exp *fmt = r->h->data;
482 6396 : sql_exp *esc = r->h->next->data;
483 6396 : sql_exp *isen = r->h->next->next->data;
484 6396 : int rewrite = 0, isnull = 0;
485 :
486 6396 : if (fmt->type == e_convert)
487 97 : fmt = fmt->l;
488 : /* check for simple like expression */
489 6396 : if (exp_is_null(fmt)) {
490 : isnull = 1;
491 6393 : } else if (is_atom(fmt->type)) {
492 6268 : atom *fa = NULL;
493 :
494 6268 : if (fmt->l)
495 6268 : fa = fmt->l;
496 6268 : if (fa && fa->data.vtype == TYPE_str && !strchr(fa->data.val.sval, '%') && !strchr(fa->data.val.sval, '_'))
497 6396 : rewrite = 1;
498 : }
499 6396 : 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 6396 : 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 6396 : if (isnull) {
524 3 : e = exp_null(v->sql->sa, sql_bind_localtype("bit"));
525 3 : v->changes++;
526 3 : return e;
527 6393 : } 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 1626662 : 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 11271 : sql_rel *r = rel->r;
537 11271 : 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 11271 : 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 1626662 : 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 7336 : 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 7307 : } else if (exp_is_not_null(e->l)) {
604 2485 : int nval = e->flag == cmp_notequal;
605 2485 : if (is_anti(e)) nval = !nval;
606 2485 : e = exp_atom_bool(v->sql->sa, nval);
607 2485 : v->changes++;
608 2485 : return e;
609 : }
610 : }
611 1624148 : if (is_atom(e->type) && ((!e->l && !e->r && !e->f) || e->r)) /* prepared statement parameter or argument */
612 : return e;
613 1623779 : if (is_atom(e->type) && e->l) { /* direct literal */
614 427740 : atom *a = e->l;
615 427740 : int flag = a->data.val.bval;
616 :
617 : /* remove simple select true expressions */
618 427740 : if (flag)
619 : return e;
620 : }
621 1231973 : if (is_compare(e->type) && is_theta_exp(e->flag)) {
622 417089 : sql_exp *l = e->l;
623 417089 : sql_exp *r = e->r;
624 :
625 417089 : if (is_func(l->type) && (e->flag == cmp_equal || e->flag == cmp_notequal)) {
626 5402 : sql_subfunc *f = l->f;
627 :
628 : /* rewrite isnull(x) = TRUE/FALSE => x =/<> NULL */
629 5402 : if (!f->func->s && is_isnull_func(f)) {
630 974 : list *args = l->l;
631 974 : sql_exp *ie = args->h->data;
632 :
633 974 : 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 668 : } 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 668 : } else if (is_atom(r->type) && r->l) { /* direct literal */
642 652 : atom *a = r->l;
643 :
644 652 : 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 652 : int flag = a->data.val.bval;
655 :
656 652 : assert(list_length(args) == 1);
657 652 : l = args->h->data;
658 652 : if (exp_subtype(l)) {
659 652 : r = exp_atom(v->sql->sa, atom_general(v->sql->sa, exp_subtype(l), NULL, 0));
660 652 : e = exp_compare(v->sql->sa, l, r, e->flag);
661 652 : if (e && !flag)
662 272 : set_anti(e);
663 652 : if (e)
664 652 : set_semantics(e);
665 652 : 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 411687 : } 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 14822218 : rel_remove_alias(visitor *v, sql_rel *rel, sql_exp *e)
752 : {
753 14822218 : if (e->type != e_column)
754 : return e;
755 10917791 : if (!rel_is_ref(rel) && rel->op == op_project && rel->l && list_length(rel->exps) > 1) {
756 4811832 : sql_rel *l = rel->l;
757 4811832 : if (l->op == op_project) {
758 1273373 : sql_exp *ne = rel_find_exp(l, e);
759 1273373 : 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 10917785 : if (!rel_is_ref(rel) && rel->op != op_project) {
772 5454966 : bool found = false;
773 5454966 : if ((is_select(rel->op) || is_join(rel->op)) && rel->l && list_length(rel->exps) > 1) {
774 333758 : sql_rel *l = rel->l;
775 333758 : 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 5436978 : if (!found && is_join(rel->op) && rel->r && list_length(rel->exps) > 1 && !is_semi(rel->op)) {
790 177040 : sql_rel *l = rel->r;
791 177040 : 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 14822208 : rel_merge_project_rse(visitor *v, sql_rel *rel, sql_exp *e)
811 : {
812 14822208 : if (is_simple_project(rel->op) && is_func(e->type) && e->l) {
813 709834 : list *fexps = e->l;
814 709834 : sql_subfunc *f = e->f;
815 :
816 : /* is and function */
817 709834 : if (!f->func->s && strcmp(f->func->base.name, "and") == 0 && list_length(fexps) == 2) {
818 17705 : sql_exp *l = list_fetch(fexps, 0), *r = list_fetch(fexps, 1);
819 :
820 : /* check merge into single between */
821 17705 : if (is_func(l->type) && is_func(r->type)) {
822 14311 : list *lfexps = l->l, *rfexps = r->l;
823 14311 : sql_subfunc *lff = l->f, *rff = r->f;
824 :
825 14311 : 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 14822176 : rel_optimize_exps_(visitor *v, sql_rel *rel, sql_exp *e, int depth)
858 : {
859 14822176 : (void) depth;
860 14822176 : if (v->value_based_opt)
861 7077301 : e = rel_simplify_predicates(v, rel, e);
862 14822202 : e = rel_merge_project_rse(v, rel, e);
863 14822211 : e = rel_remove_alias(v, rel, e);
864 14822211 : return e;
865 : }
866 :
867 : static sql_rel *
868 167792 : rel_optimize_exps(visitor *v, global_props *gp, sql_rel *rel)
869 : {
870 167792 : (void) gp;
871 167792 : return rel_exp_visitor_bottomup(v, rel, &rel_optimize_exps_, false);
872 : }
873 :
874 : run_optimizer
875 622936 : bind_optimize_exps(visitor *v, global_props *gp)
876 : {
877 622936 : int flag = v->sql->sql_optimizer;
878 607803 : return gp->opt_cycle < 2 && gp->opt_level == 1 && (gp->cnt[op_project] || gp->cnt[op_join]
879 440521 : || gp->cnt[op_left] || gp->cnt[op_right] || gp->cnt[op_full] || gp->cnt[op_semi]
880 1230543 : || gp->cnt[op_anti] || gp->cnt[op_select]) && (flag & optimize_exps) ? rel_optimize_exps : NULL;
881 : }
|