Changeset: a903388a5459 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=a903388a5459
Modified Files:
        monetdb5/modules/mal/wlc.mal
        sql/backends/monet5/sql_cat.c
        sql/backends/monet5/sqlcatalog.mal
        sql/backends/monet5/wlr.mal
        sql/common/sql_changeset.c
        sql/include/sql_catalog.h
        sql/server/rel_schema.c
        sql/storage/sql_storage.h
        sql/storage/store.c
        
sql/test/BugTracker-2019/Tests/alter_table_set_schema.Bug-6701.stable.out
Branch: Apr2019
Log Message:

Fixes for bug 6701. Instead of recreating the table, we add the schema change 
in the transaction level and apply it before any schema changes.

The case of a table changing it's schema twice during the transaction is not 
handled properly yet, but anyway it's a rare case.


diffs (truncated from 447 to 300 lines):

diff --git a/monetdb5/modules/mal/wlc.mal b/monetdb5/modules/mal/wlc.mal
--- a/monetdb5/modules/mal/wlc.mal
+++ b/monetdb5/modules/mal/wlc.mal
@@ -234,7 +234,7 @@ pattern rename_schema(sname:str, newnme:
 address WLCgeneric
 comment "Catalog operation rename_schema";
 
-pattern rename_table(sname:str, tname:str, newnme:str)
+pattern rename_table(osname:str, nsname:str, otname:str, ntname:str)
 address WLCgeneric
 comment "Catalog operation rename_table";
 
diff --git a/sql/backends/monet5/sql_cat.c b/sql/backends/monet5/sql_cat.c
--- a/sql/backends/monet5/sql_cat.c
+++ b/sql/backends/monet5/sql_cat.c
@@ -1603,30 +1603,65 @@ SQLrename_table(Client cntxt, MalBlkPtr 
 {
        mvc *sql = NULL;
        str msg = MAL_SUCCEED;
-       str schema_name = *getArgReference_str(stk, pci, 1);
-       str old_name = *getArgReference_str(stk, pci, 2);
-       str new_name = *getArgReference_str(stk, pci, 3);
-       sql_schema *s;
+       str oschema_name = *getArgReference_str(stk, pci, 1);
+       str nschema_name = *getArgReference_str(stk, pci, 2);
+       str otable_name = *getArgReference_str(stk, pci, 3);
+       str ntable_name = *getArgReference_str(stk, pci, 4);
+       sql_schema *o, *s;
        sql_table *t;
 
        initcontext();
-       if (!(s = mvc_bind_schema(sql, schema_name)))
-               throw(SQL, "sql.rename_table", SQLSTATE(42S02) "ALTER TABLE: no 
such schema '%s'", schema_name);
-       if (!mvc_schema_privs(sql, s))
-               throw(SQL, "sql.rename_table", SQLSTATE(42000) "ALTER TABLE: 
access denied for %s to schema '%s'", stack_get_string(sql, "current_user"), 
schema_name);
-       if (!(t = mvc_bind_table(sql, s, old_name)))
-               throw(SQL, "sql.rename_table", SQLSTATE(42S02) "ALTER TABLE: no 
such table '%s' in schema '%s'", old_name, schema_name);
-       if (t->system)
-               throw(SQL, "sql.rename_table", SQLSTATE(42000) "ALTER TABLE: 
cannot rename a system table");
-       if (mvc_check_dependency(sql, t->base.id, TABLE_DEPENDENCY, NULL))
-               throw (SQL,"sql.rename_table", SQLSTATE(2BM37) "ALTER TABLE: 
unable to rename table '%s' (there are database objects which depend on it)", 
old_name);
-       if (!new_name || strcmp(new_name, str_nil) == 0 || *new_name == '\0')
-               throw(SQL, "sql.rename_table", SQLSTATE(3F000) "ALTER TABLE: 
invalid new table name");
-       if (mvc_bind_table(sql, s, new_name))
-               throw(SQL, "sql.rename_table", SQLSTATE(3F000) "ALTER TABLE: 
there is a table named '%s' in schema '%s'", new_name, schema_name);
+
+       if(strcmp(oschema_name, nschema_name) == 0) { //renaming the table 
itself
+               if (!(s = mvc_bind_schema(sql, oschema_name)))
+                       throw(SQL, "sql.rename_table", SQLSTATE(42S02) "ALTER 
TABLE: no such schema '%s'", oschema_name);
+               if (!mvc_schema_privs(sql, s))
+                       throw(SQL, "sql.rename_table", SQLSTATE(42000) "ALTER 
TABLE: access denied for %s to schema '%s'", stack_get_string(sql, 
"current_user"), oschema_name);
+               if (!(t = mvc_bind_table(sql, s, otable_name)))
+                       throw(SQL, "sql.rename_table", SQLSTATE(42S02) "ALTER 
TABLE: no such table '%s' in schema '%s'", otable_name, oschema_name);
+               if (t->system)
+                       throw(SQL, "sql.rename_table", SQLSTATE(42000) "ALTER 
TABLE: cannot rename a system table");
+               if (mvc_check_dependency(sql, t->base.id, TABLE_DEPENDENCY, 
NULL))
+                       throw (SQL,"sql.rename_table", SQLSTATE(2BM37) "ALTER 
TABLE: unable to rename table '%s' (there are database objects which depend on 
it)", otable_name);
+               if (!ntable_name || strcmp(ntable_name, str_nil) == 0 || 
*ntable_name == '\0')
+                       throw(SQL, "sql.rename_table", SQLSTATE(3F000) "ALTER 
TABLE: invalid new table name");
+               if (mvc_bind_table(sql, s, ntable_name))
+                       throw(SQL, "sql.rename_table", SQLSTATE(3F000) "ALTER 
TABLE: there is a table named '%s' in schema '%s'", ntable_name, oschema_name);
+
+               if (!sql_trans_rename_table(sql->session->tr, s, t->base.id, 
ntable_name))
+                       throw(SQL, "sql.rename_table",SQLSTATE(HY001) 
MAL_MALLOC_FAIL);
+       } else { //changing the schema of the table
+               assert(strcmp(otable_name, ntable_name) == 0);
 
-       if (!sql_trans_rename_table(sql->session->tr, s, t->base.id, new_name))
-               throw(SQL, "sql.rename_table",SQLSTATE(HY001) MAL_MALLOC_FAIL);
+               if (!(o = mvc_bind_schema(sql, oschema_name)))
+                       throw(SQL, "sql.rename_table", SQLSTATE(42S02) "ALTER 
TABLE: no such schema '%s'", oschema_name);
+               if (!mvc_schema_privs(sql, o))
+                       throw(SQL, "sql.rename_table", SQLSTATE(42000) "ALTER 
TABLE: access denied for %s to schema '%s'", stack_get_string(sql, 
"current_user"), oschema_name);
+               if (!(t = mvc_bind_table(sql, o, otable_name)))
+                       throw(SQL, "sql.rename_table", SQLSTATE(42S02) "ALTER 
TABLE: no such table '%s' in schema '%s'", otable_name, oschema_name);
+               if (t->system)
+                       throw(SQL, "sql.rename_table", SQLSTATE(42000) "ALTER 
TABLE: cannot set schema of a system table");
+               if (isTempSchema(o) || isTempTable(t))
+                       throw(SQL, "sql.rename_table", SQLSTATE(42000) "ALTER 
TABLE: not possible to change a temporary table schema");
+               if (isView(t))
+                       throw(SQL, "sql.rename_table", SQLSTATE(42000) "ALTER 
TABLE: not possible to change schema of a view");
+               if (mvc_check_dependency(sql, t->base.id, TABLE_DEPENDENCY, 
NULL))
+                       throw(SQL, "sql.rename_table", SQLSTATE(2BM37) "ALTER 
TABLE: unable to set schema of table '%s' (there are database objects which 
depend on it)", otable_name);
+               if (t->members.set || t->triggers.set)
+                       throw(SQL, "sql.rename_table", SQLSTATE(2BM37) "ALTER 
TABLE: unable to set schema of table '%s' (there are database objects which 
depend on it)", otable_name);
+               if (!(s = mvc_bind_schema(sql, nschema_name)))
+                       throw(SQL, "sql.rename_table", SQLSTATE(42S02) "ALTER 
TABLE: no such schema '%s'", nschema_name);
+               if (!mvc_schema_privs(sql, s))
+                       throw(SQL, "sql.rename_table", SQLSTATE(42000) "ALTER 
TABLE: access denied for '%s' to schema '%s'", stack_get_string(sql, 
"current_user"), nschema_name);
+               if (isTempSchema(s))
+                       throw(SQL, "sql.rename_table", SQLSTATE(3F000) "ALTER 
TABLE: not possible to change table's schema to temporary");
+               if (mvc_bind_table(sql, s, otable_name))
+                       throw(SQL, "sql.rename_table", SQLSTATE(42S02) "ALTER 
TABLE: table '%s' on schema '%s' already exists", otable_name, nschema_name);
+
+               if (!sql_trans_set_table_schema(sql->session->tr, t->base.id, 
o, s))
+                       throw(SQL, "sql.rename_table",SQLSTATE(HY001) 
MAL_MALLOC_FAIL);
+       }
+
        return msg;
 }
 
diff --git a/sql/backends/monet5/sqlcatalog.mal 
b/sql/backends/monet5/sqlcatalog.mal
--- a/sql/backends/monet5/sqlcatalog.mal
+++ b/sql/backends/monet5/sqlcatalog.mal
@@ -167,7 +167,7 @@ pattern rename_schema(sname:str, newnme:
 address SQLrename_schema
 comment "Catalog operation rename_schema";
 
-pattern rename_table(sname:str, tname:str, newnme:str)
+pattern rename_table(osname:str, nsname:str, otname:str, ntname:str)
 address SQLrename_table
 comment "Catalog operation rename_table";
 
diff --git a/sql/backends/monet5/wlr.mal b/sql/backends/monet5/wlr.mal
--- a/sql/backends/monet5/wlr.mal
+++ b/sql/backends/monet5/wlr.mal
@@ -239,7 +239,7 @@ pattern rename_schema(sname:str, newnme:
 address WLRgeneric
 comment "Catalog operation rename_schema";
 
-pattern rename_table(sname:str, tname:str, newnme:str)
+pattern rename_table(osname:str, nsname:str, otname:str, ntname:str)
 address WLRgeneric
 comment "Catalog operation rename_table";
 
diff --git a/sql/common/sql_changeset.c b/sql/common/sql_changeset.c
--- a/sql/common/sql_changeset.c
+++ b/sql/common/sql_changeset.c
@@ -81,6 +81,14 @@ cs_del(changeset * cs, node *elm, int fl
        }
 }
 
+void
+cs_move(changeset *from, changeset *to, void *data)
+{
+       if (!to->set)
+               to->set = list_new(to->sa, to->destroy);
+       list_move_data(from->set, to->set, data);
+}
+
 int
 cs_size(changeset * cs)
 {
diff --git a/sql/include/sql_catalog.h b/sql/include/sql_catalog.h
--- a/sql/include/sql_catalog.h
+++ b/sql/include/sql_catalog.h
@@ -85,6 +85,7 @@
 #define SCALE_EQ       7       /* user defined functions need equal scales */
 #define SCALE_DIGITS_FIX 8     /* the geom module requires the types and 
functions to have the same scale and digits */
 
+/* Warning TR flags are a bitmask */
 #define TR_NEW 1
 #define TR_RENAMED 2
 
@@ -223,6 +224,7 @@ extern void cs_add(changeset * cs, void 
 extern void *cs_add_with_validate(changeset * cs, void *elm, int flag, 
fvalidate cmp);
 extern void cs_add_before(changeset * cs, node *n, void *elm);
 extern void cs_del(changeset * cs, node *elm, int flag);
+extern void cs_move(changeset *from, changeset *to, void *data);
 extern void *cs_transverse_with_validate(changeset * cs, void *elm, fvalidate 
cmp);
 extern int cs_size(changeset * cs);
 extern node *cs_find_name(changeset * cs, const char *name);
@@ -244,6 +246,7 @@ typedef struct sql_trans {
        int schema_updates;     /* set on schema changes */
        int status;             /* status of the last query */
        list *dropped;          /* protection against recursive cascade action*/
+       list *moved_tables;
 
        changeset schemas;
 
@@ -598,6 +601,12 @@ typedef struct sql_table {
        } part;
 } sql_table;
 
+typedef struct sql_moved_table {
+       sql_schema *from;
+       sql_schema *to;
+       sql_table *t;
+} sql_moved_table;
+
 typedef struct res_col {
        char *tn;
        char *name;
diff --git a/sql/server/rel_schema.c b/sql/server/rel_schema.c
--- a/sql/server/rel_schema.c
+++ b/sql/server/rel_schema.c
@@ -2539,6 +2539,7 @@ rel_rename_table(mvc *sql, char* schema_
        rel = rel_create(sql->sa);
        exps = new_exp_list(sql->sa);
        append(exps, exp_atom_clob(sql->sa, schema_name));
+       append(exps, exp_atom_clob(sql->sa, schema_name));
        append(exps, exp_atom_clob(sql->sa, old_name));
        append(exps, exp_atom_clob(sql->sa, new_name));
        rel->op = op_ddl;
@@ -2595,15 +2596,13 @@ rel_rename_column(mvc *sql, char* schema
        return rel;
 }
 
-extern list *rel_dependencies(mvc *sql, sql_rel *r);
-
 static sql_rel *
 rel_set_table_schema(mvc *sql, char* old_schema, char *tname, char 
*new_schema, int if_exists)
 {
-       node *n;
        sql_schema *os, *ns;
-       sql_table *ot, *nt;
-       sql_rel *l, *r, *inserts;
+       sql_table *ot;
+       sql_rel *rel;
+       list *exps;
 
        assert(old_schema && tname && new_schema);
 
@@ -2638,53 +2637,16 @@ rel_set_table_schema(mvc *sql, char* old
        if (mvc_bind_table(sql, ns, tname))
                return sql_error(sql, 02, SQLSTATE(42S02) "ALTER TABLE: table 
'%s' on schema '%s' already exists", tname, new_schema);
 
-       if ((nt = mvc_create_table(sql, ns, tname, ot->type, 0, 
SQL_DECLARED_TABLE, ot->commit_action, -1, ot->properties)) == NULL)
-               return NULL;
-
-       for (n = ot->columns.set->h; n; n = n->next) {
-               sql_column *nc, *oc = (sql_column*) n->data;
-               if (!(nc = mvc_copy_column(sql, nt, oc)))
-                       return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: 
%s_%s_%s conflicts", ns->base.name, nt->base.name, oc->base.name);
-               if (isPartitionedByColumnTable(ot) && oc->base.id == 
ot->part.pcol->base.id)
-                       nt->part.pcol = nc;
-       }
-       if (isPartitionedByExpressionTable(ot)) {
-               char *err = NULL;
-               sql_allocator *oa = sql->sa;
-
-               nt->part.pexp->exp = sa_strdup(sql->session->tr->sa, 
ot->part.pexp->exp);
-
-               sql->sa = sa_create();
-               if (!sql->sa) {
-                       sql->sa = oa;
-                       return sql_error(sql, 02, SQLSTATE(HY001) 
MAL_MALLOC_FAIL);
-               }
-
-               err = bootstrap_partition_expression(sql, sql->session->tr->sa, 
nt, 0);
-               sa_destroy(sql->sa);
-               sql->sa = NULL;
-               if (err) {
-                       sql->sa = oa;
-                       return sql_error(sql, 02, "%s", err);
-               }
-       }
-
-       if (ot->idxs.set)
-               for (n = ot->idxs.set->h; n; n = n->next)
-                       mvc_copy_idx(sql, nt, (sql_idx*) n->data);
-
-       if (ot->keys.set)
-               for (n = ot->keys.set->h; n; n = n->next)
-                       mvc_copy_key(sql, nt, (sql_key*) n->data);
-
-       l = rel_table(sql, DDL_CREATE_TABLE, new_schema, nt, 0);
-       if (!(isMergeTable(ot) || isRemote(ot) || isReplicaTable(ot))) {
-               inserts = rel_basetable(sql, ot, tname);
-               inserts = rel_project(sql->sa, inserts, rel_projections(sql, 
inserts, NULL, 1, 0));
-               l = rel_insert(sql, l, inserts);
-       }
-       r = rel_drop(sql->sa, DDL_DROP_TABLE, old_schema, tname, 0, 0);
-       return rel_list(sql->sa, l, r);
+       rel = rel_create(sql->sa);
+       exps = new_exp_list(sql->sa);
+       append(exps, exp_atom_clob(sql->sa, old_schema));
+       append(exps, exp_atom_clob(sql->sa, new_schema));
+       append(exps, exp_atom_clob(sql->sa, tname));
+       append(exps, exp_atom_clob(sql->sa, tname));
+       rel->op = op_ddl;
+       rel->flag = DDL_RENAME_TABLE;
+       rel->exps = exps;
+       return rel;
 }
 
 sql_rel *
diff --git a/sql/storage/sql_storage.h b/sql/storage/sql_storage.h
--- a/sql/storage/sql_storage.h
+++ b/sql/storage/sql_storage.h
@@ -384,6 +384,7 @@ extern int sql_trans_add_range_partition
 extern int sql_trans_add_value_partition(sql_trans *tr, sql_table *mt, 
sql_table *pt, sql_subtype tpe, list* vals, int with_nills, int update, 
sql_part **err);
 
 extern sql_table *sql_trans_rename_table(sql_trans *tr, sql_schema *s, sqlid 
id, const char *new_name);
+extern sql_table *sql_trans_set_table_schema(sql_trans *tr, sqlid id, 
sql_schema *os, sql_schema *ns);
 extern sql_table *sql_trans_del_table(sql_trans *tr, sql_table *mt, sql_table 
*pt, int drop_action);
 
 extern int sql_trans_drop_table(sql_trans *tr, sql_schema *s, sqlid id, int 
drop_action);
diff --git a/sql/storage/store.c b/sql/storage/store.c
--- a/sql/storage/store.c
+++ b/sql/storage/store.c
@@ -3652,6 +3652,20 @@ rollforward_trans(sql_trans *tr, int mod
                tr->parent->schema_updates = tr->schema_updates;
        }
 
+       if (tr->moved_tables) {
+               for (node *n = tr->moved_tables->h ; n ; n = n->next) {
+                       sql_moved_table *smt = (sql_moved_table*) n->data;
+                       sql_schema *pfrom = find_sql_schema_id(tr->parent, 
smt->from->base.id);
+                       sql_schema *pto = find_sql_schema_id(tr->parent, 
smt->to->base.id);
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to