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 -- [email protected]
To unsubscribe send an email to [email protected]