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