Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
04970a2f
Commit
04970a2f
authored
Aug 04, 2010
by
Jimmy Yang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix Bug #54582 stack overflow when opening many tables linked with
foreign keys at once
rb://391
approved by Heikki Z
parent
127ca525
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
278 additions
and
21 deletions
+278
-21
storage/innobase/dict/dict0load.c
storage/innobase/dict/dict0load.c
+75
-8
storage/innobase/handler/ha_innodb.cc
storage/innobase/handler/ha_innodb.cc
+10
-0
storage/innobase/include/db0err.h
storage/innobase/include/db0err.h
+3
-0
storage/innobase/include/dict0load.h
storage/innobase/include/dict0load.h
+2
-0
storage/innobase/include/dict0mem.h
storage/innobase/include/dict0mem.h
+21
-0
storage/innobase/include/que0que.h
storage/innobase/include/que0que.h
+3
-0
storage/innobase/row/row0mysql.c
storage/innobase/row/row0mysql.c
+19
-2
storage/innodb_plugin/ChangeLog
storage/innodb_plugin/ChangeLog
+8
-0
storage/innodb_plugin/dict/dict0load.c
storage/innodb_plugin/dict/dict0load.c
+75
-8
storage/innodb_plugin/handler/ha_innodb.cc
storage/innodb_plugin/handler/ha_innodb.cc
+13
-0
storage/innodb_plugin/include/db0err.h
storage/innodb_plugin/include/db0err.h
+3
-0
storage/innodb_plugin/include/dict0load.h
storage/innodb_plugin/include/dict0load.h
+2
-0
storage/innodb_plugin/include/dict0mem.h
storage/innodb_plugin/include/dict0mem.h
+21
-0
storage/innodb_plugin/include/que0que.h
storage/innodb_plugin/include/que0que.h
+3
-0
storage/innodb_plugin/row/row0merge.c
storage/innodb_plugin/row/row0merge.c
+1
-1
storage/innodb_plugin/row/row0mysql.c
storage/innodb_plugin/row/row0mysql.c
+19
-2
No files found.
storage/innobase/dict/dict0load.c
View file @
04970a2f
...
...
@@ -864,16 +864,27 @@ err_exit:
err
=
dict_load_indexes
(
table
,
heap
);
/* Initialize table foreign_child value. Its value could be
changed when dict_load_foreigns() is called below */
table
->
fk_max_recusive_level
=
0
;
/* If the force recovery flag is set, we open the table irrespective
of the error condition, since the user may want to dump data from the
clustered index. However we load the foreign key information only if
all indexes were loaded. */
if
(
err
==
DB_SUCCESS
)
{
err
=
dict_load_foreigns
(
table
->
name
,
TRUE
);
err
=
dict_load_foreigns
(
table
->
name
,
TRUE
,
TRUE
);
if
(
err
!=
DB_SUCCESS
)
{
dict_table_remove_from_cache
(
table
);
table
=
NULL
;
}
}
else
if
(
!
srv_force_recovery
)
{
dict_table_remove_from_cache
(
table
);
table
=
NULL
;
}
table
->
fk_max_recusive_level
=
0
;
#if 0
if (err != DB_SUCCESS && table != NULL) {
...
...
@@ -1095,8 +1106,12 @@ dict_load_foreign(
/* out: DB_SUCCESS or error code */
const
char
*
id
,
/* in: foreign constraint id as a
null-terminated string */
ibool
check_charsets
)
ibool
check_charsets
,
/* in: TRUE=check charset compatibility */
ibool
check_recursive
)
/* in: Whether to record the foreign table
parent count to avoid unlimited recursive
load of chained foreign tables */
{
dict_foreign_t
*
foreign
;
dict_table_t
*
sys_foreign
;
...
...
@@ -1110,6 +1125,8 @@ dict_load_foreign(
ulint
len
;
ulint
n_fields_and_type
;
mtr_t
mtr
;
dict_table_t
*
for_table
;
dict_table_t
*
ref_table
;
ut_ad
(
mutex_own
(
&
(
dict_sys
->
mutex
)));
...
...
@@ -1194,11 +1211,54 @@ dict_load_foreign(
dict_load_foreign_cols
(
id
,
foreign
);
/* If the foreign table is not yet in the dictionary cache, we
have to load it so that we are able to make type comparisons
in the next function call. */
dict_table_get_low
(
foreign
->
foreign_table_name
);
ref_table
=
dict_table_check_if_in_cache_low
(
foreign
->
referenced_table_name
);
/* We could possibly wind up in a deep recursive calls if
we call dict_table_get_low() again here if there
is a chain of tables concatenated together with
foreign constraints. In such case, each table is
both a parent and child of the other tables, and
act as a "link" in such table chains.
To avoid such scenario, we would need to check the
number of ancesters the current table has. If that
exceeds DICT_FK_MAX_CHAIN_LEN, we will stop loading
the child table.
Foreign constraints are loaded in a Breath First fashion,
that is, the index on FOR_NAME is scanned first, and then
index on REF_NAME. So foreign constrains in which
current table is a child (foreign table) are loaded first,
and then those constraints where current table is a
parent (referenced) table.
Thus we could check the parent (ref_table) table's
reference count (fk_max_recusive_level) to know how deep the
recursive call is. If the parent table (ref_table) is already
loaded, and its fk_max_recusive_level is larger than
DICT_FK_MAX_CHAIN_LEN, we will stop the recursive loading
by skipping loading the child table. It will not affect foreign
constraint check for DMLs since child table will be loaded
at that time for the constraint check. */
if
(
!
ref_table
||
ref_table
->
fk_max_recusive_level
<
DICT_FK_MAX_RECURSIVE_LOAD
)
{
/* If the foreign table is not yet in the dictionary cache, we
have to load it so that we are able to make type comparisons
in the next function call. */
for_table
=
dict_table_get_low
(
foreign
->
foreign_table_name
);
if
(
for_table
&&
ref_table
&&
check_recursive
)
{
/* This is to record the longest chain of ancesters
this table has, if the parent has more ancesters
than this table has, record it after add 1 (for this
parent */
if
(
ref_table
->
fk_max_recusive_level
>=
for_table
->
fk_max_recusive_level
)
{
for_table
->
fk_max_recusive_level
=
ref_table
->
fk_max_recusive_level
+
1
;
}
}
}
/* Note that there may already be a foreign constraint object in
the dictionary cache for this constraint: then the following
...
...
@@ -1223,6 +1283,8 @@ dict_load_foreigns(
/*===============*/
/* out: DB_SUCCESS or error code */
const
char
*
table_name
,
/* in: table name */
ibool
check_recursive
,
/* in: Whether to check recursive
load of tables chained by FK */
ibool
check_charsets
)
/* in: TRUE=check charset
compatibility */
{
...
...
@@ -1324,7 +1386,7 @@ loop:
/* Load the foreign constraint definition to the dictionary cache */
err
=
dict_load_foreign
(
id
,
check_charsets
);
err
=
dict_load_foreign
(
id
,
check_charsets
,
check_recursive
);
if
(
err
!=
DB_SUCCESS
)
{
btr_pcur_close
(
&
pcur
);
...
...
@@ -1352,6 +1414,11 @@ load_next_index:
mtr_start
(
&
mtr
);
/* Switch to scan index on REF_NAME, fk_max_recusive_level
already been updated when scanning FOR_NAME index, no need to
update again */
check_recursive
=
FALSE
;
goto
start_load
;
}
...
...
storage/innobase/handler/ha_innodb.cc
View file @
04970a2f
...
...
@@ -763,6 +763,16 @@ convert_error_code_to_mysql(
my_error
(
ER_QUERY_INTERRUPTED
,
MYF
(
0
));
return
(
-
1
);
}
else
if
(
error
==
DB_FOREIGN_EXCEED_MAX_CASCADE
)
{
push_warning_printf
(
thd
,
MYSQL_ERROR
::
WARN_LEVEL_WARN
,
HA_ERR_ROW_IS_REFERENCED
,
"InnoDB: Cannot delete/update "
"rows with cascading foreign key "
"constraints that exceed max "
"depth of %d. Please "
"drop extra constraints and try "
"again"
,
DICT_FK_MAX_RECURSIVE_LOAD
);
return
(
-
1
);
}
else
{
return
(
-
1
);
// Unknown error
}
...
...
storage/innobase/include/db0err.h
View file @
04970a2f
...
...
@@ -73,6 +73,9 @@ Created 5/24/1996 Heikki Tuuri
a later version of the engine. */
#define DB_INTERRUPTED 49
/* the query has been interrupted with
"KILL QUERY N;" */
#define DB_FOREIGN_EXCEED_MAX_CASCADE 50
/* Foreign key constraint related
cascading delete/update exceeds
maximum allowed depth */
/* The following are partial failure codes */
#define DB_FAIL 1000
...
...
storage/innobase/include/dict0load.h
View file @
04970a2f
...
...
@@ -82,6 +82,8 @@ dict_load_foreigns(
/*===============*/
/* out: DB_SUCCESS or error code */
const
char
*
table_name
,
/* in: table name */
ibool
check_recursive
,
/* in: Whether to check recursive
load of tables chained by FK */
ibool
check_charsets
);
/* in: TRUE=check charsets
compatibility */
/************************************************************************
...
...
storage/innobase/include/dict0mem.h
View file @
04970a2f
...
...
@@ -283,6 +283,21 @@ a foreign key constraint is enforced, therefore RESTRICT just means no flag */
#define DICT_FOREIGN_ON_DELETE_NO_ACTION 16
#define DICT_FOREIGN_ON_UPDATE_NO_ACTION 32
/** Tables could be chained together with Foreign key constraint. When
first load the parent table, we would load all of its descedents.
This could result in rescursive calls and out of stack error eventually.
DICT_FK_MAX_RECURSIVE_LOAD defines the maximum number of recursive loads,
when exceeded, the child table will not be loaded. It will be loaded when
the foreign constraint check needs to be run. */
#define DICT_FK_MAX_RECURSIVE_LOAD 250
/** Similarly, when tables are chained together with foreign key constraints
with on cascading delete/update clause, delete from parent table could
result in recursive cascading calls. This defines the maximum number of
such cascading deletes/updates allowed. When exceeded, the delete from
parent table will fail, and user has to drop excessive foreign constraint
before proceeds. */
#define FK_MAX_CASCADE_DEL 300
/* Data structure for a database table */
struct
dict_table_struct
{
...
...
@@ -339,6 +354,12 @@ struct dict_table_struct{
NOT allowed until this count gets to zero;
MySQL does NOT itself check the number of
open handles at drop */
unsigned
fk_max_recusive_level
:
8
;
/*!< maximum recursive level we support when
loading tables chained together with FK
constraints. If exceeds this level, we will
stop loading child table into memory along with
its parent table */
ulint
n_foreign_key_checks_running
;
/* count of how many foreign key check
operations are currently being performed
...
...
storage/innobase/include/que0que.h
View file @
04970a2f
...
...
@@ -367,6 +367,9 @@ struct que_thr_struct{
thus far */
ulint
lock_state
;
/* lock state of thread (table or
row) */
ulint
fk_cascade_depth
;
/*!< maximum cascading call depth
supported for foreign key constraint
related delete/updates */
};
#define QUE_THR_MAGIC_N 8476583
...
...
storage/innobase/row/row0mysql.c
View file @
04970a2f
...
...
@@ -555,6 +555,12 @@ handle_new_error:
"forcing-recovery.html"
" for help.
\n
"
,
stderr
);
}
else
if
(
err
==
DB_FOREIGN_EXCEED_MAX_CASCADE
)
{
fprintf
(
stderr
,
"InnoDB: Cannot delete/update rows with"
" cascading foreign key constraints that exceed max"
" depth of %lu
\n
"
"Please drop excessive foreign constraints"
" and try again
\n
"
,
(
ulong
)
DICT_FK_MAX_RECURSIVE_LOAD
);
}
else
{
fprintf
(
stderr
,
"InnoDB: unknown error code %lu
\n
"
,
(
ulong
)
err
);
...
...
@@ -1406,11 +1412,15 @@ row_update_for_mysql(
run_again:
thr
->
run_node
=
node
;
thr
->
prev_node
=
node
;
thr
->
fk_cascade_depth
=
0
;
row_upd_step
(
thr
);
err
=
trx
->
error_state
;
/* Reset fk_cascade_depth back to 0 */
thr
->
fk_cascade_depth
=
0
;
if
(
err
!=
DB_SUCCESS
)
{
que_thr_stop_for_mysql
(
thr
);
...
...
@@ -1597,6 +1607,12 @@ row_update_cascade_for_mysql(
trx_t
*
trx
;
trx
=
thr_get_trx
(
thr
);
thr
->
fk_cascade_depth
++
;
if
(
thr
->
fk_cascade_depth
>
FK_MAX_CASCADE_DEL
)
{
return
(
DB_FOREIGN_EXCEED_MAX_CASCADE
);
}
run_again:
thr
->
run_node
=
node
;
thr
->
prev_node
=
node
;
...
...
@@ -2129,7 +2145,7 @@ row_table_add_foreign_constraints(
if
(
err
==
DB_SUCCESS
)
{
/* Check that also referencing constraints are ok */
err
=
dict_load_foreigns
(
name
,
TRUE
);
err
=
dict_load_foreigns
(
name
,
FALSE
,
TRUE
);
}
if
(
err
!=
DB_SUCCESS
)
{
...
...
@@ -3878,7 +3894,8 @@ end:
an ALTER, not in a RENAME. */
err
=
dict_load_foreigns
(
new_name
,
old_is_tmp
?
trx
->
check_foreigns
:
TRUE
);
new_name
,
FALSE
,
old_is_tmp
?
trx
->
check_foreigns
:
TRUE
);
if
(
err
!=
DB_SUCCESS
)
{
ut_print_timestamp
(
stderr
);
...
...
storage/innodb_plugin/ChangeLog
View file @
04970a2f
2010-08-03 The InnoDB Team
* dict/dict0load.c, handler/ha_innodb.cc, include/db0err.h,
include/dict0load.h, include/dict0mem.h, include/que0que.h,
row/row0merge.c, row/row0mysql.c:
Fix Bug#54582 stack overflow when opening many tables linked
with foreign keys at once
2010-07-27 The InnoDB Team
* include/mem0pool.h, mem/mem0mem.c, mem/mem0pool.c, srv/srv0start.c:
...
...
storage/innodb_plugin/dict/dict0load.c
View file @
04970a2f
...
...
@@ -1009,16 +1009,27 @@ err_exit:
err
=
dict_load_indexes
(
table
,
heap
);
/* Initialize table foreign_child value. Its value could be
changed when dict_load_foreigns() is called below */
table
->
fk_max_recusive_level
=
0
;
/* If the force recovery flag is set, we open the table irrespective
of the error condition, since the user may want to dump data from the
clustered index. However we load the foreign key information only if
all indexes were loaded. */
if
(
err
==
DB_SUCCESS
)
{
err
=
dict_load_foreigns
(
table
->
name
,
TRUE
);
err
=
dict_load_foreigns
(
table
->
name
,
TRUE
,
TRUE
);
if
(
err
!=
DB_SUCCESS
)
{
dict_table_remove_from_cache
(
table
);
table
=
NULL
;
}
}
else
if
(
!
srv_force_recovery
)
{
dict_table_remove_from_cache
(
table
);
table
=
NULL
;
}
table
->
fk_max_recusive_level
=
0
;
#if 0
if (err != DB_SUCCESS && table != NULL) {
...
...
@@ -1241,8 +1252,12 @@ dict_load_foreign(
/*==============*/
const
char
*
id
,
/*!< in: foreign constraint id as a
null-terminated string */
ibool
check_charsets
)
ibool
check_charsets
,
/*!< in: TRUE=check charset compatibility */
ibool
check_recursive
)
/*!< in: Whether to record the foreign table
parent count to avoid unlimited recursive
load of chained foreign tables */
{
dict_foreign_t
*
foreign
;
dict_table_t
*
sys_foreign
;
...
...
@@ -1256,6 +1271,8 @@ dict_load_foreign(
ulint
len
;
ulint
n_fields_and_type
;
mtr_t
mtr
;
dict_table_t
*
for_table
;
dict_table_t
*
ref_table
;
ut_ad
(
mutex_own
(
&
(
dict_sys
->
mutex
)));
...
...
@@ -1340,11 +1357,54 @@ dict_load_foreign(
dict_load_foreign_cols
(
id
,
foreign
);
/* If the foreign table is not yet in the dictionary cache, we
have to load it so that we are able to make type comparisons
in the next function call. */
dict_table_get_low
(
foreign
->
foreign_table_name
);
ref_table
=
dict_table_check_if_in_cache_low
(
foreign
->
referenced_table_name
);
/* We could possibly wind up in a deep recursive calls if
we call dict_table_get_low() again here if there
is a chain of tables concatenated together with
foreign constraints. In such case, each table is
both a parent and child of the other tables, and
act as a "link" in such table chains.
To avoid such scenario, we would need to check the
number of ancesters the current table has. If that
exceeds DICT_FK_MAX_CHAIN_LEN, we will stop loading
the child table.
Foreign constraints are loaded in a Breath First fashion,
that is, the index on FOR_NAME is scanned first, and then
index on REF_NAME. So foreign constrains in which
current table is a child (foreign table) are loaded first,
and then those constraints where current table is a
parent (referenced) table.
Thus we could check the parent (ref_table) table's
reference count (fk_max_recusive_level) to know how deep the
recursive call is. If the parent table (ref_table) is already
loaded, and its fk_max_recusive_level is larger than
DICT_FK_MAX_CHAIN_LEN, we will stop the recursive loading
by skipping loading the child table. It will not affect foreign
constraint check for DMLs since child table will be loaded
at that time for the constraint check. */
if
(
!
ref_table
||
ref_table
->
fk_max_recusive_level
<
DICT_FK_MAX_RECURSIVE_LOAD
)
{
/* If the foreign table is not yet in the dictionary cache, we
have to load it so that we are able to make type comparisons
in the next function call. */
for_table
=
dict_table_get_low
(
foreign
->
foreign_table_name
);
if
(
for_table
&&
ref_table
&&
check_recursive
)
{
/* This is to record the longest chain of ancesters
this table has, if the parent has more ancesters
than this table has, record it after add 1 (for this
parent */
if
(
ref_table
->
fk_max_recusive_level
>=
for_table
->
fk_max_recusive_level
)
{
for_table
->
fk_max_recusive_level
=
ref_table
->
fk_max_recusive_level
+
1
;
}
}
}
/* Note that there may already be a foreign constraint object in
the dictionary cache for this constraint: then the following
...
...
@@ -1369,6 +1429,8 @@ ulint
dict_load_foreigns
(
/*===============*/
const
char
*
table_name
,
/*!< in: table name */
ibool
check_recursive
,
/*!< in: Whether to check recursive
load of tables chained by FK */
ibool
check_charsets
)
/*!< in: TRUE=check charset
compatibility */
{
...
...
@@ -1470,7 +1532,7 @@ loop:
/* Load the foreign constraint definition to the dictionary cache */
err
=
dict_load_foreign
(
id
,
check_charsets
);
err
=
dict_load_foreign
(
id
,
check_charsets
,
check_recursive
);
if
(
err
!=
DB_SUCCESS
)
{
btr_pcur_close
(
&
pcur
);
...
...
@@ -1498,6 +1560,11 @@ load_next_index:
mtr_start
(
&
mtr
);
/* Switch to scan index on REF_NAME, fk_max_recusive_level
already been updated when scanning FOR_NAME index, no need to
update again */
check_recursive
=
FALSE
;
goto
start_load
;
}
...
...
storage/innodb_plugin/handler/ha_innodb.cc
View file @
04970a2f
...
...
@@ -767,6 +767,19 @@ convert_error_code_to_mysql(
case
DB_INTERRUPTED
:
my_error
(
ER_QUERY_INTERRUPTED
,
MYF
(
0
));
/* fall through */
case
DB_FOREIGN_EXCEED_MAX_CASCADE
:
push_warning_printf
(
thd
,
MYSQL_ERROR
::
WARN_LEVEL_WARN
,
HA_ERR_ROW_IS_REFERENCED
,
"InnoDB: Cannot delete/update "
"rows with cascading foreign key "
"constraints that exceed max "
"depth of %d. Please "
"drop extra constraints and try "
"again"
,
DICT_FK_MAX_RECURSIVE_LOAD
);
/* fall through */
case
DB_ERROR
:
default:
return
(
-
1
);
/* unspecified error */
...
...
storage/innodb_plugin/include/db0err.h
View file @
04970a2f
...
...
@@ -94,6 +94,9 @@ enum db_err {
DB_PRIMARY_KEY_IS_NULL
,
/* a column in the PRIMARY KEY
was found to be NULL */
DB_FOREIGN_EXCEED_MAX_CASCADE
,
/* Foreign key constraint related
cascading delete/update exceeds
maximum allowed depth */
/* The following are partial failure codes */
DB_FAIL
=
1000
,
...
...
storage/innodb_plugin/include/dict0load.h
View file @
04970a2f
...
...
@@ -97,6 +97,8 @@ ulint
dict_load_foreigns
(
/*===============*/
const
char
*
table_name
,
/*!< in: table name */
ibool
check_recursive
,
/*!< in: Whether to check recursive
load of tables chained by FK */
ibool
check_charsets
);
/*!< in: TRUE=check charsets
compatibility */
/********************************************************************//**
...
...
storage/innodb_plugin/include/dict0mem.h
View file @
04970a2f
...
...
@@ -112,6 +112,21 @@ ROW_FORMAT=REDUNDANT. */
in table->flags. */
/* @} */
/** Tables could be chained together with Foreign key constraint. When
first load the parent table, we would load all of its descedents.
This could result in rescursive calls and out of stack error eventually.
DICT_FK_MAX_RECURSIVE_LOAD defines the maximum number of recursive loads,
when exceeded, the child table will not be loaded. It will be loaded when
the foreign constraint check needs to be run. */
#define DICT_FK_MAX_RECURSIVE_LOAD 250
/** Similarly, when tables are chained together with foreign key constraints
with on cascading delete/update clause, delete from parent table could
result in recursive cascading calls. This defines the maximum number of
such cascading deletes/updates allowed. When exceeded, the delete from
parent table will fail, and user has to drop excessive foreign constraint
before proceeds. */
#define FK_MAX_CASCADE_DEL 300
/**********************************************************************//**
Creates a table memory object.
...
...
@@ -434,6 +449,12 @@ struct dict_table_struct{
NOT allowed until this count gets to zero;
MySQL does NOT itself check the number of
open handles at drop */
unsigned
fk_max_recusive_level
:
8
;
/*!< maximum recursive level we support when
loading tables chained together with FK
constraints. If exceeds this level, we will
stop loading child table into memory along with
its parent table */
ulint
n_foreign_key_checks_running
;
/*!< count of how many foreign key check
operations are currently being performed
...
...
storage/innodb_plugin/include/que0que.h
View file @
04970a2f
...
...
@@ -381,6 +381,9 @@ struct que_thr_struct{
thus far */
ulint
lock_state
;
/*!< lock state of thread (table or
row) */
ulint
fk_cascade_depth
;
/*!< maximum cascading call depth
supported for foreign key constraint
related delete/updates */
};
#define QUE_THR_MAGIC_N 8476583
...
...
storage/innodb_plugin/row/row0merge.c
View file @
04970a2f
...
...
@@ -2395,7 +2395,7 @@ row_merge_rename_tables(
goto
err_exit
;
}
err
=
dict_load_foreigns
(
old_name
,
TRUE
);
err
=
dict_load_foreigns
(
old_name
,
FALSE
,
TRUE
);
if
(
err
!=
DB_SUCCESS
)
{
err_exit:
...
...
storage/innodb_plugin/row/row0mysql.c
View file @
04970a2f
...
...
@@ -576,6 +576,13 @@ handle_new_error:
"InnoDB: "
REFMAN
"forcing-recovery.html"
" for help.
\n
"
,
stderr
);
break
;
case
DB_FOREIGN_EXCEED_MAX_CASCADE
:
fprintf
(
stderr
,
"InnoDB: Cannot delete/update rows with"
" cascading foreign key constraints that exceed max"
" depth of %lu
\n
"
"Please drop excessive foreign constraints"
" and try again
\n
"
,
(
ulong
)
DICT_FK_MAX_RECURSIVE_LOAD
);
break
;
default:
fprintf
(
stderr
,
"InnoDB: unknown error code %lu
\n
"
,
(
ulong
)
err
);
...
...
@@ -1381,11 +1388,15 @@ row_update_for_mysql(
run_again:
thr
->
run_node
=
node
;
thr
->
prev_node
=
node
;
thr
->
fk_cascade_depth
=
0
;
row_upd_step
(
thr
);
err
=
trx
->
error_state
;
/* Reset fk_cascade_depth back to 0 */
thr
->
fk_cascade_depth
=
0
;
if
(
err
!=
DB_SUCCESS
)
{
que_thr_stop_for_mysql
(
thr
);
...
...
@@ -1576,6 +1587,12 @@ row_update_cascade_for_mysql(
trx_t
*
trx
;
trx
=
thr_get_trx
(
thr
);
thr
->
fk_cascade_depth
++
;
if
(
thr
->
fk_cascade_depth
>
FK_MAX_CASCADE_DEL
)
{
return
(
DB_FOREIGN_EXCEED_MAX_CASCADE
);
}
run_again:
thr
->
run_node
=
node
;
thr
->
prev_node
=
node
;
...
...
@@ -2056,7 +2073,7 @@ row_table_add_foreign_constraints(
name
,
reject_fks
);
if
(
err
==
DB_SUCCESS
)
{
/* Check that also referencing constraints are ok */
err
=
dict_load_foreigns
(
name
,
TRUE
);
err
=
dict_load_foreigns
(
name
,
FALSE
,
TRUE
);
}
if
(
err
!=
DB_SUCCESS
)
{
...
...
@@ -3915,7 +3932,7 @@ end:
an ALTER, not in a RENAME. */
err
=
dict_load_foreigns
(
new_name
,
!
old_is_tmp
||
trx
->
check_foreigns
);
new_name
,
FALSE
,
!
old_is_tmp
||
trx
->
check_foreigns
);
if
(
err
!=
DB_SUCCESS
)
{
ut_print_timestamp
(
stderr
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment