Changeset: 6de41a7ee41f for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=6de41a7ee41f Modified Files: sql/backends/monet5/rel_bin.c sql/include/sql_catalog.h sql/server/rel_optimizer.c sql/server/rel_updates.c sql/storage/store.c Branch: nospare Log Message:
we no-longer have the list ukey->keys -- rkey<-fkey, as object list/object available (because maintaining that in the multi-version tree is a problem) Therefor we keep a objectset (on ids) of all keys (sofar). and use the dependencies to retrieve the list when needed. diffs (truncated from 422 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 @@ -4332,10 +4332,11 @@ static stmt * join_updated_pkey(backend *be, sql_key * k, stmt *tids, stmt **updates) { mvc *sql = be->mvc; + sql_trans *tr = sql->session->tr; char *msg = NULL; int nulls = 0; node *m, *o; - sql_key *rk = (sql_key*)os_find_id(k->t->s->keys, be->mvc->session->tr, ((sql_fkey*)k)->rkey); + sql_key *rk = (sql_key*)os_find_id(tr->cat->objects, tr, ((sql_fkey*)k)->rkey); stmt *s = NULL, *dels = stmt_tid(be, rk->t, 0), *fdels, *cnteqjoin; stmt *null = NULL, *rows; sql_subtype *lng = sql_bind_localtype("lng"); @@ -4397,10 +4398,11 @@ static stmt* sql_delete_set_Fkeys(backend *be, sql_key *k, stmt *ftids /* to be updated rows of fkey table */, int action) { mvc *sql = be->mvc; + sql_trans *tr = sql->session->tr; list *l = NULL; int len = 0; node *m, *o; - sql_key *rk = (sql_key*)os_find_id(k->t->s->keys, be->mvc->session->tr, ((sql_fkey*)k)->rkey); + sql_key *rk = (sql_key*)os_find_id(tr->cat->objects, tr, ((sql_fkey*)k)->rkey); stmt **new_updates; sql_table *t = mvc_bind_table(sql, k->t->s, k->t->base.name); @@ -4439,10 +4441,11 @@ static stmt* sql_update_cascade_Fkeys(backend *be, sql_key *k, stmt *utids, stmt **updates, int action) { mvc *sql = be->mvc; + sql_trans *tr = sql->session->tr; list *l = NULL; int len = 0; node *m, *o; - sql_key *rk = (sql_key*)os_find_id(k->t->s->keys, be->mvc->session->tr, ((sql_fkey*)k)->rkey); + sql_key *rk = (sql_key*)os_find_id(tr->cat->objects, tr, ((sql_fkey*)k)->rkey); stmt **new_updates; stmt *rows; sql_table *t = mvc_bind_table(sql, k->t->s, k->t->base.name); @@ -4500,20 +4503,22 @@ cascade_ukey(backend *be, stmt **updates { /* now iterate over all keys */ sql_trans *tr = be->mvc->session->tr; - struct os_iter oi; - os_iterator(&oi, k->t->s->keys, tr, NULL); - for (sql_base *b = oi_next(&oi); b; b=oi_next(&oi)) { - sql_key *fk = (sql_key*)b; - sql_fkey *rk = (sql_fkey*)b; - - if (fk->type != fkey || rk->rkey != k->base.id) - continue; - - /* All rows of the foreign key table which are - affected by the primary key update should all - match one of the updated primary keys again. - */ - switch (((sql_fkey*)fk)->on_update) { + list *keys = sql_trans_get_dependencies(tr, k->base.id, FKEY_DEPENDENCY, NULL); + if (keys) { + for (node *n = keys->h; n; n = n->next->next) { + sqlid fkey_id = *(sqlid*)n->data; + sql_base *b = os_find_id(tr->cat->objects, tr, fkey_id); + sql_key *fk = (sql_key*)b; + sql_fkey *rk = (sql_fkey*)b; + + if (fk->type != fkey || rk->rkey != k->base.id) + continue; + + /* All rows of the foreign key table which are + affected by the primary key update should all + match one of the updated primary keys again. + */ + switch (((sql_fkey*)fk)->on_update) { case ACT_NO_ACTION: break; case ACT_SET_NULL: @@ -4525,7 +4530,9 @@ cascade_ukey(backend *be, stmt **updates default: /*RESTRICT*/ if (!join_updated_pkey(be, fk, tids, updates)) return -1; + } } + list_destroy(keys); } return 0; } @@ -4602,8 +4609,9 @@ static stmt * join_idx_update(backend *be, sql_idx * i, stmt *ftids, stmt **updates, int updcol) { mvc *sql = be->mvc; + sql_trans *tr = sql->session->tr; node *m, *o; - sql_key *rk = (sql_key*)os_find_id(i->t->s->keys, be->mvc->session->tr, ((sql_fkey*)i->key)->rkey); + sql_key *rk = (sql_key*)os_find_id(tr->cat->objects, tr, ((sql_fkey*)i->key)->rkey); stmt *s = NULL, *ptids = stmt_tid(be, rk->t, 0), *l, *r; list *lje = sa_list(sql->sa); list *rje = sa_list(sql->sa); @@ -5081,49 +5089,53 @@ sql_delete_ukey(backend *be, stmt *utids sql_subtype *lng = sql_bind_localtype("lng"); sql_subtype *bt = sql_bind_localtype("bit"); sql_trans *tr = be->mvc->session->tr; - struct os_iter oi; - - os_iterator(&oi, k->t->s->keys, tr, NULL); - for (sql_base *b = oi_next(&oi); b; b=oi_next(&oi)) { - sql_key *fk = (sql_key*)b; - sql_fkey *rk = (sql_fkey*)b; - - if (fk->type != fkey || rk->rkey != k->base.id) - continue; - char *msg = NULL; - sql_subfunc *cnt = sql_bind_func(sql, "sys", "count", sql_bind_localtype("void"), NULL, F_AGGR); - sql_subfunc *ne = sql_bind_func_result(sql, "sys", "<>", F_FUNC, bt, 2, lng, lng); - stmt *s, *tids; - - tids = stmt_tid(be, fk->idx->t, 0); - s = stmt_idx(be, fk->idx, tids, tids->partition); - s = stmt_join(be, s, utids, 0, cmp_equal, 0, 0, false); /* join over the join index */ - s = stmt_result(be, s, 0); - tids = stmt_project(be, s, tids); - 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, 1), stmt_atom_lng(be, 0), NULL, ne); - msg = sa_message(sql->sa, SQLSTATE(40002) "%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); + list *keys = sql_trans_get_dependencies(tr, k->base.id, FKEY_DEPENDENCY, NULL); + + if (keys) { + for (node *n = keys->h; n; n = n->next->next) { + sqlid fkey_id = *(sqlid*)n->data; + sql_base *b = os_find_id(tr->cat->objects, tr, fkey_id); + sql_key *fk = (sql_key*)b; + sql_fkey *rk = (sql_fkey*)b; + + if (fk->type != fkey || rk->rkey != k->base.id) + continue; + char *msg = NULL; + sql_subfunc *cnt = sql_bind_func(sql, "sys", "count", sql_bind_localtype("void"), NULL, F_AGGR); + sql_subfunc *ne = sql_bind_func_result(sql, "sys", "<>", F_FUNC, bt, 2, lng, lng); + stmt *s, *tids; + + tids = stmt_tid(be, fk->idx->t, 0); + s = stmt_idx(be, fk->idx, tids, tids->partition); + s = stmt_join(be, s, utids, 0, cmp_equal, 0, 0, false); /* join over the join index */ + s = stmt_result(be, s, 0); + tids = stmt_project(be, s, tids); + 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, 1), stmt_atom_lng(be, 0), NULL, ne); + msg = sa_message(sql->sa, SQLSTATE(40002) "%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); + } } } + list_destroy(keys); } } @@ -5244,7 +5256,7 @@ struct tablelist { }; 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, int *error) +check_for_foreign_key_references(mvc *sql, struct tablelist* tlist, struct tablelist* next_append, sql_table *t, int cascade, int *error) { node *n; int found; @@ -5266,45 +5278,50 @@ check_for_foreign_key_references(mvc *sq sql_key *k = n->data; if (k->type == ukey || k->type == pkey) { - struct os_iter oi; - os_iterator(&oi, k->t->s->keys, tr, NULL); - for (sql_base *b = oi_next(&oi); b; b=oi_next(&oi)) { - sql_key *fk = (sql_key*)b; - sql_fkey *rk = (sql_fkey*)b; - - if (fk->type != fkey || rk->rkey != k->base.id) - continue; - k = fk; - /* make sure it is not a self referencing key */ - if (k->t != t && !cascade) { - node *n = t->columns.set->h; - sql_column *c = n->data; - size_t n_rows = store->storage_api.count_col(sql->session->tr, c, 1); - size_t n_deletes = store->storage_api.count_del(sql->session->tr, c->t); - assert (n_rows >= n_deletes); - if (n_rows - n_deletes > 0) { - sql_error(sql, 02, SQLSTATE(23000) "TRUNCATE: FOREIGN KEY %s.%s depends on %s", k->t->base.name, k->base.name, t->base.name); - *error = 1; - return; - } - } 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) { - if ((new_node = SA_NEW(sql->ta, struct tablelist)) == NULL) { - sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL); + list *keys = sql_trans_get_dependencies(tr, k->base.id, FKEY_DEPENDENCY, NULL); + + if (keys) { + for (node *n = keys->h; n; n = n->next->next) { + sqlid fkey_id = *(sqlid*)n->data; + sql_base *b = os_find_id(tr->cat->objects, tr, fkey_id); + sql_key *fk = (sql_key*)b; + sql_fkey *rk = (sql_fkey*)b; + + if (fk->type != fkey || rk->rkey != k->base.id) + continue; + k = fk; + /* make sure it is not a self referencing key */ + if (k->t != t && !cascade) { + node *n = t->columns.set->h; + sql_column *c = n->data; + size_t n_rows = store->storage_api.count_col(sql->session->tr, c, 1); + size_t n_deletes = store->storage_api.count_del(sql->session->tr, c->t); + assert (n_rows >= n_deletes); + if (n_rows - n_deletes > 0) { + sql_error(sql, 02, SQLSTATE(23000) "TRUNCATE: FOREIGN KEY %s.%s depends on %s", k->t->base.name, k->base.name, t->base.name); *error = 1; return; } - 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); + } else if (k->t != t) { + found = 0; + for (node_check = tlist; node_check; node_check = node_check->next) { + if (node_check->table == k->t) + found = 1; + } + if (!found) { + if ((new_node = SA_NEW(sql->ta, struct tablelist)) == NULL) { + sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL); + *error = 1; + return; + } + new_node->table = k->t; + new_node->next = NULL; + next_append->next = new_node; + check_for_foreign_key_references(sql, tlist, new_node, k->t, cascade, error); + } } } + list_destroy(keys); } } } 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 @@ -294,6 +294,7 @@ typedef struct sql_schema { typedef struct sql_catalog { struct objectset *schemas; + struct objectset *objects; } sql_catalog; typedef struct sql_trans { _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list