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