LCOV - code coverage report
Current view: top level - sql/server - rel_propagate.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 618 694 89.0 %
Date: 2024-04-25 23:25:41 Functions: 21 21 100.0 %

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

Generated by: LCOV version 1.14