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