Changeset: 6ffee07a363f for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=6ffee07a363f
Added Files:
        sql/test/Tests/truncate-statements-extra.sql
        sql/test/Tests/truncate-statements-extra.stable.err
        sql/test/Tests/truncate-statements-extra.stable.out
Modified Files:
        sql/backends/monet5/rel_bin.c
        sql/test/Tests/All
Branch: sqlextra
Log Message:

Fixed the cascade check in truncate statements. Also approved output


diffs (truncated from 563 to 300 lines):

diff --git a/sql/backends/monet5/rel_bin.c b/sql/backends/monet5/rel_bin.c
--- a/sql/backends/monet5/rel_bin.c
+++ b/sql/backends/monet5/rel_bin.c
@@ -4372,7 +4372,7 @@ sql_delete_cascade_Fkeys(backend *be, sq
 }
 
 static void 
-sql_delete_ukey(backend *be, stmt *utids /* deleted tids from ukey table */, 
sql_key *k, list *l) 
+sql_delete_ukey(backend *be, stmt *utids /* deleted tids from ukey table */, 
sql_key *k, list *l, char* which, int cascade)
 {
        mvc *sql = be->mvc;
        sql_ukey *uk = (sql_ukey*)k;
@@ -4393,31 +4393,36 @@ sql_delete_ukey(backend *be, stmt *utids
                        s = stmt_join(be, s, utids, 0, cmp_equal); /* join over 
the join index */
                        s = stmt_result(be, s, 0);
                        tids = stmt_project(be, s, tids);
-                       switch (((sql_fkey*)fk)->on_delete) {
-                               case ACT_NO_ACTION: 
-                                       break;
-                               case ACT_SET_NULL: 
-                               case ACT_SET_DEFAULT: 
-                                       s = sql_delete_set_Fkeys(be, fk, tids, 
((sql_fkey*)fk)->on_delete);
-                                       list_prepend(l, s);
-                                       break;
-                               case ACT_CASCADE: 
-                                       s = sql_delete_cascade_Fkeys(be, fk, 
tids);
-                                       list_prepend(l, s);
-                                       break;
-                               default:        /*RESTRICT*/
-                                       /* The overlap between deleted 
primaries and foreign should be empty */
-                                       s = stmt_binop(be, stmt_aggr(be, tids, 
NULL, NULL, cnt, 1, 0), stmt_atom_lng(be, 0), ne);
-                                       msg = sa_message(sql->sa, "DELETE: 
FOREIGN KEY constraint '%s.%s' violated", fk->t->base.name, fk->base.name);
-                                       s = stmt_exception(be, s, msg, 00001);
-                                       list_prepend(l, s);
+                       if(cascade) { //for truncate statements with the 
cascade option
+                               s = sql_delete_cascade_Fkeys(be, fk, tids);
+                               list_prepend(l, s);
+                       } else {
+                               switch (((sql_fkey*)fk)->on_delete) {
+                                       case ACT_NO_ACTION:
+                                               break;
+                                       case ACT_SET_NULL:
+                                       case ACT_SET_DEFAULT:
+                                               s = sql_delete_set_Fkeys(be, 
fk, tids, ((sql_fkey*)fk)->on_delete);
+                                               list_prepend(l, s);
+                                               break;
+                                       case ACT_CASCADE:
+                                               s = 
sql_delete_cascade_Fkeys(be, fk, tids);
+                                               list_prepend(l, s);
+                                               break;
+                                       default:        /*RESTRICT*/
+                                               /* The overlap between deleted 
primaries and foreign should be empty */
+                                               s = stmt_binop(be, 
stmt_aggr(be, tids, NULL, NULL, cnt, 1, 0), stmt_atom_lng(be, 0), ne);
+                                               msg = sa_message(sql->sa, "%s: 
FOREIGN KEY constraint '%s.%s' violated", which, fk->t->base.name, 
fk->base.name);
+                                               s = stmt_exception(be, s, msg, 
00001);
+                                               list_prepend(l, s);
+                               }
                        }
                }
        }
 }
 
 static int
-sql_delete_keys(backend *be, sql_table *t, stmt *rows, list *l)
+sql_delete_keys(backend *be, sql_table *t, stmt *rows, list *l, char* which, 
int cascade)
 {
        mvc *sql = be->mvc;
        int res = 1;
@@ -4437,7 +4442,7 @@ sql_delete_keys(backend *be, sql_table *
                                
                                *local_id = k->base.id;
                                list_append(sql->cascade_action, local_id); 
-                               sql_delete_ukey(be, rows, k, l);
+                               sql_delete_ukey(be, rows, k, l, which, cascade);
                        }
                }
        }
@@ -4461,7 +4466,7 @@ sql_delete(backend *be, sql_table *t, st
        if (!sql_delete_triggers(be, t, v, 0, 1, 3))
                return sql_error(sql, 02, "DELETE: triggers failed for table 
'%s'", t->base.name);
 
-       if (!sql_delete_keys(be, t, v, l)) 
+       if (!sql_delete_keys(be, t, v, l, "DELETE", 0))
                return sql_error(sql, 02, "DELETE: failed to delete indexes for 
table '%s'", t->base.name);
 
        if (rows) { 
@@ -4511,73 +4516,135 @@ rel2bin_delete(backend *be, sql_rel *rel
        return delete;
 }
 
+struct tablelist {
+       sql_table *table;
+       struct tablelist* next;
+};
+
+static void //inspect the other tables recursively for foreign key dependencies
+check_for_foreign_key_references(mvc *sql, struct tablelist* list, struct 
tablelist* next_append, sql_table *t, int cascade, stmt **error) {
+       node *n;
+       int found;
+       struct tablelist* new_node, *node_check;
+
+       if(*error) {
+               return;
+       }
+
+       if (t->keys.set) { /* Check for foreign key references */
+               for (n = t->keys.set->h; n; n = n->next) {
+                       sql_key *k = n->data;
+
+                       if (k->type == ukey || k->type == pkey) {
+                               sql_ukey *uk = (sql_ukey *) k;
+
+                               if (uk->keys && list_length(uk->keys)) {
+                                       node *l = uk->keys->h;
+
+                                       for (; l; l = l->next) {
+                                               k = l->data;
+                                               /* make sure it is not a self 
referencing key */
+                                               if (k->t != t && !cascade) {
+                                                       *error = sql_error(sql, 
02, "TRUNCATE: FOREIGN KEY %s.%s depends on %s", k->t->base.name, k->base.name, 
t->base.name);
+                                               } else if(k->t != t) {
+                                                       found = 0;
+                                                       for (node_check = list; 
node_check; node_check = node_check->next) {
+                                                               
if(node_check->table == k->t) {
+                                                                       found = 
1;
+                                                               }
+                                                       }
+                                                       if(!found) {
+                                                               new_node = 
(struct tablelist*) GDKmalloc(sizeof(struct tablelist));
+                                                               new_node->table 
= k->t;
+                                                               new_node->next 
= NULL;
+                                                               
next_append->next = new_node;
+                                                               
check_for_foreign_key_references(sql, list, new_node, k->t, cascade, error);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
 static stmt *
-sql_truncate(backend *be, sql_table *t, int restart_sequences, int drop_action)
+sql_truncate(backend *be, sql_table *t, int restart_sequences, int cascade)
 {
        mvc *sql = be->mvc;
        list *l = sa_list(sql->sa);
-       stmt *v = stmt_tid(be, t, 0), *s = NULL;
+       stmt *v, *error = NULL, *ret, *other;
        const char *next_value_for = "next value for \"sys\".\"seq_";
        char *seq_name;
        str seq_pos = NULL;
        sql_column *col;
        sql_sequence *seq;
-       sql_schema *sche = t->s;
+       sql_schema *sche;
+       sql_table *next;
        sql_trans *tr = sql->session->tr;
        node *n;
 
-       if(restart_sequences) { /* restart the sequences if it's the case */
-               for (n = t->columns.set->h; n; n = n->next) {
-                       col = n->data;
-                       if (col->def && (seq_pos = strstr(col->def, 
next_value_for))) {
-                               seq_name = _STRDUP(seq_pos + 
(strlen(next_value_for) - strlen("seq_")));
-                               seq_name[strlen(seq_name)-1] = '\0';
-                               seq = find_sql_sequence(sche, seq_name);
-                               if (seq) {
-                                       sql_trans_sequence_restart(tr, seq, 
seq->start);
-                                       seq->base.wtime = sche->base.wtime = 
tr->wtime = tr->wstime;
-                                       tr->schema_updates++;
-                               }
-                               _DELETE(seq_name);
-                       }
-               }
+       struct tablelist* new_list = (struct tablelist*) 
GDKmalloc(sizeof(struct tablelist)), *list_node, *aux;
+       new_list->table = t;
+       new_list->next = NULL;
+       check_for_foreign_key_references(sql, new_list, new_list, t, cascade, 
&error);
+
+       if(error) {
+               goto finalize;
        }
 
-       if (!drop_action && t->keys.set) { /* Check for foreign key references 
if it's the case */
-               for (n = t->keys.set->h; n; n = n->next) {
-                       sql_key *k = n->data;
-
-                       if (k->type == ukey || k->type == pkey) {
-                               sql_ukey *uk = (sql_ukey *) k;
-
-                               if (uk->keys && list_length(uk->keys)) {
-                                       node *l = uk->keys->h;
-
-                                       for (; l; l = l->next) {
-                                               k = l->data;
-                                               /* make sure it is not a self 
referencing key */
-                                               if (k->t != t)
-                                                       return sql_error(sql, 
02, "TRUNCATE: FOREIGN KEY %s.%s depends on %s", k->t->base.name, k->base.name, 
t->base.name);
+       for (list_node = new_list; list_node; list_node = list_node->next) {
+               next = list_node->table;
+               sche = next->s;
+
+               if(restart_sequences) { /* restart the sequences if it's the 
case */
+                       for (n = next->columns.set->h; n; n = n->next) {
+                               col = n->data;
+                               if (col->def && (seq_pos = strstr(col->def, 
next_value_for))) {
+                                       seq_name = _STRDUP(seq_pos + 
(strlen(next_value_for) - strlen("seq_")));
+                                       seq_name[strlen(seq_name)-1] = '\0';
+                                       seq = find_sql_sequence(sche, seq_name);
+                                       if (seq) {
+                                               sql_trans_sequence_restart(tr, 
seq, seq->start);
+                                               seq->base.wtime = 
sche->base.wtime = tr->wtime = tr->wstime;
+                                               tr->schema_updates++;
                                        }
+                                       _DELETE(seq_name);
                                }
                        }
                }
+
+               v = stmt_tid(be, next, 0);
+
+               /* before */
+               if (!sql_delete_triggers(be, next, v, 0, 3, 4))
+                       return sql_error(sql, 02, "TRUNCATE: triggers failed 
for table '%s'", next->base.name);
+
+               if (!sql_delete_keys(be, next, v, l, "TRUNCATE", cascade))
+                       return sql_error(sql, 02, "TRUNCATE: failed to delete 
indexes for table '%s'", next->base.name);
+
+               other = stmt_table_clear(be, next);
+               list_append(l, other);
+               if(next == t) {
+                       ret = other;
+               }
+
+               /* after */
+               if (!sql_delete_triggers(be, next, v, 1, 3, 4))
+                       return sql_error(sql, 02, "TRUNCATE: triggers failed 
for table '%s'", next->base.name);
        }
 
-/* before */
-       if (!sql_delete_triggers(be, t, v, 0, 3, 4))
-               return sql_error(sql, 02, "TRUNCATE: triggers failed for table 
'%s'", t->base.name);
-
-       if (!sql_delete_keys(be, t, v, l))
-               return sql_error(sql, 02, "TRUNCATE: failed to delete indexes 
for table '%s'", t->base.name);
-
-       s = stmt_table_clear(be, t);
-       list_append(l, s);
-
-/* after */
-       if (!sql_delete_triggers(be, t, v, 1, 3, 4))
-               return sql_error(sql, 02, "TRUNCATE: triggers failed for table 
'%s'", t->base.name);
-       return s;
+       finalize:
+               for (list_node = new_list; list_node;) {
+                       aux = list_node->next;
+                       GDKfree(list_node);
+                       list_node = aux;
+               }
+               if(error) {
+                       return error;
+               }
+
+       return ret;
 }
 
 #define E_ATOM_INT(e) ((atom*)((sql_exp*)e)->l)->data.val.lval
@@ -4591,7 +4658,7 @@ rel2bin_truncate(backend *be, sql_rel *r
        sql_rel *tr = rel->l;
        sql_table *t = NULL;
        node *n;
-       int restart_sequences, drop_action;
+       int restart_sequences, cascade;
 
        if (tr->op == op_basetable)
                t = tr->l;
@@ -4600,9 +4667,9 @@ rel2bin_truncate(backend *be, sql_rel *r
 
        n = rel->exps->h;
        restart_sequences = E_ATOM_INT(n->data);
-       drop_action = E_ATOM_INT(n->next->data);
-
-       truncate = sql_truncate(be, t, restart_sequences, drop_action);
+       cascade = E_ATOM_INT(n->next->data);
+
+       truncate = sql_truncate(be, t, restart_sequences, cascade);
        if (sql->cascade_action)
                sql->cascade_action = NULL;
        return truncate;
diff --git a/sql/test/Tests/All b/sql/test/Tests/All
--- a/sql/test/Tests/All
+++ b/sql/test/Tests/All
@@ -113,5 +113,6 @@ alastair_udf_mergetable_bug
 copy-into-fwf
 
 truncate-statements
+truncate-statements-extra
 create-or-replace-triggers
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to