Changeset: 85f70509ee6b for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=85f70509ee6b Modified Files: sql/backends/monet5/rel_bin.c sql/server/rel_optimizer.c sql/server/rel_select.c sql/server/rel_select.h sql/server/rel_updates.c sql/test/merge-partitions/Tests/mergepart06.sql Branch: merge-partitions Log Message:
Propagate inserts in range partitioned tables. The next step is to handle value partitioned tables and inserts with no partition to go into (error case). diffs (truncated from 331 to 300 lines): diff --git a/sql/backends/monet5/rel_bin.c b/sql/backends/monet5/rel_bin.c --- a/sql/backends/monet5/rel_bin.c +++ b/sql/backends/monet5/rel_bin.c @@ -3326,7 +3326,7 @@ rel2bin_insert(backend *be, sql_rel *rel { mvc *sql = be->mvc; list *l; - stmt *inserts = NULL, *insert = NULL, *s, *ddl = NULL, *pin = NULL, **updates; + stmt *inserts = NULL, *insert = NULL, *s, *ddl = NULL, *pin = NULL, **updates, *ret = NULL; int idx_ins = 0, constraint = 1, len = 0; node *n, *m; sql_rel *tr = rel->l, *prel = rel->r; @@ -3340,6 +3340,10 @@ rel2bin_insert(backend *be, sql_rel *rel rel = rel->r; tr = rel->l; } + + if(find_prop(rel->p, PROP_DISTRIBUTE) && be->cur_append == 0) /* create BAT to hold the sum of affected rows */ + create_append_bat(be, TYPE_lng); + if (tr->op == op_basetable) { t = tr->l; } else { @@ -3408,6 +3412,7 @@ rel2bin_insert(backend *be, sql_rel *rel if (!sql_insert_triggers(be, t, updates, 1)) return sql_error(sql, 02, SQLSTATE(42000) "INSERT INTO: triggers failed for table '%s'", t->base.name); if (ddl) { + ret = ddl; list_prepend(l, ddl); } else { if (insert->op1->nrcols == 0) { @@ -3415,9 +3420,16 @@ rel2bin_insert(backend *be, sql_rel *rel } else { s = stmt_aggr(be, insert->op1, NULL, NULL, sql_bind_aggr(sql->sa, sql->session->schema, "count", NULL), 1, 0, 1); } - return s; + ret = s; } - return stmt_list(be, l); + + if(be->cur_append) //building the total number of rows affected across all tables + ret->nr = append_bat_value(be, TYPE_lng, ret->nr); + + if (ddl) + return stmt_list(be, l); + else + return ret; } static int @@ -4586,7 +4598,7 @@ rel2bin_delete(backend *be, sql_rel *rel else assert(0/*ddl statement*/); - if(find_prop(rel->p, PROP_DISTRIBUTE) && be->cur_append == 0) + if(find_prop(rel->p, PROP_DISTRIBUTE) && be->cur_append == 0) /* create BAT to hold the sum of affected rows */ create_append_bat(be, TYPE_lng); if (rel->r) { /* first construct the deletes relation */ @@ -4784,7 +4796,7 @@ rel2bin_truncate(backend *be, sql_rel *r else assert(0/*ddl statement*/); - if(find_prop(rel->p, PROP_DISTRIBUTE) && be->cur_append == 0) + if(find_prop(rel->p, PROP_DISTRIBUTE) && be->cur_append == 0) /* create BAT to hold the sum of affected rows */ create_append_bat(be, TYPE_lng); n = rel->exps->h; diff --git a/sql/server/rel_optimizer.c b/sql/server/rel_optimizer.c --- a/sql/server/rel_optimizer.c +++ b/sql/server/rel_optimizer.c @@ -15,6 +15,7 @@ #include "rel_prop.h" #include "rel_dump.h" #include "rel_planner.h" +#include "rel_select.h" #include "rel_updates.h" #include "sql_mvc.h" #ifdef HAVE_HGE @@ -8147,41 +8148,134 @@ rel_truncate_duplicate(sql_allocator *sa return r; } +static sql_exp * +create_table_part_atom_exp(mvc *sql, sht tpe, ptr value) +{ + switch (tpe) { + case TYPE_bit: { + bit bval = *((bit*) value); + return exp_atom_bool(sql->sa, bval ? 1 : 0); + } + case TYPE_bte: { + bte bbval = *((bte *) value); + return exp_atom_bte(sql->sa, bbval); + } + case TYPE_sht: { + sht sval = *((sht*) value); + return exp_atom_sht(sql->sa, sval); + } + case TYPE_int: { + int ival = *((int*) value); + return exp_atom_int(sql->sa, ival); + } + case TYPE_lng: { + lng lval = *((lng*) value); + return exp_atom_lng(sql->sa, lval); + } + case TYPE_flt: { + flt fval = *((flt*) value); + return exp_atom_flt(sql->sa, fval); + } + case TYPE_dbl: { + dbl dval = *((dbl*) value); + return exp_atom_dbl(sql->sa, dval); + } + case TYPE_str: + return exp_atom_clob(sql->sa, sa_strdup(sql->sa, value)); +#ifdef HAVE_HGE + case TYPE_hge: { + hge hval = *((hge*) value); + return exp_atom_hge(sql->sa, hval); + } +#endif + default: + assert(0); + } +} + /* rewrite merge tables into union of base tables and call optimizer again */ static sql_rel * rel_merge_table_rewrite(int *changes, mvc *sql, sql_rel *rel) { sql_rel *sel = NULL; - if(is_delete(rel->op) || is_truncate(rel->op)) { + if(is_delete(rel->op) || is_truncate(rel->op) || is_insert(rel->op)) { sql_rel *left = rel->l; - sql_table *t = left->l; - - if(isRangePartitionTable(t) || isListPartitionTable(t)) { //propagate deletions to the partitions - int just_one = 1; - - for (node *n = t->members.set->h; n; n = n->next) { - sql_part *pt = (sql_part *) n->data; - sql_table *sub = find_sql_table(t->s, pt->base.name); - sql_rel *s1, *dup = NULL; - - if(rel->r) { - dup = rel_copy(sql->sa, rel->r); - dup = rel_change_base_table(dup, t, sub); + if(left->op == op_basetable) { + sql_table *t = left->l; + + if(isRangePartitionTable(t) || isListPartitionTable(t)) { + int just_one = 1; + + if(is_delete(rel->op) || is_truncate(rel->op)) { //propagate deletions to the partitions + for (node *n = t->members.set->h; n; n = n->next) { + sql_part *pt = (sql_part *) n->data; + sql_table *sub = find_sql_table(t->s, pt->base.name); + sql_rel *s1, *dup = NULL; + + if(rel->r) { + dup = rel_copy(sql->sa, rel->r); + dup = rel_change_base_table(dup, t, sub); + } + if(is_delete(rel->op)) + s1 = rel_delete(sql->sa, rel_basetable(sql, sub, sub->base.name), dup); + else + s1 = rel_truncate_duplicate(sql->sa, rel_basetable(sql, sub, sub->base.name), rel); + s1->p = prop_create(sql->sa, PROP_DISTRIBUTE, s1->p); + if (just_one == 0) { + sel = rel_setop(sql->sa, sel, s1, op_union); + sel->p = prop_create(sql->sa, PROP_DISTRIBUTE, sel->p); + } else { + sel = s1; + just_one = 0; + } + (*changes)++; + } + } else { //on inserts create a selection for each partition + int colr = t->pcol->colnr; + + for (node *n = t->members.set->h; n; n = n->next) { + sql_part *pt = (sql_part *) n->data; + sql_table *sub = find_sql_table(t->s, pt->base.name); + sql_rel *s1, *dup = rel_dup(rel->r); + sql_exp *le = list_fetch(dup->exps, colr); + le = exp_column(sql->sa, exp_relname(le), exp_name(le), exp_subtype(le), le->card, has_nil(le), is_intern(le)); + + if(isRangePartitionTable(t)) { + sql_exp *e1, *e2; + + e1 = create_table_part_atom_exp(sql, pt->tpe, pt->part.range.minvalue); + e2 = create_table_part_atom_exp(sql, pt->tpe, pt->part.range.maxvalue); + dup = rel_compare_exp_(sql, dup, le, e1, e2, 3, 0); + + if(pt->part.range.with_nills) { /* handle the nulls case */ + sql_rel* extra; + sql_exp *nils = rel_unop_(sql, le, NULL, "isnull", card_value); + nils = exp_compare(sql->sa, nils, exp_atom_bool(sql->sa, 1), cmp_equal); + + extra = rel_select(sql->sa, rel->r, nils); + dup = rel_or(sql, NULL, dup, extra, NULL, NULL, NULL); + } + } else if(isListPartitionTable(t)) { + list *exps = new_exp_list(sql->sa); /* TODO the list should come from the partition itself */ + sql_exp *ein = exp_in(sql->sa, le, exps, cmp_in); + dup = rel_select(sql->sa, dup, ein); + } else { + assert(0); + } + + s1 = rel_insert(sql, rel_basetable(sql, sub, sub->base.name), dup); + s1->p = prop_create(sql->sa, PROP_DISTRIBUTE, s1->p); + if (just_one == 0) { + sel = rel_setop(sql->sa, sel, s1, op_union); + sel->p = prop_create(sql->sa, PROP_DISTRIBUTE, sel->p); + } else { + sel = s1; + just_one = 0; + } + (*changes)++; + } } - if(is_delete(rel->op)) - s1 = rel_delete(sql->sa, rel_basetable(sql, sub, sub->base.name), dup); - else - s1 = rel_truncate_duplicate(sql->sa, rel_basetable(sql, sub, sub->base.name), rel); - s1->p = prop_create(sql->sa, PROP_DISTRIBUTE, s1->p); - if (just_one == 0) { - sel = rel_setop(sql->sa, sel, s1, op_union); - sel->p = prop_create(sql->sa, PROP_DISTRIBUTE, sel->p); - } else { - sel = s1; - just_one = 0; - } - (*changes)++; } } } else { diff --git a/sql/server/rel_select.c b/sql/server/rel_select.c --- a/sql/server/rel_select.c +++ b/sql/server/rel_select.c @@ -1645,7 +1645,7 @@ exp_is_subquery( mvc *sql, sql_exp *e) return 0; } -static sql_rel * +sql_rel * rel_compare_exp_(mvc *sql, sql_rel *rel, sql_exp *ls, sql_exp *rs, sql_exp *rs2, int type, int anti ) { sql_exp *L = ls, *R = rs, *e = NULL; diff --git a/sql/server/rel_select.h b/sql/server/rel_select.h --- a/sql/server/rel_select.h +++ b/sql/server/rel_select.h @@ -12,6 +12,7 @@ #include "rel_semantic.h" #include "sql_semantic.h" +extern sql_rel *rel_compare_exp_(mvc *sql, sql_rel *rel, sql_exp *ls, sql_exp *rs, sql_exp *rs2, int type, int anti); extern sql_rel *rel_selects(mvc *sql, symbol *sym); extern sql_rel *schema_selects(mvc *sql, sql_schema *s, symbol *sym); extern sql_rel * rel_subquery(mvc *sql, sql_rel *rel, symbol *sq, exp_kind ek, int apply); diff --git a/sql/server/rel_updates.c b/sql/server/rel_updates.c --- a/sql/server/rel_updates.c +++ b/sql/server/rel_updates.c @@ -395,7 +395,7 @@ insert_allowed(mvc *sql, sql_table *t, c return sql_error(sql, 02, SQLSTATE(42S02) "%s: no such table '%s'", op, tname); } else if (isView(t)) { return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s view '%s'", op, opname, tname); - } else if (isMergeTable(t)) { + } else if (isNonPartitionedTable(t)) { return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s merge table '%s'", op, opname, tname); } else if (isStream(t)) { return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s stream '%s'", op, opname, tname); diff --git a/sql/test/merge-partitions/Tests/mergepart06.sql b/sql/test/merge-partitions/Tests/mergepart06.sql --- a/sql/test/merge-partitions/Tests/mergepart06.sql +++ b/sql/test/merge-partitions/Tests/mergepart06.sql @@ -1,31 +1,38 @@ CREATE MERGE TABLE testrangelimits (a int, b varchar(32)) PARTITION BY RANGE (a); CREATE TABLE sublimits1 (a int, b varchar(32)); CREATE TABLE sublimits2 (a int, b varchar(32)); +CREATE TABLE sublimits3 (a int, b varchar(32)); ALTER TABLE testrangelimits ADD TABLE sublimits1 AS PARTITION BETWEEN 0 AND 100; -ALTER TABLE testrangelimits ADD TABLE sublimits1 AS PARTITION BETWEEN 101 AND 200; +ALTER TABLE testrangelimits ADD TABLE sublimits2 AS PARTITION BETWEEN 101 AND 200; +ALTER TABLE testrangelimits ADD TABLE sublimits3 AS PARTITION BETWEEN 401 AND 500 WITH NULL; -INSERT INTO testrangelimits VALUES (1, 'hello'); --go to first partition -INSERT INTO testrangelimits VALUES (101, 'thanks'); --go to second partition +INSERT INTO testrangelimits VALUES (1, 'a'), (101, 'b'), (401, 'c'); +INSERT INTO testrangelimits VALUES (50, 'more'); --1st partition +INSERT INTO testrangelimits VALUES (171, 'test'); --2nd partition +INSERT INTO testrangelimits VALUES (401, 'another'), (NULL, 'test'), (450, 'to'), (500, 'pass'); --3rd partition + INSERT INTO testrangelimits VALUES (201, 'oh no'); --error - -SELECT a FROM testrangelimits; _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list