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 49809 : str_ends_with(const char *s, const char *suffix)
21 : {
22 49809 : size_t slen = strlen(s), suflen = strlen(suffix);
23 49809 : if (suflen > slen)
24 : return 1;
25 548 : return strncmp(s + slen - suflen, suffix, suflen);
26 : }
27 :
28 : static sql_exp *
29 403476 : exp_simplify_math( mvc *sql, sql_exp *e, int *changes)
30 : {
31 403476 : if (e->type == e_func || e->type == e_aggr) {
32 91941 : list *l = e->l;
33 91941 : sql_subfunc *f = e->f;
34 91941 : node *n;
35 91941 : sql_exp *le;
36 :
37 91941 : 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 91421 : if (!f->func->semantics && f->func->type != F_PROC) {
42 151746 : for (node *n = l->h ; n ; n = n->next) {
43 99910 : sql_exp *arg = n->data;
44 :
45 99910 : if (exp_is_atom(arg) && exp_is_null(arg)) {
46 45 : sql_exp *ne = exp_null(sql->sa, exp_subtype(e));
47 45 : (*changes)++;
48 45 : if (exp_name(e))
49 17 : exp_prop_alias(sql->sa, ne, e);
50 45 : return ne;
51 : }
52 : }
53 : }
54 91376 : if (!f->func->s && list_length(l) == 2 && str_ends_with(sql_func_imp(f->func), "_no_nil") == 0) {
55 116 : sql_exp *le = l->h->data;
56 116 : 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 116 : 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 115 : 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 91373 : le = l->h->data;
78 91373 : if (!EC_COMPUTE(exp_subtype(le)->type->eclass) && exp_subtype(le)->type->eclass != EC_DEC)
79 : return e;
80 :
81 63128 : if (!f->func->s && !strcmp(f->func->base.name, "sql_mul") && list_length(l) == 2) {
82 11005 : sql_exp *le = l->h->data;
83 11005 : sql_exp *re = l->h->next->data;
84 11005 : sql_subtype *et = exp_subtype(e);
85 :
86 : /* 0*a = 0 */
87 11005 : 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 11005 : 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 11003 : if (exp_is_atom(le) && exp_is_atom(re)) {
107 85 : atom *la = exp_flatten(sql, true, le);
108 85 : atom *ra = exp_flatten(sql, true, re);
109 :
110 85 : if (la && ra && subtype_cmp(atom_type(la), atom_type(ra)) == 0 && subtype_cmp(atom_type(la), exp_subtype(e)) == 0) {
111 11 : atom *a = atom_mul(sql->sa, la, ra);
112 :
113 11 : 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 10999 : if (is_func(le->type)) {
126 102 : list *l = le->l;
127 102 : sql_subfunc *f = le->f;
128 :
129 102 : 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 102 : 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->sa, 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 63109 : if (!f->func->s && !strcmp(f->func->base.name, "sql_add") && list_length(l) == 2) {
174 22694 : sql_exp *le = l->h->data;
175 22694 : sql_exp *re = l->h->next->data;
176 22694 : 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 22693 : 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 22689 : if (exp_is_atom(le) && exp_is_atom(re)) {
193 64 : atom *la = exp_flatten(sql, true, le);
194 64 : atom *ra = exp_flatten(sql, true, re);
195 :
196 64 : if (la && ra) {
197 19 : atom *a = atom_add(sql->sa, la, ra);
198 :
199 19 : if (a) {
200 8 : sql_exp *ne = exp_atom(sql->sa, a);
201 8 : 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 8 : (*changes)++;
204 8 : if (exp_name(e))
205 1 : exp_prop_alias(sql->sa, ne, e);
206 8 : return ne;
207 : }
208 : }
209 : }
210 22681 : if (is_func(le->type)) {
211 5369 : list *ll = le->l;
212 5369 : sql_subfunc *f = le->f;
213 5369 : if (!f->func->s && !strcmp(f->func->base.name, "sql_add") && list_length(ll) == 2) {
214 4915 : sql_exp *lle = ll->h->data;
215 4915 : sql_exp *lre = ll->h->next->data;
216 :
217 4915 : if (exp_is_atom(lle) && exp_is_atom(lre))
218 : return e;
219 4892 : 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 4502 : 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 62679 : if (!f->func->s && !strcmp(f->func->base.name, "sql_sub") && list_length(l) == 2) {
241 5448 : sql_exp *le = l->h->data;
242 5448 : sql_exp *re = l->h->next->data;
243 :
244 5448 : if (exp_is_atom(le) && exp_is_atom(re)) {
245 24 : atom *la = exp_flatten(sql, true, le);
246 24 : atom *ra = exp_flatten(sql, true, re);
247 :
248 24 : 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->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 5441 : if (!has_nil(le) && !has_nil(re) && exp_equal(le,re) == 0) { /* a - a = 0 */
263 2 : atom *a;
264 2 : sql_exp *ne;
265 :
266 2 : if (exp_subtype(le)->type->eclass == EC_NUM) {
267 0 : a = atom_int(sql->sa, exp_subtype(le), 0);
268 2 : } else if (exp_subtype(le)->type->eclass == EC_FLT) {
269 1 : a = atom_float(sql->sa, exp_subtype(le), 0);
270 : } else {
271 : return e;
272 : }
273 1 : ne = exp_atom(sql->sa, a);
274 1 : 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 1 : (*changes)++;
277 1 : if (exp_name(e))
278 0 : exp_prop_alias(sql->sa, ne, e);
279 1 : return ne;
280 : }
281 5439 : 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->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 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 62666 : if (l)
325 196529 : for (n = l->h; n; n = n->next)
326 133862 : if (!(n->data = exp_simplify_math(sql, n->data, changes)))
327 : return NULL;
328 : }
329 374202 : if (e->type == e_convert)
330 25059 : if (!(e->l = exp_simplify_math(sql, e->l, changes)))
331 : return NULL;
332 : return e;
333 : }
334 :
335 : static inline sql_rel *
336 1182728 : rel_simplify_math_(visitor *v, sql_rel *rel)
337 : {
338 1182728 : if ((is_simple_project(rel->op) || (rel->op == op_ddl && rel->flag == ddl_psm)) && rel->exps) {
339 298209 : int needed = 0, ochanges = 0;
340 :
341 1577206 : for (node *n = rel->exps->h; n && !needed; n = n->next) {
342 1278997 : sql_exp *e = n->data;
343 :
344 1278997 : if (e->type == e_func || e->type == e_convert || e->type == e_aggr || e->type == e_psm)
345 50027 : needed = 1;
346 : }
347 298209 : if (!needed)
348 248183 : return rel;
349 :
350 294184 : for (node *n = rel->exps->h; n; n = n->next) {
351 244158 : sql_exp *ne = exp_simplify_math(v->sql, n->data, &ochanges);
352 :
353 244158 : if (!ne)
354 : return NULL;
355 244158 : n->data = ne;
356 : }
357 50026 : v->changes += ochanges;
358 : }
359 : return rel;
360 : }
361 :
362 : static sql_rel *
363 356528 : rel_simplify_math(visitor *v, global_props *gp, sql_rel *rel)
364 : {
365 356528 : (void) gp;
366 356528 : return rel_visitor_bottomup(v, rel, &rel_simplify_math_);
367 : }
368 :
369 : run_optimizer
370 601069 : bind_simplify_math(visitor *v, global_props *gp)
371 : {
372 601069 : int flag = v->sql->sql_optimizer;
373 538553 : return gp->opt_cycle == 0 && gp->opt_level == 1 && v->value_based_opt && (gp->cnt[op_project]
374 999406 : || 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 7 : reduce_scale(mvc *sql, atom *a)
398 : {
399 7 : int i = 0;
400 7 : atom *na = a;
401 : #ifdef HAVE_HGE
402 7 : hge nval = 0;
403 : #else
404 : lng nval = 0;
405 : #endif
406 :
407 : #ifdef HAVE_HGE
408 7 : 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 6 : reduce_scale_tpe(bte, a->data.val.btval);
420 : }
421 7 : if (i) {
422 5 : na = atom_int(sql->sa, &a->tpe, nval);
423 5 : if (na->tpe.scale)
424 5 : na->tpe.scale -= i;
425 : }
426 7 : return na;
427 : }
428 :
429 : static inline sql_exp *
430 6722868 : rel_simplify_predicates(visitor *v, sql_rel *rel, sql_exp *e)
431 : {
432 6722868 : if (is_func(e->type) && list_length(e->l) == 3 && is_case_func((sql_subfunc*)e->f)) {
433 31814 : list *args = e->l;
434 31814 : sql_exp *ie = args->h->data;
435 :
436 31814 : 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 31800 : } else if (exp_is_false(ie) || exp_is_null(ie)) { /* ifthenelse(false or null, x, y) -> y */
443 11 : sql_exp *res = args->h->next->next->data;
444 11 : if (exp_name(e))
445 5 : exp_prop_alias(v->sql->sa, res, e);
446 11 : v->changes++;
447 11 : return res;
448 : }
449 : }
450 6722843 : 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 397 : list *args = e->l;
453 397 : node *n = args->h;
454 397 : sql_exp *le = n->data;
455 397 : sql_exp *re = n->next->data;
456 :
457 397 : 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 6722786 : if (is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) {
475 : /* simplify like expressions */
476 1568458 : 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 12918 : list_length((list *)e->l) == 1 && list_length((list *)e->r) == 3) {
478 6459 : list *r = e->r;
479 6459 : sql_exp *fmt = r->h->data;
480 6459 : sql_exp *esc = r->h->next->data;
481 6459 : sql_exp *isen = r->h->next->next->data;
482 6459 : int rewrite = 0, isnull = 0;
483 :
484 6459 : if (fmt->type == e_convert)
485 93 : fmt = fmt->l;
486 : /* check for simple like expression */
487 6459 : if (exp_is_null(fmt)) {
488 : isnull = 1;
489 6456 : } else if (is_atom(fmt->type)) {
490 6337 : atom *fa = NULL;
491 :
492 6337 : if (fmt->l)
493 6337 : fa = fmt->l;
494 6337 : if (fa && fa->data.vtype == TYPE_str && !strchr(fa->data.val.sval, '%') && !strchr(fa->data.val.sval, '_'))
495 6459 : rewrite = 1;
496 : }
497 6459 : if (rewrite && !isnull) { /* check escape flag */
498 135 : if (exp_is_null(esc)) {
499 : isnull = 1;
500 : } else {
501 135 : atom *ea = esc->l;
502 :
503 135 : if (!is_atom(esc->type) || !ea)
504 : rewrite = 0;
505 135 : else if (ea->data.vtype != TYPE_str || strlen(ea->data.val.sval) != 0)
506 69 : rewrite = 0;
507 : }
508 : }
509 6459 : if (rewrite && !isnull) { /* check insensitive flag */
510 66 : if (exp_is_null(isen)) {
511 : isnull = 1;
512 : } else {
513 66 : atom *ia = isen->l;
514 :
515 66 : if (!is_atom(isen->type) || !ia)
516 : rewrite = 0;
517 66 : else if (ia->data.vtype != TYPE_bit || ia->data.val.btval == 1)
518 12 : rewrite = 0;
519 : }
520 : }
521 6459 : if (isnull) {
522 3 : e = exp_null(v->sql->sa, sql_bind_localtype("bit"));
523 3 : v->changes++;
524 3 : return e;
525 6456 : } else if (rewrite) { /* rewrite to cmp_equal ! */
526 54 : list *l = e->l;
527 54 : list *r = e->r;
528 106 : e = exp_compare(v->sql->sa, l->h->data, r->h->data, is_anti(e) ? cmp_notequal : cmp_equal);
529 54 : v->changes++;
530 : }
531 : }
532 : /* rewrite e if left or right is a cast */
533 1561996 : 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 10177 : sql_rel *r = rel->r;
535 10177 : 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 10177 : if (le->type == e_convert && re->type == e_column && (e->flag == cmp_lt || e->flag == cmp_gt) && r && is_project(r->op)) {
539 72 : sql_exp *nre = rel_find_exp(r, re);
540 72 : sql_subtype *tt = exp_totype(le), *ft = exp_fromtype(le);
541 :
542 72 : 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, 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 1561996 : 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 7238 : if (exp_is_null(e->l)) {
596 25 : int nval = e->flag == cmp_equal;
597 25 : if (is_anti(e)) nval = !nval;
598 25 : e = exp_atom_bool(v->sql->sa, nval);
599 25 : v->changes++;
600 25 : return e;
601 7213 : } else if (exp_is_not_null(e->l)) {
602 1286 : int nval = e->flag == cmp_notequal;
603 1286 : if (is_anti(e)) nval = !nval;
604 1286 : e = exp_atom_bool(v->sql->sa, nval);
605 1286 : v->changes++;
606 1286 : return e;
607 : }
608 : }
609 1560685 : if (is_atom(e->type) && ((!e->l && !e->r && !e->f) || e->r)) /* prepared statement parameter or argument */
610 : return e;
611 1560365 : if (is_atom(e->type) && e->l) { /* direct literal */
612 415739 : atom *a = e->l;
613 415739 : int flag = a->data.val.bval;
614 :
615 : /* remove simple select true expressions */
616 415739 : if (flag)
617 : return e;
618 : }
619 1178052 : if (is_compare(e->type) && is_theta_exp(e->flag)) {
620 402330 : sql_exp *l = e->l;
621 402330 : sql_exp *r = e->r;
622 :
623 402330 : if (is_func(l->type) && (e->flag == cmp_equal || e->flag == cmp_notequal)) {
624 5325 : sql_subfunc *f = l->f;
625 :
626 : /* rewrite isnull(x) = TRUE/FALSE => x =/<> NULL */
627 5325 : if (!f->func->s && is_isnull_func(f)) {
628 962 : list *args = l->l;
629 962 : sql_exp *ie = args->h->data;
630 :
631 962 : if (!has_nil(ie) || exp_is_not_null(ie)) { /* is null on something that is never null, is always false */
632 271 : ie = exp_atom_bool(v->sql->sa, 0);
633 271 : v->changes++;
634 271 : e->l = ie;
635 691 : } 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 691 : } else if (is_atom(r->type) && r->l) { /* direct literal */
640 675 : atom *a = r->l;
641 :
642 675 : 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 675 : int flag = a->data.val.bval;
653 :
654 675 : assert(list_length(args) == 1);
655 675 : l = args->h->data;
656 675 : if (exp_subtype(l)) {
657 675 : r = exp_atom(v->sql->sa, atom_general(v->sql->sa, exp_subtype(l), NULL, 0));
658 675 : e = exp_compare(v->sql->sa, l, r, e->flag);
659 675 : if (e && !flag)
660 273 : set_anti(e);
661 675 : if (e)
662 675 : set_semantics(e);
663 675 : v->changes++;
664 : }
665 : }
666 : }
667 4363 : } 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 397005 : } else if (is_atom(l->type) && is_atom(r->type) && !is_semantics(e) && !is_any(e) && !e->f) {
726 : /* compute comparisons on atoms */
727 600 : if (exp_is_null(l) || exp_is_null(r)) {
728 33 : e = exp_null(v->sql->sa, sql_bind_localtype("bit"));
729 33 : v->changes++;
730 567 : } else if (l->l && r->l) {
731 567 : int res = atom_cmp(l->l, r->l);
732 567 : bool flag = !is_anti(e);
733 :
734 567 : if (res == 0)
735 63 : e = exp_atom_bool(v->sql->sa, (e->flag == cmp_equal || e->flag == cmp_gte || e->flag == cmp_lte) ? flag : !flag);
736 504 : else if (res > 0)
737 53 : e = exp_atom_bool(v->sql->sa, (e->flag == cmp_gt || e->flag == cmp_gte || e->flag == cmp_notequal) ? flag : !flag);
738 : else
739 451 : e = exp_atom_bool(v->sql->sa, (e->flag == cmp_lt || e->flag == cmp_lte || e->flag == cmp_notequal) ? flag : !flag);
740 567 : v->changes++;
741 : }
742 : }
743 : }
744 : }
745 : return e;
746 : }
747 :
748 : static inline sql_exp *
749 14510209 : rel_remove_alias(visitor *v, sql_rel *rel, sql_exp *e)
750 : {
751 14510209 : if (e->type != e_column)
752 : return e;
753 10614815 : if (!rel_is_ref(rel) && rel->op == op_project && rel->l && list_length(rel->exps) > 1) {
754 4679959 : sql_rel *l = rel->l;
755 4679959 : if (l->op == op_project) {
756 1189763 : sql_exp *ne = rel_find_exp(l, e);
757 1189763 : if (ne && ne->type == e_column && is_selfref(ne)) {
758 2173 : sql_exp *nne = NULL;
759 : /* found ne in projection, try to find reference in the same list */
760 2173 : if (ne->l)
761 1679 : nne = exps_bind_column2(l->exps, ne->l, ne->r, NULL);
762 : else
763 494 : nne = exps_bind_column(l->exps, ne->r, NULL, NULL, 1);
764 2173 : if (nne && nne != ne && list_position(l->exps, nne) < list_position(l->exps, ne)) {
765 2028 : e->l = (char*)exp_relname(nne);
766 2028 : e->r = (char*)exp_name(nne);
767 2028 : v->changes++;
768 : }
769 : }
770 : }
771 : }
772 10614805 : if (!rel_is_ref(rel) && rel->op != op_project) {
773 5447460 : bool found = false;
774 5447460 : if ((is_select(rel->op) || is_join(rel->op)) && rel->l && list_length(rel->exps) > 1) {
775 332224 : sql_rel *l = rel->l;
776 332224 : if (l->op == op_project) {
777 17624 : sql_exp *ne = rel_find_exp(l, e);
778 17624 : found = true;
779 17624 : if (ne && ne->type == e_column && is_selfref(ne)) {
780 5 : sql_exp *nne = NULL;
781 5 : if (ne->l)
782 0 : 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 5 : if (nne && nne != ne && list_position(l->exps, nne) < list_position(l->exps, ne)) {
786 5 : e->l = (char*)exp_relname(nne);
787 5 : e->r = (char*)exp_name(nne);
788 5 : v->changes++;
789 : }
790 : }
791 : }
792 : }
793 5429841 : if (!found && is_join(rel->op) && rel->r && list_length(rel->exps) > 1 && !is_semi(rel->op)) {
794 174939 : sql_rel *l = rel->r;
795 174939 : if (l->op == op_project) {
796 11304 : sql_exp *ne = rel_find_exp(l, e);
797 11304 : found = true;
798 11304 : if (ne && ne->type == e_column && is_selfref(ne)) {
799 34 : sql_exp *nne = NULL;
800 34 : if (ne->l)
801 34 : 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 34 : if (nne && nne != ne && list_position(l->exps, nne) < list_position(l->exps, ne)) {
805 34 : e->l = (char*)exp_relname(nne);
806 34 : e->r = (char*)exp_name(nne);
807 34 : v->changes++;
808 : }
809 : }
810 : }
811 : }
812 : }
813 : return e;
814 : }
815 :
816 : static inline sql_exp *
817 14510185 : rel_merge_project_rse(visitor *v, sql_rel *rel, sql_exp *e)
818 : {
819 14510185 : if (is_simple_project(rel->op) && is_func(e->type) && e->l) {
820 728914 : list *fexps = e->l;
821 728914 : sql_subfunc *f = e->f;
822 :
823 : /* is and function */
824 728914 : if (!f->func->s && strcmp(f->func->base.name, "and") == 0 && list_length(fexps) == 2) {
825 17603 : sql_exp *l = list_fetch(fexps, 0), *r = list_fetch(fexps, 1);
826 :
827 : /* check merge into single between */
828 17603 : if (is_func(l->type) && is_func(r->type)) {
829 14281 : list *lfexps = l->l, *rfexps = r->l;
830 14281 : sql_subfunc *lff = l->f, *rff = r->f;
831 :
832 14281 : if (((strcmp(lff->func->base.name, ">=") == 0 || strcmp(lff->func->base.name, ">") == 0) && list_length(lfexps) == 2) &&
833 1023 : ((strcmp(rff->func->base.name, "<=") == 0 || strcmp(rff->func->base.name, "<") == 0) && list_length(rfexps) == 2)) {
834 126 : sql_exp *le = list_fetch(lfexps, 0), *lf = list_fetch(rfexps, 0);
835 126 : int c_le = is_numeric_upcast(le), c_lf = is_numeric_upcast(lf);
836 :
837 126 : if (exp_equal(c_le?le->l:le, c_lf?lf->l:lf) == 0) {
838 107 : sql_exp *re = list_fetch(lfexps, 1), *rf = list_fetch(rfexps, 1), *ne = NULL;
839 107 : sql_subtype super;
840 :
841 107 : supertype(&super, exp_subtype(le), exp_subtype(lf)); /* le/re and lf/rf must have the same type */
842 107 : if (!(le = exp_check_type(v->sql, &super, rel, le, type_equal)) ||
843 107 : !(re = exp_check_type(v->sql, &super, rel, re, type_equal)) ||
844 107 : !(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 107 : if ((ne = exp_compare2(v->sql->sa, le, re, rf, compare_funcs2range(lff->func->base.name, rff->func->base.name), 0))) {
850 107 : if (exp_name(e))
851 0 : exp_prop_alias(v->sql->sa, ne, e);
852 107 : e = ne;
853 107 : v->changes++;
854 : }
855 : }
856 : }
857 : }
858 : }
859 : }
860 : return e;
861 : }
862 :
863 : static sql_exp *
864 14510139 : rel_optimize_exps_(visitor *v, sql_rel *rel, sql_exp *e, int depth)
865 : {
866 14510139 : (void) depth;
867 14510139 : if (v->value_based_opt)
868 6722870 : e = rel_simplify_predicates(v, rel, e);
869 14510169 : e = rel_merge_project_rse(v, rel, e);
870 14510197 : e = rel_remove_alias(v, rel, e);
871 14510198 : return e;
872 : }
873 :
874 : static sql_rel *
875 152824 : rel_optimize_exps(visitor *v, global_props *gp, sql_rel *rel)
876 : {
877 152824 : (void) gp;
878 152824 : return rel_exp_visitor_bottomup(v, rel, &rel_optimize_exps_, false);
879 : }
880 :
881 : run_optimizer
882 601040 : bind_optimize_exps(visitor *v, global_props *gp)
883 : {
884 601040 : int flag = v->sql->sql_optimizer;
885 591865 : return gp->opt_cycle < 2 && gp->opt_level == 1 && (gp->cnt[op_project] || gp->cnt[op_join]
886 439586 : || gp->cnt[op_left] || gp->cnt[op_right] || gp->cnt[op_full] || gp->cnt[op_semi]
887 1192720 : || gp->cnt[op_anti] || gp->cnt[op_select]) && (flag & optimize_exps) ? rel_optimize_exps : NULL;
888 : }
|