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

Generated by: LCOV version 1.14