LCOV - code coverage report
Current view: top level - sql/server - rel_propagate.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 545 621 87.8 %
Date: 2021-10-13 02:24:04 Functions: 20 20 100.0 %

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

Generated by: LCOV version 1.14