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_propagate.h"
15 : #include "rel_basetable.h"
16 : #include "rel_exp.h"
17 : #include "rel_select.h"
18 : #include "rel_updates.h"
19 : #include "sql_partition.h"
20 :
21 : extern sql_rel *rel_list(sql_allocator *sa, sql_rel *l, sql_rel *r);
22 :
23 : static sql_exp*
24 259 : rel_generate_anti_expression(mvc *sql, sql_rel **anti_rel, sql_table *mt, sql_table *pt)
25 : {
26 259 : sql_exp* res = NULL;
27 :
28 259 : *anti_rel = rel_basetable(sql, pt, pt->base.name);
29 :
30 259 : if (isPartitionedByColumnTable(mt)) {
31 224 : int colr = mt->part.pcol->colnr;
32 :
33 224 : res = rel_base_bind_colnr(sql, *anti_rel, colr);
34 224 : return res;
35 : //res = list_fetch((*anti_rel)->exps, colr);
36 : //res = exp_ref(sql, res);
37 35 : } else if (isPartitionedByExpressionTable(mt)) {
38 35 : *anti_rel = rel_project(sql->sa, *anti_rel, NULL);
39 35 : if (!(res = rel_parse_val(sql, mt->s, mt->part.pexp->exp, NULL, sql->emode, (*anti_rel)->l)))
40 : return NULL;
41 35 : set_processed(*anti_rel);
42 : } else {
43 0 : assert(0);
44 : }
45 35 : (*anti_rel)->exps = new_exp_list(sql->sa);
46 35 : append((*anti_rel)->exps, res);
47 35 : res = exp_ref(sql, res);
48 35 : return res;
49 : }
50 :
51 : static sql_rel*
52 113 : rel_create_common_relation(mvc *sql, sql_rel *rel, sql_table *t)
53 : {
54 113 : if (isPartitionedByColumnTable(t)) {
55 53 : return rel_dup(rel->r);
56 60 : } else if (isPartitionedByExpressionTable(t)) {
57 14 : sql_rel *inserts;
58 14 : list *l = new_exp_list(sql->sa);
59 :
60 14 : rel->r = rel_project(sql->sa, rel->r, l);
61 14 : set_processed((sql_rel*)rel->r);
62 14 : inserts = ((sql_rel*)(rel->r))->l;
63 41 : for (node *n = ol_first_node(t->columns), *m = inserts->exps->h; n && m; n = n->next, m = m->next) {
64 27 : sql_column *col = n->data;
65 27 : sql_exp *before = m->data, *help;
66 :
67 27 : help = exp_ref(sql, before);
68 27 : exp_setname(sql->sa, help, t->base.name, col->base.name);
69 27 : list_append(l, help);
70 : }
71 14 : return rel_dup(rel->r);
72 : }
73 : return NULL;
74 : }
75 :
76 : static sql_exp*
77 331 : rel_generate_anti_insert_expression(mvc *sql, sql_rel **anti_rel, sql_table *t)
78 : {
79 331 : sql_exp* res = NULL;
80 :
81 331 : if ((*anti_rel)->op != op_project && (*anti_rel)->op != op_basetable && (*anti_rel)->op != op_table) {
82 20 : sql_rel *inserts; /* In a nested partition case the operation is a op_select, then a projection must be created */
83 20 : list *l = new_exp_list(sql->sa);
84 20 : *anti_rel = rel_project(sql->sa, *anti_rel, l);
85 :
86 20 : inserts = (*anti_rel)->l;
87 20 : if (inserts->op != op_project && inserts->op != op_union && inserts->op != op_basetable && inserts->op != op_table)
88 20 : inserts = inserts->l;
89 60 : for (node *n = ol_first_node(t->columns), *m = inserts->exps->h; n && m; n = n->next, m = m->next) {
90 40 : sql_column *col = n->data;
91 40 : sql_exp *before = m->data, *help;
92 :
93 40 : help = exp_ref(sql, before);
94 40 : exp_setname(sql->sa, help, t->base.name, col->base.name);
95 40 : list_append(l, help);
96 : }
97 : }
98 :
99 648 : if (isPartitionedByColumnTable(t)) {
100 317 : int colr = t->part.pcol->colnr;
101 317 : res = list_fetch((*anti_rel)->exps, colr);
102 14 : } else if (isPartitionedByExpressionTable(t)) {
103 14 : *anti_rel = rel_project(sql->sa, *anti_rel, rel_projections(sql, *anti_rel, NULL, 1, 1));
104 14 : if (!(res = rel_parse_val(sql, t->s, t->part.pexp->exp, NULL, sql->emode, (*anti_rel)->l)))
105 : return NULL;
106 14 : exp_label(sql->sa, res, ++sql->label);
107 14 : append((*anti_rel)->exps, res);
108 : } else {
109 0 : assert(0);
110 : }
111 331 : res = exp_ref(sql, res);
112 331 : return res;
113 : }
114 :
115 : static sql_exp *
116 560 : generate_partition_limits(sql_query *query, sql_rel **r, symbol *s, sql_subtype tpe, bool nilok)
117 : {
118 560 : mvc *sql = query->sql;
119 560 : if (!s) {
120 : return NULL;
121 560 : } else if (s->token == SQL_NULL && !nilok) {
122 8 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: range bound cannot be null");
123 552 : } else if (s->token == SQL_MINVALUE) {
124 33 : atom *amin = atom_general(sql->sa, &tpe, NULL);
125 33 : if (!amin) {
126 0 : char *err = sql_subtype_string(sql->ta, &tpe);
127 0 : if (!err)
128 0 : return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
129 0 : sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: absolute minimum value not available for %s type", err);
130 0 : return NULL;
131 : }
132 33 : return exp_atom(sql->sa, amin);
133 519 : } else if (s->token == SQL_MAXVALUE) {
134 32 : atom *amax = atom_general(sql->sa, &tpe, NULL);
135 32 : if (!amax) {
136 0 : char *err = sql_subtype_string(sql->ta, &tpe);
137 0 : if (!err)
138 0 : return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
139 0 : sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: absolute maximum value not available for %s type", err);
140 0 : return NULL;
141 : }
142 32 : return exp_atom(sql->sa, amax);
143 : } else {
144 487 : exp_kind ek = {type_value, card_value, FALSE};
145 487 : sql_exp *e = rel_value_exp2(query, r, s, sql_sel | sql_values, ek);
146 :
147 487 : if (!e)
148 : return NULL;
149 486 : return exp_check_type(sql, &tpe, r ? *r : NULL, e, type_equal);
150 : }
151 : }
152 :
153 : static sql_exp*
154 199 : create_range_partition_anti_rel(sql_query* query, sql_table *mt, sql_table *pt, bit with_nills, sql_exp *pmin, sql_exp *pmax, bool all_ranges, bool max_equal_min)
155 : {
156 199 : mvc *sql = query->sql;
157 199 : sql_rel *anti_rel;
158 199 : sql_exp *aggr, *anti_exp = NULL, *anti_le, *e1, *e2, *anti_nils;
159 199 : sql_subfunc *cf = sql_bind_func(sql, "sys", "count", sql_bind_localtype("void"), NULL, F_AGGR, true);
160 199 : sql_subtype tpe;
161 :
162 199 : find_partition_type(&tpe, mt);
163 :
164 199 : anti_le = rel_generate_anti_expression(sql, &anti_rel, mt, pt);
165 199 : anti_nils = rel_unop_(sql, anti_rel, anti_le, "sys", "isnull", card_value);
166 199 : set_has_no_nil(anti_nils);
167 199 : if (pmin && pmax) {
168 187 : if (all_ranges) { /*if holds all values in range, don't generate the range comparison */
169 11 : assert(!with_nills);
170 : } else {
171 176 : sql_exp *range1, *range2;
172 :
173 176 : e1 = exp_copy(sql, pmin);
174 176 : if (!(e1 = exp_check_type(sql, &tpe, NULL, e1, type_equal)))
175 : return NULL;
176 :
177 176 : if (max_equal_min) {
178 3 : anti_exp = exp_compare(sql->sa, exp_copy(sql, anti_le), e1, cmp_notequal);
179 : } else {
180 173 : e2 = exp_copy(sql, pmax);
181 173 : if (!(e2 = exp_check_type(sql, &tpe, NULL, e2, type_equal)))
182 : return NULL;
183 :
184 173 : range1 = exp_compare(sql->sa, exp_copy(sql, anti_le), e1, cmp_lt);
185 173 : range2 = exp_compare(sql->sa, exp_copy(sql, anti_le), e2, cmp_gte);
186 173 : anti_exp = exp_or(sql->sa, list_append(new_exp_list(sql->sa), range1),
187 : list_append(new_exp_list(sql->sa), range2), 0);
188 : }
189 : }
190 176 : if (!with_nills) {
191 169 : anti_nils = exp_compare(sql->sa, anti_nils, exp_atom_bool(sql->sa, 1), cmp_equal);
192 169 : if (anti_exp)
193 158 : anti_exp = exp_or(sql->sa, list_append(new_exp_list(sql->sa), anti_exp),
194 : list_append(new_exp_list(sql->sa), anti_nils), 0);
195 : else
196 : anti_exp = anti_nils;
197 : }
198 : } else {
199 12 : anti_exp = exp_compare(sql->sa, anti_nils, exp_atom_bool(sql->sa, 0), cmp_equal);
200 : }
201 :
202 199 : anti_rel = rel_select(sql->sa, anti_rel, anti_exp);
203 199 : set_processed(anti_rel);
204 199 : anti_rel = rel_groupby(sql, anti_rel, NULL);
205 199 : aggr = exp_aggr(sql->sa, NULL, cf, 0, 0, anti_rel->card, 0);
206 199 : (void) rel_groupby_add_aggr(sql, anti_rel, aggr);
207 199 : set_processed(anti_rel);
208 199 : exp_label(sql->sa, aggr, ++sql->label);
209 :
210 199 : return exp_rel(sql, anti_rel);
211 : }
212 :
213 : static sql_exp*
214 60 : create_list_partition_anti_rel(sql_query* query, sql_table *mt, sql_table *pt, bit with_nills, list *anti_exps)
215 : {
216 60 : mvc *sql = query->sql;
217 60 : sql_rel *anti_rel;
218 60 : sql_exp *aggr, *anti_exp, *anti_le, *anti_nils;
219 60 : sql_subfunc *cf = sql_bind_func(sql, "sys", "count", sql_bind_localtype("void"), NULL, F_AGGR, true);
220 60 : sql_subtype tpe;
221 :
222 60 : find_partition_type(&tpe, mt);
223 :
224 60 : anti_le = rel_generate_anti_expression(sql, &anti_rel, mt, pt);
225 60 : anti_nils = rel_unop_(sql, anti_rel, anti_le, "sys", "isnull", card_value);
226 :
227 60 : set_has_no_nil(anti_nils);
228 60 : if (list_length(anti_exps) > 0) {
229 57 : anti_exp = exp_in(sql->sa, anti_le, anti_exps, cmp_notin);
230 57 : if (!with_nills) {
231 50 : anti_nils = exp_compare(sql->sa, anti_nils, exp_atom_bool(sql->sa, 1), cmp_equal);
232 50 : anti_exp = exp_or(sql->sa, append(new_exp_list(sql->sa), anti_exp),
233 : append(new_exp_list(sql->sa), anti_nils), 0);
234 : }
235 : } else {
236 3 : assert(with_nills);
237 3 : anti_exp = exp_compare(sql->sa, anti_nils, exp_atom_bool(sql->sa, 0), cmp_equal);
238 : }
239 :
240 60 : anti_rel = rel_select(sql->sa, anti_rel, anti_exp);
241 60 : set_processed(anti_rel);
242 60 : anti_rel = rel_groupby(sql, anti_rel, NULL);
243 60 : aggr = exp_aggr(sql->sa, NULL, cf, 0, 0, anti_rel->card, 0);
244 60 : (void) rel_groupby_add_aggr(sql, anti_rel, aggr);
245 60 : set_processed(anti_rel);
246 60 : exp_label(sql->sa, aggr, ++sql->label);
247 60 : return exp_rel(sql, anti_rel);
248 : }
249 :
250 : static sql_exp *
251 7 : add_check_count(mvc *sql, sql_exp *a, sql_exp *b)
252 : {
253 7 : if (!a)
254 : return b;
255 7 : sql_subfunc *f = sql_bind_func(sql, "sys", "sql_add", exp_subtype(a), exp_subtype(b), F_FUNC, true);
256 7 : return exp_binop(sql->sa, a, b, f);
257 : }
258 :
259 : static sql_rel *
260 257 : propagate_validation_to_upper_tables(sql_query* query, sql_table *mt, sql_table *pt, sql_rel *rel, sql_exp *check_count)
261 : {
262 257 : mvc *sql = query->sql;
263 257 : sql_part *it = NULL;
264 :
265 264 : for (sql_table *prev = mt ; prev; prev = it?it->t:NULL) {
266 264 : if ((it=partition_find_part(sql->session->tr, prev, NULL)) == NULL)
267 : break;
268 7 : sql_part *spt = it;
269 7 : if (spt) {
270 7 : sql_subtype tp;
271 7 : find_partition_type(&tp, it->t);
272 :
273 7 : if (isRangePartitionTable(it->t)) {
274 1 : int tpe = tp.type->localtype;
275 1 : int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
276 1 : const void *nil = ATOMnilptr(tpe);
277 1 : sql_exp *e1 = NULL, *e2 = NULL;
278 1 : bool found_all = false, max_equal_min = false;
279 :
280 1 : if (atomcmp(spt->part.range.minvalue, nil) != 0 && atomcmp(spt->part.range.maxvalue, nil) != 0) {
281 1 : max_equal_min = ATOMcmp(tpe, spt->part.range.maxvalue, spt->part.range.minvalue) == 0;
282 1 : e1 = exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, spt->part.range.minvalue));
283 1 : if (!max_equal_min)
284 1 : e2 = exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, spt->part.range.maxvalue));
285 : } else {
286 0 : assert(spt->with_nills);
287 0 : found_all = is_bit_nil(spt->with_nills);
288 : }
289 1 : if (!found_all || !spt->with_nills) {
290 1 : sql_exp *nres = create_range_partition_anti_rel(query, it->t, pt, spt->with_nills, e1, e2, false, max_equal_min);
291 1 : check_count = add_check_count(sql, check_count, nres);
292 : }
293 6 : } else if (isListPartitionTable(it->t)) {
294 6 : list *exps = new_exp_list(sql->sa);
295 28 : for (node *n = spt->part.values->h ; n ; n = n->next) {
296 22 : sql_part_value *next = (sql_part_value*) n->data;
297 22 : sql_exp *e1 = exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, next->value));
298 22 : list_append(exps, e1);
299 : }
300 6 : sql_exp *nres = create_list_partition_anti_rel(query, it->t, pt, spt->with_nills, exps);
301 6 : check_count = add_check_count(sql, check_count, nres);
302 : } else {
303 0 : assert(0);
304 : }
305 : } else { /* the sql_part should exist */
306 : assert(0);
307 : }
308 : }
309 257 : if (check_count) {
310 252 : append(rel->exps, check_count);
311 : } else {
312 5 : append(rel->exps, exp_atom_lng(sql->sa, 0));
313 : }
314 257 : return rel;
315 : }
316 :
317 : sql_rel *
318 209 : rel_alter_table_add_partition_range(sql_query* query, sql_table *mt, sql_table *pt, char *sname, char *tname, char *sname2,
319 : char *tname2, symbol* min, symbol* max, bit with_nills, int update)
320 : {
321 209 : mvc *sql = query->sql;
322 209 : sql_rel *rel_psm = rel_create(sql->sa);
323 209 : list *exps = new_exp_list(sql->sa);
324 209 : sql_exp *pmin, *pmax;
325 209 : sql_subtype tpe;
326 209 : bool all_ranges = false;
327 209 : sql_exp *check_count = NULL;
328 :
329 209 : if (!rel_psm || !exps)
330 : return NULL;
331 :
332 209 : find_partition_type(&tpe, mt);
333 :
334 209 : assert((!min && !max && with_nills) || (min && max));
335 209 : if (min && max) {
336 197 : pmin = generate_partition_limits(query, &rel_psm, min, tpe, false);
337 197 : pmax = generate_partition_limits(query, &rel_psm, max, tpe, false);
338 197 : if (!pmin || !pmax)
339 : return NULL;
340 191 : if (min->token == SQL_MINVALUE && max->token == SQL_MAXVALUE && with_nills)
341 5 : with_nills = bit_nil; /* holds all values in range */
342 366 : all_ranges = (min->token == SQL_MINVALUE && max->token == SQL_MAXVALUE);
343 : } else {
344 12 : pmin = exp_atom(sql->sa, atom_general(sql->sa, &tpe, NULL));
345 12 : pmax = exp_atom(sql->sa, atom_general(sql->sa, &tpe, NULL));
346 : }
347 :
348 : /* generate the psm statement */
349 203 : append(exps, exp_atom_clob(sql->sa, sname));
350 203 : append(exps, exp_atom_clob(sql->sa, tname));
351 203 : assert((sname2 && tname2) || (!sname2 && !tname2));
352 203 : if (sname2) {
353 203 : append(exps, exp_atom_clob(sql->sa, sname2));
354 203 : append(exps, exp_atom_clob(sql->sa, tname2));
355 : }
356 203 : append(exps, pmin);
357 203 : append(exps, pmax);
358 203 : append(exps, is_bit_nil(with_nills) ? exp_atom(sql->sa, atom_general(sql->sa, sql_bind_localtype("bit"), NULL)) : exp_atom_bool(sql->sa, with_nills));
359 203 : append(exps, exp_atom_int(sql->sa, update));
360 203 : rel_psm->l = NULL;
361 203 : rel_psm->r = NULL;
362 203 : rel_psm->op = op_ddl;
363 203 : rel_psm->flag = ddl_alter_table_add_range_partition;
364 203 : rel_psm->exps = exps;
365 203 : rel_psm->card = CARD_MULTI;
366 203 : rel_psm->nrcols = 0;
367 :
368 203 : if (!is_bit_nil(with_nills)) {
369 198 : bool min_max_equal = false;
370 198 : if (pmin && pmax && pmin->type == e_atom && pmax->type == e_atom && pmin->l && pmax->l) {
371 155 : atom *e1 = pmin->l, *e2 = pmax->l;
372 155 : min_max_equal = ATOMcmp(tpe.type->localtype, &e1->data.val, &e2->data.val) == 0;
373 : }
374 222 : check_count = create_range_partition_anti_rel(query, mt, pt, with_nills, (min && max) ? pmin : NULL, (min && max) ? pmax : NULL, all_ranges, min_max_equal);
375 : }
376 203 : return propagate_validation_to_upper_tables(query, mt, pt, rel_psm, check_count); /* this adds the check_count to the rel_psm exps list */
377 : }
378 :
379 : sql_rel *
380 56 : rel_alter_table_add_partition_list(sql_query *query, sql_table *mt, sql_table *pt, char *sname, char *tname, char *sname2,
381 : char *tname2, dlist* values, bit with_nills, int update)
382 : {
383 56 : mvc *sql = query->sql;
384 56 : sql_rel *rel_psm = rel_create(sql->sa);
385 56 : list *exps = new_exp_list(sql->sa), *lvals = new_exp_list(sql->sa);
386 56 : sql_subtype tpe;
387 56 : sql_exp *converted_values = NULL;
388 :
389 56 : if (!rel_psm || !exps)
390 : return NULL;
391 :
392 56 : find_partition_type(&tpe, mt);
393 :
394 56 : if (values) {
395 217 : for (dnode *dn = values->h; dn ; dn = dn->next) { /* parse the atoms and generate the expressions */
396 166 : symbol* next = dn->data.sym;
397 166 : sql_exp *pnext = generate_partition_limits(query, &rel_psm, next, tpe, true);
398 :
399 166 : if (!pnext)
400 : return NULL;
401 165 : if (next->token == SQL_NULL)
402 1 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: a list value cannot be null");
403 164 : append(lvals, pnext);
404 : }
405 : }
406 :
407 54 : converted_values = exp_values(sql->sa, lvals);
408 54 : if (!(converted_values = exp_values_set_supertype(sql, converted_values, &tpe)))
409 : return NULL;
410 215 : for (node *n = ((list*)converted_values->f)->h ; n ; n = n->next)
411 161 : if (!(n->data = exp_check_type(sql, &tpe, NULL, n->data, type_equal)))
412 : return NULL;
413 :
414 : /* generate the psm statement */
415 54 : append(exps, exp_atom_clob(sql->sa, sname));
416 54 : append(exps, exp_atom_clob(sql->sa, tname));
417 54 : assert((sname2 && tname2) || (!sname2 && !tname2));
418 54 : if (sname2) {
419 54 : append(exps, exp_atom_clob(sql->sa, sname2));
420 54 : append(exps, exp_atom_clob(sql->sa, tname2));
421 : }
422 54 : append(exps, exp_atom_bool(sql->sa, with_nills));
423 54 : append(exps, exp_atom_int(sql->sa, update));
424 54 : rel_psm->l = NULL;
425 54 : rel_psm->r = NULL;
426 54 : rel_psm->op = op_ddl;
427 54 : rel_psm->flag = ddl_alter_table_add_list_partition;
428 54 : rel_psm->exps = exps;
429 54 : rel_psm->card = CARD_MULTI;
430 54 : rel_psm->nrcols = 0;
431 :
432 54 : sql_exp *check_count = create_list_partition_anti_rel(query, mt, pt, with_nills, exps_copy(sql, (list*)converted_values->f));
433 54 : rel_psm = propagate_validation_to_upper_tables(query, mt, pt, rel_psm, check_count); /* this adds check_count to the rel_psm exps list */
434 54 : rel_psm->exps = list_merge(rel_psm->exps, converted_values->f, (fdup)NULL);
435 54 : return rel_psm;
436 : }
437 :
438 : static sql_rel* rel_change_base_table(mvc* sql, sql_rel* rel, sql_table* oldt, sql_table* newt);
439 :
440 : static sql_exp*
441 201 : exp_change_column_table(mvc *sql, sql_exp *e, sql_table* oldt, sql_table* newt)
442 : {
443 201 : if (mvc_highwater(sql))
444 0 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
445 :
446 201 : if (!e)
447 : return NULL;
448 201 : switch(e->type) {
449 0 : case e_psm: {
450 0 : if (e->flag & PSM_RETURN) {
451 0 : for (node *n = ((list*)e->r)->h ; n ; n = n->next)
452 0 : n->data = exp_change_column_table(sql, (sql_exp*) n->data, oldt, newt);
453 0 : } else if (e->flag & PSM_WHILE) {
454 0 : e->l = exp_change_column_table(sql, e->l, oldt, newt);
455 0 : for (node *n = ((list*)e->r)->h ; n ; n = n->next)
456 0 : n->data = exp_change_column_table(sql, (sql_exp*) n->data, oldt, newt);
457 0 : } else if (e->flag & PSM_IF) {
458 0 : e->l = exp_change_column_table(sql, e->l, oldt, newt);
459 0 : for (node *n = ((list*)e->r)->h ; n ; n = n->next)
460 0 : n->data = exp_change_column_table(sql, (sql_exp*) n->data, oldt, newt);
461 0 : if (e->f)
462 0 : for (node *n = ((list*)e->f)->h ; n ; n = n->next)
463 0 : n->data = exp_change_column_table(sql, (sql_exp*) n->data, oldt, newt);
464 0 : } else if (e->flag & PSM_REL) {
465 0 : rel_change_base_table(sql, e->l, oldt, newt);
466 0 : } else if (e->flag & PSM_EXCEPTION) {
467 0 : e->l = exp_change_column_table(sql, e->l, oldt, newt);
468 : }
469 : } break;
470 3 : case e_convert: {
471 3 : e->l = exp_change_column_table(sql, e->l, oldt, newt);
472 3 : } break;
473 44 : case e_atom: {
474 44 : if (e->f)
475 0 : for (node *n = ((list*)e->f)->h ; n ; n = n->next)
476 0 : n->data = exp_change_column_table(sql, (sql_exp*) n->data, oldt, newt);
477 : } break;
478 7 : case e_aggr:
479 : case e_func: {
480 7 : if (e->l)
481 21 : for (node *n = ((list*)e->l)->h ; n ; n = n->next)
482 14 : n->data = exp_change_column_table(sql, (sql_exp*) n->data, oldt, newt);
483 7 : if (e->type == e_func && e->r)
484 0 : for (node *n = ((list*)e->r)->h ; n ; n = n->next)
485 0 : n->data = exp_change_column_table(sql, (sql_exp*) n->data, oldt, newt);
486 : } break;
487 126 : case e_column: {
488 126 : if (!strcmp(e->l, oldt->base.name))
489 126 : e->l = sa_strdup(sql->sa, newt->base.name);
490 : } break;
491 21 : case e_cmp: {
492 21 : if (e->flag == cmp_in || e->flag == cmp_notin) {
493 2 : e->l = exp_change_column_table(sql, e->l, oldt, newt);
494 6 : for (node *n = ((list*)e->r)->h ; n ; n = n->next)
495 4 : n->data = exp_change_column_table(sql, (sql_exp*) n->data, oldt, newt);
496 19 : } else if (e->flag == cmp_or || e->flag == cmp_filter) {
497 0 : for (node *n = ((list*)e->l)->h ; n ; n = n->next)
498 0 : n->data = exp_change_column_table(sql, (sql_exp*) n->data, oldt, newt);
499 0 : for (node *n = ((list*)e->r)->h ; n ; n = n->next)
500 0 : n->data = exp_change_column_table(sql, (sql_exp*) n->data, oldt, newt);
501 : } else {
502 19 : if (e->l)
503 19 : e->l = exp_change_column_table(sql, e->l, oldt, newt);
504 19 : if (e->r)
505 19 : e->r = exp_change_column_table(sql, e->r, oldt, newt);
506 19 : if (e->f)
507 0 : e->f = exp_change_column_table(sql, e->f, oldt, newt);
508 : }
509 : } break;
510 : }
511 201 : if (exp_relname(e) && !strcmp(exp_relname(e), oldt->base.name))
512 142 : exp_setname(sql->sa, e, newt->base.name, NULL);
513 : return e;
514 : }
515 :
516 : static sql_rel*
517 69 : rel_change_base_table(mvc* sql, sql_rel* rel, sql_table* oldt, sql_table* newt)
518 : {
519 69 : if (mvc_highwater(sql))
520 0 : return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: running out of stack space");
521 :
522 69 : if (!rel)
523 : return NULL;
524 :
525 69 : if (rel->exps) {
526 177 : for (node *n = rel->exps->h ; n ; n = n->next)
527 108 : n->data = exp_change_column_table(sql, (sql_exp*) n->data, oldt, newt);
528 69 : list_hash_clear(rel->exps);
529 : }
530 :
531 69 : switch (rel->op) {
532 24 : case op_basetable:
533 24 : if (rel->l == oldt)
534 24 : rel->l = newt;
535 : break;
536 0 : case op_table:
537 0 : if (IS_TABLE_PROD_FUNC(rel->flag) || rel->flag == TABLE_FROM_RELATION) {
538 0 : if (rel->l)
539 0 : rel->l = rel_change_base_table(sql, rel->l, oldt, newt);
540 : }
541 : break;
542 0 : case op_join:
543 : case op_left:
544 : case op_right:
545 : case op_full:
546 : case op_semi:
547 : case op_anti:
548 : case op_union:
549 : case op_inter:
550 : case op_except:
551 : case op_insert:
552 : case op_update:
553 : case op_delete:
554 : case op_merge:
555 0 : if (rel->l)
556 0 : rel->l = rel_change_base_table(sql, rel->l, oldt, newt);
557 0 : if (rel->r)
558 0 : rel->r = rel_change_base_table(sql, rel->r, oldt, newt);
559 : break;
560 45 : case op_groupby:
561 : case op_project:
562 : case op_select:
563 : case op_topn:
564 : case op_sample:
565 : case op_truncate:
566 45 : if (rel->l)
567 45 : rel->l = rel_change_base_table(sql, rel->l, oldt, newt);
568 : break;
569 0 : case op_ddl:
570 0 : if (rel->flag == ddl_output || rel->flag == ddl_create_seq || rel->flag == ddl_alter_seq || rel->flag == ddl_alter_table || rel->flag == ddl_create_table || rel->flag == ddl_create_view) {
571 0 : if (rel->l)
572 0 : rel->l = rel_change_base_table(sql, rel->l, oldt, newt);
573 : } else if (rel->flag == ddl_list || rel->flag == ddl_exception) {
574 0 : if (rel->l)
575 0 : rel->l = rel_change_base_table(sql, rel->l, oldt, newt);
576 0 : if (rel->r)
577 0 : rel->r = rel_change_base_table(sql, rel->r, oldt, newt);
578 : }
579 : break;
580 : }
581 : return rel;
582 : }
583 :
584 : static sql_rel *
585 17 : rel_truncate_duplicate(mvc *sql, sql_rel *table, sql_rel *ori)
586 : {
587 17 : sql_rel *r = rel_create(sql->sa);
588 :
589 17 : r->exps = exps_copy(sql, ori->exps);
590 17 : r->op = op_truncate;
591 17 : r->l = table;
592 17 : r->r = NULL;
593 17 : return r;
594 : }
595 :
596 : static sql_rel*
597 21 : rel_generate_subdeletes(mvc *sql, sql_rel *rel, sql_table *t, int *changes)
598 : {
599 21 : int just_one = 1;
600 21 : sql_rel *sel = NULL;
601 :
602 56 : for (node *n = t->members->h; n; n = n->next) {
603 35 : sql_part *pt = (sql_part *) n->data;
604 35 : sql_table *sub = find_sql_table_id(sql->session->tr, t->s, pt->member);
605 35 : sql_rel *s1, *dup = NULL;
606 :
607 69 : if (!update_allowed(sql, sub, sub->base.name, is_delete(rel->op) ? "DELETE": "TRUNCATE",
608 35 : is_delete(rel->op) ? "delete": "truncate", is_delete(rel->op) ? 1 : 2))
609 : return NULL;
610 :
611 35 : if (rel->r) {
612 8 : dup = rel_copy(sql, rel->r, 1);
613 8 : dup = rel_change_base_table(sql, dup, t, sub);
614 : }
615 35 : if (is_delete(rel->op))
616 18 : s1 = rel_delete(sql->sa, rel_basetable(sql, sub, sub->base.name), dup);
617 : else
618 17 : s1 = rel_truncate_duplicate(sql, rel_basetable(sql, sub, sub->base.name), rel);
619 35 : if (just_one == 0) {
620 14 : sel = rel_list(sql->sa, sel, s1);
621 : } else {
622 : sel = s1;
623 : just_one = 0;
624 : }
625 35 : (*changes)++;
626 : }
627 21 : rel_destroy(rel);
628 21 : return sel;
629 : }
630 :
631 : static sql_rel*
632 11 : rel_generate_subupdates(mvc *sql, sql_rel *rel, sql_table *t, int *changes)
633 : {
634 11 : int just_one = 1;
635 11 : sql_rel *sel = NULL;
636 :
637 27 : for (node *n = t->members->h; n; n = n->next) {
638 16 : sql_part *pt = (sql_part *) n->data;
639 16 : sql_table *sub = find_sql_table_id(sql->session->tr, t->s, pt->member);
640 16 : sql_rel *s1, *dup = NULL;
641 16 : list *uexps = exps_copy(sql, rel->exps), *checked_updates = new_exp_list(sql->sa);
642 16 : sql_rel *bt = rel_basetable(sql, sub, sub->base.name);
643 :
644 16 : if (!update_allowed(sql, sub, sub->base.name, "UPDATE", "update", 0))
645 : return NULL;
646 :
647 48 : for (node *n = uexps->h ; n ; n = n->next) {
648 32 : sql_exp *e = (sql_exp *) n->data;
649 32 : const char *cname = exp_name(e);
650 :
651 32 : if (cname[0] != '%') { /* Skip TID column */
652 16 : sql_column *c = mvc_bind_column(sql, sub, cname);
653 :
654 16 : if (!c)
655 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "UPDATE: no such column '%s.%s'\n", sub->base.name, cname);
656 16 : rel_base_use(sql, bt, c->colnr);
657 16 : if (!(e = update_check_column(sql, sub, c, e, rel, c->base.name, "UPDATE")))
658 : return NULL;
659 : }
660 32 : list_append(checked_updates, e);
661 : }
662 :
663 16 : if (rel->r) {
664 16 : dup = rel_copy(sql, rel->r, 1);
665 16 : dup = rel_change_base_table(sql, dup, t, sub);
666 : }
667 :
668 48 : for (node *ne = checked_updates->h ; ne ; ne = ne->next)
669 32 : ne->data = exp_change_column_table(sql, (sql_exp*) ne->data, t, sub);
670 :
671 16 : s1 = rel_update(sql, bt, dup, NULL, checked_updates);
672 16 : if (just_one == 0) {
673 5 : sel = rel_list(sql->sa, sel, s1);
674 : } else {
675 : sel = s1;
676 : just_one = 0;
677 : }
678 16 : (*changes)++;
679 : }
680 11 : rel_destroy(rel);
681 11 : return sel;
682 : }
683 :
684 : static sql_rel*
685 97 : rel_generate_subinserts(sql_query *query, sql_rel *rel, sql_table *t, int *changes,
686 : const char *operation, const char *desc)
687 : {
688 97 : mvc *sql = query->sql;
689 97 : int just_one = 1, found_nils = 0, found_all_range_values = 0;
690 97 : sql_rel *new_table = NULL, *sel = NULL, *anti_rel = NULL;
691 97 : sql_exp *anti_exp = NULL, *anti_le = NULL, *anti_nils = NULL, *accum = NULL, *aggr = NULL;
692 97 : list *anti_exps = new_exp_list(sql->sa);
693 97 : sql_subfunc *cf = sql_bind_func(sql, "sys", "count", sql_bind_localtype("void"), NULL, F_AGGR, true);
694 97 : char buf[BUFSIZ];
695 97 : sql_subtype tp;
696 :
697 97 : find_partition_type(&tp, t);
698 97 : if (isPartitionedByColumnTable(t)) {
699 87 : anti_rel = rel_dup(rel->r);
700 10 : } else if (isPartitionedByExpressionTable(t)) {
701 10 : anti_rel = rel_create_common_relation(sql, rel, t);
702 10 : if (!anti_rel)
703 : return NULL;
704 : } else {
705 0 : assert(0);
706 : }
707 97 : anti_le = rel_generate_anti_insert_expression(sql, &anti_rel, t);
708 :
709 291 : for (node *n = t->members->h; n; n = n->next) {
710 196 : sql_part *pt = (sql_part *) n->data;
711 196 : sql_table *sub = find_sql_table_id(sql->session->tr, t->s, pt->member);
712 196 : sql_rel *s1 = NULL, *dup = NULL;
713 196 : sql_exp *le = NULL;
714 :
715 196 : if (!insert_allowed(sql, sub, sub->base.name, "INSERT", "insert"))
716 2 : return NULL;
717 :
718 194 : if (isPartitionedByColumnTable(t)) {
719 177 : dup = rel_dup(rel->r);
720 177 : le = rel_generate_anti_insert_expression(sql, &dup, t);
721 17 : } else if (isPartitionedByExpressionTable(t)) {
722 17 : dup = rel_dup(anti_rel);
723 17 : le = anti_le;
724 : } else {
725 0 : assert(0);
726 : }
727 :
728 194 : if (isRangePartitionTable(t)) {
729 114 : sql_exp *range = NULL, *full_range = NULL;
730 114 : int tpe = tp.type->localtype;
731 114 : int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
732 114 : const void *nil = ATOMnilptr(tpe);
733 114 : bool is_min_nil = atomcmp(pt->part.range.minvalue, nil) == 0, is_max_nil = atomcmp(pt->part.range.maxvalue, nil) == 0;
734 :
735 114 : if (is_min_nil && is_max_nil) {
736 8 : found_all_range_values |= (pt->with_nills != 1);
737 8 : found_nils |= is_bit_nil(pt->with_nills);
738 8 : if (pt->with_nills == false) { /* full range without nils */
739 2 : sql_exp *nils = rel_unop_(sql, dup, le, "sys", "isnull", card_value);
740 :
741 2 : set_has_no_nil(nils);
742 2 : nils = exp_compare(sql->sa, nils, exp_atom_bool(sql->sa, 0), cmp_equal);
743 2 : full_range = range = nils; /* ugh */
744 : }
745 106 : } else if (is_min_nil) {
746 1 : full_range = range = exp_compare(sql->sa, le, exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, pt->part.range.maxvalue)), cmp_lt);
747 105 : } else if (is_max_nil) {
748 5 : full_range = range = exp_compare(sql->sa, le, exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, pt->part.range.minvalue)), cmp_gte);
749 : } else {
750 100 : bool max_equal_min = ATOMcmp(tpe, pt->part.range.maxvalue, pt->part.range.minvalue) == 0;
751 :
752 100 : full_range = range = max_equal_min ?
753 100 : exp_compare(sql->sa, le, exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, pt->part.range.minvalue)), cmp_equal) :
754 100 : exp_compare2(sql->sa, le, exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, pt->part.range.minvalue)),
755 : exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, pt->part.range.maxvalue)), 1, 0);
756 : }
757 114 : if (pt->with_nills == true) { /* handle the nulls case */
758 19 : sql_exp *nils = rel_unop_(sql, dup, le, "sys", "isnull", card_value);
759 :
760 19 : set_has_no_nil(nils);
761 19 : nils = exp_compare(sql->sa, nils, exp_atom_bool(sql->sa, 1), cmp_equal);
762 19 : if (full_range) {
763 14 : full_range = exp_or(sql->sa, list_append(new_exp_list(sql->sa), full_range),
764 : list_append(new_exp_list(sql->sa), nils), 0);
765 : } else {
766 : full_range = nils;
767 : }
768 : found_nils = 1;
769 : }
770 114 : if (accum && range) {
771 55 : accum = exp_or(sql->sa, list_append(new_exp_list(sql->sa), accum),
772 55 : list_append(new_exp_list(sql->sa), exp_copy(sql, range)), 0);
773 59 : } else if (range) {
774 53 : accum = exp_copy(sql, range);
775 : }
776 114 : if (full_range) {
777 113 : dup = rel_select(sql->sa, dup, full_range);
778 113 : set_processed(dup);
779 : }
780 80 : } else if (isListPartitionTable(t)) {
781 80 : sql_exp *ein = NULL;
782 :
783 80 : if (list_length(pt->part.values)) { /* if the partition holds non-null values */
784 78 : list *exps = new_exp_list(sql->sa);
785 312 : for (node *nn = pt->part.values->h ; nn ; nn = nn->next) {
786 234 : sql_part_value *next = (sql_part_value*) nn->data;
787 234 : sql_exp *e1 = exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, next->value));
788 234 : list_append(exps, e1);
789 234 : list_append(anti_exps, exp_copy(sql, e1));
790 : }
791 78 : ein = exp_in(sql->sa, le, exps, cmp_in);
792 : } else {
793 2 : assert(pt->with_nills);
794 : }
795 80 : if (pt->with_nills) { /* handle the nulls case */
796 19 : sql_exp *nils = rel_unop_(sql, dup, le, "sys", "isnull", card_value);
797 :
798 19 : set_has_no_nil(nils);
799 19 : nils = exp_compare(sql->sa, nils, exp_atom_bool(sql->sa, 1), cmp_equal);
800 19 : if (ein) {
801 17 : ein = exp_or(sql->sa, list_append(new_exp_list(sql->sa), ein),
802 : list_append(new_exp_list(sql->sa), nils), 0);
803 : } else {
804 : ein = nils;
805 : }
806 : found_nils = 1;
807 : }
808 80 : dup = rel_select(sql->sa, dup, ein);
809 80 : set_processed(dup);
810 : } else {
811 0 : assert(0);
812 : }
813 :
814 194 : new_table = rel_basetable(sql, sub, sub->base.name);
815 194 : rel_base_use_all(query->sql, new_table);
816 194 : new_table = rewrite_basetable(query->sql, new_table);
817 194 : new_table->p = prop_create(sql->sa, PROP_USED, new_table->p); /* don't create infinite loops in the optimizer */
818 :
819 194 : if (isPartitionedByExpressionTable(t)) {
820 17 : sql_exp *del;
821 17 : dup = rel_project(sql->sa, dup, rel_projections(sql, dup, NULL, 1, 1));
822 17 : del = list_fetch(dup->exps, list_length(dup->exps) - 1);
823 17 : list_remove_data(dup->exps, NULL, del);
824 : }
825 :
826 194 : s1 = rel_insert(query->sql, new_table, dup);
827 194 : if (just_one == 0) {
828 99 : sel = rel_list(sql->sa, sel, s1);
829 : } else {
830 : sel = s1;
831 : just_one = 0;
832 : }
833 194 : (*changes)++;
834 : }
835 :
836 95 : if (!found_all_range_values || !found_nils) {
837 : /* generate the exception */
838 93 : if (isRangePartitionTable(t)) {
839 54 : if (accum) {
840 52 : set_anti(accum);
841 52 : anti_exp = accum;
842 : }
843 39 : } else if (isListPartitionTable(t)) {
844 39 : if (list_length(anti_exps))
845 38 : anti_exp = exp_in(sql->sa, anti_le, anti_exps, cmp_notin);
846 : } else {
847 0 : assert(0);
848 : }
849 93 : if (!found_nils) {
850 56 : assert(anti_exp);
851 56 : anti_nils = rel_unop_(sql, NULL, anti_le, "sys", "isnull", card_value);
852 56 : set_has_no_nil(anti_nils);
853 56 : anti_nils = exp_compare(sql->sa, anti_nils, exp_atom_bool(sql->sa, 1), cmp_equal);
854 56 : anti_exp = exp_or(sql->sa, list_append(new_exp_list(sql->sa), anti_exp),
855 : list_append(new_exp_list(sql->sa), anti_nils), 0);
856 37 : } else if (!anti_exp) {
857 3 : anti_nils = rel_unop_(sql, NULL, exp_copy(sql, anti_le), "sys", "isnull", card_value);
858 3 : set_has_no_nil(anti_nils);
859 3 : anti_exp = exp_compare(sql->sa, anti_nils, exp_atom_bool(sql->sa, 0), cmp_equal);
860 : }
861 : /* generate a count aggregation for the values not present in any of the partitions */
862 93 : anti_rel = rel_select(sql->sa, anti_rel, anti_exp);
863 93 : set_processed(anti_rel);
864 93 : anti_rel = rel_groupby(sql, anti_rel, NULL);
865 93 : aggr = exp_aggr(sql->sa, NULL, cf, 0, 0, anti_rel->card, 0);
866 93 : (void) rel_groupby_add_aggr(sql, anti_rel, aggr);
867 93 : set_processed(anti_rel);
868 93 : exp_label(sql->sa, aggr, ++sql->label);
869 :
870 93 : aggr = exp_ref(sql, aggr);
871 186 : snprintf(buf, BUFSIZ, "%s: the %s violates the partition %s of values", operation, desc,
872 93 : isRangePartitionTable(t) ? "range (NB higher limit exclusive)" : "list");
873 :
874 93 : sql_exp *exception = exp_exception(sql->sa, aggr, buf);
875 93 : sel = rel_exception(query->sql->sa, sel, anti_rel, list_append(new_exp_list(query->sql->sa), exception));
876 : }
877 95 : rel_destroy(rel);
878 95 : return sel;
879 : }
880 :
881 : static sql_rel*
882 97 : rel_propagate_insert(sql_query *query, sql_rel *rel, sql_table *t, int *changes)
883 : {
884 97 : return rel_generate_subinserts(query, rel, t, changes, "INSERT", "insert");
885 : }
886 :
887 : static sql_rel*
888 21 : rel_propagate_delete(mvc *sql, sql_rel *rel, sql_table *t, int *changes)
889 : {
890 21 : return rel_generate_subdeletes(sql, rel, t, changes);
891 : }
892 :
893 : static bool
894 11 : update_move_across_partitions(sql_rel *rel, sql_table *t)
895 : {
896 33 : for (node *n = ((sql_rel*)rel->r)->exps->h; n; n = n->next) {
897 22 : sql_exp* exp = (sql_exp*) n->data;
898 22 : if (exp->type == e_column && exp->l && exp->r && !strcmp((char*)exp->l, t->base.name)) {
899 11 : char* colname = (char*)exp->r;
900 :
901 11 : if (isPartitionedByColumnTable(t)) {
902 8 : if (!strcmp(colname, t->part.pcol->base.name))
903 : return true;
904 3 : } else if (isPartitionedByExpressionTable(t)) {
905 6 : for (node *nn = t->part.pexp->cols->h; nn; nn = nn->next) {
906 3 : int next = *(int*) nn->data;
907 3 : sql_column *col = find_sql_column(t, colname);
908 3 : if (col && next == col->colnr)
909 : return true;
910 : }
911 : } else {
912 0 : assert(0);
913 : }
914 : }
915 : }
916 : return false;
917 : }
918 :
919 : static sql_rel*
920 11 : rel_propagate_update(mvc *sql, sql_rel *rel, sql_table *t, int *changes)
921 : {
922 11 : bool found_partition_col = update_move_across_partitions(rel, t);
923 11 : sql_rel *sel = NULL;
924 :
925 11 : if (!found_partition_col) { /* easy scenario where the partitioned column is not being updated, just propagate */
926 11 : sel = rel_generate_subupdates(sql, rel, t, changes);
927 : } else { /* harder scenario, has to insert and delete across partitions. */
928 : /*sql_exp *exception = NULL;
929 : sql_rel *inserts = NULL, *deletes = NULL, *anti_rel = NULL;
930 :
931 : deletes = rel_generate_subdeletes(sql, rel, t, changes);
932 : inserts = rel_generate_subinserts(query, rel, &anti_rel, &exception, t, changes, "UPDATE", "update");
933 : inserts = rel_exception(sql->sa, inserts, anti_rel, list_append(new_exp_list(sql->sa), exception));
934 : return rel_list(sql->sa, deletes, inserts);*/
935 0 : assert(0);
936 : }
937 11 : return sel;
938 : }
939 :
940 : static sql_rel*
941 103 : rel_subtable_insert(sql_query *query, sql_rel *rel, sql_table *t, int *changes)
942 : {
943 103 : mvc *sql = query->sql;
944 103 : sql_part *upper = partition_find_part(sql->session->tr, t, NULL);
945 103 : if (!upper)
946 : return NULL;
947 103 : sql_part *pt = upper;
948 103 : sql_rel *anti_dup = rel_create_common_relation(sql, rel, upper->t), *left = rel->l;
949 103 : if (!anti_dup)
950 : return NULL;
951 57 : sql_exp *anti_exp = NULL, *anti_le = rel_generate_anti_insert_expression(sql, &anti_dup, upper->t), *aggr = NULL,
952 57 : *exception = NULL, *anti_nils = NULL;
953 57 : list *anti_exps = new_exp_list(sql->sa);
954 57 : sql_subfunc *cf = sql_bind_func(sql, "sys", "count", sql_bind_localtype("void"), NULL, F_AGGR, true);
955 57 : char buf[BUFSIZ];
956 57 : bool found_nils = false, found_all_range_values = false;
957 57 : sql_subtype tp;
958 :
959 57 : find_partition_type(&tp, upper->t);
960 57 : if (isRangePartitionTable(upper->t)) {
961 37 : int tpe = tp.type->localtype;
962 37 : int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
963 37 : const void *nil = ATOMnilptr(tpe);
964 :
965 37 : if (pt->with_nills == true || is_bit_nil(pt->with_nills))
966 : found_nils = true;
967 :
968 37 : if (atomcmp(pt->part.range.minvalue, nil) == 0) {
969 7 : if (atomcmp(pt->part.range.maxvalue, nil) == 0) {
970 7 : found_all_range_values = pt->with_nills != 1;
971 7 : if (pt->with_nills == true) {
972 4 : anti_nils = rel_unop_(sql, anti_dup, exp_copy(sql, anti_le), "sys", "isnull", card_value);
973 4 : set_has_no_nil(anti_nils);
974 4 : anti_exp = exp_compare(sql->sa, anti_nils, exp_atom_bool(sql->sa, 0), cmp_equal);
975 : }
976 : } else {
977 0 : sql_exp *e2 = exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, pt->part.range.maxvalue));
978 0 : anti_exp = exp_compare(sql->sa, exp_copy(sql, anti_le), e2, cmp_gte);
979 : }
980 : } else {
981 30 : if (atomcmp(pt->part.range.maxvalue, nil) == 0) {
982 2 : sql_exp *e1 = exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, pt->part.range.minvalue));
983 2 : anti_exp = exp_compare(sql->sa, exp_copy(sql, anti_le), e1, cmp_lt);
984 : } else {
985 28 : sql_exp *e1 = exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, pt->part.range.minvalue));
986 28 : bool max_equal_min = ATOMcmp(tpe, pt->part.range.maxvalue, pt->part.range.minvalue) == 0;
987 :
988 28 : if (max_equal_min) {
989 0 : anti_exp = exp_compare(sql->sa, exp_copy(sql, anti_le), e1, cmp_notequal);
990 : } else {
991 28 : sql_exp *e2 = exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, pt->part.range.maxvalue)),
992 28 : *range1 = exp_compare(sql->sa, exp_copy(sql, anti_le), e1, cmp_lt),
993 28 : *range2 = exp_compare(sql->sa, exp_copy(sql, anti_le), e2, cmp_gte);
994 :
995 28 : anti_exp = exp_or(sql->sa, list_append(new_exp_list(sql->sa), range1),
996 : list_append(new_exp_list(sql->sa), range2), 0);
997 : }
998 : }
999 : }
1000 37 : if (!pt->with_nills) { /* handle the nulls case */
1001 30 : anti_nils = rel_unop_(sql, anti_dup, exp_copy(sql, anti_le), "sys", "isnull", card_value);
1002 30 : set_has_no_nil(anti_nils);
1003 30 : anti_nils = exp_compare(sql->sa, anti_nils, exp_atom_bool(sql->sa, 1), cmp_equal);
1004 30 : if (anti_exp)
1005 28 : anti_exp = exp_or(sql->sa, list_append(new_exp_list(sql->sa), anti_exp),
1006 : list_append(new_exp_list(sql->sa), anti_nils), 0);
1007 : else
1008 : anti_exp = anti_nils;
1009 : }
1010 20 : } else if (isListPartitionTable(upper->t)) {
1011 20 : if (list_length(pt->part.values)) { /* if the partition holds non-null values */
1012 79 : for (node *n = pt->part.values->h ; n ; n = n->next) {
1013 60 : sql_part_value *next = (sql_part_value*) n->data;
1014 60 : sql_exp *e1 = exp_atom(sql->sa, atom_general_ptr(sql->sa, &tp, next->value));
1015 60 : list_append(anti_exps, exp_copy(sql, e1));
1016 : }
1017 19 : anti_exp = exp_in(sql->sa, exp_copy(sql, anti_le), anti_exps, cmp_notin);
1018 :
1019 19 : if (!pt->with_nills) { /* handle the nulls case */
1020 16 : anti_nils = rel_unop_(sql, anti_dup, exp_copy(sql, anti_le), "sys", "isnull", card_value);
1021 16 : set_has_no_nil(anti_nils);
1022 16 : anti_nils = exp_compare(sql->sa, anti_nils, exp_atom_bool(sql->sa, 1), cmp_equal);
1023 16 : anti_exp = exp_or(sql->sa, list_append(new_exp_list(sql->sa), anti_exp),
1024 : list_append(new_exp_list(sql->sa), anti_nils), 0);
1025 : }
1026 : } else {
1027 1 : assert(pt->with_nills);
1028 1 : anti_nils = rel_unop_(sql, anti_dup, exp_copy(sql, anti_le), "sys", "isnull", card_value);
1029 1 : set_has_no_nil(anti_nils);
1030 1 : anti_exp = exp_compare(sql->sa, anti_nils, exp_atom_bool(sql->sa, 0), cmp_equal);
1031 : }
1032 : } else {
1033 0 : assert(0);
1034 : }
1035 :
1036 57 : if (!found_all_range_values || !found_nils) {
1037 : /* generate a count aggregation for the values not present in any of the partitions */
1038 56 : anti_dup = rel_select(sql->sa, anti_dup, anti_exp);
1039 56 : set_processed(anti_dup);
1040 56 : anti_dup = rel_groupby(sql, anti_dup, NULL);
1041 56 : aggr = exp_aggr(sql->sa, NULL, cf, 0, 0, anti_dup->card, 0);
1042 56 : (void) rel_groupby_add_aggr(sql, anti_dup, aggr);
1043 56 : exp_label(sql->sa, aggr, ++sql->label);
1044 56 : set_processed(anti_dup);
1045 :
1046 : /* generate the exception */
1047 56 : aggr = exp_ref(sql, aggr);
1048 112 : snprintf(buf, BUFSIZ, "INSERT: table %s.%s is part of merge table %s.%s and the insert violates the "
1049 56 : "partition %s of values", t->s->base.name, t->base.name, upper->t->s->base.name,
1050 56 : upper->t->base.name, isRangePartitionTable(upper->t) ? "range" : "list");
1051 56 : exception = exp_exception(sql->sa, aggr, buf);
1052 :
1053 56 : left->p = prop_create(sql->sa, PROP_USED, left->p);
1054 56 : (*changes)++;
1055 :
1056 56 : rel = rel_exception(sql->sa, rel, anti_dup, list_append(new_exp_list(sql->sa), exception));
1057 : }
1058 : return rel;
1059 : }
1060 :
1061 : static sql_rel*
1062 57 : rel_find_propagate( sql_rel *rel)
1063 : {
1064 57 : if (is_ddl(rel->op) && rel->flag == ddl_list)
1065 56 : return rel->r;
1066 1 : if (is_ddl(rel->op) && rel->flag == ddl_exception)
1067 0 : return rel->r;
1068 1 : assert(is_insert(rel->op));
1069 : return rel;
1070 : }
1071 :
1072 : sql_rel *
1073 1079 : rel_propagate(sql_query *query, sql_rel *rel, int *changes)
1074 : {
1075 1079 : mvc *sql = query->sql;
1076 1079 : bool isSubtable = false;
1077 1079 : sql_rel *l = rel->l, *propagate = rel;
1078 :
1079 1079 : if (l->op == op_basetable) {
1080 1031 : sql_table *t = l->l;
1081 :
1082 1031 : if (partition_find_part(sql->session->tr, t, NULL) && !find_prop(l->p, PROP_USED)) {
1083 197 : isSubtable = true;
1084 197 : if (is_insert(rel->op)) { /* insertion directly to sub-table (must do validation) */
1085 103 : sql_rel *nrel = rel_subtable_insert(query, rel, t, changes);
1086 103 : if (!nrel)
1087 : return rel;
1088 57 : rel = nrel;
1089 57 : propagate = rel_find_propagate(nrel);
1090 57 : isSubtable = (rel != propagate);
1091 : }
1092 : }
1093 985 : if (isMergeTable(t)) {
1094 129 : assert(list_length(t->members));
1095 129 : if (is_delete(propagate->op) || is_truncate(propagate->op)) { /* propagate deletions to the partitions */
1096 21 : rel = rel_propagate_delete(sql, rel, t, changes);
1097 108 : } else if (isRangePartitionTable(t) || isListPartitionTable(t)) {
1098 108 : if (is_insert(propagate->op)) { /* on inserts create a selection for each partition */
1099 97 : if (isSubtable) {
1100 2 : rel->r = rel_propagate_insert(query, propagate, t, changes);
1101 : } else {
1102 95 : rel = rel_propagate_insert(query, rel, t, changes);
1103 : }
1104 11 : } else if (is_update(propagate->op)) { /* for updates propagate like in deletions */
1105 11 : rel = rel_propagate_update(sql, rel, t, changes);
1106 : } else {
1107 0 : assert(0);
1108 : }
1109 : } else {
1110 0 : assert(0);
1111 : }
1112 : }
1113 : }
1114 : return rel;
1115 : }
|