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