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