Changeset: 6947709904d5 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/6947709904d5
Added Files:
sql/test/mergetables/Tests/replicas.test
Modified Files:
sql/server/rel_distribute.c
sql/test/mergetables/Tests/All
Branch: default
Log Message:
Nested replica tables are allowed by the parser, so handle them correctly in
the backend
diffs (241 lines):
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
@@ -13,6 +13,7 @@
#include "rel_exp.h"
#include "rel_prop.h"
#include "rel_dump.h"
+#include "sql_privileges.h"
static int
has_remote_or_replica( sql_rel *rel )
@@ -65,34 +66,40 @@ has_remote_or_replica( sql_rel *rel )
}
static sql_rel *
-rewrite_replica( mvc *sql, sql_rel *rel, sql_table *t, sql_part *pd, int
remote_prop)
+rewrite_replica(mvc *sql, list *exps, sql_table *t, sql_table *p, int
remote_prop)
{
node *n, *m;
- sql_table *p = find_sql_table_id(sql->session->tr, t->s, pd->member);
sql_rel *r = rel_basetable(sql, p, t->base.name);
+ int allowed = 1;
- for (n = rel->exps->h; n; n = n->next) {
+ if (!table_privs(sql, p, PRIV_SELECT)) /* Test for privileges */
+ allowed = 0;
+
+ for (n = exps->h; n; n = n->next) {
sql_exp *e = n->data;
+ const char *nname = exp_name(e);
- node *n = ol_find_name(t->columns, exp_name(e));
- if (n) {
- sql_column *c = n->data;
+ node *nn = ol_find_name(t->columns, nname);
+ if (nn) {
+ sql_column *c = nn->data;
+ if (!allowed && !column_privs(sql, ol_fetch(p->columns,
c->colnr), PRIV_SELECT))
+ return sql_error(sql, 02, SQLSTATE(42000) "The
user %s SELECT permissions on table '%s.%s' don't match %s '%s.%s'",
get_string_global_var(sql, "current_user"),
+
p->s->base.name, p->base.name, TABLE_TYPE_DESCRIPTION(t->type, t->properties),
t->s->base.name, t->base.name);
rel_base_use(sql, r, c->colnr);
- } else if (strcmp(exp_name(e), TID) == 0) {
+ } else if (strcmp(nname, TID) == 0) {
rel_base_use_tid(sql, r);
} else {
assert(0);
}
}
- rel = rewrite_basetable(sql, r);
- for (n = rel->exps->h, m = r->exps->h; n && m; n = n->next, m =
m->next) {
+ r = rewrite_basetable(sql, r);
+ for (n = exps->h, m = r->exps->h; n && m; n = n->next, m = m->next) {
sql_exp *e = n->data;
sql_exp *ne = m->data;
exp_prop_alias(sql->sa, ne, e);
}
- rel_destroy(rel);
/* set_remote() */
if (remote_prop && p && isRemote(p)) {
@@ -104,10 +111,56 @@ rewrite_replica( mvc *sql, sql_rel *rel,
}
static sql_rel *
+replica_rewrite(visitor *v, sql_table *t, list *exps)
+{
+ sql_rel *res = NULL;
+ const char *uri = (const char *) v->data;
+
+ 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) {
+ 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;
+ }
+ }
+ } else { /* no match, find one without remote or use first */
+ sql_table *pt = NULL;
+ int remote = 1;
+
+ for (node *n = t->members->h; n; n = n->next) {
+ sql_part *p = n->data;
+ sql_table *next =
find_sql_table_id(v->sql->session->tr, t->s, p->member);
+
+ /* give preference to local tables and avoid empty
merge or replica tables */
+ if (!isRemote(next) && ((!isReplicaTable(next) &&
!isMergeTable(next)) || !list_empty(next->members))) {
+ pt = next;
+ remote = 0;
+ break;
+ }
+ }
+ if (!pt) {
+ sql_part *p = t->members->h->data;
+ pt = find_sql_table_id(v->sql->session->tr, t->s,
p->member);
+ }
+
+ if ((isMergeTable(pt) || isReplicaTable(pt)) &&
list_empty(pt->members))
+ return sql_error(v->sql, 02, SQLSTATE(42000) "The %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);
+ }
+ return res;
+}
+
+static sql_rel *
replica(visitor *v, sql_rel *rel)
{
- const char *uri = v->data;
-
if (rel_is_ref(rel)) {
if (has_remote_or_replica(rel)) {
sql_rel *nrel = rel_copy(v->sql, rel, 1);
@@ -121,36 +174,13 @@ replica(visitor *v, sql_rel *rel)
if (is_basetable(rel->op)) {
sql_table *t = rel->l;
- if (t && isReplicaTable(t) && !list_empty(t->members)) {
- if (uri) {
- /* replace by the replica which matches the uri
*/
- for (node *n = t->members->h; n; n = n->next) {
- sql_part *p = n->data;
- sql_table *pt =
find_sql_table_id(v->sql->session->tr, t->s, p->member);
+ if (t && isReplicaTable(t)) {
+ if (list_empty(t->members)) /* in DDL statement cases
skip if replica is empty */
+ return rel;
- if (isRemote(pt) && strcmp(uri,
pt->query) == 0) {
- rel = rewrite_replica(v->sql,
rel, t, p, 0);
- break;
- }
- }
- } else { /* no match, find one without remote or use
first */
- int fnd = 0;
- sql_part *p;
- for (node *n = t->members->h; n; 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)) {
- fnd = 1;
- rel = rewrite_replica(v->sql,
rel, t, p, 0);
- break;
- }
- }
- if (!fnd) {
- p = t->members->h->data;
- rel = rewrite_replica(v->sql, rel, t,
p, 1);
- }
- }
+ sql_rel *r = replica_rewrite(v, t, rel->exps);
+ rel_destroy(rel);
+ rel = r;
}
}
return rel;
@@ -178,7 +208,7 @@ distribute(visitor *v, sql_rel *rel)
sql_table *t = rel->l;
/* set_remote() */
- if (t && isRemote(t)) {
+ if (t && isRemote(t) && (p = find_prop(rel->p, PROP_REMOTE)) ==
NULL) {
char *local_name = sa_strconcat(v->sql->sa,
sa_strconcat(v->sql->sa, t->s->base.name, "."), t->base.name);
p = rel->p = prop_create(v->sql->sa, PROP_REMOTE,
rel->p);
p->value = local_name;
diff --git a/sql/test/mergetables/Tests/All b/sql/test/mergetables/Tests/All
--- a/sql/test/mergetables/Tests/All
+++ b/sql/test/mergetables/Tests/All
@@ -18,6 +18,7 @@ KNOWNFAIL?singlekeyconstraint
part-elim
mergedropcascade
addtable
+replicas
transaction-conflict
HAVE_NETCDF&HAVE_NETCDF?mergedb_create
diff --git a/sql/test/mergetables/Tests/replicas.test
b/sql/test/mergetables/Tests/replicas.test
new file mode 100644
--- /dev/null
+++ b/sql/test/mergetables/Tests/replicas.test
@@ -0,0 +1,52 @@
+statement ok
+create replica table t1 (a int)
+
+statement ok
+create replica table t2 (a int)
+
+statement ok
+create table t3 (a int)
+
+statement ok rowcount 3
+insert into t3 values (1), (2), (3)
+
+statement ok
+alter table t1 add table t2
+
+statement error 42000!The REPLICA TABLE 'sys.t2' should have at least one
table associated
+select a from t1
+
+statement error 42000!MERGE or REPLICA TABLE should have at least one table
associated
+select a from t2
+
+statement ok
+alter table t2 add table t3
+
+query I rowsort
+select a from t1
+----
+1
+2
+3
+
+query I rowsort
+select a from t2
+----
+1
+2
+3
+
+statement ok
+alter table t2 drop table t3
+
+statement ok
+alter table t1 drop table t2
+
+statement ok
+drop table t1
+
+statement ok
+drop table t2
+
+statement ok
+drop table t3
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list