Changeset: 79a9fe10c2c2 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/79a9fe10c2c2
Added Files:
        sql/test/merge-statements/Tests/mergestmt05.test
Modified Files:
        monetdb5/optimizer/opt_emptybind.c
        sql/backends/monet5/rel_bin.c
        sql/backends/monet5/rel_physical.c
        sql/include/sql_relation.h
        sql/server/rel_distribute.c
        sql/server/rel_dump.c
        sql/server/rel_exp.c
        sql/server/rel_optimize_others.c
        sql/server/rel_optimize_proj.c
        sql/server/rel_optimize_sel.c
        sql/server/rel_optimizer_private.h
        sql/server/rel_propagate.c
        sql/server/rel_rel.c
        sql/server/rel_rewriter.c
        sql/server/rel_updates.c
        sql/server/sql_partition.c
        sql/test/dict/Tests/dict01.test
        sql/test/merge-statements/Tests/All
Branch: default
Log Message:

re-implemented merge statements using normal insert/delete and updates
added support for additional search conditions after the WHEN [NOT] MATCHED.


diffs (truncated from 709 to 300 lines):

diff --git a/monetdb5/optimizer/opt_emptybind.c 
b/monetdb5/optimizer/opt_emptybind.c
--- a/monetdb5/optimizer/opt_emptybind.c
+++ b/monetdb5/optimizer/opt_emptybind.c
@@ -141,13 +141,8 @@ OPTemptybindImplementation(Client cntxt,
                                if (q && getModuleId(q) == sqlRef && 
isUpdateInstruction(q)) {
                                        int c = getFunctionId(q) == claimRef;   
/* claim has 2 results */
                                        int cl = getFunctionId(q) == 
clear_tableRef;    /* clear table has no mvc dependency */
-                                       if (strcmp(getVarConstant(mb, getArg(q,
-                                                                               
                                 2 - cl + c)).val.sval,
-                                                          sch) == 0
-                                               && strcmp(getVarConstant(mb,
-                                                                               
                 getArg(q,
-                                                                               
                                3 - cl + c)).val.sval,
-                                                                 tbl) == 0) {
+                                       if (strcmp(getVarConstant(mb, getArg(q, 
2 - cl + c)).val.sval, sch) == 0
+                                               && strcmp(getVarConstant(mb, 
getArg(q, 3 - cl + c)).val.sval, tbl) == 0) {
                                                empty[getArg(p, 0)] = 0;
                                                if (p->retc == 2) {
                                                        empty[getArg(p, 1)] = 0;
@@ -156,8 +151,7 @@ OPTemptybindImplementation(Client cntxt,
                                        }
                                }
                                if (q && getModuleId(q) == sqlcatalogRef) {
-                                       if (strcmp(getVarConstant(mb, getArg(q, 
2)).val.sval, sch)
-                                               == 0) {
+                                       if (strcmp(getVarConstant(mb, getArg(q, 
2)).val.sval, sch) == 0) {
                                                empty[getArg(p, 0)] = 0;
                                                if (p->retc == 2) {
                                                        empty[getArg(p, 1)] = 0;
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
@@ -2465,7 +2465,6 @@ rel2bin_args(backend *be, sql_rel *rel, 
 
        case op_inter:
        case op_except:
-       case op_merge:
                args = rel2bin_args(be, rel->l, args);
                args = rel2bin_args(be, rel->r, args);
                break;
@@ -7273,133 +7272,6 @@ rel2bin_output(backend *be, sql_rel *rel
        return res;
 }
 
-static list *
-merge_stmt_join_projections(backend *be, stmt *left, stmt *right, stmt *jl, 
stmt *jr, stmt *diff)
-{
-       mvc *sql = be->mvc;
-       list *l = sa_list(sql->sa);
-
-       if (left)
-               for (node *n = left->op4.lval->h; n; n = n->next) {
-                       stmt *c = n->data;
-                       assert(c->type == st_alias);
-                       const char *rnme = table_name(sql->sa, c);
-                       const char *nme = column_name(sql->sa, c);
-                       stmt *s = stmt_project(be, jl ? jl : diff, column(be, 
c));
-
-                       s = stmt_alias(be, s, c->label, rnme, nme);
-                       list_append(l, s);
-               }
-       if (right)
-               for (node *n = right->op4.lval->h; n; n = n->next) {
-                       stmt *c = n->data;
-                       assert(c->type == st_alias);
-                       const char *rnme = table_name(sql->sa, c);
-                       const char *nme = column_name(sql->sa, c);
-                       stmt *s = stmt_project(be, jr ? jr : diff, column(be, 
c));
-
-                       s = stmt_alias(be, s, c->label, rnme, nme);
-                       list_append(l, s);
-               }
-       return l;
-}
-
-static void
-validate_merge_delete_update(backend *be, bool delete, stmt *bt_stmt, sql_rel 
*bt, stmt *jl, stmt *ld)
-{
-       mvc *sql = be->mvc;
-       str msg;
-       sql_table *t = bt->l;
-       char *alias = (char *) rel_name(bt);
-       stmt *cnt1 = stmt_aggr(be, jl, NULL, NULL, sql_bind_func(sql, "sys", 
"count", sql_bind_localtype("void"), NULL, F_AGGR, true, true), 1, 0, 1);
-       stmt *cnt2 = stmt_aggr(be, ld, NULL, NULL, sql_bind_func(sql, "sys", 
"count", sql_bind_localtype("void"), NULL, F_AGGR, true, true), 1, 0, 1);
-       sql_subfunc *add = sql_bind_func(sql, "sys", "sql_add", 
tail_type(cnt1), tail_type(cnt2), F_FUNC, true, true);
-       stmt *s1 = stmt_binop(be, cnt1, cnt2, NULL, add);
-       stmt *cnt3 = stmt_aggr(be, bin_find_smallest_column(be, bt_stmt), NULL, 
NULL, sql_bind_func(sql, "sys", "count", sql_bind_localtype("void"), NULL, 
F_AGGR, true, true), 1, 0, 1);
-       sql_subfunc *bf = sql_bind_func(sql, "sys", ">", tail_type(s1), 
tail_type(cnt3), F_FUNC, true, true);
-       stmt *s2 = stmt_binop(be, s1, cnt3, NULL, bf);
-
-       if (alias && strcmp(alias, t->base.name) == 0) /* detect if alias is 
present */
-               alias = NULL;
-       msg = sa_message(sql->sa, SQLSTATE(40002) "MERGE %s: Multiple rows in 
the input relation match the same row in the target %s '%s%s%s'",
-                                        delete ? "DELETE" : "UPDATE",
-                                        alias ? "relation" : "table",
-                                        alias ? alias : t->s ? t->s->base.name 
: "", alias ? "" : ".", alias ? "" : t->base.name);
-       (void)stmt_exception(be, s2, msg, 00001);
-}
-
-static stmt *
-rel2bin_merge_apply_update(backend *be, sql_rel *join, sql_rel *upd, list 
*refs, stmt *bt_stmt, stmt *target_stmt, stmt *jl, stmt *jr, stmt *ld, stmt 
**rd)
-{
-       if (is_insert(upd->op)) {
-               if (!*rd) {
-                       *rd = stmt_tdiff(be, stmt_mirror(be, 
bin_find_smallest_column(be, target_stmt)), jr, NULL);
-               }
-               stmt *s = stmt_list(be, merge_stmt_join_projections(be, NULL, 
target_stmt, NULL, NULL, *rd));
-               refs_update_stmt(refs, join, s); /* project the differences on 
the target side for inserts */
-
-               return rel2bin_insert(be, upd, refs);
-       } else {
-               stmt *s = stmt_list(be, merge_stmt_join_projections(be, 
bt_stmt, is_update(upd->op) ? target_stmt : NULL, jl, is_update(upd->op) ? jr : 
NULL, NULL));
-               refs_update_stmt(refs, join, s); /* project the matched values 
on both sides for updates and deletes */
-
-               assert(is_update(upd->op) || is_delete(upd->op));
-               /* the left joined values + left difference must be smaller 
than the table count */
-               validate_merge_delete_update(be, is_update(upd->op), bt_stmt, 
join->l, jl, ld);
-
-               return is_update(upd->op) ? rel2bin_update(be, upd, refs) : 
rel2bin_delete(be, upd, refs);
-       }
-}
-
-static stmt *
-rel2bin_merge(backend *be, sql_rel *rel, list *refs)
-{
-       mvc *sql = be->mvc;
-       sql_rel *join;
-
-       if (is_project(((sql_rel*)rel->l)->op)) {
-               join = ((sql_rel*)rel->l)->l;
-       } else {
-               join = rel->l;
-       }
-
-       sql_rel *r = rel->r;
-       stmt *join_st, *bt_stmt, *target_stmt, *jl, *jr, *ld, *rd = NULL, *ns;
-       list *slist = sa_list(sql->sa);
-
-       assert(rel_is_ref(join) && is_left(join->op));
-       join_st = subrel_bin(be, join, refs);
-       if (!join_st)
-               return NULL;
-
-       /* grab generated left join outputs and generate updates accordingly to 
matched and not matched values */
-       assert(join_st->type == st_list && list_length(join_st->extra) == 5);
-       bt_stmt = join_st->extra->h->data;
-       target_stmt = join_st->extra->h->next->data;
-       jl = join_st->extra->h->next->next->data;
-       jr = join_st->extra->h->next->next->next->data;
-       ld = join_st->extra->h->next->next->next->next->data;
-
-       if (is_ddl(r->op)) {
-               assert(r->flag == ddl_list);
-               if (r->l) {
-                       if ((ns = rel2bin_merge_apply_update(be, join, r->l, 
refs, bt_stmt, target_stmt, jl, jr, ld, &rd)) == NULL)
-                               return NULL;
-                       list_append(slist, ns);
-               }
-               if (r->r) {
-                       if ((ns = rel2bin_merge_apply_update(be, join, r->r, 
refs, bt_stmt, target_stmt, jl, jr, ld, &rd)) == NULL)
-                               return NULL;
-                       list_append(slist, ns);
-               }
-       } else {
-               if (!(ns = rel2bin_merge_apply_update(be, join, r, refs, 
bt_stmt, target_stmt, jl, jr, ld, &rd)))
-                       return NULL;
-               list_append(slist, ns);
-       }
-       return stmt_list(be, slist);
-}
-
 static stmt *
 rel2bin_list(backend *be, sql_rel *rel, list *refs)
 {
@@ -7871,11 +7743,6 @@ subrel_bin(backend *be, sql_rel *rel, li
                if (sql->type == Q_TABLE)
                        sql->type = Q_UPDATE;
                break;
-       case op_merge:
-               s = rel2bin_merge(be, rel, refs);
-               if (sql->type == Q_TABLE)
-                       sql->type = Q_UPDATE;
-               break;
        case op_ddl:
                s = rel2bin_ddl(be, rel, refs);
                break;
diff --git a/sql/backends/monet5/rel_physical.c 
b/sql/backends/monet5/rel_physical.c
--- a/sql/backends/monet5/rel_physical.c
+++ b/sql/backends/monet5/rel_physical.c
@@ -89,7 +89,6 @@ find_basetables(mvc *sql, sql_rel *rel, 
        case op_insert:
        case op_update:
        case op_delete:
-       case op_merge:
                if (rel->l)
                        find_basetables(sql, rel->l, tables);
                if (rel->r)
@@ -174,8 +173,6 @@ has_groupby(sql_rel *rel)
 
                case op_inter:
                case op_except:
-
-               case op_merge:
                        return has_groupby(rel->l) || has_groupby(rel->r);
                case op_munion:
                        for (node *n = ((list*)rel->l)->h; n; n = n->next)
@@ -231,8 +228,6 @@ rel_partition(mvc *sql, sql_rel *rel)
 
        case op_inter:
        case op_except:
-
-       case op_merge:
                if (rel->l)
                        rel_partition(sql, rel->l);
                if (rel->r)
diff --git a/sql/include/sql_relation.h b/sql/include/sql_relation.h
--- a/sql/include/sql_relation.h
+++ b/sql/include/sql_relation.h
@@ -174,7 +174,6 @@ typedef enum operator_type {
        op_update,      /* update(l=table, r update expressions) */
        op_delete,      /* delete(l=table, r delete expression) */
        op_truncate, /* truncate(l=table) */
-       op_merge         /* IMPORTANT: keep op_merge last */
 } operator_type;
 
 #define is_atom(et)            (et == e_atom)
@@ -211,13 +210,12 @@ typedef enum operator_type {
 #define is_project(op)                 (op == op_project || op == op_groupby 
|| is_set(op) || is_munion(op))
 #define is_groupby(op)                 (op == op_groupby)
 #define is_topn(op)            (op == op_topn)
-#define is_modify(op)          (op == op_insert || op == op_update || op == 
op_delete || op == op_truncate || op == op_merge)
+#define is_modify(op)          (op == op_insert || op == op_update || op == 
op_delete || op == op_truncate)
 #define is_sample(op)          (op == op_sample)
 #define is_insert(op)          (op == op_insert)
 #define is_update(op)          (op == op_update)
 #define is_delete(op)          (op == op_delete)
 #define is_truncate(op)        (op == op_truncate)
-#define is_merge(op)           (op == op_merge)
 
 /* ZERO on empty sets, needed for sum (of counts)). */
 #define zero_if_empty(e)       ((e)->zero_if_empty)
diff --git a/sql/server/rel_distribute.c b/sql/server/rel_distribute.c
--- a/sql/server/rel_distribute.c
+++ b/sql/server/rel_distribute.c
@@ -74,7 +74,6 @@ has_remote_or_replica( sql_rel *rel )
 
        case op_inter:
        case op_except:
-       case op_merge:
 
        case op_insert:
        case op_update:
@@ -410,7 +409,6 @@ rel_rewrite_remote_(visitor *v, sql_rel 
        case op_insert:
        case op_update:
        case op_delete:
-       case op_merge:
 
                if (rel->flag&MERGE_LEFT) /* search for any remote tables but 
don't propagate over to this relation */
                        return rel;
diff --git a/sql/server/rel_dump.c b/sql/server/rel_dump.c
--- a/sql/server/rel_dump.c
+++ b/sql/server/rel_dump.c
@@ -702,17 +702,13 @@ rel_print_rel(mvc *sql, stream  *fout, s
        case op_insert:
        case op_update:
        case op_delete:
-       case op_truncate:
-       case op_merge: {
-
+       case op_truncate: {
                if (rel->op == op_insert)
                        mnstr_printf(fout, "insert(");
                else if (rel->op == op_update)
                        mnstr_printf(fout, "update(");
                else if (rel->op == op_delete)
                        mnstr_printf(fout, "delete(");
-               else if (rel->op == op_merge)
-                       mnstr_printf(fout, "merge(");
                else if (rel->op == op_truncate) {
                        assert(list_length(rel->exps) == 2);
                        sql_exp *first = (sql_exp*) rel->exps->h->data, *second 
= (sql_exp*) rel->exps->h->next->data;
@@ -740,7 +736,7 @@ rel_print_rel(mvc *sql, stream  *fout, s
                }
                print_indent(sql, fout, depth, decorate);
                mnstr_printf(fout, ")");
-               if (rel->op != op_truncate && rel->op != op_merge && rel->exps)
+               if (rel->op != op_truncate && rel->exps)
                        exps_print(sql, fout, rel->exps, depth, refs, 1, 0, 
decorate, 0);
        }       break;
        default:
@@ -839,7 +835,6 @@ rel_print_refs(mvc *sql, stream* fout, s
        case op_update:
        case op_delete:
        case op_truncate:
-       case op_merge:
                if (rel->l)
                        rel_print_refs(sql, fout, rel->l, depth, refs, 
decorate);
                if (rel->l && rel_is_ref(rel->l) && !find_ref(refs, rel->l)) {
diff --git a/sql/server/rel_exp.c b/sql/server/rel_exp.c
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to