diff options
author | unknown <marko@hundin.mysql.fi> | 2004-07-15 15:46:22 +0300 |
---|---|---|
committer | unknown <marko@hundin.mysql.fi> | 2004-07-15 15:46:22 +0300 |
commit | 139855210b9b1c8ce098ecc40bf66e0057d0c8df (patch) | |
tree | 9393fd73cf98bf7af60cc6f5cc9dc9556efcd0fc /innobase | |
parent | 9e6f619834527dfa031df16cf494765de3098720 (diff) | |
download | mariadb-git-139855210b9b1c8ce098ecc40bf66e0057d0c8df.tar.gz |
InnoDB: limit the recursion depth for ON (UPDATE|DELETE) CASCADE
(Bug #4446)
innobase/row/row0ins.c:
row_ins_foreign_check_on_constraint(): limit recursion for UPDATE too
mysql-test/r/innodb.result:
Add test for recursion depth limit
mysql-test/t/innodb.test:
Add test for recursion depth limit
Diffstat (limited to 'innobase')
-rw-r--r-- | innobase/row/row0ins.c | 78 |
1 files changed, 65 insertions, 13 deletions
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 93d360eaaeb..458970da4e2 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -370,6 +370,32 @@ row_ins_cascade_ancestor_updates_table( return(FALSE); } +/************************************************************************* +Returns the number of ancestor UPDATE or DELETE nodes of a +cascaded update/delete node. */ +static +ulint +row_ins_cascade_n_ancestors( +/*========================*/ + /* out: number of ancestors */ + que_node_t* node) /* in: node in a query graph */ +{ + que_node_t* parent; + ulint n_ancestors = 0; + + parent = que_node_get_parent(node); + + while (que_node_get_type(parent) == QUE_NODE_UPDATE) { + n_ancestors++; + + parent = que_node_get_parent(parent); + + ut_a(parent); + } + + return(n_ancestors); +} + /********************************************************************** Calculates the update vector node->cascade->update for a child table in a cascaded update. */ @@ -616,6 +642,34 @@ row_ins_foreign_report_add_err( } /************************************************************************* +Invalidate the query cache for the given table. */ +static +void +row_ins_invalidate_query_cache( +/*===========================*/ + que_thr_t* thr, /* in: query thread whose run_node + is an update node */ + const char* name) /* in: table name prefixed with + database name and a '/' character */ +{ + char* buf; + char* ptr; + ulint len = strlen(name) + 1; + + buf = mem_strdupl(name, len); + + ptr = strchr(buf, '/'); + ut_a(ptr); + *ptr = '\0'; + + /* We call a function in ha_innodb.cc */ +#ifndef UNIV_HOTBACKUP + innobase_invalidate_query_cache(thr_get_trx(thr), buf, len); +#endif + mem_free(buf); +} + +/************************************************************************* Perform referential actions or checks when a parent row is deleted or updated and the constraint had an ON DELETE or ON UPDATE condition which was not RESTRICT. */ @@ -650,26 +704,14 @@ row_ins_foreign_check_on_constraint( ulint n_to_update; ulint err; ulint i; - char* ptr; - char table_name_buf[1000]; ut_a(thr && foreign && pcur && mtr); /* Since we are going to delete or update a row, we have to invalidate the MySQL query cache for table */ - ut_a(ut_strlen(table->name) < 998); - strcpy(table_name_buf, table->name); + row_ins_invalidate_query_cache(thr, table->name); - ptr = strchr(table_name_buf, '/'); - ut_a(ptr); - *ptr = '\0'; - - /* We call a function in ha_innodb.cc */ -#ifndef UNIV_HOTBACKUP - innobase_invalidate_query_cache(thr_get_trx(thr), table_name_buf, - ut_strlen(table->name) + 1); -#endif node = thr->run_node; if (node->is_delete && 0 == (foreign->type & @@ -756,6 +798,16 @@ row_ins_foreign_check_on_constraint( goto nonstandard_exit_func; } + if (row_ins_cascade_n_ancestors(cascade) >= 15) { + err = DB_ROW_IS_REFERENCED; + + row_ins_foreign_report_err( +(char*)"Trying a too deep cascaded delete or update\n", + thr, foreign, btr_pcur_get_rec(pcur), entry); + + goto nonstandard_exit_func; + } + index = btr_pcur_get_btr_cur(pcur)->index; ut_a(index == foreign->foreign_index); |