Changeset: b22b663c3f2d for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/b22b663c3f2d
Modified Files:
        sql/backends/monet5/sql_gencode.c
Branch: default
Log Message:

Merge new_rmt_opt into default.


diffs (truncated from 484 to 300 lines):

diff --git a/sql/backends/monet5/sql_gencode.c 
b/sql/backends/monet5/sql_gencode.c
--- a/sql/backends/monet5/sql_gencode.c
+++ b/sql/backends/monet5/sql_gencode.c
@@ -354,7 +354,8 @@ static int
        Client c = MCgetClient(m->clientid);
        MalBlkPtr curBlk = 0;
        InstrPtr curInstr = 0, p, o;
-       sqlid table_id = prp->id;
+       tid_uri *tu = ((list*)prp->value.pval)->h->data;
+       sqlid table_id = tu->id;
        node *n;
        int i, q, v, res = -1, added_to_cache = 0, *lret, *rret;
        size_t len = 1024, nr, pwlen = 0;
@@ -389,6 +390,7 @@ static int
 
        sql_table *rt = sql_trans_find_table(m->session->tr, table_id);
        const char *uri = mapiuri_uri(rt->query, m->sa);
+       assert(strcmp(tu->uri, uri) == 0);
        if (!rt) {
                sql_error(m, 10, SQLSTATE(HY013) MAL_MALLOC_FAIL);
                goto cleanup;
@@ -928,8 +930,12 @@ static int
        Symbol symbackup = c->curprg;
        exception_buffer ebsave = m->sa->eb;
 
-       if (prp->id == 0) {
-               sql_error(m, 003, SQLSTATE(42000) "Missing property on the 
input relation");
+       if (list_empty(prp->value.pval)) {
+               sql_error(m, 003, SQLSTATE(42000) "Missing REMOTE property on 
the input relation");
+               goto bailout;
+       }
+       if (list_length(prp->value.pval) != 1) {
+               sql_error(m, 003, SQLSTATE(42000) "REMOTE property on the input 
relation is NOT unique");
                goto bailout;
        }
        if (strlen(mod) >= IDLENGTH) {
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
@@ -15,6 +15,12 @@
 #include "rel_remote.h"
 #include "sql_privileges.h"
 
+typedef struct rmt_prop_state {
+       int depth;
+       prop* rmt;
+       sql_rel* orig;
+} rps;
+
 static int
 has_remote_or_replica( sql_rel *rel )
 {
@@ -66,7 +72,7 @@ has_remote_or_replica( sql_rel *rel )
 }
 
 static sql_rel *
-rewrite_replica(mvc *sql, list *exps, sql_table *t, sql_table *p, int 
remote_prop)
+do_replica_rewrite(mvc *sql, list *exps, sql_table *t, sql_table *p, int 
remote_prop)
 {
        node *n, *m;
        sql_rel *r = rel_basetable(sql, p, t->base.name);
@@ -96,11 +102,15 @@ rewrite_replica(mvc *sql, list *exps, sq
 
        /* set_remote() */
        if (remote_prop && p && isRemote(p)) {
-               sqlid id = p->base.id;
-               char *local_name = sa_strconcat(sql->sa, sa_strconcat(sql->sa, 
p->s->base.name, "."), p->base.name);
-               prop *p = r->p = prop_create(sql->sa, PROP_REMOTE, r->p);
-               p->id = id;
-               p->value.pval = local_name;
+               list *uris = sa_list(sql->sa);
+               tid_uri *tu = SA_NEW(sql->sa, tid_uri);
+               tu->id = p->base.id;
+               tu->uri = sa_strconcat(sql->sa, sa_strconcat(sql->sa, 
p->s->base.name, "."), p->base.name);
+               append(uris, tu);
+
+               prop *rmt_prop = r->p = prop_create(sql->sa, PROP_REMOTE, r->p);
+               rmt_prop->id = p->base.id;
+               rmt_prop->value.pval = uris;
        }
        return r;
 }
@@ -109,24 +119,33 @@ static sql_rel *
 replica_rewrite(visitor *v, sql_table *t, list *exps)
 {
        sql_rel *res = NULL;
-       const char *uri = (const char *) v->data;
+       prop *rp = ((rps*)v->data)->rmt;
+       sqlid tid = rp->id;
+       list *uris = rp->value.pval;
 
        if (mvc_highwater(v->sql))
                return sql_error(v->sql, 10, SQLSTATE(42000) "Query too 
complex: running out of stack space");
 
-       if (uri) {
-               /* replace by the replica which matches the uri */
-               for (node *n = t->members->h; n; n = n->next) {
+       /* if there was a REMOTE property in any higher node and there is not
+        * a local tid then use the available uris to rewrite */
+       if (uris && !tid) {
+               for (node *n = t->members->h; n && !res; n = n->next) {
                        sql_part *p = n->data;
                        sql_table *pt = find_sql_table_id(v->sql->session->tr, 
t->s, p->member);
 
-                       if (isRemote(pt) && strcmp(uri, pt->query) == 0) {
-                               res = rewrite_replica(v->sql, exps, t, pt, 0);
-                               break;
+                       if (!isRemote(pt))
+                               continue;
+
+                       for (node *m = uris->h; m && !res; m = m->next) {
+                               if (strcmp(((tid_uri*)m->data)->uri, pt->query) 
== 0) {
+                                       res = do_replica_rewrite(v->sql, exps, 
t, pt, 0);
+                               }
                        }
                }
        }
-       if (!res) { /* no match, find one without remote or use first */
+
+       /* no match, find one without remote or use first */
+       if (!res) {
                sql_table *pt = NULL;
                int remote = 1;
 
@@ -138,6 +157,10 @@ replica_rewrite(visitor *v, sql_table *t
                        if (!isRemote(next) && ((!isReplicaTable(next) && 
!isMergeTable(next)) || !list_empty(next->members))) {
                                pt = next;
                                remote = 0;
+                               /* if we resolved the replica to a local table 
we have to
+                                * go and remove the remote property from the 
subtree */
+                               sql_rel *r = ((rps*)v->data)->orig;
+                               r->p = prop_remove(r->p, rp);
                                break;
                        }
                }
@@ -149,29 +172,64 @@ replica_rewrite(visitor *v, sql_table *t
                if ((isMergeTable(pt) || isReplicaTable(pt)) && 
list_empty(pt->members))
                        return sql_error(v->sql, 02, SQLSTATE(42000) "%s 
'%s'.'%s' should have at least one table associated",
                                                        
TABLE_TYPE_DESCRIPTION(pt->type, pt->properties), pt->s->base.name, 
pt->base.name);
-               res = isReplicaTable(pt) ? replica_rewrite(v, pt, exps) : 
rewrite_replica(v->sql, exps, t, pt, remote);
+               res = isReplicaTable(pt) ? replica_rewrite(v, pt, exps) : 
do_replica_rewrite(v->sql, exps, t, pt, remote);
        }
        return res;
 }
 
+static bool
+eliminate_remote_or_replica_refs(visitor *v, sql_rel **rel)
+{
+       if (rel_is_ref(*rel) && !((*rel)->flag&MERGE_LEFT)) {
+               if (has_remote_or_replica(*rel)) {
+                       sql_rel *nrel = rel_copy(v->sql, *rel, 1);
+                       rel_destroy(*rel);
+                       *rel = nrel;
+                       return true;
+               } else {
+                       // TODO why do we want to bail out if we have a non 
rmt/rpl ref?
+                       return false;
+               }
+       }
+       return true;
+}
+
 static sql_rel *
 rel_rewrite_replica_(visitor *v, sql_rel *rel)
 {
-       /* for merge statement join, ignore the multiple references */
-       if (rel_is_ref(rel) && !(rel->flag&MERGE_LEFT)) {
-               if (has_remote_or_replica(rel)) {
-                       sql_rel *nrel = rel_copy(v->sql, rel, 1);
+       if (!eliminate_remote_or_replica_refs(v, &rel))
+               return rel;
 
-                       rel_destroy(rel);
-                       rel = nrel;
-               } else {
-                       return rel;
+       /* no-leaf nodes: store the REMOTE property uris in the state of the 
visitor
+        * leaf nodes: check if they are basetable replicas and proceed with 
the rewrite */
+       prop *p;
+       if (!is_basetable(rel->op)) {
+               /* if we are higher in the tree clear the previous REMOTE prop 
in the visitor state */
+               if (v->data && v->depth <= ((rps*)v->data)->depth) {
+                       v->data = NULL;
                }
-       }
-       if (is_basetable(rel->op)) {
+               /* if there is a REMOTE prop set it to the visitor state */
+               if ((p = find_prop(rel->p, PROP_REMOTE)) != NULL) {
+                       rps *rp = SA_NEW(v->sql->sa, rps);
+                       rp->depth = v->depth;
+                       rp->rmt = p;
+                       rp->orig = rel;
+                       v->data = rp;
+               }
+       } else {
                sql_table *t = rel->l;
 
                if (t && isReplicaTable(t)) {
+                       /* we might have reached a replica table through a 
branch that has
+                        * no REMOTE property. In this case we have to set the 
v->data */
+                       if (!v->data && (p = find_prop(rel->p, PROP_REMOTE)) != 
NULL) {
+                               rps *rp = SA_NEW(v->sql->sa, rps);
+                               rp->depth = v->depth;
+                               rp->rmt = p;
+                               rp->orig = rel;
+                               v->data = rp;
+                       }
+
                        if (list_empty(t->members)) /* in DDL statement cases 
skip if replica is empty */
                                return rel;
 
@@ -187,7 +245,7 @@ static sql_rel *
 rel_rewrite_replica(visitor *v, global_props *gp, sql_rel *rel)
 {
        (void) gp;
-       return rel_visitor_bottomup(v, rel, &rel_rewrite_replica_);
+       return rel_visitor_topdown(v, rel, &rel_rewrite_replica_);
 }
 
 run_optimizer
@@ -197,23 +255,31 @@ bind_rewrite_replica(visitor *v, global_
        return gp->needs_mergetable_rewrite || gp->needs_remote_replica_rewrite 
? rel_rewrite_replica : NULL;
 }
 
+static list*
+rel_merge_remote_prop(visitor *v, prop *pl, prop *pr)
+{
+       list* uris = sa_list(v->sql->sa);
+       // TODO this double loop must go (maybe use the hashmap of the list?)
+       for (node* n = ((list*)pl->value.pval)->h; n; n = n->next) {
+               for (node* m = ((list*)pr->value.pval)->h; m; m = m->next) {
+                       tid_uri* ltu = n->data;
+                       tid_uri* rtu = m->data;
+                       if (strcmp(ltu->uri, rtu->uri) == 0) {
+                               append(uris, n->data);
+                       }
+               }
+       }
+       return uris;
+}
 
 static sql_rel *
 rel_rewrite_remote_(visitor *v, sql_rel *rel)
 {
        prop *p, *pl, *pr;
 
-       /* for merge statement join, ignore the multiple references */
-       if (rel_is_ref(rel) && !(rel->flag&MERGE_LEFT)) {
-               if (has_remote_or_replica(rel)) {
-                       sql_rel *nrel = rel_copy(v->sql, rel, 1);
+       if (!eliminate_remote_or_replica_refs(v, &rel))
+               return rel;
 
-                       rel_destroy(rel);
-                       rel = nrel;
-               } else {
-                       return rel;
-               }
-       }
        sql_rel *l = rel->l, *r = rel->r; /* look on left and right relations 
after possibly doing rel_copy */
 
        switch (rel->op) {
@@ -224,13 +290,49 @@ rel_rewrite_remote_(visitor *v, sql_rel 
                 * uri to the REMOTE property. As the property is pulled up the 
tree it can be used in
                 * the case of binary rel operators (see later switch cases) in 
order to
                 * 1. resolve properly (same uri) replica tables in the other 
subtree (that's why we
-                *    call the rewrite_replica)
+                *    call the do_replica_rewrite)
                 * 2. pull REMOTE over the binary op if the other subtree has a 
matching uri remote table
                 */
                if (t && isRemote(t) && (p = find_prop(rel->p, PROP_REMOTE)) == 
NULL) {
+                       if (t->query) {
+                               tid_uri *tu = SA_NEW(v->sql->sa, tid_uri);
+                               tu->id = t->base.id;
+                               tu->uri = mapiuri_uri(t->query, v->sql->sa);
+                               list *uris = sa_list(v->sql->sa);
+                               append(uris, tu);
+
+                               p = rel->p = prop_create(v->sql->sa, 
PROP_REMOTE, rel->p);
+                               p->id = 0;
+                               p->value.pval = uris;
+                       }
+               }
+               if (t && isReplicaTable(t) && !list_empty(t->members)) {
+                       /* the parts of a replica are either
+                        * - remote tables for which we have to store tid and 
uri
+                        * - local table for which we only care if they exist 
(localpart var)
+                        * the relevant info are passed in the REMOTE property 
value.pval and id members
+                        */
+                       list *uris = sa_list(v->sql->sa);
+                       sqlid localpart = 0;
+                       for (node *n = t->members->h; n; n = n->next) {
+                               sql_part *part = n->data;
+                               sql_table *ptable = 
find_sql_table_id(v->sql->session->tr, t->s, part->member);
+
+                               if (isRemote(ptable)) {
+                                       assert(ptable->query);
+                                       tid_uri *tu = SA_NEW(v->sql->sa, 
tid_uri);
+                                       tu->id = ptable->base.id;
+                                       tu->uri = mapiuri_uri(ptable->query, 
v->sql->sa);
_______________________________________________
checkin-list mailing list -- checkin-list@monetdb.org
To unsubscribe send an email to checkin-list-le...@monetdb.org

Reply via email to