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 "sql_decimal.h"
16 : #include "rel_unnest.h"
17 : #include "rel_basetable.h"
18 : #include "rel_exp.h"
19 : #include "rel_select.h"
20 : #include "rel_rewriter.h"
21 :
22 : static void
23 19372 : exp_set_freevar(mvc *sql, sql_exp *e, sql_rel *r)
24 : {
25 20412 : switch(e->type) {
26 0 : case e_cmp:
27 0 : if (e->flag == cmp_or || e->flag == cmp_filter) {
28 0 : exps_set_freevar(sql, e->l, r);
29 0 : exps_set_freevar(sql, e->r, r);
30 0 : } else if (e->flag == cmp_in || e->flag == cmp_notin) {
31 0 : exp_set_freevar(sql, e->l, r);
32 0 : exps_set_freevar(sql, e->r, r);
33 : } else {
34 0 : exp_set_freevar(sql, e->l, r);
35 0 : exp_set_freevar(sql, e->r, r);
36 0 : if (e->f)
37 : exp_set_freevar(sql, e->f, r);
38 : }
39 : break;
40 1040 : case e_convert:
41 1040 : exp_set_freevar(sql, e->l, r);
42 1040 : break;
43 5580 : case e_func:
44 : case e_aggr:
45 5580 : if (e->l)
46 5579 : exps_set_freevar(sql, e->l, r);
47 : break;
48 7646 : case e_column:
49 7646 : if ((e->l && rel_bind_column2(sql, r, e->l, e->r, 0)) ||
50 3598 : (!e->l && rel_bind_column(sql, r, e->r, 0, 1)))
51 4049 : return;
52 3597 : set_freevar(e, 0);
53 3597 : break;
54 6146 : case e_atom:
55 6146 : if (e->f)
56 0 : exps_set_freevar(sql, e->f, r);
57 : break;
58 : case e_psm:
59 : break;
60 : }
61 : }
62 :
63 : void
64 5579 : exps_set_freevar(mvc *sql, list *exps, sql_rel *r)
65 : {
66 5579 : node *n;
67 :
68 5579 : if (list_empty(exps))
69 : return;
70 16513 : for(n = exps->h; n; n = n->next)
71 10934 : exp_set_freevar(sql, n->data, r);
72 : }
73 :
74 : /* check if the set is distinct (ie we did a domain reduction for the general unnest) for the set of free variables */
75 : static int
76 9361 : is_distinct_set(mvc *sql, sql_rel *rel, list *ad)
77 : {
78 9413 : int distinct = 0;
79 9413 : if (ad && is_groupby(rel->op) && exp_match_list(rel->r, ad))
80 : return 1;
81 9401 : distinct = need_distinct(rel);
82 9401 : if (is_project(rel->op) && rel->l && !distinct)
83 : distinct = is_distinct_set(sql, rel->l, ad);
84 : return distinct;
85 : }
86 :
87 : int
88 14223146 : exp_has_freevar(mvc *sql, sql_exp *e)
89 : {
90 14672220 : if (mvc_highwater(sql)) {
91 1 : (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
92 1 : return 0;
93 : }
94 :
95 14672219 : if (is_freevar(e))
96 122042 : return is_freevar(e);
97 14550177 : switch(e->type) {
98 1764870 : case e_cmp:
99 1764870 : if (e->flag == cmp_or || e->flag == cmp_filter) {
100 59544 : return (exps_have_freevar(sql, e->l) || exps_have_freevar(sql, e->r));
101 1706148 : } else if (e->flag == cmp_in || e->flag == cmp_notin) {
102 128906 : return (exp_has_freevar(sql, e->l) || exps_have_freevar(sql, e->r));
103 : } else {
104 3154504 : return (exp_has_freevar(sql, e->l) || exp_has_freevar(sql, e->r) ||
105 1470984 : (e->f && exp_has_freevar(sql, e->f)));
106 : }
107 449074 : break;
108 449074 : case e_convert:
109 449074 : return exp_has_freevar(sql, e->l);
110 954082 : case e_func:
111 : case e_aggr:
112 954082 : if (e->l)
113 922082 : return exps_have_freevar(sql, e->l);
114 : /* fall through */
115 : case e_psm:
116 34020 : if (exp_is_rel(e))
117 2020 : return rel_has_freevar(sql, e->l);
118 : break;
119 3126273 : case e_atom:
120 3126273 : if (e->f)
121 148589 : return exps_have_freevar(sql, e->f);
122 : break;
123 : case e_column:
124 : default:
125 : return 0;
126 : }
127 : return 0;
128 : }
129 :
130 : int
131 4140972 : exps_have_freevar(mvc *sql, list *exps)
132 : {
133 4140972 : if (mvc_highwater(sql)) {
134 0 : (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
135 0 : return 0;
136 : }
137 4140974 : if (!exps)
138 : return 0;
139 14302393 : for (node *n = exps->h; n; n = n->next) {
140 10423903 : int vf = 0;
141 10423903 : sql_exp *e = n->data;
142 10423903 : if ((vf =exp_has_freevar(sql, e)) != 0)
143 160793 : return vf;
144 : }
145 : return 0;
146 : }
147 :
148 : int
149 3299599 : rel_has_freevar(mvc *sql, sql_rel *rel)
150 : {
151 3299599 : if (mvc_highwater(sql)) {
152 0 : (void) sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
153 0 : return 0;
154 : }
155 :
156 3299599 : if (is_basetable(rel->op)) {
157 : return 0;
158 2484970 : } else if (is_base(rel->op)) {
159 916 : return exps_have_freevar(sql, rel->exps) ||
160 458 : (rel->l && rel_has_freevar(sql, rel->l));
161 2484512 : } else if (is_simple_project(rel->op) || is_groupby(rel->op) || is_select(rel->op) || is_topn(rel->op) || is_sample(rel->op)) {
162 1700991 : if ((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->r && exps_have_freevar(sql, rel->r))
163 : return 1;
164 3401278 : return exps_have_freevar(sql, rel->exps) ||
165 1604538 : (rel->l && rel_has_freevar(sql, rel->l));
166 783521 : } else if (is_join(rel->op) || is_set(rel->op) || is_semi(rel->op) || is_modify(rel->op)) {
167 1564627 : return exps_have_freevar(sql, rel->exps) ||
168 1551826 : rel_has_freevar(sql, rel->l) || rel_has_freevar(sql, rel->r);
169 : }
170 : return 0;
171 : }
172 :
173 : static void exps_only_freevar(sql_query *query, list *exps, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols);
174 : static void rel_only_freevar(sql_query *query, sql_rel *rel, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols);
175 :
176 : void /* look for expressions with either only freevars or atoms */
177 54945 : exp_only_freevar(sql_query *query, sql_exp *e, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols)
178 : {
179 57975 : if (mvc_highwater(query->sql)) {
180 0 : (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
181 0 : return ;
182 : }
183 :
184 57975 : if (is_freevar(e)) {
185 418 : sql_rel *outer;
186 :
187 418 : *found_one_freevar = true;
188 418 : if (e->type == e_column) {
189 418 : if ((outer = query_fetch_outer(query, is_freevar(e)-1))) {
190 398 : sql_exp *a = rel_find_exp(outer, e);
191 398 : if (!a || !is_aggr(a->type)) {
192 384 : if (!*ungrouped_cols)
193 357 : *ungrouped_cols = new_exp_list(query->sql->sa);
194 384 : list_append(*ungrouped_cols, e);
195 : }
196 : }
197 : }
198 418 : return ;
199 : }
200 57557 : switch(e->type) {
201 16 : case e_cmp:
202 16 : if (e->flag == cmp_or || e->flag == cmp_filter) {
203 0 : exps_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
204 0 : exps_only_freevar(query, e->r, arguments_correlated, found_one_freevar, ungrouped_cols);
205 16 : } else if (e->flag == cmp_in || e->flag == cmp_notin) {
206 2 : exp_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
207 2 : exps_only_freevar(query, e->r, arguments_correlated, found_one_freevar, ungrouped_cols);
208 : } else {
209 14 : exp_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
210 14 : exp_only_freevar(query, e->r, arguments_correlated, found_one_freevar, ungrouped_cols);
211 14 : if (e->f)
212 : exp_only_freevar(query, e->f, arguments_correlated, found_one_freevar, ungrouped_cols);
213 : }
214 : break;
215 3028 : case e_convert:
216 3028 : exp_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
217 3028 : break;
218 13760 : case e_func:
219 : case e_aggr:
220 13760 : if (e->l)
221 13760 : exps_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
222 : break;
223 34 : case e_psm:
224 34 : if (exp_is_rel(e))
225 34 : rel_only_freevar(query, e->l, arguments_correlated, found_one_freevar, ungrouped_cols);
226 : break;
227 10047 : case e_atom:
228 10047 : if (e->f)
229 17 : exps_only_freevar(query, e->f, arguments_correlated, found_one_freevar, ungrouped_cols);
230 : break;
231 30672 : case e_column:
232 30672 : *arguments_correlated = 0;
233 30672 : break;
234 : }
235 : }
236 :
237 : void
238 13825 : exps_only_freevar(sql_query *query, list *exps, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols)
239 : {
240 13825 : if (mvc_highwater(query->sql)) {
241 0 : (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
242 0 : return ;
243 : }
244 13825 : if (!exps)
245 : return ;
246 41787 : for (node *n = exps->h; n ; n = n->next)
247 27962 : exp_only_freevar(query, n->data, arguments_correlated, found_one_freevar, ungrouped_cols);
248 : }
249 :
250 : void
251 34 : rel_only_freevar(sql_query *query, sql_rel *rel, bool *arguments_correlated, bool *found_one_freevar, list **ungrouped_cols)
252 : {
253 100 : if (mvc_highwater(query->sql)) {
254 0 : (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
255 0 : return ;
256 : }
257 :
258 100 : if (is_basetable(rel->op)) {
259 : return ;
260 73 : } else if (is_base(rel->op)) {
261 0 : exps_only_freevar(query, rel->exps, arguments_correlated, found_one_freevar, ungrouped_cols);
262 0 : if (rel->r)
263 : rel_only_freevar(query, rel->r, arguments_correlated, found_one_freevar, ungrouped_cols);
264 73 : } else if (is_simple_project(rel->op) || is_groupby(rel->op) || is_select(rel->op) || is_topn(rel->op) || is_sample(rel->op)) {
265 73 : if ((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->r)
266 5 : exps_only_freevar(query, rel->r, arguments_correlated, found_one_freevar, ungrouped_cols);
267 73 : if (rel->card > CARD_ATOM)
268 41 : exps_only_freevar(query, rel->exps, arguments_correlated, found_one_freevar, ungrouped_cols);
269 73 : if (rel->l)
270 : rel_only_freevar(query, rel->l, arguments_correlated, found_one_freevar, ungrouped_cols);
271 0 : } else if (is_join(rel->op) || is_set(rel->op) || is_semi(rel->op) || is_modify(rel->op)) {
272 0 : exps_only_freevar(query, rel->exps, arguments_correlated, found_one_freevar, ungrouped_cols);
273 0 : rel_only_freevar(query, rel->l, arguments_correlated, found_one_freevar, ungrouped_cols);
274 0 : rel_only_freevar(query, rel->r, arguments_correlated, found_one_freevar, ungrouped_cols);
275 : }
276 : return ;
277 : }
278 :
279 : static int
280 66327 : freevar_equal( sql_exp *e1, sql_exp *e2)
281 : {
282 66327 : assert(e1 && e2 && is_freevar(e1) && is_freevar(e2));
283 66327 : if (e1 == e2)
284 : return 0;
285 66182 : if (e1->type != e_column || e2->type != e_column)
286 : return -1;
287 66182 : if (e1->l && e2->l && strcmp(e1->l, e2->l) == 0)
288 50489 : return strcmp(e1->r, e2->r);
289 15693 : if (!e1->l && !e2->l)
290 6 : return strcmp(e1->r, e2->r);
291 : return -1;
292 : }
293 :
294 : static list *
295 655825 : merge_freevar(list *l, list *r, bool all)
296 : {
297 655825 : if (!l)
298 : return r;
299 146855 : if (!r)
300 : return l;
301 32415 : r = list_merge(l, r, (fdup)NULL);
302 32415 : if (all)
303 : return r;
304 32319 : return list_distinct(r, (fcmp)freevar_equal, (fdup)NULL);
305 : }
306 :
307 : static list * exps_freevar(mvc *sql, list *exps);
308 : static list * rel_freevar(mvc *sql, sql_rel *rel);
309 :
310 : static list *
311 676533 : exp_freevar(mvc *sql, sql_exp *e, bool all)
312 : {
313 676533 : if (mvc_highwater(sql))
314 0 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
315 :
316 676533 : switch(e->type) {
317 300249 : case e_column:
318 300249 : if (is_freevar(e))
319 87121 : return append(sa_list(sql->sa), e);
320 : break;
321 25536 : case e_convert:
322 25536 : return exp_freevar(sql, e->l, all);
323 98450 : case e_aggr:
324 : case e_func:
325 98450 : if (e->l)
326 86503 : return exps_freevar(sql, e->l);
327 : break;
328 82804 : case e_cmp:
329 82804 : if (e->flag == cmp_or || e->flag == cmp_filter) {
330 957 : list *l = exps_freevar(sql, e->l);
331 957 : list *r = exps_freevar(sql, e->r);
332 957 : return merge_freevar(l, r, all);
333 81847 : } else if (e->flag == cmp_in || e->flag == cmp_notin) {
334 12 : list *l = exp_freevar(sql, e->l, all);
335 12 : list *r = exps_freevar(sql, e->r);
336 12 : return merge_freevar(l, r, all);
337 : } else {
338 81835 : list *l = exp_freevar(sql, e->l, all);
339 81835 : list *r = exp_freevar(sql, e->r, all);
340 81835 : l = merge_freevar(l, r, all);
341 81835 : if (e->f) {
342 161 : r = exp_freevar(sql, e->f, all);
343 161 : return merge_freevar(l, r, all);
344 : }
345 : return l;
346 : }
347 32 : break;
348 32 : case e_psm:
349 32 : if (exp_is_rel(e))
350 32 : if (rel_has_freevar(sql, e->l))
351 20 : return rel_freevar(sql, e->l);
352 : return NULL;
353 169462 : case e_atom:
354 169462 : if (e->f)
355 43 : return exps_freevar(sql, e->f);
356 : return NULL;
357 : default:
358 : return NULL;
359 : }
360 : return NULL;
361 : }
362 :
363 : static list *
364 250332 : exps_freevar(mvc *sql, list *exps)
365 : {
366 250332 : node *n;
367 250332 : list *c = NULL;
368 :
369 250332 : if (mvc_highwater(sql))
370 0 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
371 250332 : if (!exps)
372 : return NULL;
373 650065 : for (n = exps->h; n; n = n->next) {
374 400839 : sql_exp *e = n->data;
375 400839 : list *var = exp_freevar(sql, e, false);
376 :
377 400839 : c = merge_freevar(c,var, false);
378 : }
379 : return c;
380 : }
381 :
382 : static list *
383 208590 : rel_freevar(mvc *sql, sql_rel *rel)
384 : {
385 208590 : list *lexps = NULL, *rexps = NULL, *exps = NULL;
386 :
387 208590 : if (mvc_highwater(sql))
388 0 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
389 208590 : if (!rel)
390 : return NULL;
391 194627 : switch(rel->op) {
392 2128 : case op_join:
393 : case op_left:
394 : case op_right:
395 : case op_full:
396 2128 : exps = exps_freevar(sql, rel->exps);
397 2128 : lexps = rel_freevar(sql, rel->l);
398 2128 : rexps = rel_freevar(sql, rel->r);
399 2128 : lexps = merge_freevar(lexps, rexps, false);
400 2128 : exps = merge_freevar(exps, lexps, false);
401 2128 : return exps;
402 :
403 : case op_basetable:
404 : return NULL;
405 134 : case op_table: {
406 134 : sql_exp *call = rel->r;
407 134 : if (rel->flag != TRIGGER_WRAPPER && rel->l)
408 107 : lexps = rel_freevar(sql, rel->l);
409 134 : exps = (rel->flag != TRIGGER_WRAPPER && call)?exps_freevar(sql, call->l):NULL;
410 134 : return merge_freevar(exps, lexps, false);
411 : }
412 7788 : case op_union:
413 : case op_except:
414 : case op_inter:
415 7788 : exps = exps_freevar(sql, rel->exps);
416 7788 : lexps = rel_freevar(sql, rel->l);
417 7788 : rexps = rel_freevar(sql, rel->r);
418 7788 : lexps = merge_freevar(lexps, rexps, false);
419 7788 : exps = merge_freevar(exps, lexps, false);
420 7788 : return exps;
421 148935 : case op_ddl:
422 : case op_semi:
423 : case op_anti:
424 :
425 : case op_select:
426 : case op_topn:
427 : case op_sample:
428 :
429 : case op_groupby:
430 : case op_project:
431 148935 : exps = exps_freevar(sql, rel->exps);
432 148935 : lexps = rel_freevar(sql, rel->l);
433 148935 : if (rel->r) {
434 3120 : if (is_groupby(rel->op) || is_simple_project(rel->op))
435 2875 : rexps = exps_freevar(sql, rel->r);
436 : else
437 245 : rexps = rel_freevar(sql, rel->r);
438 3120 : lexps = merge_freevar(lexps, rexps, false);
439 : }
440 148935 : exps = merge_freevar(exps, lexps, false);
441 148935 : return exps;
442 : default:
443 : return NULL;
444 : }
445 :
446 : }
447 :
448 : static list *
449 33788 : rel_dependent_var(mvc *sql, sql_rel *l, sql_rel *r)
450 : {
451 33788 : list *res = NULL;
452 :
453 33788 : if (rel_has_freevar(sql, r)){
454 33712 : list *freevar = rel_freevar(sql, r);
455 33712 : if (freevar) {
456 33712 : node *n;
457 33712 : list *boundvar = rel_projections(sql, l, NULL, 1, 0);
458 :
459 85895 : for(n = freevar->h; n; n = n->next) {
460 52183 : sql_exp *e = n->data, *ne = NULL;
461 : /* each freevar should be an e_column */
462 52183 : if (e->l) {
463 52144 : ne = exps_bind_column2(boundvar, e->l, e->r, NULL);
464 : } else {
465 39 : ne = exps_bind_column(boundvar, e->r, NULL, NULL, 1);
466 : }
467 52183 : if (ne) {
468 51898 : if (!res)
469 33615 : res = sa_list(sql->sa);
470 51898 : append(res, ne);
471 : }
472 : }
473 : }
474 : }
475 33788 : return res;
476 : }
477 :
478 : /*
479 : * try to bind any freevar in the expression e
480 : */
481 : void
482 86315 : rel_bind_var(mvc *sql, sql_rel *rel, sql_exp *e)
483 : {
484 86315 : list *fvs = exp_freevar(sql, e, true);
485 :
486 86315 : if (fvs) {
487 15255 : node *n;
488 :
489 30683 : for(n = fvs->h; n; n=n->next) {
490 15428 : sql_exp *e = n->data;
491 :
492 15428 : if (is_freevar(e) && (exp_is_atom(e) || rel_find_exp(rel,e)))
493 11006 : reset_freevar(e);
494 : }
495 : }
496 86315 : }
497 :
498 : void
499 17748 : rel_bind_vars(mvc *sql, sql_rel *rel, list *exps)
500 : {
501 17748 : if (list_empty(exps))
502 : return;
503 81655 : for(node *n=exps->h; n; n = n->next)
504 63965 : rel_bind_var(sql, rel, n->data);
505 : }
506 :
507 : static sql_exp * push_up_project_exp(mvc *sql, sql_rel *rel, sql_exp *e);
508 :
509 : static list *
510 9561 : push_up_project_exps(mvc *sql, sql_rel *rel, list *exps)
511 : {
512 9561 : node *n;
513 :
514 9561 : if (!exps)
515 : return exps;
516 :
517 891 : for(n=exps->h; n; n=n->next) {
518 411 : sql_exp *e = n->data;
519 :
520 411 : n->data = push_up_project_exp(sql, rel, e);
521 : }
522 480 : list_hash_clear(exps);
523 480 : return exps;
524 : }
525 :
526 : static sql_exp *
527 1083 : push_up_project_exp(mvc *sql, sql_rel *rel, sql_exp *e)
528 : {
529 1138 : if (mvc_highwater(sql))
530 0 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
531 :
532 1138 : switch(e->type) {
533 294 : case e_cmp:
534 294 : if (e->flag == cmp_or || e->flag == cmp_filter) {
535 17 : e->l = push_up_project_exps(sql, rel, e->l);
536 17 : e->r = push_up_project_exps(sql, rel, e->r);
537 17 : return e;
538 277 : } else if (e->flag == cmp_in || e->flag == cmp_notin) {
539 0 : e->l = push_up_project_exp(sql, rel, e->l);
540 0 : e->r = push_up_project_exps(sql, rel, e->r);
541 0 : return e;
542 : } else {
543 277 : e->l = push_up_project_exp(sql, rel, e->l);
544 277 : e->r = push_up_project_exp(sql, rel, e->r);
545 277 : if (e->f)
546 1 : e->f = push_up_project_exp(sql, rel, e->f);
547 : }
548 : break;
549 117 : case e_convert:
550 117 : e->l = push_up_project_exp(sql, rel, e->l);
551 117 : break;
552 51 : case e_func:
553 : case e_aggr:
554 51 : if (e->l)
555 48 : e->l = push_up_project_exps(sql, rel, e->l);
556 : break;
557 503 : case e_column:
558 : {
559 503 : sql_exp *ne;
560 :
561 : /* include project or just lookup */
562 503 : if (e->l) {
563 481 : ne = exps_bind_column2(rel->exps, e->l, e->r, NULL);
564 : } else {
565 22 : ne = exps_bind_column(rel->exps, e->r, NULL, NULL, 1);
566 : }
567 503 : if (ne) {
568 239 : if (ne->type == e_column) {
569 : /* deref alias */
570 184 : e->l = ne->l;
571 184 : e->r = ne->r;
572 : } else {
573 55 : ne = exp_copy(sql, ne);
574 55 : return push_up_project_exp(sql, rel, ne);
575 : }
576 : }
577 : } break;
578 173 : case e_atom:
579 173 : if (e->f)
580 0 : e->f = push_up_project_exps(sql, rel, e->f);
581 : break;
582 : case e_psm:
583 : break;
584 : }
585 : return e;
586 : }
587 :
588 : static sql_exp *exp_rewrite(mvc *sql, sql_rel *rel, sql_exp *e, list *ad);
589 :
590 : static list *
591 2341 : exps_rewrite(mvc *sql, sql_rel *rel, list *exps, list *ad)
592 : {
593 2341 : list *nexps;
594 2341 : node *n;
595 :
596 2341 : if (list_empty(exps))
597 : return exps;
598 2323 : nexps = sa_list(sql->sa);
599 7383 : for(n=exps->h; n; n = n->next)
600 5060 : append(nexps, exp_rewrite(sql, rel, n->data, ad));
601 : return nexps;
602 : }
603 :
604 : /* recursively rewrite some functions */
605 : static sql_exp *
606 11849 : exp_rewrite(mvc *sql, sql_rel *rel, sql_exp *e, list *ad)
607 : {
608 11849 : sql_subfunc *sf;
609 :
610 11849 : if (e->type == e_convert) {
611 300 : e->l = exp_rewrite(sql, rel, e->l, ad);
612 300 : return e;
613 : }
614 11549 : if (e->type != e_func)
615 : return e;
616 2341 : e->l = exps_rewrite(sql, rel, e->l, ad);
617 2341 : sf = e->f;
618 : /* window functions need to be run per freevars */
619 2341 : if (sf->func->type == F_ANALYTIC && strcmp(sf->func->base.name, "window_bound") != 0 && strcmp(sf->func->base.name, "diff") != 0 && ad) {
620 58 : sql_subtype *bt = sql_bind_localtype("bit");
621 58 : list *rankopargs = e->l, *gbe = ((list*)e->r)->h->data;
622 58 : sql_exp *pe = list_empty(gbe) ? NULL : (sql_exp*)gbe->t->data, *last;
623 80 : bool has_pe = pe != NULL;
624 80 : int i = 0;
625 :
626 22 : if (!pe || pe->type != e_func || strcmp(((sql_subfunc *)pe->f)->func->base.name, "diff") != 0)
627 : pe = NULL;
628 :
629 135 : for(node *d = ad->h; d; d=d->next) {
630 77 : sql_subfunc *df;
631 77 : sql_exp *de = d->data;
632 77 : list *args = sa_list(sql->sa);
633 77 : if (pe) {
634 19 : df = sql_bind_func(sql, NULL, "diff", bt, exp_subtype(de), F_ANALYTIC, true);
635 19 : append(args, pe);
636 : } else {
637 58 : df = sql_bind_func(sql, NULL, "diff", exp_subtype(de), NULL, F_ANALYTIC, true);
638 : }
639 77 : assert(df);
640 77 : append(args, de);
641 77 : pe = exp_op(sql->sa, args, df);
642 : }
643 :
644 127 : for (node *n = rankopargs->h; n ; n = n->next, i++) { /* at rel_select pe is added right after the function's arguments */
645 127 : if (i == list_length(sf->func->ops)) {
646 58 : n->data = pe;
647 58 : break;
648 : }
649 : }
650 58 : last = rankopargs->t->data; /* if the window function has bounds calls, update them */
651 58 : if (last && last->type == e_func && !strcmp(((sql_subfunc *)last->f)->func->base.name, "window_bound")) {
652 18 : sql_exp *window1 = list_fetch(rankopargs, list_length(rankopargs) - 2), *window2 = list_fetch(rankopargs, list_length(rankopargs) - 1);
653 18 : list *lw1 = window1->l, *lw2 = window2->l; /* the value functions require bound functions always */
654 :
655 18 : if (has_pe) {
656 8 : assert(list_length(window1->l) == 6);
657 8 : lw1->h->data = exp_copy(sql, pe);
658 8 : lw2->h->data = exp_copy(sql, pe);
659 : } else {
660 10 : window1->l = list_prepend(lw1, exp_copy(sql, pe));
661 10 : window2->l = list_prepend(lw2, exp_copy(sql, pe));
662 : }
663 : }
664 : }
665 : return e;
666 : }
667 :
668 : static sql_exp *
669 1318 : rel_reduce2one_exp(mvc *sql, sql_rel *sq)
670 : {
671 1318 : sql_exp *e = NULL;
672 :
673 1318 : if (list_empty(sq->exps))
674 : return NULL;
675 1318 : if (list_length(sq->exps) == 1)
676 1132 : return sq->exps->t->data;
677 416 : for(node *n = sq->exps->h; n && !e; n = n->next) {
678 230 : sql_exp *t = n->data;
679 :
680 230 : if (!is_freevar(t))
681 183 : e = t;
682 : }
683 186 : if (!e)
684 3 : e = sq->exps->t->data;
685 186 : sq->exps = append(sa_list(sql->sa), e);
686 186 : return e;
687 : }
688 :
689 : static sql_exp *
690 15 : rel_bound_exp(mvc *sql, sql_rel *rel )
691 : {
692 30 : while (rel->l) {
693 30 : rel = rel->l;
694 30 : if (is_base(rel->op) || is_project(rel->op))
695 : break;
696 : }
697 :
698 15 : if (rel && !list_empty(rel->exps)) {
699 15 : for(node *n = rel->exps->h; n; n = n->next){
700 15 : sql_exp *e = n->data;
701 :
702 15 : if (exp_is_atom(e))
703 5 : return e;
704 10 : if (!exp_has_freevar(sql, e))
705 10 : return exp_ref(sql, e);
706 : }
707 : }
708 0 : if (rel && is_project(rel->op)) /* add dummy expression */
709 0 : return rel_project_add_exp(sql, rel, exp_atom_bool(sql->sa, 1));
710 : return NULL;
711 : }
712 :
713 : /*
714 : * join j was just rewriten, but some join expressions may now
715 : * be too low in de relation rel. These need to move up.
716 : * */
717 : static void
718 4331 : move_join_exps(mvc *sql, sql_rel *j, sql_rel *rel)
719 : {
720 4331 : node *n;
721 4331 : list *exps = rel->exps;
722 :
723 4331 : if (list_empty(exps))
724 : return;
725 4 : rel->exps = sa_list(sql->sa);
726 4 : if (!j->exps)
727 4 : j->exps = sa_list(sql->sa);
728 8 : for(n = exps->h; n; n = n->next){
729 4 : sql_exp *e = n->data;
730 :
731 4 : if (rel_rebind_exp(sql, rel, e)) {
732 2 : if (exp_has_freevar(sql, e))
733 0 : rel_bind_var(sql, rel->l, e);
734 2 : append(rel->exps, e);
735 : } else {
736 2 : if (exp_has_freevar(sql, e))
737 0 : rel_bind_var(sql, j->l, e);
738 2 : append(j->exps, e);
739 : }
740 : }
741 : }
742 :
743 : static sql_rel *
744 4257 : rel_general_unnest(mvc *sql, sql_rel *rel, list *ad)
745 : {
746 4257 : if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel) && ad) {
747 4257 : list *fd;
748 4257 : node *n, *m;
749 4257 : int nr;
750 :
751 4257 : sql_rel *l = rel->l, *r = rel->r, *inner_r;
752 :
753 : /* cleanup empty selects (should be done before any rel_dup(l) */
754 4257 : if (l && is_select(l->op) && list_empty(l->exps) && !rel_is_ref(l)) {
755 0 : rel->l = l->l;
756 0 : l->l = NULL;
757 0 : rel_destroy(l);
758 0 : l = rel->l;
759 : }
760 : /* rewrite T1 dependent join T2 -> T1 join D dependent join T2, where the T1/D join adds (equality) predicates (for the Domain (ad)) and D is are the distinct(projected(ad) from T1) */
761 4257 : sql_rel *D = rel_project(sql->sa, rel_dup(l), exps_copy(sql, ad));
762 4257 : set_distinct(D);
763 :
764 4257 : int single = is_single(r);
765 4257 : reset_single(r);
766 4257 : sql_rel *or = r;
767 4257 : r = rel_crossproduct(sql->sa, D, r, rel->op);
768 4257 : if (single)
769 10 : set_single(or);
770 4257 : r->op = op_join;
771 4257 : move_join_exps(sql, rel, r);
772 4257 : set_dependent(r);
773 4257 : set_processed(r);
774 4257 : inner_r = r;
775 :
776 4257 : r = rel_project(sql->sa, r, (is_semi(inner_r->op))?sa_list(sql->sa):rel_projections(sql, r->r, NULL, 1, 1));
777 :
778 4257 : if (!is_semi(inner_r->op)) { /* skip the free vars */
779 4257 : list *exps = sa_list(sql->sa);
780 :
781 9344 : for(node *n=r->exps->h; n; n = n->next) {
782 5087 : sql_exp *e = n->data, *ne = NULL;
783 :
784 5087 : if (e->l) {
785 5080 : ne = exps_bind_column2(ad, e->l, e->r, NULL);
786 : } else {
787 7 : ne = exps_bind_column(ad, e->r, NULL, NULL, 1);
788 : }
789 5087 : if (!ne)
790 5034 : append(exps,e);
791 : }
792 4257 : r->exps = exps;
793 : }
794 :
795 : /* append ad + rename */
796 4257 : nr = sql->label+1;
797 4257 : sql->label += list_length(ad);
798 4257 : fd = exps_label(sql->sa, exps_copy(sql, ad), nr);
799 11573 : for (n = ad->h, m = fd->h; n && m; n = n->next, m = m->next) {
800 7316 : sql_exp *l = n->data, *r = m->data, *e;
801 :
802 7316 : l = exp_ref(sql, l);
803 7316 : r = exp_ref(sql, r);
804 7316 : e = exp_compare(sql->sa, l, r, cmp_equal);
805 7316 : set_semantics(e);
806 7316 : if (!rel->exps)
807 4173 : rel->exps = sa_list(sql->sa);
808 7316 : append(rel->exps, e);
809 : }
810 4257 : list_merge(r->exps, fd, (fdup)NULL);
811 4257 : rel->r = r;
812 4257 : reset_dependent(rel);
813 4257 : return rel;
814 : }
815 : return rel;
816 : }
817 :
818 : static sql_rel *
819 9479 : push_up_project(mvc *sql, sql_rel *rel, list *ad)
820 : {
821 9479 : sql_rel *r = rel->r;
822 :
823 9479 : assert(is_simple_project(r->op));
824 9479 : if (rel_is_ref(r)) {
825 9 : sql_rel *nr = rel_project(sql->sa, r->l ? rel_dup(r->l) : NULL, exps_copy(sql, r->exps));
826 :
827 9 : if (is_single(r))
828 0 : set_single(nr);
829 9 : if (need_distinct(r))
830 0 : set_distinct(nr);
831 9 : nr->p = prop_copy(sql->sa, r->p);
832 9 : nr->r = exps_copy(sql, r->r);
833 9 : rel_destroy(r);
834 9 : rel->r = r = nr;
835 : }
836 :
837 : /* input rel is dependent outerjoin with on the right a project, we first try to push inner side expressions down (because these cannot be pushed up) */
838 9479 : if (rel && is_join(rel->op) && is_dependent(rel)) {
839 9370 : sql_rel *r = rel->r;
840 :
841 : /* find constant expressions and move these down */
842 9370 : if (r && r->op == op_project) {
843 9370 : node *n;
844 9370 : list *nexps = NULL;
845 9370 : list *cexps = NULL;
846 9370 : sql_rel *l = r->l;
847 :
848 9386 : while (l && is_simple_project(l->op) && l->l) {
849 : /* if current project is just one constant, remove lower project */
850 675 : if (list_length(r->exps) == 1) {
851 318 : sql_exp *e = r->exps->h->data;
852 :
853 318 : if (exp_is_atom(e)) {
854 16 : r->l = rel_dup(l->l);
855 16 : rel_destroy(l);
856 16 : l = r->l;
857 16 : continue;
858 : }
859 : }
860 : break;
861 : }
862 :
863 9370 : if (l && (is_select(l->op) || l->op == op_join || is_semi(l->op)) && !rel_is_ref(l) && list_empty(r->attr)) {
864 4171 : if (!list_empty(r->exps)) {
865 11060 : for(n=r->exps->h; n; n=n->next) {
866 6889 : sql_exp *e = n->data;
867 :
868 6889 : if (exp_is_atom(e) || rel_find_exp(l->l,e)) { /* move down */
869 6794 : if (!cexps)
870 4136 : cexps = sa_list(sql->sa);
871 6794 : append(cexps, e);
872 : } else {
873 95 : if (!nexps)
874 59 : nexps = sa_list(sql->sa);
875 95 : append(nexps, e);
876 : }
877 : }
878 : }
879 4171 : if (cexps) {
880 4136 : sql_rel *p = l->l = rel_project( sql->sa, l->l,
881 4136 : rel_projections(sql, l->l, NULL, 1, 1));
882 4136 : p->exps = list_distinct(list_merge(p->exps, cexps, (fdup)NULL), (fcmp)exp_equal, (fdup)NULL);
883 4136 : if (list_empty(nexps)) {
884 4112 : rel->r = l; /* remove empty project */
885 : } else {
886 94 : for (n = cexps->h; n; n = n->next) { /* add pushed down renamed expressions */
887 70 : sql_exp *e = n->data;
888 70 : append(nexps, exp_ref(sql, e));
889 : }
890 24 : r->exps = nexps;
891 : }
892 : }
893 : }
894 : }
895 : }
896 : /* input rel is dependent join with on the right a project */
897 9479 : if (rel && is_join(rel->op) && is_dependent(rel)) {
898 9370 : sql_rel *r = rel->r;
899 :
900 : /* merge project expressions into the join expressions */
901 9370 : rel->exps = push_up_project_exps(sql, r, rel->exps);
902 :
903 9370 : if (r && r->op == op_project) {
904 5258 : sql_exp *id = NULL;
905 5258 : node *m;
906 :
907 5258 : if (!r->l) {
908 549 : sql_rel *l = rel->l;
909 549 : l = rel_dup(l);
910 549 : if (!is_project(l->op) || rel_is_ref(l))
911 549 : l = rel_project( sql->sa, l, rel_projections(sql, l, NULL, 1, 1));
912 :
913 549 : if (is_left(rel->op) && !list_empty(rel->attr)) {
914 6 : assert(list_length(rel->exps)==1);
915 6 : sql_exp *e = rel->exps->h->data;
916 6 : sql_exp *oe = rel->attr->h->data;
917 6 : rel_project_add_exp(sql, l, e);
918 6 : exp_setname(sql->sa, e, exp_relname(oe), exp_name(oe));
919 : }
920 549 : if (!list_empty(r->exps)) {
921 1112 : for (m=r->exps->h; m; m = m->next) {
922 563 : sql_exp *e = m->data;
923 :
924 563 : if (exp_has_freevar(sql, e))
925 553 : rel_bind_var(sql, l, e);
926 563 : append(l->exps, e);
927 : }
928 : }
929 549 : rel_destroy(rel);
930 549 : return l;
931 : }
932 : /* move project up, ie all attributes of left + the old expression list */
933 4709 : sql_rel *n = rel_project( sql->sa, (r->l)?rel:rel->l,
934 4709 : rel_projections(sql, rel->l, NULL, 1, 1));
935 :
936 4709 : if (is_left(rel->op) && !list_empty(rel->attr))
937 124 : rel_project_add_exp(sql, n, exp_ref(sql, rel->attr->h->data));
938 4709 : if (list_empty(rel->attr) && !list_empty(r->exps)) {
939 11074 : for (m=r->exps->h; m; m = m->next) {
940 6490 : sql_exp *e = m->data;
941 :
942 6490 : if (!is_freevar(e) || exp_name(e)) { /* only skip full freevars */
943 6490 : if (exp_has_freevar(sql, e) || is_atom(e->type)) {
944 738 : rel_bind_var(sql, rel->l, e);
945 738 : if (is_left(rel->op)) { /* add ifthenelse */
946 : /* if id is NULL then NULL else e */
947 93 : sql_subtype *tp = exp_subtype(e);
948 93 : if (!tp)
949 1 : return sql_error(sql, 10, SQLSTATE(42000) "Query projection must have at least one parameter with known SQL type");
950 92 : if (!id) {
951 90 : sql_rel *l = r->l;
952 90 : if (is_join(l->op))
953 15 : id = rel_bound_exp(sql, r);
954 : else
955 75 : r->l = rel_add_identity(sql, r->l, &id);
956 : }
957 92 : sql_exp *ne = rel_unop_(sql, NULL, exp_ref(sql, id), "sys", "isnull", card_value);
958 92 : set_has_no_nil(ne);
959 92 : ne = rel_nop_(sql, NULL, ne, exp_null(sql->sa, tp), e, NULL, "sys", "ifthenelse", card_value);
960 92 : exp_prop_alias(sql->sa, ne, e);
961 92 : e = ne;
962 : }
963 : }
964 : }
965 6489 : if (r->l)
966 6489 : e = exp_rewrite(sql, r->l, e, ad);
967 6489 : append(n->exps, e);
968 : }
969 : }
970 4708 : if (!list_empty(r->r)) {
971 31 : list *exps = r->r, *oexps = n->r = sa_list(sql->sa);
972 :
973 84 : for (m=exps->h; m; m = m->next) {
974 53 : sql_exp *e = m->data;
975 :
976 53 : if (!is_freevar(e) || exp_name(e)) { /* only skip full freevars */
977 53 : if (exp_has_freevar(sql, e))
978 4 : rel_bind_var(sql, rel->l, e);
979 : }
980 53 : append(oexps, e);
981 : }
982 : }
983 : /* remove old project */
984 4708 : if (r->l) {
985 4708 : rel->r = r->l;
986 4708 : r->l = NULL;
987 : }
988 4708 : rel_destroy(r);
989 4708 : return n;
990 : }
991 : }
992 : /* a dependent semi/anti join with a project on the right side, could be removed */
993 4221 : if (rel && is_semi(rel->op) && is_dependent(rel)) {
994 109 : sql_rel *r = rel->r;
995 :
996 : /* merge project expressions into the join expressions */
997 109 : rel->exps = push_up_project_exps(sql, r, rel->exps);
998 109 : rel_bind_vars(sql, rel, rel->exps);
999 :
1000 109 : if (r && r->op == op_project && r->l) {
1001 : /* remove old project */
1002 100 : rel->r = rel_dup(r->l);
1003 100 : rel_destroy(r);
1004 100 : return rel;
1005 9 : } else if (r && r->op == op_project) {
1006 : /* remove freevars from projection */
1007 9 : list *exps = r->exps, *nexps = sa_list(sql->sa);
1008 9 : node *m;
1009 :
1010 9 : if (!list_empty(exps)) {
1011 18 : for (m=exps->h; m; m = m->next) {
1012 9 : sql_exp *e = m->data;
1013 :
1014 9 : if (!exp_has_freevar(sql, e))
1015 0 : append(nexps, e);
1016 : }
1017 : }
1018 9 : if (list_empty(nexps)) {
1019 9 : assert(!r->l);
1020 : /* remove old project and change outer into select */
1021 9 : rel->r = NULL;
1022 9 : rel_destroy(r);
1023 9 : operator_type op = rel->op;
1024 9 : rel->op = op_select;
1025 9 : if (!list_empty(rel->exps)) {
1026 15 : for(m=rel->exps->h; m; m = m->next) {
1027 8 : sql_exp *e = m->data;
1028 :
1029 8 : if (op == op_anti && is_compare(e->type) && e->flag == cmp_equal)
1030 2 : e->flag = cmp_notequal;
1031 0 : else if (op == op_anti && is_compare(e->type) && e->flag == cmp_notequal)
1032 0 : e->flag = cmp_equal;
1033 : }
1034 : }
1035 9 : return rel;
1036 : }
1037 0 : r->exps = nexps;
1038 : }
1039 : }
1040 : return rel;
1041 : }
1042 :
1043 : static sql_rel *
1044 5 : push_up_topn_and_sample(mvc *sql, sql_rel *rel)
1045 : {
1046 : /* a dependent semi/anti join with a project on the right side, could be removed */
1047 5 : if (rel && (is_semi(rel->op) || is_join(rel->op)) && is_dependent(rel)) {
1048 5 : sql_rel *r = rel->r;
1049 :
1050 5 : if (r && (is_topn(r->op) || is_sample(r->op))) {
1051 : /* remove old topn/sample */
1052 5 : sql_rel *(*func) (sql_allocator *, sql_rel *, list *) = is_topn(r->op) ? rel_topn : rel_sample;
1053 5 : rel->r = rel_dup(r->l);
1054 5 : rel = func(sql->sa, rel, r->exps);
1055 5 : set_processed(rel);
1056 5 : rel_destroy(r);
1057 5 : return rel;
1058 : }
1059 : }
1060 : return rel;
1061 : }
1062 :
1063 : static sql_rel *
1064 7534 : push_up_select(mvc *sql, sql_rel *rel, list *ad)
1065 : {
1066 7534 : sql_rel *d = rel->l;
1067 7534 : sql_rel *r = rel->r;
1068 7534 : int inner = 0;
1069 :
1070 7534 : if (rel && is_dependent(rel) && r && is_select(r->op)) {
1071 7534 : sql_rel *rl = r->l;
1072 :
1073 7534 : if (rl && rel_has_freevar(sql, rl)) {
1074 2020 : list *inner_ad = rel_dependent_var(sql, d, rl);
1075 :
1076 2020 : inner = !list_empty(inner_ad);
1077 : }
1078 : }
1079 2020 : if (inner && is_left(rel->op) && !need_distinct(d))
1080 31 : return rel_general_unnest(sql, rel, ad);
1081 : /* input rel is dependent join with on the right a select */
1082 7503 : if ((!inner || is_semi(rel->op)) && rel && is_dependent(rel)) {
1083 5550 : sql_rel *r = rel->r;
1084 :
1085 5550 : if (r && is_select(r->op)) { /* move into join */
1086 5550 : node *n;
1087 :
1088 5550 : if (!list_empty(r->exps)) {
1089 12206 : for (n=r->exps->h; n; n = n->next) {
1090 6656 : sql_exp *e = n->data;
1091 :
1092 6656 : e = exp_copy(sql, e);
1093 6656 : if (exp_has_freevar(sql, e))
1094 6637 : rel_bind_var(sql, rel->l, e);
1095 6656 : rel_join_add_exp(sql->sa, rel, e);
1096 : }
1097 : }
1098 : /* remove select */
1099 5550 : rel->r = rel_dup(r->l);
1100 5550 : rel_destroy(r);
1101 5550 : r = rel->r;
1102 5550 : if (is_single(r)) {
1103 2 : set_single(rel);
1104 2 : rel->op = op_left;
1105 : }
1106 5550 : if (!inner)
1107 5515 : reset_dependent(rel);
1108 : }
1109 1953 : } else if (rel && is_join(rel->op) && is_dependent(rel)) {
1110 1953 : int cp = rel_is_ref(r);
1111 1953 : sql_rel *r = rel->r;
1112 1953 : list *exps = r->exps;
1113 :
1114 : /* remove select */
1115 1953 : rel->r = rel_dup(r->l);
1116 1953 : rel = rel_select(sql->sa, rel, NULL);
1117 1953 : rel->exps = !cp?exps:exps_copy(sql, exps);
1118 1953 : rel_bind_vars(sql, rel, rel->exps);
1119 1953 : set_processed(rel);
1120 1953 : rel_destroy(r);
1121 : }
1122 : return rel;
1123 : }
1124 :
1125 : static int
1126 14 : exps_is_constant( list *exps )
1127 : {
1128 14 : sql_exp *e;
1129 :
1130 14 : if (!exps || list_empty(exps))
1131 0 : return 1;
1132 14 : if (list_length(exps) > 1)
1133 : return 0;
1134 14 : e = exps->h->data;
1135 14 : return exp_is_atom(e);
1136 : }
1137 :
1138 : static int
1139 185735 : exp_is_count(sql_exp *e, sql_rel *rel)
1140 : {
1141 284907 : if (!e || !rel)
1142 : return 0;
1143 278341 : if (is_alias(e->type) && is_project(rel->op)) {
1144 99172 : sql_exp *ne = rel_find_exp(rel->l, e);
1145 99172 : return exp_is_count(ne, rel->l);
1146 : }
1147 179169 : if (is_aggr(e->type) && exp_aggr_is_count(e))
1148 : return 1;
1149 : return 0;
1150 : }
1151 :
1152 : static sql_rel *
1153 2865 : push_up_groupby(mvc *sql, sql_rel *rel, list *ad)
1154 : {
1155 : /* input rel is dependent join with on the right a groupby */
1156 2865 : if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
1157 2865 : sql_rel *l = rel->l, *r = rel->r;
1158 :
1159 : /* left of rel should be a set */
1160 2865 : if (l && is_distinct_set(sql, l, ad) && r && is_groupby(r->op)) {
1161 2865 : list *sexps, *jexps, *a = rel_projections(sql, rel->l, NULL, 1, 1);
1162 2865 : node *n;
1163 2865 : sql_exp *id = NULL;
1164 :
1165 : /* move groupby up, ie add attributes of left + the old expression list */
1166 :
1167 2865 : if (l && list_length(a) > 1 && !need_distinct(l)) { /* add identity call only if there's more than one column in the groupby */
1168 3 : if (!(rel->l = rel_add_identity(sql, l, &id))) /* add identity call for group by */
1169 : return NULL;
1170 3 : assert(id);
1171 : }
1172 :
1173 : //assert(rel->op != op_anti);
1174 2865 : if (rel->op == op_semi)
1175 1 : rel->op = op_join;
1176 2865 : if (rel->op == op_anti) {
1177 0 : rel->op = op_join;
1178 : /* need to change all exps */
1179 0 : if (!list_empty(rel->exps)) {
1180 0 : for(node *n = rel->exps->h; n; n = n->next) {
1181 0 : sql_exp *e = n->data;
1182 0 : e->anti = !e->anti;
1183 : }
1184 : }
1185 : }
1186 :
1187 2865 : if (!list_empty(r->exps)) {
1188 5863 : for (n = r->exps->h; n; n = n->next ) {
1189 2998 : sql_exp *e = n->data;
1190 :
1191 : /* count_nil(* or constant) -> count(t.TID) */
1192 2998 : if (exp_is_count(e, r) && (!e->l || exps_is_constant(e->l))) {
1193 2361 : sql_rel *p = r->l; /* ugh */
1194 2361 : sql_rel *pp = r;
1195 4985 : while(p && p->l && (!is_project(p->op) && !is_base(p->op))) { /* find first project */
1196 : pp = p;
1197 : p = p->l;
1198 : }
1199 2361 : if (p && p->l && is_project(p->op) && list_empty(p->exps)) { /* skip empty project */
1200 1 : pp = p;
1201 1 : p = p->l;
1202 : }
1203 2361 : sql_exp *col = list_length(p->exps) ? p->exps->t->data : NULL;
1204 2361 : const char *cname = col ? exp_name(col) : NULL;
1205 :
1206 2361 : if ((!cname || strcmp(cname, TID) != 0) && !(pp->l = p = rel_add_identity(sql, p, &col)))
1207 0 : return NULL;
1208 2361 : col = exp_ref(sql, col);
1209 2361 : append(e->l=sa_list(sql->sa), col);
1210 2361 : set_no_nil(e);
1211 : }
1212 2998 : if (exp_has_freevar(sql, e))
1213 7 : rel_bind_var(sql, rel->l, e);
1214 : }
1215 : }
1216 2865 : r->exps = list_distinct(list_merge(r->exps, a, (fdup)NULL), (fcmp)exp_equal, (fdup)NULL);
1217 2865 : if (list_empty(r->r)) {
1218 2820 : if (id)
1219 3 : r->r = list_append(sa_list(sql->sa), exp_ref(sql, id));
1220 : else
1221 2817 : r->r = exps_copy(sql, a);
1222 2820 : r->card = CARD_AGGR;
1223 : /* After the unnesting, the cardinality of the aggregate function becomes larger */
1224 9641 : for(node *n = r->exps->h; n; n = n->next) {
1225 6821 : sql_exp *e = n->data;
1226 :
1227 6821 : e->card = CARD_AGGR;
1228 : }
1229 : } else {
1230 99 : for (n = ((list*)r->r)->h; n; n = n->next ) {
1231 54 : sql_exp *e = n->data;
1232 :
1233 54 : if (exp_has_freevar(sql, e))
1234 23 : rel_bind_var(sql, rel->l, e);
1235 : }
1236 45 : if (id)
1237 0 : list_append(r->r, exp_ref(sql, id));
1238 : else
1239 45 : r->r = list_distinct(list_merge(r->r, exps_copy(sql, a), (fdup)NULL), (fcmp)exp_equal, (fdup)NULL);
1240 : }
1241 :
1242 2865 : if (!r->l) {
1243 0 : r->l = rel->l;
1244 0 : rel->l = NULL;
1245 0 : rel->r = NULL;
1246 0 : rel_destroy(rel);
1247 : /* merge (distinct) projects / group by (over the same group by cols) */
1248 0 : while (r->l && exps_have_freevar(sql, r->exps)) {
1249 0 : sql_rel *l = r->l;
1250 :
1251 0 : if (!is_project(l->op))
1252 : break;
1253 0 : if (l->op == op_project && need_distinct(l)) { /* TODO: check if group by exps and distinct list are equal */
1254 0 : r->l = rel_dup(l->l);
1255 0 : rel_destroy(l);
1256 : }
1257 0 : if (is_groupby(l->op)) { /* TODO: check if group by exps and distinct list are equal */
1258 : /* add aggr exps of r to l, replace r by l */
1259 0 : if (!list_empty(r->exps)) {
1260 0 : for(node *n = r->exps->h; n; n = n->next) {
1261 0 : sql_exp *e = n->data;
1262 :
1263 0 : if (e->type == e_aggr)
1264 0 : append(l->exps, e);
1265 0 : if (exp_has_freevar(sql, e))
1266 0 : rel_bind_var(sql, l, e);
1267 : }
1268 : }
1269 0 : r->l = NULL;
1270 0 : rel_destroy(r);
1271 0 : r = l;
1272 : }
1273 : }
1274 0 : return r;
1275 : } else {
1276 2865 : rel->r = r->l;
1277 2865 : r->l = rel;
1278 : }
1279 : /* check if a join expression needs to be moved above the group by (into a select) */
1280 2865 : sexps = sa_list(sql->sa);
1281 2865 : jexps = sa_list(sql->sa);
1282 2865 : if (!list_empty(rel->exps)) {
1283 2 : for (n = rel->exps->h; n; n = n->next ) {
1284 1 : sql_exp *e = n->data;
1285 :
1286 1 : if (rel_find_exp(rel, e)) {
1287 0 : append(jexps, e);
1288 : } else {
1289 1 : append(sexps, e);
1290 : }
1291 : }
1292 : }
1293 2865 : rel->exps = jexps;
1294 2865 : if (list_length(sexps)) {
1295 1 : r = rel_select(sql->sa, r, NULL);
1296 1 : r->exps = sexps;
1297 1 : set_processed(r);
1298 : }
1299 2865 : return r;
1300 : }
1301 : }
1302 : return rel;
1303 : }
1304 :
1305 : static sql_rel *
1306 0 : push_up_select_l(mvc *sql, sql_rel *rel)
1307 : {
1308 0 : (void)sql;
1309 : /* input rel is dependent join with on the right a project */
1310 0 : if (rel && (is_join(rel->op) || is_semi(rel->op))) {
1311 0 : sql_rel *l = rel->l;
1312 :
1313 0 : if (is_select(l->op) && rel_has_freevar(sql, l) && !rel_is_ref(l) ) {
1314 : /* push up select (above join) */
1315 0 : rel->l = l->l;
1316 0 : l->l = rel;
1317 0 : return l;
1318 : }
1319 : }
1320 : return rel;
1321 : }
1322 :
1323 : static void
1324 15 : bind_join_vars(mvc *sql, sql_rel *rel)
1325 : {
1326 15 : if (list_empty(rel->exps))
1327 : return;
1328 43 : for(node *n = rel->exps->h; n; n = n->next){
1329 28 : sql_exp *e = n->data;
1330 :
1331 28 : if (exp_has_freevar(sql, e))
1332 23 : rel_bind_var(sql, rel->l, e);
1333 : }
1334 : }
1335 :
1336 : static sql_rel * rewrite_outer2inner_union(visitor *v, sql_rel *rel);
1337 :
1338 : static sql_rel *
1339 135 : push_up_join(mvc *sql, sql_rel *rel, list *ad)
1340 : {
1341 : /* input rel is dependent join */
1342 135 : if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
1343 135 : sql_rel *d = rel->l, *j = rel->r;
1344 :
1345 : /* left of rel should be a set */
1346 135 : if (d && is_distinct_set(sql, d, ad) && j && (is_join(j->op) || is_semi(j->op))) {
1347 135 : sql_rel *jl = j->l, *jr = j->r;
1348 : /* op_join if F(jl) intersect A(D) = empty -> jl join (D djoin jr)
1349 : * F(jr) intersect A(D) = empty -> (D djoin jl) join jr
1350 : * else (D djoin jl) natural join (D djoin jr)
1351 : *
1352 : * */
1353 135 : list *rd = NULL, *ld = NULL;
1354 135 : int labelleft = j->op == op_right;
1355 :
1356 135 : if (is_semi(j->op) && is_select(jl->op) && rel_has_freevar(sql, jl) && !rel_is_ref(jl)) {
1357 0 : rel->r = j = push_up_select_l(sql, j);
1358 0 : return rel; /* ie try again */
1359 : }
1360 135 : rd = (j->op != op_full && j->op != op_right)?rel_dependent_var(sql, d, jr):(list*)1;
1361 135 : ld = ((j->op == op_join || j->op == op_right))?rel_dependent_var(sql, d, jl):(list*)1;
1362 :
1363 135 : if (is_outerjoin(j->op) && j->exps && !list_empty(rel->attr)) {
1364 1 : visitor v = { .sql = sql };
1365 1 : rel->r = j = rewrite_outer2inner_union(&v, j);
1366 1 : if (!j)
1367 : return NULL;
1368 1 : return rel;
1369 : }
1370 :
1371 134 : if (ld && rd) {
1372 60 : node *m;
1373 60 : sql_rel *n, *nr, *nj, *nl;
1374 60 : list *inner_exps = exps_copy(sql, j->exps);
1375 60 : list *outer_exps = exps_copy(sql, rel->exps);
1376 60 : list *attr = j->attr;
1377 60 : int single = is_single(j);
1378 :
1379 60 : rel->r = rel_dup(jl);
1380 60 : rel->exps = sa_list(sql->sa);
1381 60 : nj = rel_crossproduct(sql->sa, rel_dup(d), rel_dup(jr), j->op);
1382 60 : set_processed(nj);
1383 60 : rel_destroy(j);
1384 60 : j = nj;
1385 60 : set_dependent(j);
1386 60 : n = rel_crossproduct(sql->sa, rel, j, j->op);
1387 60 : n->exps = outer_exps;
1388 60 : if (single)
1389 8 : set_single(n);
1390 60 : if (!n->exps)
1391 47 : n->exps = inner_exps;
1392 : else
1393 13 : n->exps = list_merge(n->exps, inner_exps, (fdup)NULL);
1394 60 : j->op = rel->op;
1395 60 : if (is_semi(rel->op)) {
1396 0 : j->op = op_left;
1397 0 : rel->op = op_left;
1398 : }
1399 60 : nl = n->l = rel_project(sql->sa, n->l, rel_projections(sql, n->l, NULL, 1, 1));
1400 60 : nr = n->r;
1401 60 : nr = n->r = rel_project(sql->sa, n->r, is_semi(nr->op)?sa_list(sql->sa):rel_projections(sql, nr->r, NULL, 1, 1));
1402 : /* add nr->l exps with labels */
1403 : /* create jexps */
1404 60 : if (!n->exps)
1405 26 : n->exps = sa_list(sql->sa);
1406 60 : if (!list_empty(d->exps)) {
1407 171 : for (m = d->exps->h; m; m = m->next) {
1408 111 : sql_exp *e = m->data, *le, *re, *je;
1409 :
1410 111 : le = exp_ref(sql, e);
1411 111 : re = exp_ref(sql, e);
1412 :
1413 111 : if (labelleft) {
1414 7 : sql_exp *f = NULL;
1415 7 : if ((f=rel_find_exp(nl, le)) != NULL)
1416 7 : le = f;
1417 7 : if (!has_label(le))
1418 7 : le = exp_label(sql->sa, le, ++sql->label);
1419 7 : if (!f)
1420 0 : append(nl->exps, le);
1421 7 : le = exp_ref(sql, le);
1422 : }
1423 :
1424 7 : if (!labelleft)
1425 104 : re = exp_label(sql->sa, re, ++sql->label);
1426 111 : append(nr->exps, re);
1427 111 : re = exp_ref(sql, re);
1428 111 : je = exp_compare(sql->sa, le, re, cmp_equal);
1429 111 : set_semantics(je);
1430 111 : append(n->exps, je);
1431 : }
1432 : }
1433 60 : list_hash_clear(nl->exps);
1434 60 : n->attr = attr;
1435 60 : set_processed(n);
1436 60 : rel_bind_vars(sql, n, n->exps);
1437 60 : return n;
1438 : }
1439 :
1440 74 : if (!rd) {
1441 38 : rel->r = rel_dup(jl);
1442 38 : sql_rel *nj = rel_crossproduct(sql->sa, rel, rel_dup(jr), j->op);
1443 38 : if (is_single(j))
1444 3 : set_single(nj);
1445 38 : nj->exps = exps_copy(sql, j->exps);
1446 38 : nj->attr = j->attr;
1447 38 : set_processed(nj);
1448 38 : rel_destroy(j);
1449 38 : j = nj;
1450 38 : if (is_semi(rel->op))
1451 0 : rel->op = op_left;
1452 38 : move_join_exps(sql, j, rel);
1453 38 : rel_bind_vars(sql, j, j->exps);
1454 38 : return j;
1455 : }
1456 36 : if (!ld) {
1457 36 : rel->r = rel_dup(jr);
1458 36 : sql_rel *nj = rel_crossproduct(sql->sa, rel_dup(jl), rel, j->op);
1459 36 : if (is_single(j))
1460 9 : set_single(nj);
1461 36 : nj->exps = exps_copy(sql, j->exps);
1462 36 : nj->attr = j->attr;
1463 36 : set_processed(nj);
1464 36 : rel_destroy(j);
1465 36 : j = nj;
1466 36 : if (is_semi(rel->op))
1467 2 : rel->op = op_left;
1468 36 : move_join_exps(sql, j, rel);
1469 36 : rel_bind_vars(sql, j, j->exps);
1470 36 : return j;
1471 : }
1472 0 : assert(0);
1473 : return rel;
1474 : }
1475 : }
1476 : return rel;
1477 : }
1478 :
1479 : static sql_rel *
1480 1549 : push_up_set(mvc *sql, sql_rel *rel, list *ad)
1481 : {
1482 1549 : if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
1483 1549 : int single = is_single(rel);
1484 1549 : sql_rel *d = rel->l, *s = rel->r;
1485 3094 : int need_distinct = is_semi(rel->op) && need_distinct(d);
1486 :
1487 : /* left of rel should be a set */
1488 3094 : if (d && is_distinct_set(sql, d, ad) && s && is_set(s->op)) {
1489 1549 : sql_rel *sl = s->l, *sr = s->r, *ns;
1490 :
1491 1549 : sl = rel_project(sql->sa, rel_dup(sl), rel_projections(sql, sl, NULL, 1, 1));
1492 3168 : for (node *n = sl->exps->h, *m = s->exps->h; n && m; n = n->next, m = m->next)
1493 1619 : exp_prop_alias(sql->sa, n->data, m->data);
1494 1549 : list_hash_clear(sl->exps);
1495 1549 : sr = rel_project(sql->sa, rel_dup(sr), rel_projections(sql, sr, NULL, 1, 1));
1496 3168 : for (node *n = sr->exps->h, *m = s->exps->h; n && m; n = n->next, m = m->next)
1497 1619 : exp_prop_alias(sql->sa, n->data, m->data);
1498 1549 : list_hash_clear(sr->exps);
1499 :
1500 1549 : int llen = list_length(sl->exps), rlen = list_length(sr->exps), l = 0;
1501 :
1502 1549 : if (llen != rlen) {
1503 1201 : if (llen < rlen) {
1504 246 : list *nr = sa_list(sql->sa);
1505 492 : for(node *n = sr->exps->h ; n && l < llen; n=n->next, l++)
1506 246 : append(nr, n->data);
1507 246 : sr->exps = nr;
1508 246 : sr->nrcols = list_length(nr);
1509 : } else {
1510 955 : list *nl = sa_list(sql->sa);
1511 1910 : for(node *n = sl->exps->h; n && l < rlen; n=n->next, l++)
1512 955 : append(nl, n->data);
1513 955 : sl->exps = nl;
1514 955 : sl->nrcols = list_length(nl);
1515 : }
1516 : }
1517 :
1518 : /* D djoin (sl setop sr) -> (D djoin sl) setop (D djoin sr) */
1519 1549 : sl = rel_crossproduct(sql->sa, rel_dup(d), sl, rel->op);
1520 1549 : sl->exps = exps_copy(sql, rel->exps);
1521 1549 : set_dependent(sl);
1522 1549 : set_processed(sl);
1523 1549 : sr = rel_crossproduct(sql->sa, rel_dup(d), sr, rel->op);
1524 1549 : sr->exps = exps_copy(sql, rel->exps);
1525 1549 : set_dependent(sr);
1526 1549 : set_processed(sr);
1527 1549 : ns = rel_setop(sql->sa, sl, sr, s->op);
1528 1549 : ns->exps = exps_copy(sql, s->exps);
1529 1549 : set_processed(ns);
1530 1549 : if (single || is_single(s))
1531 4 : set_single(ns);
1532 1549 : if (need_distinct || need_distinct(s))
1533 65 : set_distinct(ns);
1534 :
1535 1549 : if (is_join(rel->op)) {
1536 1545 : list *sexps = sa_list(sql->sa), *dexps = rel_projections(sql, d, NULL, 1, 1);
1537 5715 : for (node *m = dexps->h; m; m = m->next) {
1538 4170 : sql_exp *e = m->data;
1539 :
1540 4170 : list_append(sexps, exp_ref(sql, e));
1541 : }
1542 1545 : ns->exps = list_merge(sexps, ns->exps, (fdup)NULL);
1543 : }
1544 : /* add/remove projections to inner parts of the union (as we push a join or semijoin down) */
1545 1549 : ns->l = rel_project(sql->sa, ns->l, rel_projections(sql, ns->l, NULL, 1, 1));
1546 1549 : ns->r = rel_project(sql->sa, ns->r, rel_projections(sql, ns->r, NULL, 1, 1));
1547 1549 : if (is_semi(rel->op))
1548 4 : ns->exps = rel_projections(sql, ns->r, NULL, 1, 1);
1549 1549 : if (rel->op == op_anti && s->op == op_union)
1550 0 : ns->op = op_inter;
1551 1549 : if (rel->op == op_anti && s->op == op_inter)
1552 0 : ns->op = op_union;
1553 1549 : rel_destroy(rel);
1554 1549 : return ns;
1555 : }
1556 : }
1557 : return rel;
1558 : }
1559 :
1560 : static sql_rel * rel_unnest_dependent(mvc *sql, sql_rel *rel);
1561 :
1562 : static sql_rel *
1563 21 : push_up_table(mvc *sql, sql_rel *rel, list *ad)
1564 : {
1565 21 : (void)sql;
1566 21 : if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
1567 21 : sql_rel *d = rel->l, *tf = rel->r;
1568 21 : sql_exp *id = NULL;
1569 :
1570 : /* push d into function */
1571 21 : if (d && is_distinct_set(sql, d, ad) && tf && is_base(tf->op)) {
1572 21 : if (tf->l) {
1573 21 : sql_rel *l = tf->l;
1574 :
1575 21 : assert(tf->flag == TABLE_FROM_RELATION || !l->l);
1576 21 : if (l->l) {
1577 11 : sql_exp *tfe = tf->r;
1578 11 : list *ops = tfe->l;
1579 11 : if (!(rel->l = d = rel_add_identity(sql, d, &id)))
1580 21 : return NULL;
1581 11 : id = exp_ref(sql, id);
1582 11 : list *exps = rel_projections(sql, l, NULL, 1, 1);
1583 11 : list_append(exps, id);
1584 11 : l = tf->l = rel_crossproduct(sql->sa, rel_dup(d), l, op_join);
1585 11 : set_dependent(l);
1586 11 : set_processed(l);
1587 11 : tf->l = rel_unnest_dependent(sql, l);
1588 11 : tf->l = rel_project(sql->sa, tf->l, exps);
1589 11 : id = exp_ref(sql, id);
1590 11 : list_append(ops, id);
1591 11 : id = exp_ref(sql, id);
1592 : } else {
1593 10 : l->l = rel_dup(d);
1594 10 : if (is_project(l->op))
1595 10 : rel_bind_vars(sql, l, l->exps);
1596 : }
1597 : } else {
1598 0 : tf->l = rel_dup(d);
1599 : }
1600 : /* we should add the identity in the resulting projection list */
1601 21 : if (id) {
1602 11 : sql_exp *ne = exp_copy(sql, id);
1603 :
1604 11 : ne = exp_label(sql->sa, ne, ++sql->label);
1605 11 : ne = exp_ref(sql, ne);
1606 11 : list_prepend(tf->exps, ne);
1607 11 : ne = exp_ref(sql, ne);
1608 :
1609 11 : ne = exp_compare(sql->sa, id, ne, cmp_equal);
1610 : //set_semantics(e);
1611 11 : if (!rel->exps)
1612 9 : rel->exps = sa_list(sql->sa);
1613 11 : list_append(rel->exps, ne);
1614 : }
1615 21 : reset_dependent(rel);
1616 21 : return rel;
1617 : }
1618 : }
1619 : return rel;
1620 : }
1621 :
1622 : static bool
1623 9490 : exps_have_rank(list *exps)
1624 : {
1625 9490 : if (!exps)
1626 : return false;
1627 23644 : for(node *n=exps->h; n; n = n->next) {
1628 14254 : sql_exp *e = n->data;
1629 14254 : if (is_analytic(e))
1630 : return true;
1631 : }
1632 : return false;
1633 : }
1634 :
1635 : static sql_rel *
1636 648648 : rel_unnest_dependent(mvc *sql, sql_rel *rel)
1637 : {
1638 670240 : sql_rel *nrel = rel;
1639 :
1640 670240 : if (mvc_highwater(sql))
1641 0 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
1642 :
1643 : /* current unnest only possible for equality joins, <, <> etc needs more work */
1644 670240 : if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
1645 : /* howto find out the left is a set */
1646 30102 : sql_rel *l, *r;
1647 :
1648 30102 : l = rel->l;
1649 30102 : r = rel->r;
1650 :
1651 30102 : if (rel_has_freevar(sql, l)) {
1652 75 : rel->l = rel_unnest_dependent(sql, rel->l);
1653 75 : if (rel_has_freevar(sql, rel->l)) {
1654 75 : if (rel->op == op_right) {
1655 0 : sql_rel *l = rel->l;
1656 :
1657 0 : rel->l = rel->r;
1658 0 : rel->r = l;
1659 0 : rel->op = op_left;
1660 0 : return rel_unnest_dependent(sql, rel);
1661 75 : } else if (rel->op == op_left && list_empty(rel->attr) && !rel_has_freevar(sql, rel->r) && rel_dependent_var(sql, rel->r, rel->l)) {
1662 0 : sql_rel *l = rel->l;
1663 :
1664 0 : rel->l = rel->r;
1665 0 : rel->r = l;
1666 0 : rel->op = op_right;
1667 0 : return rel_unnest_dependent(sql, rel);
1668 : }
1669 : }
1670 : }
1671 :
1672 30102 : if (!rel_has_freevar(sql, r)) {
1673 4248 : if (rel_has_freevar(sql, l) && is_join(rel->op) && !rel->exps) {
1674 5 : rel->l = r;
1675 5 : rel->r = l;
1676 5 : l = rel->l;
1677 5 : r = rel->r;
1678 : } else {
1679 4243 : reset_dependent(rel);
1680 4243 : return rel;
1681 : }
1682 : }
1683 :
1684 : /* try to push dependent join down */
1685 25859 : if (rel_has_freevar(sql, r)) {
1686 25859 : list *ad = rel_dependent_var(sql, rel->l, rel->r);
1687 :
1688 25859 : if (list_empty(ad)) {
1689 20 : reset_dependent(rel);
1690 20 : return rel;
1691 : }
1692 25839 : if (r && is_select(r->op)) {
1693 7544 : sql_rel *l = r->l;
1694 :
1695 7544 : if (!rel_is_ref(r) && l && !rel_is_ref(l) && l->op == op_join && list_empty(l->exps)) {
1696 10 : l->exps = r->exps;
1697 10 : r->l = NULL;
1698 10 : rel_destroy(r);
1699 10 : rel->r = l;
1700 10 : return rel_unnest_dependent(sql, rel);
1701 : }
1702 : }
1703 :
1704 25829 : if (rel && (is_join(rel->op) || is_semi(rel->op)) && is_dependent(rel)) {
1705 25829 : sql_rel *j = rel->r;
1706 :
1707 25829 : if (j->op == op_join && !rel_is_ref(rel) && !rel_is_ref(j) && j->exps && exps_have_freevar(sql, j->exps)) {
1708 15 : rel->exps = rel->exps?list_merge(rel->exps, j->exps, (fdup)NULL):j->exps;
1709 15 : j->exps = NULL;
1710 15 : bind_join_vars(sql, rel);
1711 15 : return rel_unnest_dependent(sql, rel);
1712 : }
1713 : }
1714 :
1715 25814 : if (r && is_simple_project(r->op) && ((!r->r && !exps_have_rank(r->exps)) || (!exps_have_freevar(sql, r->exps) && !exps_have_unsafe(r->exps, 1)) || is_distinct_set(sql, l, ad))) {
1716 9479 : rel = push_up_project(sql, rel, ad);
1717 9479 : return rel_unnest_dependent(sql, rel);
1718 : }
1719 :
1720 16335 : if (r && (is_topn(r->op) || is_sample(r->op))) {
1721 5 : rel = push_up_topn_and_sample(sql, rel);
1722 5 : return rel_unnest_dependent(sql, rel);
1723 : }
1724 :
1725 16330 : if (r && is_select(r->op) && ad) {
1726 7534 : rel = push_up_select(sql, rel, ad);
1727 7534 : return rel_unnest_dependent(sql, rel);
1728 : }
1729 :
1730 8796 : if (r && is_groupby(r->op) && !is_left(rel->op) && is_distinct_set(sql, l, ad)) {
1731 2865 : rel = push_up_groupby(sql, rel, ad);
1732 2865 : return rel_unnest_dependent(sql, rel);
1733 : }
1734 :
1735 5931 : if (r && (is_join(r->op) || is_semi(r->op)) && is_distinct_set(sql, l, ad)) {
1736 135 : rel = push_up_join(sql, rel, ad);
1737 135 : return rel_unnest_dependent(sql, rel);
1738 : }
1739 :
1740 5796 : if (r && is_set(r->op) && !is_left(rel->op) && rel->op != op_anti && is_distinct_set(sql, l, ad)) {
1741 1549 : rel = push_up_set(sql, rel, ad);
1742 1549 : return rel_unnest_dependent(sql, rel);
1743 : }
1744 :
1745 4247 : if (r && is_base(r->op) && is_distinct_set(sql, l, ad)) {
1746 21 : rel = push_up_table(sql, rel, ad);
1747 21 : return rel;
1748 : }
1749 :
1750 : /* fallback */
1751 4226 : if (ad != NULL)
1752 4226 : rel = rel_general_unnest(sql, rel, ad);
1753 :
1754 : /* no dependent variables */
1755 4226 : reset_dependent(rel);
1756 4226 : rel->r = rel_unnest_dependent(sql, rel->r);
1757 : } else {
1758 0 : rel->l = rel_unnest_dependent(sql, rel->l);
1759 0 : rel->r = rel_unnest_dependent(sql, rel->r);
1760 : }
1761 : } else {
1762 629465 : if (rel && (is_simple_project(rel->op) || is_groupby(rel->op) || is_select(rel->op) || is_topn(rel->op) || is_sample(rel->op)))
1763 308599 : rel->l = rel_unnest_dependent(sql, rel->l);
1764 : else if (rel && (is_join(rel->op) || is_semi(rel->op) || is_set(rel->op) || is_modify(rel->op) || is_ddl(rel->op))) {
1765 163435 : rel->l = rel_unnest_dependent(sql, rel->l);
1766 163435 : rel->r = rel_unnest_dependent(sql, rel->r);
1767 : }
1768 : }
1769 : return nrel;
1770 : }
1771 :
1772 : static list * add_missing_project_exps(mvc *sql, sql_rel *rel, list *exps);
1773 :
1774 : static sql_exp *
1775 12946 : add_missing_project_exp(mvc *sql, sql_rel *rel, sql_exp *e)
1776 : {
1777 12946 : if (is_freevar(e))
1778 : return e;
1779 8717 : if (is_convert(e->type)) {
1780 65 : e->l = add_missing_project_exp(sql, rel, e->l);
1781 8652 : } else if (is_compare(e->type)) {
1782 4315 : if (e->flag == cmp_in || e->flag == cmp_notin) {
1783 2 : e->l = add_missing_project_exp(sql, rel, e->l);
1784 2 : e->r = add_missing_project_exps(sql, rel, e->r);
1785 4313 : } else if (e->flag == cmp_or || e->flag == cmp_filter) {
1786 52 : e->l = add_missing_project_exps(sql, rel, e->l);
1787 52 : e->r = add_missing_project_exps(sql, rel, e->r);
1788 : } else {
1789 4261 : e->l = add_missing_project_exp(sql, rel, e->l);
1790 4261 : e->r = add_missing_project_exp(sql, rel, e->r);
1791 4261 : if (e->f)
1792 11 : e->f = add_missing_project_exp(sql, rel, e->f);
1793 : }
1794 4337 : } else if (is_atom(e->type)) {
1795 207 : if (is_values(e))
1796 0 : e->f = add_missing_project_exps(sql, rel, e->f);
1797 207 : return e;
1798 : }
1799 4130 : else if (!list_find_exp(rel->exps, e)) {
1800 4070 : exp_label(sql->sa, e, ++sql->label);
1801 4070 : append(rel->exps, e);
1802 4070 : return exp_ref(sql, e);
1803 : }
1804 : return e;
1805 : }
1806 :
1807 : static list *
1808 4262 : add_missing_project_exps(mvc *sql, sql_rel *rel, list *exps)
1809 : {
1810 4262 : if (list_empty(exps))
1811 : return exps;
1812 8608 : for(node *n = exps->h; n; n = n->next)
1813 4346 : n->data = add_missing_project_exp(sql, rel, n->data);
1814 : return exps;
1815 : }
1816 :
1817 : static sql_rel *
1818 4929 : push_up_select2(visitor *v, sql_rel *rel)
1819 : {
1820 4929 : sql_rel *l = rel->l;
1821 4929 : sql_rel *r = rel->r;
1822 :
1823 : /* TODO make sure we do not have empty selects */
1824 4929 : if (is_simple_project(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) {
1825 4156 : sql_rel *nl = rel_select(v->sql->sa, rel, NULL);
1826 4156 : nl->exps = add_missing_project_exps(v->sql, rel, l->exps);
1827 4156 : l->exps = NULL;
1828 4156 : rel->l = rel_dup(l->l);
1829 4156 : rel_destroy(l);
1830 4156 : rel_bind_vars(v->sql, nl, nl->exps);
1831 4156 : v->changes++;
1832 4156 : return nl;
1833 : }
1834 773 : if (!is_single(rel) && is_innerjoin(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) {
1835 22 : sql_rel *nl = rel_select(v->sql->sa, rel, NULL);
1836 22 : nl->exps = l->exps;
1837 22 : l->exps = NULL;
1838 22 : rel->l = rel_dup(l->l);
1839 22 : rel_destroy(l);
1840 22 : rel_bind_vars(v->sql, nl, nl->exps);
1841 22 : v->changes++;
1842 22 : nl->l = push_up_select2(v, nl->l);
1843 22 : return nl;
1844 : }
1845 751 : if (is_single(rel) && is_innerjoin(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) {
1846 0 : if (rel->exps)
1847 0 : rel->exps = list_merge(rel->exps, l->exps, NULL);
1848 : else
1849 0 : rel->exps = l->exps;
1850 0 : l->exps = NULL;
1851 0 : rel->l = rel_dup(l->l);
1852 0 : rel_destroy(l);
1853 0 : rel_bind_vars(v->sql, rel, rel->exps);
1854 0 : v->changes++;
1855 0 : rel = push_up_select2(v, rel);
1856 0 : return rel;
1857 : }
1858 751 : if (!is_single(rel) && is_innerjoin(rel->op) && r && is_select(r->op) && exps_have_freevar(v->sql, r->exps) && !rel_is_ref(r)) {
1859 14 : sql_rel *nr = rel_select(v->sql->sa, rel, NULL);
1860 14 : nr->exps = r->exps;
1861 14 : r->exps = NULL;
1862 14 : rel->r = rel_dup(r->l);
1863 14 : rel_destroy(r);
1864 14 : rel_bind_vars(v->sql, nr, nr->exps);
1865 14 : v->changes++;
1866 14 : return nr;
1867 : }
1868 737 : if (is_single(rel) && is_innerjoin(rel->op) && r && is_select(r->op) && exps_have_freevar(v->sql, r->exps) && !rel_is_ref(r)) {
1869 8 : if (rel->exps)
1870 0 : rel->exps = list_merge(rel->exps, r->exps, NULL);
1871 : else
1872 8 : rel->exps = r->exps;
1873 8 : r->exps = NULL;
1874 8 : rel->r = rel_dup(r->l);
1875 8 : rel_destroy(r);
1876 8 : rel_bind_vars(v->sql, rel, rel->exps);
1877 8 : v->changes++;
1878 8 : return rel;
1879 : }
1880 729 : if (is_left(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) {
1881 14 : sql_rel *nl = rel_select(v->sql->sa, rel, NULL);
1882 14 : nl->exps = l->exps;
1883 14 : l->exps = NULL;
1884 14 : rel->l = rel_dup(l->l);
1885 14 : rel_destroy(l);
1886 14 : rel_bind_vars(v->sql, nl, nl->exps);
1887 14 : v->changes++;
1888 14 : nl->l = push_up_select2(v, nl->l);
1889 14 : return nl;
1890 : }
1891 715 : if (is_left(rel->op) && r && is_select(r->op) && exps_have_freevar(v->sql, r->exps) && !rel_is_ref(r)) {
1892 678 : if (rel->exps)
1893 44 : rel->exps = list_merge(rel->exps, r->exps, NULL);
1894 : else
1895 634 : rel->exps = r->exps;
1896 678 : r->exps = NULL;
1897 678 : rel->r = rel_dup(r->l);
1898 678 : rel_destroy(r);
1899 678 : rel_bind_vars(v->sql, rel, rel->exps);
1900 678 : v->changes++;
1901 678 : return rel;
1902 : }
1903 37 : if (is_right(rel->op) && r && is_select(r->op) && exps_have_freevar(v->sql, r->exps) && !rel_is_ref(r)) {
1904 1 : sql_rel *nr = rel_select(v->sql->sa, rel, NULL);
1905 1 : nr->exps = r->exps;
1906 1 : r->exps = NULL;
1907 1 : rel->r = rel_dup(r->l);
1908 1 : rel_destroy(r);
1909 1 : rel_bind_vars(v->sql, nr, nr->exps);
1910 1 : v->changes++;
1911 1 : nr->l = push_up_select2(v, nr->l);
1912 1 : return nr;
1913 : }
1914 36 : if (is_right(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) {
1915 3 : if (rel->exps)
1916 3 : rel->exps = list_merge(rel->exps, l->exps, NULL);
1917 : else
1918 0 : rel->exps = l->exps;
1919 3 : l->exps = NULL;
1920 3 : rel->l = rel_dup(l->l);
1921 3 : rel_destroy(l);
1922 3 : rel_bind_vars(v->sql, rel, rel->exps);
1923 3 : v->changes++;
1924 3 : return rel;
1925 : }
1926 : return rel;
1927 : }
1928 :
1929 : static sql_rel *
1930 2291843 : _rel_unnest(visitor *v, sql_rel *rel)
1931 : {
1932 2291843 : sql_rel *l = rel->l;
1933 2291843 : sql_rel *r = rel->r;
1934 : /* try to push select up */
1935 2291843 : if (!rel_is_ref(rel) && ((is_simple_project(rel->op) && !rel->r && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) ||
1936 2255601 : (is_join(rel->op) && l && is_select(l->op) && exps_have_freevar(v->sql, l->exps) && !rel_is_ref(l)) ||
1937 2255562 : (is_join(rel->op) && r && is_select(r->op) && exps_have_freevar(v->sql, r->exps) && !rel_is_ref(r)))) {
1938 4892 : rel = push_up_select2(v, rel);
1939 4892 : if (rel && is_select(rel->op)) {
1940 4207 : sql_rel *l = rel->l;
1941 4207 : if (is_dependent(l)) {
1942 17 : rel->l = l = rel_unnest_dependent(v->sql, l);
1943 17 : v->changes++;
1944 : }
1945 : }
1946 : }
1947 2291843 : if (is_dependent(rel)) {
1948 8850 : rel = rel_unnest_dependent(v->sql, rel);
1949 8850 : v->changes++;
1950 : }
1951 2291843 : return rel;
1952 : }
1953 :
1954 : static void exp_reset_props(sql_rel *rel, sql_exp *e, bool setnil);
1955 :
1956 : static void
1957 110 : exps_reset_props(sql_rel *rel, list *exps, bool setnil)
1958 : {
1959 110 : if (!list_empty(exps))
1960 301 : for(node *n=exps->h; n; n=n->next)
1961 191 : exp_reset_props(rel, n->data, setnil);
1962 110 : }
1963 :
1964 : static void
1965 21853 : exp_reset_props(sql_rel *rel, sql_exp *e, bool setnil)
1966 : {
1967 21853 : switch (e->type) {
1968 19793 : case e_column: {
1969 19793 : if (setnil && (((is_right(rel->op) || is_full(rel->op)) && rel_find_exp(rel->l, e) != NULL) ||
1970 13930 : ((is_left(rel->op) || is_full(rel->op)) && rel_find_exp(rel->r, e) != NULL)))
1971 13838 : set_has_nil(e);
1972 : } break;
1973 67 : case e_convert: {
1974 67 : exp_reset_props(rel, e->l, setnil);
1975 67 : if (setnil && has_nil((sql_exp*)e->l))
1976 32 : set_has_nil(e);
1977 : } break;
1978 80 : case e_func: {
1979 80 : sql_subfunc *f = e->f;
1980 :
1981 80 : exps_reset_props(rel, e->l, setnil);
1982 80 : if (setnil && !f->func->semantics && e->l && have_nil(e->l))
1983 10 : set_has_nil(e);
1984 : } break;
1985 0 : case e_aggr: {
1986 0 : sql_subfunc *a = e->f;
1987 :
1988 0 : exps_reset_props(rel, e->l, setnil);
1989 0 : if (setnil && (a->func->s || strcmp(a->func->base.name, "count") != 0) && !a->func->semantics && !has_nil(e) && e->l && have_nil(e->l))
1990 0 : set_has_nil(e);
1991 : } break;
1992 60 : case e_cmp: {
1993 60 : if (e->flag == cmp_or || e->flag == cmp_filter) {
1994 15 : exps_reset_props(rel, e->l, setnil);
1995 15 : exps_reset_props(rel, e->r, setnil);
1996 15 : if (setnil && (have_nil(e->l) || have_nil(e->r)))
1997 14 : set_has_nil(e);
1998 45 : } else if (e->flag == cmp_in || e->flag == cmp_notin) {
1999 0 : exp_reset_props(rel, e->l, setnil);
2000 0 : exps_reset_props(rel, e->r, setnil);
2001 0 : if (setnil && (has_nil((sql_exp*)e->l) || have_nil(e->r)))
2002 0 : set_has_nil(e);
2003 : } else {
2004 45 : exp_reset_props(rel, e->l, setnil);
2005 45 : exp_reset_props(rel, e->r, setnil);
2006 45 : if (e->f)
2007 5 : exp_reset_props(rel, e->f, setnil);
2008 45 : if (setnil && !is_semantics(e) && (((sql_exp*)e->l) || has_nil((sql_exp*)e->r) || (e->f && has_nil((sql_exp*)e->f))))
2009 37 : set_has_nil(e);
2010 : }
2011 : } break;
2012 : default:
2013 : break;
2014 : }
2015 21853 : set_not_unique(e);
2016 21853 : }
2017 :
2018 : static sql_exp *
2019 22122 : rewrite_inner(mvc *sql, sql_rel *rel, sql_rel *inner, operator_type op, sql_rel **rewrite)
2020 : {
2021 22122 : int single = is_single(inner);
2022 22122 : sql_rel *d = NULL;
2023 :
2024 22122 : reset_single(inner);
2025 22122 : if (single && is_project(rel->op))
2026 22122 : op = op_left;
2027 :
2028 22122 : if (is_join(rel->op)){
2029 7 : if (rel_has_freevar(sql, inner)) {
2030 0 : list *rv = rel_dependent_var(sql, rel->r, inner);
2031 0 : if (!list_empty(rv))
2032 0 : d = rel->r = rel_crossproduct(sql->sa, rel->r, inner, op);
2033 : else
2034 0 : d = rel->l = rel_crossproduct(sql->sa, rel->l, inner, op);
2035 7 : } else if (is_right(rel->op))
2036 4 : d = rel->l = rel_crossproduct(sql->sa, rel->l, inner, op);
2037 : else
2038 3 : d = rel->r = rel_crossproduct(sql->sa, rel->r, inner, op);
2039 7 : if (single)
2040 5 : set_single(d);
2041 7 : set_processed(d);
2042 22115 : } else if (is_project(rel->op)){ /* projection -> op_left */
2043 13314 : if (rel->l || single || op == op_left) {
2044 13291 : if ((single || op == op_left) && !rel->l) {
2045 544 : sql_exp *e = exp_atom_bool(sql->sa, 1);
2046 544 : exp_label(sql->sa, e, ++sql->label);
2047 544 : rel->l = rel_project(sql->sa, rel->l, list_append(sa_list(sql->sa), e));
2048 : }
2049 13291 : d = rel->l = rel_crossproduct(sql->sa, rel->l, inner, op_left);
2050 13291 : if (single)
2051 1551 : set_single(d);
2052 13291 : set_processed(d);
2053 : } else {
2054 23 : d = rel->l = inner;
2055 : }
2056 : } else {
2057 8801 : d = rel->l = rel_crossproduct(sql->sa, rel->l, inner, op);
2058 8801 : if (single)
2059 2955 : set_single(d);
2060 8801 : set_processed(d);
2061 : }
2062 22122 : assert(d);
2063 22122 : if (rel_has_freevar(sql, inner)) {
2064 5739 : list *dv = rel_dependent_var(sql, d, inner);
2065 5739 : list *fv = rel_freevar(sql, inner);
2066 : /* check if the inner depends on the new join (d) or one leve up */
2067 5739 : if (list_length(dv))
2068 5664 : set_dependent(d);
2069 5739 : if (list_length(fv) != list_length(dv))
2070 147 : set_dependent(rel);
2071 : }
2072 22122 : if (rewrite)
2073 21443 : *rewrite = d;
2074 22122 : if (is_project(inner->op))
2075 22114 : return inner->exps->t->data;
2076 : return NULL;
2077 : }
2078 :
2079 : static sql_exp *
2080 11376002 : rewrite_exp_rel(visitor *v, sql_rel *rel, sql_exp *e, int depth)
2081 : {
2082 11376002 : if (exp_has_rel(e) && !is_ddl(rel->op)) {
2083 9402 : sql_rel *rewrite = NULL;
2084 13581 : sql_exp *ne = rewrite_inner(v->sql, rel, exp_rel_get_rel(v->sql->sa, e), depth?op_left:op_join, &rewrite);
2085 :
2086 9402 : if (!ne)
2087 1 : return ne;
2088 9401 : if (exp_is_rel(e)) {
2089 9401 : ne = exp_ref(v->sql, ne);
2090 9401 : if (exp_name(e))
2091 9401 : exp_prop_alias(v->sql->sa, ne, e);
2092 9401 : if (!exp_name(ne))
2093 0 : ne = exp_label(v->sql->sa, ne, ++v->sql->label);
2094 : e = ne;
2095 : } else {
2096 0 : e = exp_rel_update_exp(v->sql, e, false);
2097 : }
2098 9401 : exp_reset_props(rewrite, e, is_left(rewrite->op));
2099 9401 : v->changes++;
2100 : }
2101 : return e;
2102 : }
2103 :
2104 : /* add an dummy true projection column */
2105 : static inline sql_rel *
2106 2238288 : rewrite_empty_project(visitor *v, sql_rel *rel)
2107 : {
2108 2238288 : if ((is_simple_project(rel->op) || is_groupby(rel->op)) && list_empty(rel->exps)) {
2109 29 : sql_exp *e = exp_atom_bool(v->sql->sa, 1);
2110 :
2111 29 : exp_label(v->sql->sa, e, ++v->sql->label);
2112 29 : list_append(rel->exps, e);
2113 29 : v->changes++;
2114 : }
2115 2238284 : return rel;
2116 : }
2117 :
2118 : /*
2119 : * For decimals and intervals we need to adjust the scale for some operations.
2120 : *
2121 : * TODO move the decimal scale handling to this function.
2122 : */
2123 : #define is_division(sf) (strcmp(sf->func->base.name, "sql_div") == 0)
2124 : #define is_multiplication(sf) (strcmp(sf->func->base.name, "sql_mul") == 0)
2125 :
2126 : static inline sql_exp *
2127 13910336 : exp_physical_types(visitor *v, sql_rel *rel, sql_exp *e, int depth)
2128 : {
2129 13910336 : (void)rel;
2130 13910336 : (void)depth;
2131 13910336 : sql_exp *ne = e;
2132 :
2133 13910336 : if (!e || (e->type != e_func && e->type != e_convert) || !e->l)
2134 : return e;
2135 :
2136 945261 : if (e->type == e_convert) {
2137 343418 : sql_subtype *ft = exp_fromtype(e);
2138 343418 : sql_subtype *tt = exp_totype(e);
2139 :
2140 : /* complex conversion matrix */
2141 343418 : if (ft->type->eclass == EC_SEC && tt->type->eclass == EC_SEC && ft->type->digits > tt->type->digits) {
2142 : /* no conversion needed, just time adjustment */
2143 0 : ne = e->l;
2144 0 : ne->tpe = *tt; // ugh
2145 : }
2146 : } else {
2147 601843 : list *args = e->l;
2148 601843 : sql_subfunc *f = e->f;
2149 :
2150 : /* multiplication and division on decimals */
2151 601843 : if (is_multiplication(f) && list_length(args) == 2) {
2152 19910 : sql_exp *le = args->h->data;
2153 19910 : sql_subtype *lt = exp_subtype(le);
2154 :
2155 19910 : if (lt->type->eclass == EC_SEC || lt->type->eclass == EC_MONTH) {
2156 49 : sql_exp *re = args->h->next->data;
2157 49 : sql_subtype *rt = exp_subtype(re);
2158 :
2159 49 : if (rt->type->eclass == EC_DEC && rt->scale) {
2160 7 : int scale = (int) rt->scale; /* shift with scale */
2161 7 : sql_subtype *it = sql_bind_localtype(lt->type->impl);
2162 7 : sql_subfunc *c = sql_bind_func(v->sql, "sys", "scale_down", lt, it, F_FUNC, true);
2163 :
2164 7 : if (!c) {
2165 0 : TRC_CRITICAL(SQL_PARSER, "scale_down missing (%s)\n", lt->type->impl);
2166 0 : return NULL;
2167 : }
2168 : #ifdef HAVE_HGE
2169 7 : hge val = scale2value(scale);
2170 : #else
2171 : lng val = scale2value(scale);
2172 : #endif
2173 7 : atom *a = atom_int(v->sql->sa, it, val);
2174 7 : ne = exp_binop(v->sql->sa, e, exp_atom(v->sql->sa, a), c);
2175 : }
2176 : }
2177 581933 : } else if (is_division(f) && list_length(args) == 2) {
2178 2249 : sql_exp *le = args->h->data;
2179 2249 : sql_subtype *lt = exp_subtype(le);
2180 :
2181 2249 : if (lt->type->eclass == EC_SEC || lt->type->eclass == EC_MONTH) {
2182 35 : sql_exp *re = args->h->next->data;
2183 35 : sql_subtype *rt = exp_subtype(re);
2184 :
2185 35 : if (rt->type->eclass == EC_DEC && rt->scale) {
2186 10 : int scale = (int) rt->scale; /* shift with scale */
2187 : #ifdef HAVE_HGE
2188 10 : hge val = scale2value(scale);
2189 : #else
2190 : lng val = scale2value(scale);
2191 : #endif
2192 :
2193 10 : if (lt->type->eclass == EC_SEC) {
2194 5 : sql_subtype *it = sql_bind_localtype(lt->type->impl);
2195 5 : sql_subfunc *c = sql_bind_func(v->sql, "sys", "scale_up", lt, it, F_FUNC, true);
2196 :
2197 5 : if (!c) {
2198 0 : TRC_CRITICAL(SQL_PARSER, "scale_up missing (%s)\n", lt->type->impl);
2199 0 : return NULL;
2200 : }
2201 5 : atom *a = atom_int(v->sql->sa, it, val);
2202 5 : ne = exp_binop(v->sql->sa, e, exp_atom(v->sql->sa, a), c);
2203 : } else { /* EC_MONTH */
2204 5 : sql_subtype *it = sql_bind_localtype(rt->type->impl);
2205 5 : sql_subfunc *c = sql_bind_func(v->sql, "sys", "scale_down", rt, it, F_FUNC, true);
2206 :
2207 5 : if (!c) {
2208 0 : TRC_CRITICAL(SQL_PARSER, "scale_down missing (%s)\n", lt->type->impl);
2209 0 : return NULL;
2210 : }
2211 5 : atom *a = atom_int(v->sql->sa, it, val);
2212 5 : args->h->next->data = exp_binop(v->sql->sa, args->h->next->data, exp_atom(v->sql->sa, a), c);
2213 : }
2214 : }
2215 : }
2216 : }
2217 : }
2218 945261 : if (ne != e) {
2219 12 : if (exp_name(e))
2220 1 : exp_prop_alias(v->sql->sa, ne, e);
2221 12 : v->changes++;
2222 : }
2223 : return ne;
2224 : }
2225 :
2226 : static sql_exp *
2227 13910322 : exp_reset_card_and_freevar_set_physical_type(visitor *v, sql_rel *rel, sql_exp *e, int depth)
2228 : {
2229 13910322 : if (e->type == e_func && e->r) /* mark as normal (analytic) function now */
2230 7664 : e->r = NULL;
2231 13910322 : reset_freevar(e); /* unnesting is done, we can remove the freevar flag */
2232 :
2233 13910322 : if (!(e = exp_physical_types(v, rel, e, depth))) /* for decimals and intervals we need to adjust the scale for some operations */
2234 : return NULL;
2235 13910570 : if (!rel->l)
2236 : return e;
2237 :
2238 10287800 : switch(rel->op){
2239 6825110 : case op_select:
2240 : case op_join:
2241 : case op_left:
2242 : case op_right:
2243 : case op_full:
2244 : case op_semi:
2245 : case op_anti:
2246 : case op_project: {
2247 6825110 : switch(e->type) {
2248 502962 : case e_aggr:
2249 : case e_func: {
2250 502962 : e->card = list_empty(e->l)?CARD_MULTI:exps_card(e->l);
2251 502962 : } break;
2252 4523569 : case e_column: {
2253 4523569 : sql_exp *le = NULL, *re = NULL;
2254 4523569 : bool underjoinl = false, underjoinr = false;
2255 :
2256 4523569 : le = rel_find_exp_and_corresponding_rel(rel->l, e, false, NULL, &underjoinl);
2257 4523572 : if (!is_simple_project(rel->op) && !is_inter(rel->op) && !is_except(rel->op) && !is_semi(rel->op) && rel->r) {
2258 547667 : re = rel_find_exp_and_corresponding_rel(rel->r, e, false, NULL, &underjoinr);
2259 : /* if the expression is found under a join, the cardinality expands to multi */
2260 547667 : e->card = MAX(le?underjoinl?CARD_MULTI:le->card:CARD_ATOM, re?underjoinr?CARD_MULTI:re->card:CARD_ATOM);
2261 3975905 : } else if (e->card == CARD_ATOM) { /* unnested columns vs atoms */
2262 197352 : e->card = le?underjoinl?CARD_MULTI:le->card:CARD_ATOM;
2263 : } else { /* general case */
2264 3778553 : e->card = (le && !underjoinl)?le->card:CARD_MULTI;
2265 : }
2266 4523572 : } break;
2267 300399 : case e_convert: {
2268 300399 : e->card = exp_card(e->l);
2269 300399 : } break;
2270 582335 : case e_cmp: {
2271 582335 : if (e->flag == cmp_or || e->flag == cmp_filter) {
2272 22349 : e->card = MAX(exps_card(e->l), exps_card(e->r));
2273 559986 : } else if (e->flag == cmp_in || e->flag == cmp_notin) {
2274 36900 : e->card = MAX(exp_card(e->l), exps_card(e->r));
2275 : } else {
2276 523086 : e->card = MAX(exp_card(e->l), exp_card(e->r));
2277 523086 : if (e->f)
2278 4324 : e->card = MAX(e->card, exp_card(e->f));
2279 : }
2280 : } break;
2281 : case e_atom:
2282 : case e_psm:
2283 : break;
2284 : }
2285 : } break;
2286 257393 : case op_inter:
2287 : case op_except:
2288 : case op_union: {
2289 257393 : e->card = CARD_MULTI;
2290 257393 : } break;
2291 122345 : case op_groupby: {
2292 122345 : switch(e->type) {
2293 37604 : case e_aggr:
2294 37604 : e->card = rel->card;
2295 37604 : break;
2296 77379 : case e_column: {
2297 77379 : if (e->card == CARD_ATOM) { /* unnested columns vs atoms */
2298 4090 : sql_exp *le = rel_find_exp(rel->l, e);
2299 : /* if it's from the left relation, it's either a constant or column, so set to min between le->card and aggr */
2300 4090 : e->card = le?MIN(le->card, CARD_AGGR):CARD_ATOM;
2301 : } else {
2302 73289 : e->card = rel->card;
2303 : }
2304 : } break;
2305 : default:
2306 : break;
2307 : }
2308 : } break;
2309 : default:
2310 : break;
2311 : }
2312 10287803 : if (is_simple_project(rel->op) && need_distinct(rel)) /* Need distinct, all expressions should have CARD_AGGR at max */
2313 56359 : e->card = MIN(e->card, CARD_AGGR);
2314 10287803 : if (!is_set(rel->op) && (!is_groupby(rel->op) || !list_empty(rel->r))) /* global groupings have atomic cardinality */
2315 10007793 : rel->card = MAX(e->card, rel->card); /* the relation cardinality may get updated too */
2316 : return e;
2317 : }
2318 :
2319 : static sql_exp *
2320 158 : exp_set_type(sql_allocator *sa, sql_exp *te, sql_exp *e)
2321 : {
2322 158 : if (te->type == e_convert) {
2323 14 : if (e->type == e_column) {
2324 14 : return exp_convert(sa, e, exp_subtype(e), exp_subtype(te));
2325 : } else {
2326 0 : e->tpe = *exp_subtype(te);
2327 0 : if (e->l)
2328 0 : e->l = atom_set_type(sa, e->l, &e->tpe);
2329 : }
2330 : }
2331 : return e;
2332 : }
2333 :
2334 : static sql_rel *
2335 2907613 : rel_set_type(visitor *v, sql_rel *rel)
2336 : {
2337 2907613 : if (is_project(rel->op) && rel->l) {
2338 905153 : if (is_set(rel->op)) {
2339 84440 : sql_rel *l = rel->l, *r = rel->r;
2340 84440 : list *exps = l->exps;
2341 168880 : while(exps) {
2342 691164 : for(node *n = exps->h, *m = rel->exps->h; n && m; n = n->next, m = m->next) {
2343 522284 : sql_exp *e = n->data;
2344 522284 : sql_subtype *t = exp_subtype(e);
2345 :
2346 522284 : if (t && !t->type->localtype)
2347 158 : n->data = exp_set_type(v->sql->sa, m->data, e);
2348 : }
2349 168880 : if (exps != r->exps)
2350 : exps = r->exps;
2351 : else
2352 : exps = NULL;
2353 : }
2354 820713 : } else if ((is_simple_project(rel->op) || is_groupby(rel->op)) && rel->l) {
2355 820714 : list *exps = rel->exps;
2356 859451 : while(exps) {
2357 4589022 : for(node *n = exps->h; n; n = n->next) {
2358 3752158 : sql_exp *te = n->data;
2359 3752158 : if (te->type == e_convert) {
2360 70273 : sql_exp *l = te->l;
2361 70273 : if (l->type == e_column) {
2362 46738 : sql_rel *sl = rel->l;
2363 46738 : sql_exp *e = rel_find_exp(sl, l);
2364 46740 : if (is_groupby(sl->op) && exp_equal(e, l) == 0) {
2365 821 : sql_exp *e2 = list_find_exp(sl->r, l);
2366 821 : if (e2) {
2367 46740 : e = e2;
2368 : }
2369 : }
2370 46740 : sql_subtype *t = exp_subtype(e);
2371 :
2372 46740 : if (t && !t->type->localtype) {
2373 247 : if (e && e->type == e_column) {
2374 13 : sql_rel *l = rel->l;
2375 13 : if (is_project(l->op)) {
2376 31 : for(node *n = l->exps->h; n; n = n->next) {
2377 31 : if (n->data == e) {
2378 13 : n->data = exp_convert(v->sql->sa, e, t, exp_subtype(te));
2379 13 : break;
2380 : }
2381 : }
2382 : }
2383 : } else {
2384 234 : e->tpe = *exp_subtype(te);
2385 234 : if (e->l && e->type == e_atom)
2386 229 : e->l = atom_set_type(v->sql->sa, e->l, &e->tpe);
2387 : }
2388 : }
2389 : }
2390 3681885 : } else if (te->type == e_atom && !te->f) {
2391 158730 : sql_subtype *t = exp_subtype(te);
2392 158732 : if (t && !t->type->localtype) {
2393 137 : te->tpe = *sql_bind_localtype("bte");
2394 137 : if (te->l)
2395 137 : te->l = atom_set_type(v->sql->sa, te->l, &te->tpe);
2396 8 : } else if (!t && !te->l && !te->r) { /* parameter, set type, or return ERR?? */
2397 8 : sql_arg *a = sql_bind_paramnr(v->sql, te->flag);
2398 8 : if (!a->type.type)
2399 8 : return sql_error(v->sql, 10, SQLSTATE(42000) "Could not determine type for argument number %d", te->flag+1);
2400 0 : te->tpe = a->type;
2401 : }
2402 : }
2403 : }
2404 836864 : if (is_groupby(rel->op) && exps != rel->r)
2405 : exps = rel->r;
2406 : else
2407 : exps = NULL;
2408 : }
2409 : }
2410 : }
2411 : return rel;
2412 : }
2413 :
2414 : static list*
2415 2984 : aggrs_split_args(mvc *sql, list *aggrs, list *exps, int is_groupby_list)
2416 : {
2417 2984 : bool clear_hash = false;
2418 :
2419 2984 : if (list_empty(aggrs))
2420 : return aggrs;
2421 13210 : for (node *n=aggrs->h; n; n = n->next) {
2422 10711 : sql_exp *a = n->data;
2423 :
2424 10711 : if (is_func(a->type) && !is_groupby_list)
2425 9 : continue;
2426 10702 : if (!is_aggr(a->type)) {
2427 7160 : sql_exp *e1 = a, *found = NULL;
2428 :
2429 24958 : for (node *nn = exps->h; nn && !found; nn = nn->next) {
2430 17798 : sql_exp *e2 = nn->data;
2431 :
2432 17798 : if (!exp_equal(e1, e2))
2433 3566 : found = e2;
2434 : }
2435 7160 : if (!found) {
2436 3594 : if (!exp_name(e1))
2437 0 : e1 = exp_label(sql->sa, e1, ++sql->label);
2438 3594 : append(exps, e1);
2439 : } else {
2440 : e1 = found;
2441 : }
2442 7160 : e1 = exp_ref(sql, e1);
2443 7160 : n->data = e1; /* replace by reference */
2444 7160 : clear_hash = true;
2445 7160 : continue;
2446 : }
2447 3542 : list *args = a->l;
2448 :
2449 3542 : if (!list_empty(args)) {
2450 7465 : for (node *an = args->h; an; an = an->next) {
2451 4234 : sql_exp *e1 = an->data, *found = NULL, *eo = e1;
2452 : /* we keep converts as they reuse names of inner columns */
2453 4234 : int convert = is_convert(e1->type);
2454 :
2455 4234 : if (convert)
2456 113 : e1 = e1->l;
2457 24312 : for (node *nn = exps->h; nn && !found; nn = nn->next) {
2458 20078 : sql_exp *e2 = nn->data;
2459 :
2460 20078 : if (!exp_equal(e1, e2))
2461 88 : found = e2;
2462 : }
2463 4234 : if (!found) {
2464 4146 : if (!exp_name(e1))
2465 3683 : e1 = exp_label(sql->sa, e1, ++sql->label);
2466 4146 : append(exps, e1);
2467 : } else {
2468 : e1 = found;
2469 : }
2470 4234 : e1 = exp_ref(sql, e1);
2471 : /* replace by reference */
2472 4234 : if (convert) {
2473 113 : eo->l = e1;
2474 : } else {
2475 4121 : an->data = e1;
2476 4121 : clear_hash = true;
2477 : }
2478 : }
2479 : }
2480 : }
2481 2499 : if (clear_hash)
2482 2450 : list_hash_clear(aggrs);
2483 : return aggrs;
2484 : }
2485 :
2486 : /* make sure e_func expressions don't appear on groupby expression lists */
2487 : static sql_rel *
2488 1492 : aggrs_split_funcs(mvc *sql, sql_rel *rel)
2489 : {
2490 1492 : if (!list_empty(rel->exps)) {
2491 1492 : list *projs = NULL;
2492 8623 : for (node *n = rel->exps->h; n;) {
2493 7131 : node *next = n->next;
2494 7131 : sql_exp *e = n->data;
2495 :
2496 7131 : if (e->type == e_func || exps_find_exp(projs, e)) {
2497 9 : if (!projs)
2498 9 : projs = sa_list(sql->sa);
2499 9 : list_append(projs, e);
2500 9 : list_remove_node(rel->exps, NULL, n);
2501 : }
2502 : n = next;
2503 : }
2504 1492 : if (!list_empty(projs)) {
2505 : /* the grouping relation may have more than 1 reference, a replacement is needed */
2506 9 : sql_rel *l = rel_dup_copy(sql->sa, rel);
2507 9 : list *nexps = list_merge(rel_projections(sql, l, NULL, 1, 1), projs, NULL);
2508 9 : rel = rel_inplace_project(sql->sa, rel, l, nexps);
2509 9 : rel->card = exps_card(nexps);
2510 : }
2511 : }
2512 1492 : return rel;
2513 : }
2514 :
2515 : static int
2516 63073 : exps_complex(list *exps)
2517 : {
2518 63073 : if (list_empty(exps))
2519 : return 0;
2520 48946 : for(node *n = exps->h; n; n = n->next) {
2521 28506 : sql_exp *e = n->data;
2522 :
2523 28506 : if (e->type != e_column && e->type != e_atom)
2524 : return 1;
2525 : }
2526 : return 0;
2527 : }
2528 :
2529 : static int
2530 29503 : aggrs_complex(list *exps)
2531 : {
2532 29503 : if (list_empty(exps))
2533 : return 0;
2534 72616 : for(node *n = exps->h; n; n = n->next) {
2535 44476 : sql_exp *e = n->data;
2536 :
2537 44476 : if (e->type == e_func || (e->type == e_aggr && exps_complex(e->l)))
2538 1363 : return 1;
2539 : }
2540 : return 0;
2541 : }
2542 :
2543 : /* simplify aggregates, ie push functions under the groupby relation */
2544 : /* rel visitor */
2545 : static inline sql_rel *
2546 2238265 : rewrite_aggregates(visitor *v, sql_rel *rel)
2547 : {
2548 2238265 : if (is_groupby(rel->op) && (exps_complex(rel->r) || aggrs_complex(rel->exps))) {
2549 1492 : list *exps = sa_list(v->sql->sa);
2550 :
2551 1492 : rel->r = aggrs_split_args(v->sql, rel->r, exps, 1);
2552 1492 : rel->exps = aggrs_split_args(v->sql, rel->exps, exps, 0);
2553 1492 : rel->l = rel_project(v->sql->sa, rel->l, exps);
2554 1492 : rel = aggrs_split_funcs(v->sql, rel);
2555 1492 : v->changes++;
2556 1492 : return rel;
2557 : }
2558 : return rel;
2559 : }
2560 :
2561 : static inline sql_rel *
2562 2238272 : rewrite_split_select_exps(visitor *v, sql_rel *rel)
2563 : {
2564 2238272 : if (is_select(rel->op) && !list_empty(rel->exps)) {
2565 156225 : int i = 0;
2566 156225 : bool has_complex_exps = false, has_simple_exps = false, *complex_exps = SA_NEW_ARRAY(v->sql->ta, bool, list_length(rel->exps));
2567 :
2568 334486 : for (node *n = rel->exps->h ; n ; n = n->next) {
2569 178261 : sql_exp *e = n->data;
2570 :
2571 178261 : if (exp_has_rel(e) || exp_has_freevar(v->sql, e)) {
2572 15927 : complex_exps[i] = true;
2573 15927 : has_complex_exps = true;
2574 : } else {
2575 162334 : complex_exps[i] = false;
2576 162334 : has_simple_exps = true;
2577 : }
2578 178261 : i++;
2579 : }
2580 :
2581 156225 : if (has_complex_exps && has_simple_exps) {
2582 4497 : sql_rel *nsel = rel_select_copy(v->sql->sa, rel->l, NULL);
2583 4497 : rel->l = nsel;
2584 :
2585 4497 : i = 0;
2586 14521 : for (node *n = rel->exps->h ; n ; ) {
2587 10024 : node *nxt = n->next;
2588 :
2589 10024 : if (!complex_exps[i]) {
2590 5349 : rel_select_add_exp(v->sql->sa, nsel, n->data);
2591 5349 : list_remove_node(rel->exps, NULL, n);
2592 : }
2593 10024 : n = nxt;
2594 10024 : i++;
2595 : }
2596 4497 : set_processed(nsel);
2597 4497 : v->changes++;
2598 : }
2599 : }
2600 2238272 : return rel;
2601 : }
2602 :
2603 : static void /* replace diff arguments to avoid duplicate work. The arguments must be iterated in this order! */
2604 17941 : diff_replace_arguments(mvc *sql, sql_exp *e, list *ordering, int *pos, int *i)
2605 : {
2606 17941 : if (e->type == e_func && !strcmp(((sql_subfunc*)e->f)->func->base.name, "diff")) {
2607 5485 : list *args = (list*)e->l;
2608 5485 : sql_exp *first = args->h->data, *second = list_length(args) == 2 ? args->h->next->data : NULL;
2609 :
2610 5485 : if (first->type == e_func && !strcmp(((sql_subfunc*)first->f)->func->base.name, "diff")) {
2611 76 : diff_replace_arguments(sql, first, ordering, pos, i);
2612 : } else {
2613 5409 : sql_exp *ne = args->h->data = exp_ref(sql, list_fetch(ordering, pos[*i]));
2614 5409 : set_descending(ne);
2615 5409 : set_nulls_first(ne);
2616 5409 : *i = *i + 1;
2617 : }
2618 5485 : if (second && second->type == e_func && !strcmp(((sql_subfunc*)second->f)->func->base.name, "diff")) {
2619 : diff_replace_arguments(sql, second, ordering, pos, i);
2620 : } else if (second) {
2621 76 : sql_exp *ne = args->h->next->data = exp_ref(sql, list_fetch(ordering, pos[*i]));
2622 76 : set_descending(ne);
2623 76 : set_nulls_first(ne);
2624 76 : *i = *i + 1;
2625 : }
2626 : }
2627 17941 : }
2628 :
2629 : /* exp visitor */
2630 : static inline sql_exp *
2631 9486676 : rewrite_rank(visitor *v, sql_rel *rel, sql_exp *e, int depth)
2632 : {
2633 9486676 : sql_rel *rell = NULL;
2634 :
2635 9486676 : if (!is_simple_project(rel->op) || e->type != e_func || list_length(e->r) < 2 /* e->r means window function */)
2636 9479014 : return e;
2637 :
2638 7662 : (void)depth;
2639 : /* ranks/window functions only exist in the projection */
2640 7662 : list *l = e->l, *r = e->r, *gbe = r->h->data, *obe = r->h->next->data;
2641 7662 : e->card = (rel->card == CARD_AGGR) ? CARD_AGGR : CARD_MULTI; /* After the unnesting, the cardinality of the window function becomes larger */
2642 :
2643 7662 : int needed = (gbe || obe);
2644 7662 : if (l)
2645 22229 : for (node *n = l->h; n && !needed; n = n->next) {
2646 14567 : sql_exp *e = n->data;
2647 14567 : needed = e->ref;
2648 : }
2649 :
2650 7662 : if (needed) {
2651 3143 : rell = rel->l = rel_project(v->sql->sa, rel->l, rel_projections(v->sql, rel->l, NULL, 1, 1));
2652 21966 : for (node *n = l->h; n; n = n->next) {
2653 18823 : sql_exp *e = n->data;
2654 :
2655 18823 : if (e->ref) {
2656 1271 : e->ref = 0;
2657 1271 : append(rell->exps, e);
2658 1271 : n->data = exp_ref(v->sql, e);
2659 : }
2660 : }
2661 : }
2662 :
2663 : /* The following array remembers the original positions of gbe and obe expressions to replace them in order later at diff_replace_arguments */
2664 7662 : if (gbe || obe) {
2665 3081 : int gbeoffset = list_length(gbe), i = 0, added = 0;
2666 3081 : int *pos = SA_NEW_ARRAY(v->sql->ta, int, gbeoffset + list_length(obe));
2667 3081 : if (gbe)
2668 5019 : for (i = 0 ; i < gbeoffset ; i++)
2669 2525 : pos[i] = i;
2670 :
2671 3081 : if (gbe && obe) {
2672 2328 : gbe = list_merge(sa_list(v->sql->sa), gbe, (fdup)NULL); /* make sure the p->r is a different list than the gbe list */
2673 2328 : i = 0;
2674 4678 : for(node *n = obe->h ; n ; n = n->next, i++) {
2675 2350 : sql_exp *e1 = n->data;
2676 2350 : bool found = false;
2677 2350 : int j = 0;
2678 :
2679 4436 : for(node *nn = gbe->h ; nn ; nn = nn->next, j++) {
2680 2409 : sql_exp *e2 = nn->data;
2681 : /* the partition expression order should be the same as the one in the order by clause (if it's in there as well) */
2682 2409 : if (exp_match(e1, e2)) {
2683 323 : if (is_ascending(e1))
2684 221 : set_ascending(e2);
2685 : else
2686 102 : set_descending(e2);
2687 323 : if (nulls_last(e1))
2688 102 : set_nulls_last(e2);
2689 : else
2690 221 : set_nulls_first(e2);
2691 323 : found = true;
2692 323 : break;
2693 : }
2694 : }
2695 2350 : if (!found) {
2696 2027 : pos[gbeoffset + i] = gbeoffset + added;
2697 2027 : added++;
2698 2027 : append(gbe, e1);
2699 : } else {
2700 323 : pos[gbeoffset + i] = j;
2701 : }
2702 : }
2703 753 : } else if (obe) {
2704 587 : assert(!gbe);
2705 587 : i = 0;
2706 1197 : for(node *n = obe->h ; n ; n = n->next, i++) {
2707 610 : sql_exp *oe = n->data;
2708 610 : if (!exps_find_exp(rell->exps, oe)) {
2709 22 : sql_exp *ne = exp_ref(v->sql, oe);
2710 :
2711 22 : if (is_ascending(oe))
2712 20 : set_ascending(ne);
2713 22 : if (nulls_last(oe))
2714 4 : set_nulls_last(ne);
2715 : /* disable sorting info (ie back to defaults) */
2716 22 : set_descending(oe);
2717 22 : set_nulls_first(oe);
2718 22 : n->data = ne;
2719 22 : append(rell->exps, oe);
2720 : }
2721 610 : pos[i] = i;
2722 : }
2723 : gbe = obe;
2724 : }
2725 :
2726 3081 : list *ordering = sa_list(v->sql->sa); /* add exps from gbe and obe as ordering expressions */
2727 8243 : for(node *n = gbe->h ; n ; n = n->next) {
2728 5162 : sql_exp *next = n->data;
2729 5162 : sql_exp *found = exps_find_exp(rell->exps, next);
2730 5235 : sql_exp *ref = exp_ref(v->sql, found ? found : next);
2731 :
2732 5162 : if (is_ascending(next))
2733 4188 : set_ascending(ref);
2734 5162 : if (nulls_last(next))
2735 979 : set_nulls_last(ref);
2736 5162 : set_descending(next);
2737 5162 : set_nulls_first(next);
2738 5162 : if (!found)
2739 73 : list_append(rell->exps, next);
2740 5162 : list_append(ordering, ref);
2741 : }
2742 3081 : rell = rel_project(v->sql->sa, rell, rel_projections(v->sql, rell, NULL, 1, 1));
2743 3081 : rell->r = ordering;
2744 3081 : rel->l = rell;
2745 :
2746 : /* remove obe argument, so this function won't be called again on this expression */
2747 3081 : list_remove_node(r, NULL, r->t);
2748 :
2749 : /* add project with rank */
2750 3081 : rell = rel->l = rel_project(v->sql->sa, rel->l, rel_projections(v->sql, rell->l, NULL, 1, 1));
2751 3081 : i = 0;
2752 :
2753 21520 : for (node *n = l->h; n ; n = n->next) { /* replace the updated arguments */
2754 18439 : sql_exp *e = n->data;
2755 :
2756 18439 : if (e->type == e_func && !strcmp(((sql_subfunc*)e->f)->func->base.name, "window_bound"))
2757 574 : continue;
2758 17865 : diff_replace_arguments(v->sql, e, ordering, pos, &i);
2759 : }
2760 :
2761 3081 : sql_exp *b1 = (sql_exp*) list_fetch(l, list_length(l) - 2); /* the 'window_bound' calls are added after the function arguments and frame type */
2762 3081 : sql_exp *b2 = (sql_exp*) list_fetch(l, list_length(l) - 1);
2763 :
2764 3081 : if (b1 && b1->type == e_func && !strcmp(((sql_subfunc*)b1->f)->func->base.name, "window_bound")) {
2765 287 : list *ll = b1->l;
2766 287 : rell = rel->l = rel_project(v->sql->sa, rell, rel_projections(v->sql, rell, NULL, 1, 1));
2767 :
2768 287 : int pe_pos = list_length(l) - 5; /* append the new partition expression to the list of expressions */
2769 287 : sql_exp *pe = (sql_exp*) list_fetch(l, pe_pos);
2770 287 : list_append(rell->exps, pe);
2771 :
2772 287 : if (list_length(ll) == 6) { /* update partition definition for window function input if that's the case */
2773 186 : ((list*)b1->l)->h->data = exp_ref(v->sql, pe);
2774 186 : ((list*)b2->l)->h->data = exp_ref(v->sql, pe);
2775 : }
2776 287 : i = 0; /* the partition may get a new reference, update it on the window function list of arguments as well */
2777 686 : for (node *n = l->h; n ; n = n->next, i++) {
2778 686 : if (i == pe_pos) {
2779 287 : n->data = exp_ref(v->sql, pe);
2780 287 : break;
2781 : }
2782 : }
2783 :
2784 287 : sql_exp *frame_type = (sql_exp*) list_fetch(l, list_length(l) - 3);
2785 287 : atom *a = frame_type->l;
2786 287 : int nr = (int)atom_get_int(a);
2787 :
2788 287 : if (nr == FRAME_RANGE && obe) { /* for range we pass the last order by column (otherwise it's either invalid or is a special case)*/
2789 112 : int oe_pos = list_length(ll) - 5;
2790 112 : sql_exp *oe = (sql_exp*) list_fetch(ll, oe_pos);
2791 112 : if (oe->type != e_column && oe->type != e_atom) {
2792 4 : sql_exp *common = list_fetch(ordering, pos[gbeoffset + list_length(obe) - 1]);
2793 :
2794 4 : if (list_length(ll) == 5) {
2795 2 : ((list*)b1->l)->h->data = exp_ref(v->sql, common);
2796 2 : ((list*)b2->l)->h->data = exp_ref(v->sql, common);
2797 : } else {
2798 2 : ((list*)b1->l)->h->next->data = exp_ref(v->sql, common);
2799 2 : ((list*)b2->l)->h->next->data = exp_ref(v->sql, common);
2800 : }
2801 : }
2802 175 : } else if (nr == FRAME_ROWS || nr == FRAME_GROUPS) {
2803 161 : int oe_pos = list_length(l) - 4; /* for groups and rows, we push the ordering diff call, reference it back */
2804 : /* now this is the tricky, part, the ordering expression, may be a column, or any projection, only the later requires the push down */
2805 161 : sql_exp *oe = (sql_exp*) list_fetch(l, oe_pos);
2806 161 : if (oe->type != e_column && oe->type != e_atom) {
2807 152 : list_append(rell->exps, oe);
2808 :
2809 152 : if (list_length(ll) == 5) {
2810 38 : ((list*)b1->l)->h->data = exp_ref(v->sql, oe);
2811 38 : ((list*)b2->l)->h->data = exp_ref(v->sql, oe);
2812 : } else {
2813 114 : ((list*)b1->l)->h->next->data = exp_ref(v->sql, oe);
2814 114 : ((list*)b2->l)->h->next->data = exp_ref(v->sql, oe);
2815 : }
2816 : }
2817 : }
2818 : }
2819 :
2820 : /* move rank down add ref */
2821 3081 : if (!exp_name(e))
2822 1259 : e = exp_label(v->sql->sa, e, ++v->sql->label);
2823 3081 : append(rell->exps, e);
2824 3081 : e = exp_ref(v->sql, e);
2825 3081 : v->changes++;
2826 : } else {
2827 : /* remove obe argument, so this function won't be called again on this expression */
2828 4581 : list_remove_node(r, NULL, r->t);
2829 4581 : v->changes++;
2830 : }
2831 : return e;
2832 : }
2833 :
2834 : static sql_rel *
2835 7157 : rel_union_exps(mvc *sql, sql_exp **l, list *vals, int is_tuple)
2836 : {
2837 7157 : sql_rel *u = NULL;
2838 7157 : list *exps = NULL;
2839 :
2840 7157 : if (mvc_highwater(sql))
2841 0 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
2842 :
2843 14341 : for (node *n=vals->h; n; n = n->next) {
2844 7184 : sql_exp *ve = n->data, *r, *s;
2845 7184 : sql_rel *sq = NULL;
2846 7184 : int freevar = 0;
2847 :
2848 7184 : exp_label(sql->sa, ve, ++sql->label); /* an alias is needed */
2849 7184 : if (exp_has_rel(ve)) {
2850 7139 : sq = exp_rel_get_rel(sql->sa, ve); /* get subquery */
2851 7139 : if (sq)
2852 7139 : freevar = rel_has_freevar(sql,sq);
2853 : } else {
2854 45 : sq = rel_project(sql->sa, NULL, append(sa_list(sql->sa), ve));
2855 45 : if (!exp_is_atom(ve))
2856 15 : freevar = 1;
2857 45 : set_processed(sq);
2858 : }
2859 7184 : if (is_tuple) { /* cast each one */
2860 5727 : for (node *m=sq->exps->h, *o = ((list *)(*l)->f)->h; m && o; m = m->next, o = o->next) {
2861 3979 : r = m->data;
2862 3979 : s = o->data;
2863 3979 : if (rel_convert_types(sql, NULL, NULL, &s, &r, 1, type_equal) < 0)
2864 0 : return NULL;
2865 3979 : m->data = r;
2866 : }
2867 : } else {
2868 5436 : sq->nrcols = list_length(sq->exps);
2869 : /* union a project[(values(a),..,(b),(c)] with freevars */
2870 5436 : if (sq->card > CARD_ATOM && rel_has_freevar(sql, sq) && is_project(sq->op) &&
2871 109 : !sq->l && sq->nrcols == 1 && is_values((sql_exp*)sq->exps->h->data)) {
2872 : /* needs check on projection */
2873 0 : sql_exp *vals = sq->exps->h->data;
2874 0 : if (!(sq = rel_union_exps(sql, l, exp_get_values(vals), is_tuple)))
2875 : return NULL;
2876 : } else {
2877 5436 : if (rel_convert_types(sql, NULL, NULL, l, &ve, 1, type_equal) < 0)
2878 : return NULL;
2879 : /* flatten expressions */
2880 5436 : if (exp_has_rel(ve)) {
2881 5391 : ve = exp_rel_update_exp(sql, ve, false);
2882 5391 : sq = rel_project(sql->sa, sq, append(sa_list(sql->sa), ve));
2883 5391 : set_processed(sq);
2884 : }
2885 5436 : if (freevar)
2886 148 : exp_set_freevar(sql, ve, sq);
2887 : }
2888 : }
2889 7184 : if (!u) {
2890 : u = sq;
2891 : } else {
2892 27 : u = rel_setop(sql->sa, u, sq, op_union);
2893 27 : rel_setop_set_exps(sql, u, exps, false);
2894 27 : set_distinct(u);
2895 27 : set_processed(u);
2896 : }
2897 7184 : exps = rel_projections(sql, sq, NULL, 1/*keep names */, 1);
2898 : }
2899 : return u;
2900 : }
2901 :
2902 : static sql_exp *
2903 10392 : exp_in_project(mvc *sql, sql_exp **l, list *vals, int anyequal)
2904 : {
2905 10392 : sql_exp *e = NULL;
2906 :
2907 66805 : for(node *n=vals->h; n; n = n->next) {
2908 56413 : sql_exp *r = n->data, *ne;
2909 :
2910 56413 : if (rel_convert_types(sql, NULL, NULL, l, &r, 1, type_equal_no_any) < 0)
2911 0 : return NULL;
2912 56413 : if (anyequal)
2913 56213 : ne = rel_binop_(sql, NULL, *l, r, "sys", "=", card_value);
2914 : else
2915 200 : ne = rel_binop_(sql, NULL, *l, r, "sys", "<>", card_value);
2916 56413 : if (!e) {
2917 : e = ne;
2918 46021 : } else if (anyequal) {
2919 45914 : e = rel_binop_(sql, NULL, e, ne, "sys", "or", card_value);
2920 : } else {
2921 107 : e = rel_binop_(sql, NULL, e, ne, "sys", "and", card_value);
2922 : }
2923 : }
2924 : return e;
2925 : }
2926 :
2927 : static sql_exp *
2928 74 : exp_in_compare(mvc *sql, sql_exp **l, list *vals, int anyequal)
2929 : {
2930 74 : int vals_only = 1;
2931 :
2932 241 : for(node *n=vals->h; n; n = n->next) {
2933 167 : sql_exp *r = n->data;
2934 :
2935 167 : if (rel_convert_types(sql, NULL, NULL, l, &r, 1, type_equal_no_any) < 0)
2936 0 : return NULL;
2937 167 : n->data = r;
2938 167 : if (!exp_is_atom(r))
2939 124 : vals_only = 0;
2940 : }
2941 74 : if (vals_only)
2942 5 : return exp_in(sql->sa, *l, vals, anyequal?cmp_in:cmp_notin);
2943 :
2944 71 : if (!(*l = exp_in_project(sql, l, vals, anyequal)))
2945 : return NULL;
2946 71 : return exp_compare(sql->sa, *l, exp_atom_bool(sql->sa, 1), cmp_equal);
2947 : }
2948 :
2949 : /* exp visitor */
2950 : static inline sql_exp *
2951 441222 : rewrite_anyequal(visitor *v, sql_rel *rel, sql_exp *e, int depth)
2952 : {
2953 441222 : assert(e->type == e_func);
2954 :
2955 441222 : sql_subfunc *sf = e->f;
2956 441222 : if (is_ddl(rel->op))
2957 : return e;
2958 340444 : if (is_anyequal_func(sf) && !list_empty(e->l)) {
2959 18163 : list *l = e->l;
2960 18163 : mvc *sql = v->sql;
2961 :
2962 18163 : if (list_length(l) == 2) { /* input is a set */
2963 :
2964 18163 : sql_exp *ile = l->h->data, *le, *re = l->h->next->data;
2965 18163 : sql_rel *lsq = NULL, *rsq = NULL;
2966 18163 : int is_tuple = 0;
2967 :
2968 18163 : if (exp_has_rel(ile))
2969 35 : lsq = exp_rel_get_rel(sql->sa, ile); /* get subquery */
2970 :
2971 35 : if (lsq)
2972 35 : le = exp_rel_update_exp(sql, ile, false);
2973 : else
2974 18128 : le = ile;
2975 :
2976 18163 : if (is_values(le)) /* exp_values */
2977 18163 : is_tuple = 1;
2978 :
2979 : /* re should be a values list */
2980 18163 : if (!lsq && !is_tuple && is_values(re) && !exps_have_rel_exp(re->f)) { /* exp_values */
2981 10395 : list *vals = re->f;
2982 :
2983 10395 : rel_bind_var(sql, rel->l, le);
2984 10395 : rel_bind_vars(sql, rel->l, vals);
2985 10395 : if (depth == 0 && is_select(rel->op)) {
2986 74 : v->changes++;
2987 74 : return exp_in_compare(sql, &le, vals, is_anyequal(sf));
2988 : } else {
2989 10321 : le = exp_in_project(sql, &le, vals, is_anyequal(sf));
2990 10321 : if (le && exp_name(e))
2991 696 : exp_prop_alias(sql->sa, le, e);
2992 10321 : v->changes++;
2993 10321 : return le;
2994 : }
2995 7768 : } else if (!lsq && !exps_have_rel_exp(re->f)) {
2996 : return e; /* leave as is, handled later */
2997 : }
2998 :
2999 7157 : if (is_atom(re->type) && re->f) { /* exp_values */
3000 : /* flatten using unions */
3001 7157 : rsq = rel_union_exps(sql, &le, re->f, is_tuple);
3002 7157 : if (!rsq)
3003 : return NULL;
3004 7157 : if (!is_tuple) {
3005 5411 : re = rsq->exps->t->data;
3006 :
3007 5411 : if (!is_tuple && is_func(re->type))
3008 3 : depth++;
3009 :
3010 5411 : if (rsq && lsq)
3011 34 : exp_set_freevar(sql, re, rsq);
3012 5411 : if (!is_tuple && !is_freevar(re)) {
3013 5409 : re = exp_label(sql->sa, re, ++sql->label); /* unique name */
3014 5409 : list_hash_clear(rsq->exps);
3015 5409 : re = exp_ref(sql, re);
3016 2 : } else if (has_label(re)) {
3017 2 : re = exp_ref(sql, re);
3018 : }
3019 : }
3020 7157 : set_processed(rsq);
3021 : }
3022 :
3023 7157 : if (is_project(rel->op) || ((is_select(rel->op) || is_outerjoin(rel->op)) && depth > 0)) {
3024 : /* we introduced extra selects */
3025 2553 : assert(is_project(rel->op) || is_select(rel->op) || is_outerjoin(rel->op));
3026 :
3027 2553 : sql_rel *join = NULL;
3028 2553 : if (lsq) {
3029 25 : sql_rel *rewrite = NULL;
3030 25 : (void)rewrite_inner(sql, rel, lsq, op_left, &rewrite);
3031 25 : exp_reset_props(rewrite, le, is_left(rewrite->op));
3032 25 : join = (is_full(rel->op)||is_left(rel->op))?rel->r:rel->l;
3033 : }
3034 2553 : if (rsq) {
3035 2553 : (void)rewrite_inner(sql, rel, rsq, op_left, &join);
3036 2553 : exp_reset_props(join, re, is_left(join->op));
3037 : }
3038 2553 : assert(join && is_join(join->op));
3039 2553 : if (join && !join->exps)
3040 2553 : join->exps = sa_list(sql->sa);
3041 2553 : bool use_any = 0;
3042 2553 : if (is_tuple) {
3043 5 : list *t = le->f;
3044 5 : int s1 = list_length(t), s2 = rsq?list_length(rsq->exps):0;
3045 :
3046 : /* find out list of right expression */
3047 5 : if (s1 != s2)
3048 0 : return sql_error(sql, 02, SQLSTATE(42000) "Subquery has too %s columns", (s2 < s1) ? "few" : "many");
3049 15 : for (node *n = t->h, *m = rsq->exps->h; n && m; n = n->next, m = m->next ) {
3050 10 : sql_exp *le = n->data;
3051 10 : sql_exp *re = m->data;
3052 :
3053 10 : re = exp_ref(sql, re);
3054 :
3055 10 : sql_exp *inexp = exp_compare(v->sql->sa, le, re, cmp_equal);
3056 10 : if (inexp)
3057 10 : set_any(inexp);
3058 10 : append(join->exps, inexp);
3059 : }
3060 5 : return sql_error(sql, 02, SQLSTATE(42000) "Tuple matching at projections not implemented in the backend yet");
3061 : } else {
3062 2548 : use_any = true;
3063 2548 : sql_exp *inexp = exp_compare(v->sql->sa, le, re, cmp_equal);
3064 2548 : if (inexp)
3065 2548 : set_any(inexp);
3066 2548 : exp_set_freevar(sql, le, join);
3067 2548 : rel_bind_var(sql, join, inexp);
3068 2548 : append(join->exps, inexp);
3069 2548 : if (exp_has_freevar(v->sql, inexp) && is_join(rel->op))
3070 0 : set_dependent(rel);
3071 : }
3072 2548 : v->changes++;
3073 2548 : if (join) {
3074 2548 : if (!join->attr)
3075 2548 : join->attr = sa_list(sql->sa);
3076 2548 : sql_exp *a = exp_atom_bool(v->sql->sa, !use_any?1:is_anyequal(sf));
3077 2548 : exp_setname(sql->sa, a, exp_relname(e), exp_name(e));
3078 2548 : re = exp_ref(sql, a);
3079 2548 : set_has_nil(re); /* outerjoins could have introduced nils */
3080 2548 : re->card = CARD_MULTI; /* mark as multi value, the real attribute is introduced later */
3081 2548 : append(join->attr, a);
3082 2548 : assert(is_project(rel->op) || depth);
3083 2548 : if ((is_project(rel->op) || depth))
3084 : return re;
3085 : }
3086 0 : set_has_nil(le); /* outer joins could have introduced nils */
3087 0 : set_has_nil(re); /* outer joins could have introduced nils */
3088 0 : return exp_compare(v->sql->sa, le, re, is_anyequal(sf)?cmp_equal:cmp_notequal);
3089 : } else {
3090 4604 : if (lsq) {
3091 10 : sql_rel *rewrite = NULL;
3092 18 : (void)rewrite_inner(sql, rel, lsq, rel->card<=CARD_ATOM?op_left:op_join, &rewrite);
3093 10 : exp_reset_props(rewrite, le, is_left(rewrite->op));
3094 : }
3095 4604 : if (rsq) {
3096 4604 : sql_rel *rewrite = NULL;
3097 4604 : operator_type op = !is_tuple?op_join:is_anyequal(sf)?op_semi:op_anti;
3098 4604 : (void)rewrite_inner(sql, rel, rsq, op, &rewrite);
3099 4604 : exp_reset_props(rewrite, re, is_left(rewrite->op));
3100 : }
3101 4604 : if (is_tuple) {
3102 1741 : list *t = le->f;
3103 1741 : list *l = sa_list(sql->sa);
3104 1741 : list *r = sa_list(sql->sa);
3105 1741 : int s1 = list_length(t), s2 = list_length(rsq->exps);
3106 :
3107 : /* find out list of right expression */
3108 1741 : if (s1 != s2)
3109 0 : return sql_error(sql, 02, SQLSTATE(42000) "Subquery has too %s columns", (s2 < s1) ? "few" : "many");
3110 5706 : for (node *n = t->h, *m = rsq->exps->h; n && m; n = n->next, m = m->next ) {
3111 3965 : sql_exp *le = n->data;
3112 3965 : sql_exp *re = m->data;
3113 :
3114 3965 : append(l, le);
3115 3965 : re = exp_ref(sql, re);
3116 3965 : append(r, re);
3117 : }
3118 1741 : v->changes++;
3119 1741 : return exp_in_func(sql, exp_values(sql->sa, l), exp_values(sql->sa, r), is_anyequal(sf), 1);
3120 : } else {
3121 2863 : if (exp_has_freevar(sql, le))
3122 1 : rel_bind_var(sql, rel, le);
3123 2863 : v->changes++;
3124 2863 : return exp_in_func(sql, le, re, is_anyequal(sf), 0);
3125 : }
3126 : }
3127 : }
3128 : }
3129 : return e;
3130 : }
3131 :
3132 : /* exp visitor */
3133 : /* rewrite compare expressions including quantifiers any and all */
3134 : static inline sql_exp *
3135 422310 : rewrite_compare(visitor *v, sql_rel *rel, sql_exp *e, int depth)
3136 : {
3137 422310 : assert(e->type == e_func);
3138 :
3139 422310 : if (is_ddl(rel->op))
3140 : return e;
3141 :
3142 321536 : sql_subfunc *sf = e->f;
3143 321536 : if (is_compare_func(sf) && !list_empty(e->l)) {
3144 36825 : list *l = e->l;
3145 :
3146 : /* TODO handle range expressions */
3147 36825 : if (list_length(l) == 2) { /* input is a set */
3148 36825 : char *op = sf->func->base.name;
3149 :
3150 36825 : sql_exp *ile = l->h->data, *le, *re = l->h->next->data, *rnull = NULL;
3151 36825 : sql_rel *lsq = NULL, *rsq = NULL;
3152 36825 : int is_tuple = 0; /* TODO add this feature, ie select (1,2) = (1,2) etc */
3153 : /* cleanup tuple handling by introducing an expression for tuples */
3154 36825 : int quantifier = e->flag;
3155 :
3156 : /* possibly this is already done ? */
3157 36825 : if (exp_has_rel(ile)) {
3158 47 : depth += exp_rel_depth(ile);
3159 47 : lsq = exp_rel_get_rel(v->sql->sa, ile); /* get subquery */
3160 : }
3161 :
3162 47 : if (lsq)
3163 47 : le = exp_rel_update_exp(v->sql, ile, false);
3164 : else
3165 36778 : le = ile;
3166 :
3167 36825 : if (exp_has_rel(re))
3168 4167 : rsq = exp_rel_get_rel(v->sql->sa, re); /* get subquery */
3169 4167 : if (rsq) {
3170 4167 : if (!lsq && is_simple_project(rsq->op) && !rsq->l) {
3171 11 : sql_exp *ire = rsq->exps->h->data;
3172 11 : if (is_values(ire) && list_length(ire->f) == 1 && !is_values(le)) {
3173 0 : list *exps = ire->f;
3174 0 : re = exps->h->data;
3175 0 : rsq = exp_rel_get_rel(v->sql->sa, re);
3176 : }
3177 : }
3178 24 : if (rsq)
3179 4167 : re = exp_rel_update_exp(v->sql, re, false);
3180 : }
3181 :
3182 36825 : if (is_values(le)) /* exp_values */
3183 36825 : is_tuple = 1;
3184 :
3185 36825 : if (!is_tuple && !lsq && !rsq) { /* trivial case, just re-write into a comparison */
3186 32630 : e->flag = 0; /* remove quantifier */
3187 :
3188 32630 : if (rel_convert_types(v->sql, NULL, NULL, &le, &re, 1, type_equal) < 0)
3189 : return NULL;
3190 32630 : if (depth == 0 && is_select(rel->op)) {
3191 0 : v->changes++;
3192 0 : return exp_compare(v->sql->sa, le, re, compare_str2type(op));
3193 : } else {
3194 : return e;
3195 : /*
3196 : le = exp_compare_func(v->sql, le, re, op, 0);
3197 : if (exp_name(e))
3198 : exp_prop_alias(v->sql->sa, le, e);
3199 : v->changes++;
3200 : return le;
3201 : */
3202 : }
3203 : }
3204 4195 : if (!is_tuple && is_values(re) && !exps_have_rel_exp(re->f)) { /* exp_values */
3205 0 : list *vals = re->f;
3206 :
3207 0 : if (depth == 0 && is_select(rel->op)) {
3208 0 : v->changes++;
3209 0 : return exp_in_compare(v->sql, &le, vals, is_anyequal(sf));
3210 : } else {
3211 0 : le = exp_in_project(v->sql, &le, vals, is_anyequal(sf));
3212 0 : if (le && exp_name(e))
3213 0 : exp_prop_alias(v->sql->sa, le, e);
3214 0 : v->changes++;
3215 0 : return le;
3216 : }
3217 : }
3218 :
3219 4195 : if (is_values(re)) { /* exp_values */
3220 : /* flatten using unions */
3221 0 : rsq = rel_union_exps(v->sql, &le, re->f, is_tuple);
3222 0 : if (!rsq)
3223 : return NULL;
3224 0 : re = rsq->exps->t->data;
3225 :
3226 0 : if (!is_tuple) {
3227 0 : re = exp_label(v->sql->sa, re, ++v->sql->label); /* unique name */
3228 0 : list_hash_clear(rsq->exps);
3229 0 : re = exp_ref(v->sql, re);
3230 : }
3231 0 : set_processed(rsq);
3232 : }
3233 :
3234 4195 : int is_cnt = 0;
3235 4195 : if (rsq)
3236 4167 : is_cnt = exp_is_count(re, rsq);
3237 4195 : if (is_project(rel->op) || depth > 0 || quantifier || is_cnt) {
3238 1226 : sql_rel *sq = lsq;
3239 :
3240 1226 : assert(!is_tuple);
3241 :
3242 1226 : if (!lsq)
3243 1226 : lsq = rel->l;
3244 45 : if (sq) {
3245 45 : sql_rel *rewrite = NULL;
3246 45 : operator_type op = (depth||quantifier)?op_left:op_join;
3247 45 : (void)rewrite_inner(v->sql, rel, sq, op, &rewrite);
3248 45 : exp_reset_props(rewrite, le, is_left(rewrite->op));
3249 45 : rel_bind_var(v->sql, rel, le);
3250 : }
3251 1226 : if (quantifier) {
3252 174 : sql_subfunc *a;
3253 :
3254 174 : rsq = rel_groupby(v->sql, rsq, NULL);
3255 174 : a = sql_bind_func(v->sql, "sys", "null", exp_subtype(re), NULL, F_AGGR, true);
3256 174 : rnull = exp_aggr1(v->sql->sa, re, a, 0, 1, CARD_AGGR, has_nil(re));
3257 174 : rnull = rel_groupby_add_aggr(v->sql, rsq, rnull);
3258 :
3259 174 : if (is_notequal_func(sf))
3260 174 : op = "=";
3261 174 : if (op[0] == '<') {
3262 50 : a = sql_bind_func(v->sql, "sys", (quantifier==1)?"max":"min", exp_subtype(re), NULL, F_AGGR, true);
3263 140 : } else if (op[0] == '>') {
3264 97 : a = sql_bind_func(v->sql, "sys", (quantifier==1)?"min":"max", exp_subtype(re), NULL, F_AGGR, true);
3265 : } else /* (op[0] == '=')*/ /* only = ALL */ {
3266 75 : a = sql_bind_func(v->sql, "sys", "all", exp_subtype(re), NULL, F_AGGR, true);
3267 75 : is_cnt = 1;
3268 : }
3269 174 : re = exp_aggr1(v->sql->sa, re, a, 0, 1, CARD_AGGR, has_nil(re));
3270 174 : re = rel_groupby_add_aggr(v->sql, rsq, re);
3271 174 : set_processed(rsq);
3272 : }
3273 1226 : if (rsq) {
3274 1199 : sql_rel *rewrite = NULL;
3275 1199 : operator_type op = ((!quantifier && depth > 0)||is_cnt||quantifier)?op_left:op_join;
3276 1199 : (void)rewrite_inner(v->sql, rel, rsq, op, &rewrite);
3277 1199 : exp_reset_props(rewrite, re, is_left(rewrite->op));
3278 1199 : rel_bind_var(v->sql, rel, re);
3279 : }
3280 :
3281 1226 : if (rel_convert_types(v->sql, NULL, NULL, &le, &re, 1, type_equal) < 0)
3282 : return NULL;
3283 1226 : if (rnull) { /* complex compare operator */
3284 174 : sql_exp *lnull = rel_unop_(v->sql, rel, le, "sys", "isnull", card_value);
3285 174 : set_has_no_nil(lnull);
3286 174 : le = exp_compare_func(v->sql, le, re, op, 0);
3287 297 : sql_subfunc *f = sql_bind_func3(v->sql, "sys", (quantifier==1)?"any":"all", exp_subtype(le), exp_subtype(lnull), exp_subtype(rnull), F_FUNC, true);
3288 174 : le = exp_op3(v->sql->sa, le, lnull, rnull, f);
3289 174 : if (is_select(rel->op) && depth == 0) {
3290 91 : le = exp_compare(v->sql->sa, le, exp_atom_bool(v->sql->sa, is_notequal_func(sf) ? 0 : 1), cmp_equal);
3291 126 : } else if (is_notequal_func(sf)) {
3292 15 : le = rel_unop_(v->sql, rel, le, "sys", "not", card_value);
3293 : }
3294 1052 : } else if (is_project(rel->op) || depth) {
3295 1043 : le = exp_compare_func(v->sql, le, re, op, 0);
3296 : } else {
3297 9 : v->changes++;
3298 9 : return exp_compare(v->sql->sa, le, re, compare_str2type(op));
3299 : }
3300 1217 : if (exp_name(e))
3301 50 : exp_prop_alias(v->sql->sa, le, e);
3302 1217 : v->changes++;
3303 1217 : return le;
3304 : } else {
3305 2969 : if (lsq) {
3306 2 : sql_rel *rewrite = NULL;
3307 2 : (void)rewrite_inner(v->sql, rel, lsq, op_join, &rewrite);
3308 2 : exp_reset_props(rewrite, le, is_left(rewrite->op));
3309 : }
3310 2969 : if (rsq) {
3311 2968 : sql_rel *rewrite = NULL;
3312 2968 : operator_type op = !is_tuple?op_join:is_anyequal(sf)?op_semi:op_anti;
3313 2968 : (void)rewrite_inner(v->sql, rel, rsq, op, &rewrite);
3314 2968 : exp_reset_props(rewrite, re, is_left(rewrite->op));
3315 : }
3316 2969 : if (is_tuple) {
3317 0 : list *t = le->f;
3318 0 : list *l = sa_list(v->sql->sa);
3319 0 : list *r = sa_list(v->sql->sa);
3320 0 : int s1 = list_length(t), s2 = list_length(rsq->exps); /* subtract identity column */
3321 :
3322 : /* find out list of right expression */
3323 0 : if (s1 != s2)
3324 0 : return sql_error(v->sql, 02, SQLSTATE(42000) "Subquery has too %s columns", (s2 < s1) ? "few" : "many");
3325 0 : for (node *n = t->h, *m = rsq->exps->h; n && m; n = n->next, m = m->next ) {
3326 0 : sql_exp *le = n->data;
3327 0 : sql_exp *re = m->data;
3328 :
3329 0 : append(l, le);
3330 0 : append(r, re);
3331 : }
3332 0 : v->changes++;
3333 0 : return exp_compare(v->sql->sa, exp_values(v->sql->sa, l), exp_values(v->sql->sa, r), compare_str2type(op));
3334 : } else {
3335 2969 : if (exp_has_freevar(v->sql, le))
3336 13 : rel_bind_var(v->sql, rel, le);
3337 2969 : if (rel_convert_types(v->sql, NULL, NULL, &le, &re, 1, type_equal) < 0)
3338 : return NULL;
3339 2969 : v->changes++;
3340 2969 : return exp_compare(v->sql->sa, le, re, compare_str2type(op));
3341 : }
3342 : }
3343 : }
3344 : }
3345 : return e;
3346 : }
3347 :
3348 : static sql_rel *
3349 2286796 : rewrite_join2semi(visitor *v, sql_rel *rel)
3350 : {
3351 2286796 : if (mvc_highwater(v->sql))
3352 0 : return sql_error(v->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
3353 :
3354 2286798 : if (is_select(rel->op) && !list_empty(rel->exps)) {
3355 164102 : sql_rel *j = rel->l, *jl = j->l, *ojl = jl;
3356 164102 : int needed = 0, changed = 0;
3357 :
3358 164102 : if (!j || (!is_join(j->op) && !is_semi(j->op)) || !list_empty(j->exps))
3359 154690 : return rel;
3360 : /* if needed first push select exps down under the join */
3361 19229 : for (node *n = rel->exps->h; n;) {
3362 9817 : node *next = n->next;
3363 9817 : sql_exp *e = n->data;
3364 9817 : sql_subfunc *sf = e->f;
3365 :
3366 9817 : if (is_func(e->type) && is_anyequal_func(sf)) {
3367 4675 : if (exp_card(e) > CARD_ATOM && rel_has_all_exps(jl, e->l)) {
3368 72 : if (!is_select(jl->op) || rel_is_ref(jl))
3369 70 : j->l = jl = rel_select(v->sql->sa, jl, NULL);
3370 72 : rel_select_add_exp(v->sql->sa, jl, e);
3371 72 : list_remove_node(rel->exps, NULL, n);
3372 72 : changed = 1;
3373 72 : v->changes++;
3374 : } else {
3375 : needed = 1;
3376 : }
3377 : }
3378 : n = next;
3379 : }
3380 9412 : if (ojl != jl)
3381 70 : set_processed(jl);
3382 9412 : if (changed && !(j->l = rewrite_join2semi(v, j->l)))
3383 : return NULL;
3384 9412 : if (!needed)
3385 4810 : return try_remove_empty_select(v, rel);
3386 4602 : if (!j->exps)
3387 4602 : j->exps = sa_list(v->sql->sa);
3388 4602 : list *sexps = sa_list(v->sql->sa);
3389 9230 : for (node *n = rel->exps->h; n; ) {
3390 4628 : node *next = n->next;
3391 4628 : sql_exp *e = n->data;
3392 4628 : sql_subfunc *sf = e->f;
3393 :
3394 : /* Any compare expression based only on the left side will be split into a
3395 : * select under the anti join.
3396 : */
3397 4628 : assert((is_func(e->type) && is_anyequal_func(sf)) || e->type == e_cmp);
3398 4628 : if ((is_func(e->type) && is_anyequal_func(sf)) || !rel_rebind_exp(v->sql, j->l, e)) {
3399 4609 : if (e->type == e_cmp) {
3400 6 : append(j->exps, e);
3401 : } else {
3402 4603 : list *args = e->l;
3403 4603 : sql_exp *l, *r;
3404 :
3405 4603 : assert(list_length(args)==2);
3406 4603 : l = args->h->data;
3407 4603 : r = args->h->next->data;
3408 4603 : j->op = (is_anyequal(sf))?op_semi:op_anti;
3409 :
3410 4603 : if (is_values(l)) {
3411 1741 : assert(is_values(r));
3412 1741 : list *ll = l->f, *rl = r->f;
3413 5706 : for(node *n=ll->h, *m=rl->h; n && m; n=n->next, m=m->next) {
3414 3965 : e = exp_compare(v->sql->sa, n->data, m->data, cmp_equal );
3415 3965 : append(j->exps, e);
3416 : }
3417 : } else {
3418 2862 : e = exp_compare(v->sql->sa, l, r, cmp_equal);
3419 2862 : if (e && j->op == op_anti)
3420 1859 : set_semantics(e);
3421 2862 : append(j->exps, e);
3422 : }
3423 : }
3424 4609 : list_remove_node(rel->exps, NULL, n);
3425 19 : } else if (!rel_rebind_exp(v->sql, j->r, e) && j->op == op_anti) {
3426 1 : append(sexps, e);
3427 1 : list_remove_node(rel->exps, NULL, n);
3428 : }
3429 : n = next;
3430 : }
3431 4602 : v->changes++;
3432 4602 : if (list_length(sexps)) {
3433 1 : sql_rel *jl = j->l = rel_select(v->sql->sa, j->l, NULL);
3434 1 : set_processed(jl);
3435 1 : jl->exps = sexps;
3436 : }
3437 4602 : rel = try_remove_empty_select(v, rel);
3438 : }
3439 : return rel;
3440 : }
3441 :
3442 : /* exp visitor */
3443 : static sql_exp *
3444 423670 : rewrite_exists(visitor *v, sql_rel *rel, sql_exp *e, int depth)
3445 : {
3446 423670 : assert(e->type == e_func);
3447 :
3448 423670 : sql_subfunc *sf = e->f;
3449 423670 : if (is_exists_func(sf) && !list_empty(e->l)) {
3450 1360 : list *l = e->l;
3451 :
3452 1360 : if (list_length(l) == 1) { /* exp_values */
3453 1360 : sql_exp *ie = l->h->data, *le;
3454 1360 : sql_rel *sq = NULL;
3455 :
3456 1360 : if (!exp_is_rel(ie)) { /* exists over a constant or a single value */
3457 42 : le = exp_atom_bool(v->sql->sa, is_exists(sf)?1:0);
3458 42 : if (depth == 0 && is_select(rel->op))
3459 0 : le = exp_compare(v->sql->sa, le, exp_atom_bool(v->sql->sa, 1), cmp_equal);
3460 42 : else if (exp_name(e))
3461 4 : exp_prop_alias(v->sql->sa, le, e);
3462 42 : v->changes++;
3463 42 : return le;
3464 : }
3465 :
3466 1318 : sq = exp_rel_get_rel(v->sql->sa, ie); /* get subquery */
3467 : /* number of expressions in set relations must match the children */
3468 1318 : if (!is_project(sq->op) || (is_set(sq->op) && list_length(sq->exps) > 1) || (is_simple_project(sq->op) && !list_empty(sq->r)))
3469 7 : sq = rel_project(v->sql->sa, sq, rel_projections(v->sql, sq, NULL, 1, 1));
3470 7 : if (!sq)
3471 : return NULL;
3472 1318 : le = rel_reduce2one_exp(v->sql, sq);
3473 1318 : le = exp_ref(v->sql, le);
3474 :
3475 1318 : if (depth == 1 && is_ddl(rel->op)) { /* exists is at a ddl statment, it must be inside a relation */
3476 4 : sq = rel_groupby(v->sql, sq, NULL);
3477 4 : sql_subfunc *ea = sql_bind_func(v->sql, "sys", is_exists(sf)?"exist":"not_exist", exp_subtype(le), NULL, F_AGGR, true);
3478 4 : le = rel_groupby_add_aggr(v->sql, sq, exp_aggr1(v->sql->sa, le, ea, 0, 0, CARD_AGGR, 0));
3479 4 : return exp_rel(v->sql, sq);
3480 : }
3481 1314 : if (is_project(rel->op) || depth > 0 || is_outerjoin(rel->op)) {
3482 635 : sql_rel *join = NULL, *rewrite = NULL;
3483 :
3484 635 : (void)rewrite_inner(v->sql, rel, sq, op_left, &rewrite);
3485 635 : exp_reset_props(rewrite, le, is_left(rewrite->op));
3486 635 : join = (is_full(rel->op)||is_left(rel->op))?rel->r:rel->l;
3487 635 : if (!join)
3488 : return NULL;
3489 635 : if (join && !join->exps)
3490 635 : join->exps = sa_list(v->sql->sa);
3491 635 : v->changes++;
3492 635 : if (join) {
3493 635 : if (!join->attr)
3494 635 : join->attr = sa_list(v->sql->sa);
3495 635 : sql_exp *a = exp_atom_bool(v->sql->sa, is_exists(sf));
3496 635 : set_no_nil(a);
3497 635 : exp_setname(v->sql->sa, a, exp_relname(e), exp_name(e));
3498 635 : le = exp_ref(v->sql, a);
3499 635 : le->card = CARD_MULTI; /* mark as multi value, the real attribute is introduced later */
3500 635 : append(join->attr, a);
3501 635 : assert(is_project(rel->op) || depth);
3502 635 : if ((is_project(rel->op) || depth))
3503 : return le;
3504 : }
3505 0 : set_has_nil(le); /* outer joins could have introduced nils */
3506 0 : return le;
3507 : } else { /* rewrite into semi/anti join */
3508 706 : (void)rewrite_inner(v->sql, rel, sq, is_exists(sf)?op_semi:op_anti, NULL);
3509 679 : v->changes++;
3510 679 : return exp_compare(v->sql->sa, exp_atom_bool(v->sql->sa, 1), exp_atom_bool(v->sql->sa, 1), cmp_equal);
3511 : }
3512 : v->changes++;
3513 : return le;
3514 : }
3515 : }
3516 : return e;
3517 : }
3518 :
3519 : /* exp visitor */
3520 : static sql_exp *
3521 11274369 : rewrite_ifthenelse(visitor *v, sql_rel *rel, sql_exp *e, int depth)
3522 : {
3523 11274369 : (void)depth;
3524 : /* for ifthenelse and rank flatten referenced inner expressions */
3525 11274369 : if (e->ref) {
3526 20 : sql_rel *r = rel->l = rel_project(v->sql->sa, rel->l, rel_projections(v->sql, rel->l, NULL, 1, 1));
3527 :
3528 20 : e->ref = 0;
3529 20 : set_processed(r);
3530 20 : append(r->exps, e);
3531 20 : v->changes++;
3532 20 : return exp_ref(v->sql, e);
3533 : }
3534 :
3535 11274349 : sql_subfunc *sf;
3536 11274349 : if (e->type != e_func)
3537 : return e;
3538 :
3539 515754 : sf = e->f;
3540 : /* TODO also handle ifthenelse with more than 3 arguments */
3541 515754 : if (is_case_func(sf) && !list_empty(e->l) && list_length(e->l) == 3 && rel_has_freevar(v->sql, rel)) {
3542 1988 : list *l = e->l;
3543 :
3544 : /* remove unecessary = true expressions under ifthenelse */
3545 7952 : for (node *n = l->h ; n ; n = n->next) {
3546 5964 : sql_exp *e = n->data;
3547 :
3548 5964 : if (e->type == e_cmp && e->flag == cmp_equal && exp_is_true(e) && exp_is_true(e->r))
3549 0 : n->data = e->l;
3550 : }
3551 :
3552 1988 : sql_exp *cond = l->h->data;
3553 1988 : sql_exp *then_exp = l->h->next->data;
3554 1988 : sql_exp *else_exp = l->h->next->next->data;
3555 1988 : sql_exp *not_cond;
3556 :
3557 1988 : if (!exp_has_rel(cond) && (exp_has_rel(then_exp) || exp_has_rel(else_exp))) {
3558 1427 : bool single = false;
3559 : //return sql_error(v->sql, 10, SQLSTATE(42000) "time to rewrite into union\n");
3560 : // union(
3561 : // select(
3562 : // project [then]
3563 : // )[cond]
3564 : // select(
3565 : // project [else]
3566 : // )[not(cond) or cond is null]
3567 : //) [ cols ]
3568 1427 : sql_rel *lsq = NULL, *rsq = NULL, *usq = NULL;
3569 :
3570 1427 : if (exp_has_rel(then_exp)) {
3571 1183 : lsq = exp_rel_get_rel(v->sql->sa, then_exp);
3572 1183 : then_exp = exp_rel_update_exp(v->sql, then_exp, false);
3573 1183 : if (is_single(lsq))
3574 1182 : single = true;
3575 1183 : reset_single(lsq);
3576 : }
3577 1427 : exp_set_freevar(v->sql, then_exp, lsq);
3578 1427 : lsq = rel_project(v->sql->sa, lsq, append(sa_list(v->sql->sa), then_exp));
3579 1427 : exp_set_freevar(v->sql, cond, lsq);
3580 1427 : set_processed(lsq);
3581 1427 : lsq = rel_select(v->sql->sa, lsq, exp_compare(v->sql->sa, cond, exp_atom_bool(v->sql->sa, 1), cmp_equal));
3582 1427 : set_processed(lsq);
3583 1427 : if (exp_has_rel(else_exp)) {
3584 244 : rsq = exp_rel_get_rel(v->sql->sa, else_exp);
3585 244 : else_exp = exp_rel_update_exp(v->sql, else_exp, false);
3586 244 : if (is_single(rsq))
3587 244 : single = true;
3588 244 : reset_single(rsq);
3589 : }
3590 1427 : exp_set_freevar(v->sql, else_exp, rsq);
3591 1427 : rsq = rel_project(v->sql->sa, rsq, append(sa_list(v->sql->sa), else_exp));
3592 1427 : cond = exp_copy(v->sql, cond);
3593 1427 : exp_set_freevar(v->sql, cond, rsq);
3594 1427 : not_cond = exp_compare(v->sql->sa, cond, exp_atom_bool(v->sql->sa, 1), cmp_notequal);
3595 1427 : set_semantics(not_cond); /* also compare nulls */
3596 1427 : set_processed(rsq);
3597 1427 : rsq = rel_select(v->sql->sa, rsq, not_cond);
3598 1427 : set_processed(rsq);
3599 1427 : usq = rel_setop(v->sql->sa, lsq, rsq, op_union);
3600 1427 : rel_setop_set_exps(v->sql, usq, append(sa_list(v->sql->sa), exp_ref(v->sql, e)), false);
3601 1427 : if (single)
3602 1426 : set_single(usq);
3603 1427 : set_processed(usq);
3604 1427 : e = exp_rel(v->sql, usq);
3605 1427 : v->changes++;
3606 : }
3607 : }
3608 : return e;
3609 : }
3610 :
3611 : static list *
3612 294571 : rewrite_compare_exps(visitor *v, sql_rel *rel, list *exps)
3613 : {
3614 294571 : if (mvc_highwater(v->sql))
3615 0 : return sql_error(v->sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
3616 294571 : if (list_empty(exps))
3617 : return exps;
3618 :
3619 635178 : for(node *n = exps->h; n; n = n->next) {
3620 340607 : sql_exp *e = n->data;
3621 :
3622 340607 : if (!is_compare(e->type)) {
3623 393 : sql_subtype bt;
3624 393 : sql_find_subtype(&bt, "boolean", 0, 0);
3625 393 : if (!(e = exp_check_type(v->sql, &bt, rel, e, type_equal)))
3626 0 : return NULL;
3627 393 : n->data = e = exp_compare(v->sql->sa, e, exp_atom_bool(v->sql->sa, 1), cmp_equal);
3628 393 : v->changes++;
3629 : }
3630 340607 : if (is_compare(e->type) && e->flag == cmp_or) {
3631 17035 : if (!(e->l = rewrite_compare_exps(v, rel, e->l)))
3632 : return NULL;
3633 17035 : if (!(e->r = rewrite_compare_exps(v, rel, e->r)))
3634 : return NULL;
3635 : }
3636 : }
3637 : return exps;
3638 : }
3639 :
3640 : /* add an dummy true projection column */
3641 : static inline sql_rel *
3642 2286721 : rewrite_compare_exp(visitor *v, sql_rel *rel)
3643 : {
3644 2286721 : if ((is_select(rel->op) || is_join(rel->op) || is_semi(rel->op)) && !list_empty(rel->exps))
3645 260501 : if (!(rel->exps = rewrite_compare_exps(v, rel, rel->exps)))
3646 : return NULL;
3647 : return rel;
3648 : }
3649 :
3650 : static inline sql_rel *
3651 2286719 : rewrite_remove_xp_project(visitor *v, sql_rel *rel)
3652 : {
3653 2286719 : if (rel->op == op_join && list_empty(rel->exps) && !rel_is_ref(rel)) {
3654 29033 : sql_rel *r = rel->r;
3655 :
3656 29033 : if (is_simple_project(r->op) && r->l && !project_unsafe(r, 1)) {
3657 6464 : sql_rel *rl = r->l;
3658 :
3659 6464 : if (is_simple_project(rl->op) && !rl->l && list_length(rl->exps) == 1) {
3660 109 : sql_exp *t = rl->exps->h->data;
3661 :
3662 109 : if (is_atom(t->type) && !exp_name(t)) { /* atom with out alias cannot be used later */
3663 0 : sql_rel *nrel = rel->l;
3664 0 : rel->l = NULL;
3665 0 : rel_destroy(rel);
3666 0 : rel = rel_project(v->sql->sa, nrel, rel_projections(v->sql, nrel, NULL, 1, 1));
3667 0 : list_merge(rel->exps, r->exps, (fdup)NULL);
3668 0 : set_processed(rel);
3669 0 : v->changes++;
3670 : }
3671 : }
3672 : }
3673 : }
3674 2286719 : return rel;
3675 : }
3676 :
3677 : static inline sql_rel *
3678 2902758 : rewrite_remove_xp(visitor *v, sql_rel *rel)
3679 : {
3680 2902758 : if (rel->op == op_join && list_empty(rel->exps) && !rel_is_ref(rel)) {
3681 46646 : sql_rel *r = rel->r;
3682 :
3683 46646 : if (is_simple_project(r->op) && !r->l && list_length(r->exps) == 1) {
3684 218 : sql_exp *t = r->exps->h->data;
3685 :
3686 218 : if (is_atom(t->type) && !exp_name(t)) { /* atom with out alias cannot be used later */
3687 0 : sql_rel *nrel = rel->l;
3688 0 : rel->l = NULL;
3689 0 : rel_destroy(rel);
3690 0 : rel = nrel;
3691 0 : v->changes++;
3692 : }
3693 : }
3694 : }
3695 2902758 : return rel;
3696 : }
3697 :
3698 : /* rel visitor */
3699 : static sql_rel *
3700 2891776 : rewrite_fix_count(visitor *v, sql_rel *rel)
3701 : {
3702 2891776 : if (rel->op == op_left && !is_single(rel)) {
3703 70187 : int rel_changes = 0;
3704 70187 : sql_rel *r = rel->r;
3705 :
3706 70187 : if (!is_rewrite_fix_count_used(r->used)) {
3707 65056 : list *rexps = r->exps, *exps = NULL;
3708 :
3709 65056 : if (!is_project(r->op))
3710 11135 : rexps = rel_projections(v->sql, r, NULL, 1, 1);
3711 :
3712 232893 : for(node *n = rexps->h; n && !rel_changes; n=n->next) {
3713 167837 : sql_exp *e = n->data;
3714 :
3715 167837 : if (exp_is_count(e, r))
3716 7304 : rel_changes = 1;
3717 : }
3718 65056 : if (!rel_changes)
3719 : return rel;
3720 :
3721 7304 : if (r->exps == rexps)
3722 7304 : rexps = rel_projections(v->sql, r, NULL, 1, 1);
3723 18037 : for(node *n = rexps->h; n; n=n->next) {
3724 10733 : sql_exp *e = n->data, *ne;
3725 :
3726 10733 : if (exp_is_count(e, r)) {
3727 : /* rewrite count in subquery */
3728 7292 : list *args, *targs;
3729 7292 : sql_subfunc *isnil = sql_bind_func(v->sql, "sys", "isnull", exp_subtype(e), NULL, F_FUNC, true), *ifthen;
3730 :
3731 7292 : ne = exp_unop(v->sql->sa, e, isnil);
3732 7292 : set_has_no_nil(ne);
3733 7292 : targs = sa_list(v->sql->sa);
3734 7292 : append(targs, sql_bind_localtype("bit"));
3735 7292 : append(targs, exp_subtype(e));
3736 7292 : append(targs, exp_subtype(e));
3737 7292 : ifthen = sql_bind_func_(v->sql, "sys", "ifthenelse", targs, F_FUNC, true);
3738 7292 : args = sa_list(v->sql->sa);
3739 7292 : append(args, ne);
3740 7292 : append(args, exp_atom(v->sql->sa, atom_zero_value(v->sql->sa, exp_subtype(e))));
3741 7292 : append(args, e);
3742 7292 : ne = exp_op(v->sql->sa, args, ifthen);
3743 7292 : if (exp_name(e))
3744 7292 : exp_prop_alias(v->sql->sa, ne, e);
3745 7292 : n->data = ne;
3746 : }
3747 : }
3748 7304 : exps = list_merge(rel_projections(v->sql, rel->l, NULL, 1, 1), rexps, (fdup)NULL);
3749 7304 : rel = rel_project(v->sql->sa, rel, exps);
3750 7304 : set_processed(rel);
3751 7304 : r->used |= rewrite_fix_count_used;
3752 7304 : v->changes++;
3753 : }
3754 : }
3755 : return rel;
3756 : }
3757 :
3758 : static inline sql_rel *
3759 2902761 : rewrite_groupings(visitor *v, sql_rel *rel)
3760 : {
3761 2902761 : prop *found;
3762 :
3763 2902761 : if (is_groupby(rel->op)) {
3764 : /* ROLLUP, CUBE, GROUPING SETS cases */
3765 38245 : if ((found = find_prop(rel->p, PROP_GROUPINGS))) {
3766 111 : list *sets = (list*) found->value.pval;
3767 111 : sql_rel *unions = NULL;
3768 :
3769 111 : rel->p = prop_remove(rel->p, found); /* remove property */
3770 637 : for (node *n = sets->h ; n ; n = n->next) {
3771 526 : sql_rel *nrel;
3772 526 : list *l = (list*) n->data, *exps = sa_list(v->sql->sa), *pexps = sa_list(v->sql->sa);
3773 :
3774 526 : l = list_flatten(l);
3775 526 : nrel = rel_groupby(v->sql, rel_dup(rel->l), l);
3776 :
3777 3377 : for (node *m = rel->exps->h ; m ; m = m->next) {
3778 2851 : sql_exp *e = (sql_exp*) m->data, *ne = NULL;
3779 2851 : sql_subfunc *agr = (sql_subfunc*) e->f;
3780 :
3781 3227 : if (e->type == e_aggr && !agr->func->s && !strcmp(agr->func->base.name, "grouping")) {
3782 : /* replace grouping aggregate calls with constants */
3783 376 : sql_subtype tpe = ((sql_arg*) agr->func->res->h->data)->type;
3784 376 : list *groups = (list*) e->l;
3785 376 : atom *a = atom_int(v->sql->sa, &tpe, 0);
3786 : #ifdef HAVE_HGE
3787 376 : hge counter = (hge) list_length(groups) - 1;
3788 : #else
3789 : lng counter = (lng) list_length(groups) - 1;
3790 : #endif
3791 376 : assert(groups && list_length(groups) > 0);
3792 :
3793 1196 : for (node *nn = groups->h ; nn ; nn = nn->next) {
3794 820 : sql_exp *exp = (sql_exp*) nn->data;
3795 820 : if (!exps_find_exp(l, exp)) {
3796 415 : switch (ATOMstorage(a->data.vtype)) {
3797 379 : case TYPE_bte:
3798 379 : a->data.val.btval += (bte) (1 << counter);
3799 379 : break;
3800 36 : case TYPE_sht:
3801 36 : a->data.val.shval += (sht) (1 << counter);
3802 36 : break;
3803 0 : case TYPE_int:
3804 0 : a->data.val.ival += (int) (1 << counter);
3805 0 : break;
3806 0 : case TYPE_lng:
3807 0 : a->data.val.lval += (lng) (1 << counter);
3808 0 : break;
3809 : #ifdef HAVE_HGE
3810 0 : case TYPE_hge:
3811 0 : a->data.val.hval += (hge) (1 << counter);
3812 0 : break;
3813 : #endif
3814 : default:
3815 0 : assert(0);
3816 : }
3817 : }
3818 820 : counter--;
3819 : }
3820 :
3821 376 : ne = exp_atom(v->sql->sa, a);
3822 376 : if (exp_name(e))
3823 376 : exp_prop_alias(v->sql->sa, ne, e);
3824 2475 : } else if (e->type == e_column && !exps_find_exp(l, e) && !has_label(e)) {
3825 : /* do not include in the output of the group by, but add to the project as null */
3826 745 : ne = exp_atom(v->sql->sa, atom_general(v->sql->sa, exp_subtype(e), NULL));
3827 745 : if (exp_name(e))
3828 745 : exp_prop_alias(v->sql->sa, ne, e);
3829 : } else {
3830 1730 : sql_exp *ec = exp_copy(v->sql, e);
3831 1730 : ne = exp_ref(v->sql, ec);
3832 1730 : append(exps, ec);
3833 : }
3834 2851 : append(pexps, ne);
3835 : }
3836 526 : if (list_empty(exps)) {
3837 24 : sql_exp *e = exp_atom_bool(v->sql->sa, 1);
3838 24 : exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
3839 24 : list_append(exps, e);
3840 : }
3841 526 : nrel->exps = exps;
3842 526 : if (!list_empty(rel->r) && !list_empty(nrel->r)) { /* aliases on grouping columns, ugh */
3843 1290 : for (node *n = ((list*)nrel->r)->h ; n ; n = n->next) {
3844 857 : sql_exp *e = n->data;
3845 857 : const char *rname = exp_relname(e), *cname = exp_name(e);
3846 857 : if (rname && cname) {
3847 784 : n->data = exp_copy(v->sql, exps_bind_column2(rel->r, rname, cname, NULL));
3848 73 : } else if (cname) {
3849 73 : n->data = exp_copy(v->sql, exps_bind_column(rel->r, cname, NULL, NULL, 1));
3850 : }
3851 : }
3852 433 : list_hash_clear(nrel->r);
3853 : }
3854 526 : set_processed(nrel);
3855 526 : if (list_empty(pexps)) {
3856 0 : sql_exp *e = exp_atom_bool(v->sql->sa, 1);
3857 0 : exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
3858 0 : list_append(pexps, e);
3859 : }
3860 526 : nrel = rel_project(v->sql->sa, nrel, pexps);
3861 526 : set_processed(nrel);
3862 :
3863 526 : if (!unions)
3864 : unions = nrel;
3865 : else {
3866 415 : unions = rel_setop(v->sql->sa, unions, nrel, op_union);
3867 415 : rel_setop_set_exps(v->sql, unions, rel_projections(v->sql, rel, NULL, 1, 1), false);
3868 415 : set_processed(unions);
3869 : }
3870 415 : if (!unions)
3871 : return unions;
3872 : }
3873 : /* always do relation inplace, so it will be fine when the input group has more than 1 reference */
3874 111 : if (is_union(unions->op)) {
3875 111 : rel = rel_inplace_setop(v->sql, rel, unions->l, unions->r, op_union, unions->exps);
3876 : } else {
3877 0 : assert(is_simple_project(unions->op));
3878 0 : rel = rel_inplace_project(v->sql->sa, rel, unions->l, unions->exps);
3879 0 : rel->card = exps_card(unions->exps);
3880 : }
3881 111 : unions->l = unions->r = NULL;
3882 111 : rel_destroy(unions);
3883 111 : v->changes++;
3884 111 : return rel;
3885 : } else {
3886 38134 : bool found_grouping = false;
3887 107056 : for (node *n = rel->exps->h ; n ; n = n->next) {
3888 68929 : sql_exp *e = (sql_exp*) n->data;
3889 68929 : sql_subfunc *agr = (sql_subfunc*) e->f;
3890 :
3891 68929 : if (e->type == e_aggr && !agr->func->s && !strcmp(agr->func->base.name, "grouping")) {
3892 : found_grouping = true;
3893 : break;
3894 : }
3895 : }
3896 38134 : if (found_grouping) {
3897 : /* replace grouping calls with constants of value 0 */
3898 7 : sql_rel *nrel = rel_groupby(v->sql, rel_dup(rel->l), rel->r);
3899 7 : list *exps = sa_list(v->sql->sa), *pexps = sa_list(v->sql->sa);
3900 7 : sql_subtype *bt = sql_bind_localtype("bte");
3901 :
3902 19 : for (node *n = rel->exps->h ; n ; n = n->next) {
3903 12 : sql_exp *e = (sql_exp*) n->data, *ne;
3904 12 : sql_subfunc *agr = (sql_subfunc*) e->f;
3905 :
3906 12 : if (e->type == e_aggr && !agr->func->s && !strcmp(agr->func->base.name, "grouping")) {
3907 7 : ne = exp_atom(v->sql->sa, atom_int(v->sql->sa, bt, 0));
3908 7 : if (exp_name(e))
3909 7 : exp_prop_alias(v->sql->sa, ne, e);
3910 : } else {
3911 5 : ne = exp_ref(v->sql, e);
3912 5 : append(exps, e);
3913 : }
3914 12 : append(pexps, ne);
3915 : }
3916 7 : if (list_empty(exps)) {
3917 4 : sql_exp *e = exp_atom_bool(v->sql->sa, 1);
3918 4 : exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
3919 4 : list_append(exps, e);
3920 : }
3921 7 : nrel->exps = exps;
3922 7 : set_processed(nrel);
3923 7 : if (list_empty(pexps)) {
3924 0 : sql_exp *e = exp_atom_bool(v->sql->sa, 1);
3925 0 : exp_label(v->sql->sa, e, ++v->sql->label); /* protection against empty projections */
3926 0 : list_append(pexps, e);
3927 : }
3928 : /* always do relation inplace, so it will be fine when the input group has more than 1 reference */
3929 7 : rel = rel_inplace_project(v->sql->sa, rel, nrel, pexps);
3930 7 : rel->card = exps_card(pexps);
3931 7 : v->changes++;
3932 7 : return rel;
3933 : }
3934 : }
3935 : }
3936 : return rel;
3937 : }
3938 :
3939 : static int
3940 120 : include_tid(sql_rel *r)
3941 : {
3942 120 : if (is_basetable(r->op))
3943 72 : r->nrcols = list_length(r->exps);
3944 120 : return r->nrcols;
3945 : }
3946 :
3947 : static sql_rel *
3948 69 : add_null_projects(visitor *v, sql_rel *prel, sql_rel *irel, bool end)
3949 : {
3950 69 : list *l = NULL;
3951 69 : node *n = prel->exps->h;
3952 69 : sql_rel *nilrel = rel_project(v->sql->sa, irel, rel_projections(v->sql, irel, NULL, 1, 1));
3953 69 : int nr = prel->nrcols - nilrel->nrcols;
3954 69 : if (end) {
3955 112 : for(node *m = nilrel->exps->h; n && m; n = n->next, m = m->next)
3956 : ;
3957 : } else {
3958 39 : l = sa_list(v->sql->sa);
3959 : }
3960 247 : for(; nr; n = n->next, nr--) {
3961 179 : sql_exp *e = n->data, *ne;
3962 179 : sql_subtype *tp = exp_subtype(e);
3963 :
3964 179 : if (!tp)
3965 1 : return sql_error(v->sql, 10, SQLSTATE(42000) "Cannot rewrite subquery because of parameter with unknown type");
3966 178 : ne = exp_atom(v->sql->sa, atom_general(v->sql->sa, tp, NULL));
3967 178 : exp_setname(v->sql->sa, ne, exp_relname(e), exp_name(e));
3968 178 : if (end)
3969 58 : append(nilrel->exps, ne);
3970 : else
3971 120 : append(l, ne);
3972 : }
3973 68 : if (!end)
3974 39 : nilrel->exps = list_merge(l, nilrel->exps, NULL);
3975 68 : nilrel->nrcols = list_length(nilrel->exps);
3976 68 : return nilrel;
3977 : }
3978 :
3979 : static sql_rel *
3980 60 : rewrite_outer2inner_union(visitor *v, sql_rel *rel)
3981 : {
3982 60 : if (is_outerjoin(rel->op) && rel->flag != MERGE_LEFT) {
3983 60 : int nrcols = rel->nrcols;
3984 :
3985 60 : nrcols = include_tid(rel->l);
3986 60 : nrcols += include_tid(rel->r);
3987 60 : rel->nrcols = nrcols;
3988 60 : if (is_left(rel->op)) {
3989 21 : sql_rel *inner = rel_crossproduct(v->sql->sa, rel_dup(rel->l), rel_dup(rel->r), op_join);
3990 21 : inner->exps = rel->exps;
3991 21 : if(is_dependent(rel))
3992 16 : set_dependent(inner);
3993 21 : sql_rel *prel = rel_project(v->sql->sa, inner, rel_projections(v->sql, inner, NULL, 1, 1));
3994 42 : sql_rel *except = rel_setop(v->sql->sa,
3995 21 : rel_project(v->sql->sa, rel_dup(rel->l), rel_projections(v->sql, rel->l, NULL, 1, 1)),
3996 42 : rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->l, NULL, 1, 1)), op_except);
3997 21 : rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->l, NULL, 1, 1), false);
3998 21 : set_processed(except);
3999 21 : sql_rel *nilrel = add_null_projects(v, prel, except, true);
4000 21 : if (!nilrel)
4001 : return NULL;
4002 :
4003 20 : sql_rel *nrel = rel_setop(v->sql->sa, prel, nilrel, op_union);
4004 20 : rel_setop_set_exps(v->sql, nrel, rel_projections(v->sql, rel, NULL, 1, 1), false);
4005 20 : set_processed(nrel);
4006 20 : if(is_single(rel))
4007 0 : set_single(nrel);
4008 20 : v->changes++;
4009 20 : rel_destroy(rel);
4010 20 : return nrel;
4011 39 : } else if (is_right(rel->op)) {
4012 30 : sql_rel *inner = rel_crossproduct(v->sql->sa, rel_dup(rel->l), rel_dup(rel->r), op_join);
4013 30 : inner->exps = rel->exps;
4014 30 : if(is_dependent(rel))
4015 18 : set_dependent(inner);
4016 30 : sql_rel *prel = rel_project(v->sql->sa, inner, rel_projections(v->sql, inner, NULL, 1, 1));
4017 60 : sql_rel *except = rel_setop(v->sql->sa,
4018 30 : rel_project(v->sql->sa, rel_dup(rel->r), rel_projections(v->sql, rel->r, NULL, 1, 1)),
4019 60 : rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->r, NULL, 1, 1)), op_except);
4020 30 : rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->r, NULL, 1, 1), false);
4021 30 : set_processed(except);
4022 30 : sql_rel *nilrel = add_null_projects(v, prel, except, false);
4023 30 : if (!nilrel)
4024 : return NULL;
4025 :
4026 30 : sql_rel *nrel = rel_setop(v->sql->sa, prel, nilrel, op_union);
4027 30 : rel_setop_set_exps(v->sql, nrel, rel_projections(v->sql, rel, NULL, 1, 1), false);
4028 30 : set_processed(nrel);
4029 30 : if(is_single(rel))
4030 0 : set_single(nrel);
4031 30 : v->changes++;
4032 30 : rel_destroy(rel);
4033 30 : return nrel;
4034 9 : } else if (is_full(rel->op)) {
4035 9 : sql_rel *inner = rel_crossproduct(v->sql->sa, rel_dup(rel->l), rel_dup(rel->r), op_join);
4036 9 : inner->exps = rel->exps;
4037 9 : if(is_dependent(rel))
4038 3 : set_dependent(inner);
4039 9 : sql_rel *prel = rel_project(v->sql->sa, inner, rel_projections(v->sql, inner, NULL, 1, 1));
4040 18 : sql_rel *except = rel_setop(v->sql->sa,
4041 9 : rel_project(v->sql->sa, rel_dup(rel->l), rel_projections(v->sql, rel->l, NULL, 1, 1)),
4042 18 : rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->l, NULL, 1, 1)), op_except);
4043 9 : rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->l, NULL, 1, 1), false);
4044 9 : set_processed(except);
4045 9 : sql_rel *lrel = add_null_projects(v, prel, except, true);
4046 9 : if (!lrel)
4047 : return NULL;
4048 :
4049 18 : except = rel_setop(v->sql->sa,
4050 9 : rel_project(v->sql->sa, rel_dup(rel->r), rel_projections(v->sql, rel->r, NULL, 1, 1)),
4051 18 : rel_project(v->sql->sa, rel_dup(prel), rel_projections(v->sql, rel->r, NULL, 1, 1)), op_except);
4052 9 : rel_setop_set_exps(v->sql, except, rel_projections(v->sql, rel->r, NULL, 1, 1), false);
4053 9 : set_processed(except);
4054 9 : sql_rel *rrel = add_null_projects(v, prel, except, false);
4055 9 : if (!rrel)
4056 : return NULL;
4057 :
4058 9 : lrel = rel_setop(v->sql->sa, lrel, rrel, op_union);
4059 9 : rel_setop_set_exps(v->sql, lrel, rel_projections(v->sql, rel, NULL, 1, 1), false);
4060 9 : set_processed(lrel);
4061 9 : lrel = rel_setop(v->sql->sa, prel, lrel, op_union);
4062 9 : rel_setop_set_exps(v->sql, lrel, rel_projections(v->sql, rel, NULL, 1, 1), false);
4063 9 : set_processed(lrel);
4064 9 : if(is_single(rel))
4065 0 : set_single(lrel);
4066 9 : v->changes++;
4067 9 : rel_destroy(rel);
4068 9 : return lrel;
4069 : }
4070 : }
4071 : return rel;
4072 : }
4073 :
4074 : static sql_rel *
4075 2238269 : rewrite_swap_fullouter(visitor *v, sql_rel *rel)
4076 : {
4077 2238269 : if (is_full(rel->op) && rel_has_freevar(v->sql, rel->r)) { /* swap */
4078 3 : sql_rel *s = rel->r;
4079 3 : rel->r = rel->l;
4080 3 : rel->l = s;
4081 : }
4082 2238269 : return rel;
4083 : }
4084 :
4085 : static sql_exp *
4086 11422874 : rewrite_complex(visitor *v, sql_rel *rel, sql_exp *e, int depth)
4087 : {
4088 11422874 : if (e->type != e_func)
4089 : return e;
4090 :
4091 441222 : sql_exp *res = rewrite_anyequal(v, rel, e, depth);
4092 441222 : if (res == e)
4093 423670 : res = rewrite_exists(v, rel, e, depth);
4094 441222 : if (res == e)
4095 422310 : res = rewrite_compare(v, rel, e, depth);
4096 : return res;
4097 : }
4098 :
4099 : static sql_rel *
4100 103 : flatten_values(visitor *v, sql_rel *rel)
4101 : {
4102 103 : list *exps = sa_list(v->sql->sa);
4103 103 : sql_exp *e = rel->exps->h->data;
4104 103 : sql_rel *cur = NULL;
4105 103 : list *vals = exp_get_values(e);
4106 103 : if (vals) {
4107 254 : for(int i = 0; i<list_length(vals); i++) {
4108 151 : sql_rel *nrel = rel_project(v->sql->sa, NULL, sa_list(v->sql->sa));
4109 151 : set_processed(nrel);
4110 344 : for(node *n = rel->exps->h; n; n = n->next) {
4111 193 : sql_exp *e = n->data;
4112 193 : list *vals = exp_get_values(e);
4113 :
4114 193 : if (vals) {
4115 193 : if (i == 0)
4116 127 : append(exps, exp_ref(v->sql, e));
4117 193 : sql_exp *val = list_fetch(vals, i);
4118 193 : exp_setname(v->sql->sa, val, exp_relname(e), exp_name(e));
4119 193 : append(nrel->exps, val);
4120 193 : rel_set_exps(nrel, nrel->exps);
4121 : }
4122 : }
4123 151 : if (cur) {
4124 48 : nrel = rel_setop(v->sql->sa, cur, nrel, op_union);
4125 48 : rel_setop_set_exps(v->sql, nrel, exps, false);
4126 48 : set_processed(nrel);
4127 : }
4128 151 : cur = nrel;
4129 : }
4130 103 : if (is_single(rel))
4131 9 : set_single(cur);
4132 103 : rel_destroy(rel);
4133 103 : rel = cur;
4134 103 : v->changes++;
4135 : }
4136 103 : return rel;
4137 : }
4138 :
4139 : /* rewrite project [ [multi values], [multi values2] , .. [] ] -> union ) */
4140 : static inline sql_rel *
4141 2238284 : rewrite_values(visitor *v, sql_rel *rel)
4142 : {
4143 2238284 : if (!is_simple_project(rel->op) || list_empty(rel->exps) || is_rewrite_values_used(rel->used))
4144 1500569 : return rel;
4145 :
4146 737715 : sql_exp *e = rel->exps->h->data;
4147 737715 : if (!is_values(e) || (!exps_have_rel_exp(rel->exps) && !exps_have_freevar(v->sql, rel->exps)))
4148 737612 : return rel;
4149 103 : if (rel_is_ref(rel)) { /* need extra project */
4150 0 : rel->l = rel_project(v->sql->sa, rel->l, rel->exps);
4151 0 : rel->exps = rel_projections(v->sql, rel->l, NULL, 1, 1);
4152 0 : ((sql_rel*)rel->l)->r = rel->r; /* propagate order by exps */
4153 0 : rel->r = NULL;
4154 0 : rel->used |= rewrite_values_used;
4155 0 : v->changes++;
4156 0 : return rel;
4157 : }
4158 103 : return flatten_values(v, rel);
4159 : }
4160 :
4161 : static inline sql_rel *
4162 2238263 : rewrite_rel(visitor *v, sql_rel *rel)
4163 : {
4164 2238263 : if (!is_outerjoin(rel->op) || list_empty(rel->exps) || rel_is_ref(rel))
4165 2226807 : return rel;
4166 11456 : sql_rel *l = rel->l, *r = rel->r;
4167 :
4168 11456 : if ((l && is_project(l->op) && !l->l) ||
4169 10878 : (r && is_project(r->op) && !r->l))
4170 : return rel;
4171 :
4172 10842 : sql_rel *or = rel;
4173 22023 : for (node *n = rel->exps->h; n; ) {
4174 11240 : node *next = n->next;
4175 11240 : sql_exp *e = n->data;
4176 :
4177 11240 : if (exp_has_rel(e) /*&& exp_has_freevar(v->sql, e)*/) {
4178 59 : list *exps = or->exps;
4179 59 : or->exps = NULL;
4180 59 : sql_rel *ir = exp_rel_get_rel(v->sql->sa, e);
4181 :
4182 59 : rel = rewrite_outer2inner_union(v, rel);
4183 59 : if (!rel || or == rel)
4184 : return rel;
4185 : /* change referenced project into join with outer(ir) */
4186 58 : sql_rel *nr = rel->l;
4187 58 : assert(is_project(nr->op));
4188 58 : if (!rel_is_ref(nr))
4189 0 : nr = nr->l;
4190 58 : sql_rel *s = rel_crossproduct(v->sql->sa, nr->l, ir, op_semi);
4191 58 : s->exps = exps;
4192 58 : set_dependent(s);
4193 58 : nr->l = s;
4194 58 : e = exp_rel_update_exp(v->sql, e, false);
4195 58 : exp_reset_props(nr, e, true);
4196 58 : v->changes++;
4197 58 : break;
4198 : }
4199 : n = next;
4200 : }
4201 : return rel;
4202 : }
4203 :
4204 : /* add an dummy true projection column */
4205 : static sql_rel *
4206 2238281 : rel_unnest_simplify(visitor *v, sql_rel *rel)
4207 : {
4208 : /* at rel_select.c explicit cross-products generate empty selects, if these are not used, they can be removed at rewrite_simplify */
4209 2238281 : if (rel)
4210 2238282 : rel = rewrite_basetable(v->sql, rel); /* add proper exps lists */
4211 2238289 : if (rel)
4212 2238289 : rel = rewrite_empty_project(v, rel); /* remove empty project/groupby */
4213 2238275 : if (rel)
4214 2238275 : rel = rewrite_simplify(v, 0, false, rel);
4215 2238270 : if (rel)
4216 2238270 : rel = rewrite_split_select_exps(v, rel); /* has to run before rewrite_complex */
4217 2238267 : if (rel)
4218 2238267 : rel = rewrite_swap_fullouter(v, rel);
4219 2238264 : if (rel)
4220 2238264 : rel = rewrite_aggregates(v, rel);
4221 2238264 : if (rel)
4222 2238264 : rel = rewrite_values(v, rel);
4223 2238260 : if (rel)
4224 2238260 : rel = rewrite_rel(v, rel);
4225 2238258 : return rel;
4226 : }
4227 :
4228 : static sql_rel *
4229 2902758 : rel_unnest_projects(visitor *v, sql_rel *rel)
4230 : {
4231 2902758 : if (rel)
4232 2902758 : rel = rewrite_remove_xp(v, rel); /* remove crossproducts with project [ atom ] */
4233 2902758 : if (rel)
4234 2902758 : rel = rewrite_groupings(v, rel); /* transform group combinations into union of group relations */
4235 2902760 : return rel;
4236 : }
4237 :
4238 : static sql_rel *
4239 2286713 : rel_unnest_comparison_rewriters(visitor *v, sql_rel *rel)
4240 : {
4241 2286713 : if (rel)
4242 2286713 : rel = rewrite_join2semi(v, rel); /* where possible convert anyequal functions into marks */
4243 2286718 : if (rel)
4244 2286718 : rel = rewrite_compare_exp(v, rel); /* only allow for e_cmp in selects and handling */
4245 2286719 : if (rel)
4246 2286719 : rel = rewrite_remove_xp_project(v, rel); /* remove crossproducts with project ( project [ atom ] ) [ etc ] */
4247 2286717 : if (rel)
4248 2286717 : rel = rewrite_simplify(v, 0, false, rel); /* as expressions got merged before, lets try to simplify again */
4249 2286721 : return rel;
4250 : }
4251 :
4252 : static sql_exp *
4253 9486622 : rel_simplify_exp_and_rank(visitor *v, sql_rel *rel, sql_exp *e, int depth)
4254 : {
4255 9486622 : if (e)
4256 9486622 : e = rewrite_simplify_exp(v, rel, e, depth);
4257 9486659 : if (e)
4258 9486659 : e = rewrite_rank(v, rel, e, depth);
4259 9486673 : return e;
4260 : }
4261 :
4262 : static inline sql_rel *
4263 3433912 : run_exp_rewriter(visitor *v, sql_rel *rel, exp_rewrite_fptr rewriter, bool direction, const char *name)
4264 : {
4265 3433912 : (void)name;
4266 : /*
4267 : #ifndef NDEBUG
4268 : int changes = v->changes;
4269 : lng clk = GDKusec();
4270 : rel = rel_exp_visitor_bottomup(v, rel, rewriter, direction);
4271 : printf("%s %d " LLFMT "\n", name, (v->changes - changes), (GDKusec() - clk));
4272 : return rel;
4273 : #else
4274 : */
4275 3433912 : return rel_exp_visitor_bottomup(v, rel, rewriter, direction);
4276 : //#endif
4277 : }
4278 :
4279 : static inline sql_rel *
4280 3433901 : run_rel_rewriter(visitor *v, sql_rel *rel, rel_rewrite_fptr rewriter, const char *name)
4281 : {
4282 3433901 : (void)name;
4283 : /*
4284 : #ifndef NDEBUG
4285 : int changes = v->changes;
4286 : lng clk = GDKusec();
4287 : rel = rel_visitor_bottomup(v, rel, rewriter);
4288 : printf("%s %d " LLFMT "\n", name, (v->changes - changes), (GDKusec() - clk));
4289 : return rel;
4290 : #else
4291 : */
4292 3433901 : return rel_visitor_bottomup(v, rel, rewriter);
4293 : //#endif
4294 : }
4295 :
4296 : sql_rel *
4297 686798 : rel_unnest(mvc *sql, sql_rel *rel)
4298 : {
4299 686798 : visitor v = { .sql = sql };
4300 :
4301 686798 : rel = run_exp_rewriter(&v, rel, &rel_simplify_exp_and_rank, false, "simplify_exp_and_rank");
4302 686779 : rel = run_rel_rewriter(&v, rel, &rel_unnest_simplify, "unnest_simplify");
4303 : //if (0) {
4304 686779 : rel = run_exp_rewriter(&v, rel, &rewrite_complex, true, "rewrite_complex");
4305 686781 : rel = run_exp_rewriter(&v, rel, &rewrite_ifthenelse, false, "rewrite_ifthenelse"); /* add isnull handling */
4306 686786 : rel = run_exp_rewriter(&v, rel, &rewrite_exp_rel, true, "rewrite_exp_rel");
4307 :
4308 686785 : rel = run_rel_rewriter(&v, rel, &rel_unnest_comparison_rewriters, "unnest_comparison_rewriters");
4309 686782 : rel = run_rel_rewriter(&v, rel, &_rel_unnest, "unnest");
4310 686780 : rel = run_rel_rewriter(&v, rel, &rewrite_fix_count, "fix_count"); /* fix count inside a left join (adds a project (if (cnt IS null) then (0) else (cnt)) */
4311 686775 : rel = run_rel_rewriter(&v, rel, &rel_unnest_projects, "unnest_projects");
4312 : //}
4313 686768 : rel = run_exp_rewriter(&v, rel, &exp_reset_card_and_freevar_set_physical_type, false, "exp_reset_card_and_freevar_set_physical_type");
4314 686778 : rel = rel_visitor_topdown(&v, rel, &rel_set_type);
4315 686779 : return rel;
4316 : }
|