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