MySQL 9.6.0
Source Code Documentation
sql_foreign_key_constraint.cc File Reference
#include "sql/sql_foreign_key_constraint.h"
#include <set>
#include "scope_guard.h"
#include "sql/dd/dd.h"
#include "sql/dd/dd_table.h"
#include "sql/dd/dictionary.h"
#include "sql/dd/types/foreign_key.h"
#include "sql/dd/types/foreign_key_element.h"
#include "sql/field.h"
#include "sql/histograms/table_histograms.h"
#include "sql/key.h"
#include "sql/mysqld.h"
#include "sql/sql_base.h"
#include "sql/sql_class.h"
#include "sql/table.h"

Classes

class  Foreign_key_chain
 Class to store all foreign key names during CASCADE. More...
 
class  No_fk_checks_guard
 Helper to temporarily enable OPTION_NO_FOREIGN_KEY_CHECKS within a scope and restore the thread option bits during exit. More...
 

Functions

static bool check_all_child_fk_ref (THD *thd, const TABLE *table_p, enum_fk_dml_type dml_type, Foreign_key_chain *chain)
 Check all foreign key constraints on child tables for DML operation on a parent table. More...
 
static std::string build_fk_error_message (THD *thd, bool check_child_access, bool check_parent_access, const TABLE *tbl, TABLE_SHARE_FOREIGN_KEY_INFO *fk)
 Helper function to prepare error message. More...
 
static bool report_row_referenced_error (THD *thd, const TABLE *table_c, TABLE_SHARE_FOREIGN_KEY_INFO *fk)
 Reports ER_ROW_IS_REFERENCED_2 error with fk information. More...
 
static bool report_no_referenced_row_error (THD *thd, const TABLE *table_c, TABLE_SHARE_FOREIGN_KEY_INFO *fk)
 Reports ER_NO_REFERENCED_ROW_2 error with fk information. More...
 
static TABLEfind_fk_table_from_open_tables (THD *thd, const char *db_name, const char *table_name, const char *fk_name)
 Find TABLE instance of a foreign key table from the THD::open_tables list. More...
 
static uint get_key_index (const TABLE *table, uint num_columns, LEX_CSTRING *col_names)
 Function to get index of key matching col_names in keys list. More...
 
static bool is_column_updated (const TABLE *table, uint num_key_cols, LEX_CSTRING *col_names)
 Function to check if any of the foreign key columns updated. More...
 
static bool is_self_fk_value_same (const TABLE *table_c, TABLE_SHARE_FOREIGN_KEY_INFO *fk)
 Function to check value of foreign key columns and parent columns are same in case self referencing foreign key. More...
 
static bool check_and_acquire_MDL_lock (THD *thd, const char *db_name, const char *table_name, enum_mdl_type mdl_type)
 Check if MDL lock is already acquired on the table. More...
 
static TABLEopen_table_for_fk (THD *thd, const char *db_name, const char *table_name)
 Function to open table for foreign key validation. More...
 
static bool is_fk_cascade (TABLE *table, enum_fk_dml_type dml_type, const char *fk_name)
 Function to check if CASCADE action is defined for a foreign key on UPDATE or DELETE operations. More...
 
static bool get_foreign_key_table (THD *thd, const char *db_name, const char *table_name, const char *fk_name, enum_fk_dml_type dml_type, bool open_table, TABLE **table, bool *table_exists, bool *is_table_opened)
 Function to get TABLE instance of a other table in FK relationship. More...
 
static bool set_updated_key_value (THD *thd, TABLE *table_c, int child_key_idx, const TABLE *table_p, int parent_key_idx, TABLE_SHARE_FOREIGN_KEY_INFO *fk)
 Function to copy value to child table columns during UPDATE CASCADE operation. More...
 
static bool set_key_value_null (TABLE *table, uint num_key_cols, LEX_CSTRING *col_names)
 Function to set the null value for key columns. More...
 
bool is_cascade_from_parent_legal (const TABLE *table_p, const KEY *key_info_p, const KEY *key_info_c)
 Determine whether a cascaded update from the current state of the parent table record's foreign keys to the corresponding child table's foreign keys is legal. More...
 
static bool on_delete_on_update_restrict_or_no_action (THD *thd, const TABLE *table_c, TABLE_SHARE_FOREIGN_KEY_INFO *fk_c, enum_fk_dml_type dml_type)
 Helper function to apply ON DELETE/ON UPDATE RESTRICT or NOACTION to child table on DML operation. More...
 
static bool on_delete_cascade (THD *thd, TABLE *table_c, TABLE_SHARE_FOREIGN_KEY_INFO *fk_c, enum_fk_dml_type dml_type, uchar *key_value, int key_len, Foreign_key_chain *chain, int *error)
 Helper function to apply ON DELETE CASCADE to child table on DML operation. More...
 
static bool on_update_cascade (THD *thd, const TABLE *table_p, TABLE *table_c, TABLE_SHARE_FOREIGN_KEY_INFO *fk_c, KEY *key_info_p, uint parent_key_idx, KEY *key_info_c, uint child_key_idx, enum_fk_dml_type dml_type, uchar *key_value, int key_len, Foreign_key_chain *chain, int *error)
 Function to apply ON UPDATE CASCADE to child table on DML operation. More...
 
static bool on_delete_on_update_set_null (THD *thd, const TABLE *table_p, TABLE *table_c, TABLE_SHARE_FOREIGN_KEY_INFO *fk_c, enum_fk_dml_type dml_type, uchar *key_value, int key_len, Foreign_key_chain *chain, int *error)
 Helper function to apply ON DELETE/ON UPDATE SET NULL to child table on DML operation. More...
 
static bool check_child_fk_ref (THD *thd, const TABLE *table_p, TABLE *table_c, TABLE_SHARE_FOREIGN_KEY_INFO *fk_c, enum_fk_dml_type dml_type, Foreign_key_chain *chain)
 Checks foreign key constraint on child table. More...
 
static bool check_parent_fk_ref (THD *thd, const TABLE *table_c, TABLE *table_p, TABLE_SHARE_FOREIGN_KEY_INFO *fk, enum_fk_dml_type dml_type)
 
static bool skip_foreign_key_checks (THD *thd, const TABLE *table)
 Helper function to skip foreign checks. More...
 
bool check_all_parent_fk_ref (THD *thd, const TABLE *table_c, enum_fk_dml_type dml_type)
 Check all foreign key constraints on parent tables for DML operation on a child table. More...
 
bool check_all_child_fk_ref (THD *thd, const TABLE *table, enum_fk_dml_type dml_type)
 Check all foreign key constraints on child tables for DML operation on a parent table. More...
 
bool is_foreign_key_table_opened (THD *thd, const char *db_name, const char *table_name, const char *fk_name)
 Check if TABLE instance for foreign key is already opened. More...
 

Variables

constexpr uint32_t FK_MAX_CASCADE_DEPTH = 15
 With the ON CASCADE DELETE/UPDATE clause, deleting from the parent table can trigger recursive cascading calls. More...
 

Function Documentation

◆ build_fk_error_message()

static std::string build_fk_error_message ( THD thd,
bool  check_child_access,
bool  check_parent_access,
const TABLE tbl,
TABLE_SHARE_FOREIGN_KEY_INFO fk 
)
static

Helper function to prepare error message.

Parameters
thdThread handle.
check_child_accessCheck child table privileges.
check_parent_accessCheck parent table privileges.
tblTABLE instance.
fkForeign Key Info instance.
Returns
std::string Error message.

◆ check_all_child_fk_ref() [1/2]

bool check_all_child_fk_ref ( THD thd,
const TABLE table_p,
enum_fk_dml_type  dml_type 
)

Check all foreign key constraints on child tables for DML operation on a parent table.

Parameters
thdThread handle.
table_pTABLE instance of a parent table.
dml_typeDML operation type.
Returns
true On error.
false On Success.

◆ check_all_child_fk_ref() [2/2]

static bool check_all_child_fk_ref ( THD thd,
const TABLE table_p,
enum_fk_dml_type  dml_type,
Foreign_key_chain chain 
)
static

Check all foreign key constraints on child tables for DML operation on a parent table.

Parameters
thdThread handle.
table_pTABLE instance of a parent table.
dml_typeDML operation type.
chainForeign key chain.
Returns
true On error.
false On Success.

◆ check_all_parent_fk_ref()

bool check_all_parent_fk_ref ( THD thd,
const TABLE table_c,
enum_fk_dml_type  dml_type 
)

Check all foreign key constraints on parent tables for DML operation on a child table.

Parameters
thdThread handle.
table_cTABLE instance of a child table.
dml_typeDML operation type.
Returns
true On error.
false On Success.

◆ check_and_acquire_MDL_lock()

static bool check_and_acquire_MDL_lock ( THD thd,
const char *  db_name,
const char *  table_name,
enum_mdl_type  mdl_type 
)
static

Check if MDL lock is already acquired on the table.

If not, then acquire MDL lock on the schema and table.

Parameters
thdThread Handle.
db_nameDB name.
table_nameTable name.
mdl_typeMDL lock type.
Returns
true On error.
false On success.

◆ check_child_fk_ref()

static bool check_child_fk_ref ( THD thd,
const TABLE table_p,
TABLE table_c,
TABLE_SHARE_FOREIGN_KEY_INFO fk_c,
enum_fk_dml_type  dml_type,
Foreign_key_chain chain 
)
static

Checks foreign key constraint on child table.

Parameters
thdThread Handle.
table_pTABLE instance of a parent table.
table_cTABLE instance of a child table.
fk_cForeign key information.
dml_typeDML operation type.
chainForeign key chain.
Returns
true On error.
false On success.

◆ check_parent_fk_ref()

static bool check_parent_fk_ref ( THD thd,
const TABLE table_c,
TABLE table_p,
TABLE_SHARE_FOREIGN_KEY_INFO fk,
enum_fk_dml_type  dml_type 
)
static

◆ find_fk_table_from_open_tables()

static TABLE * find_fk_table_from_open_tables ( THD thd,
const char *  db_name,
const char *  table_name,
const char *  fk_name 
)
static

Find TABLE instance of a foreign key table from the THD::open_tables list.

Parameters
thdThread Handle.
db_nameDB name.
table_nameTable name.
fk_nameForeign key name.
Returns
TABLE* TABLE instance if found, otherwise nullptr.

◆ get_foreign_key_table()

static bool get_foreign_key_table ( THD thd,
const char *  db_name,
const char *  table_name,
const char *  fk_name,
enum_fk_dml_type  dml_type,
bool  open_table,
TABLE **  table,
bool *  table_exists,
bool *  is_table_opened 
)
static

Function to get TABLE instance of a other table in FK relationship.

Table is first searched in the open table list. If table is not opened or scan is already opened, then table is opened.

Parameters
thdThread Handle.
db_nameDB name.
table_nameTable name.
fk_nameForeign key name. If lock is not acquired, then MDL is acquired before opening the table.
dml_typeDML operation type. If lock is not acquired, then MDL is acquired before opening the table.
open_tableDo not search table in open_tables list, instead open table always.
[out]tableTABLE instance.
[out]table_existsFlag is set to true, if table does not exists.
[out]is_table_openedFlag is set to true, if a table is opened.
Returns
true On error.
false On success.

◆ get_key_index()

static uint get_key_index ( const TABLE table,
uint  num_columns,
LEX_CSTRING col_names 
)
static

Function to get index of key matching col_names in keys list.

Parameters
tableTABLE instance.
num_columnsNumber of columns.
col_namesList of column names.
Returns
index of key in keys list on success, UINT_MAX if key not found.

◆ is_cascade_from_parent_legal()

bool is_cascade_from_parent_legal ( const TABLE table_p,
const KEY key_info_p,
const KEY key_info_c 
)

Determine whether a cascaded update from the current state of the parent table record's foreign keys to the corresponding child table's foreign keys is legal.

An example of an illegal cascade is when a parent table foreign key column is a VARCHAR with a corresponding child foreign key CHAR column AND the length of the value in the parent column exceeds the number of characters allowed in the child column.

Parameters
table_pparent table from which to check cascade.
key_info_pdescriptor of the foreign key index in the parent table.
key_info_cdescriptor of the foreign key index in the child table.
Return values
trueif the cascaded update is legal, false if the cascaded update is not legal.

◆ is_column_updated()

static bool is_column_updated ( const TABLE table,
uint  num_key_cols,
LEX_CSTRING col_names 
)
static

Function to check if any of the foreign key columns updated.

Parameters
tableTABLE instance for a table.
num_key_colsNumber of columns.
col_namesList of columns.
Returns
true If any column is updated.
false If columns are not updated.

◆ is_fk_cascade()

static bool is_fk_cascade ( TABLE table,
enum_fk_dml_type  dml_type,
const char *  fk_name 
)
static

Function to check if CASCADE action is defined for a foreign key on UPDATE or DELETE operations.

Parameters
tableTABLE instance of a table.
dml_typeDML operation type.
fk_nameForeign key information.
Returns
true If CASCADE action for a DML operation is set.
false Otherwise.

◆ is_foreign_key_table_opened()

bool is_foreign_key_table_opened ( THD thd,
const char *  db_name,
const char *  table_name,
const char *  fk_name 
)

Check if TABLE instance for foreign key is already opened.

Parameters
thdThread handle.
db_nameDB name.
table_nameTable name.
fk_nameForeign key name.
Returns
true If table for foreign key is already opened.
false If table is not opened.

◆ is_self_fk_value_same()

static bool is_self_fk_value_same ( const TABLE table_c,
TABLE_SHARE_FOREIGN_KEY_INFO fk 
)
static

Function to check value of foreign key columns and parent columns are same in case self referencing foreign key.

Parameters
table_cTABLE instance of a table.
fkForeign key information.
Returns
true If values are same.
false otherwise.

◆ on_delete_cascade()

static bool on_delete_cascade ( THD thd,
TABLE table_c,
TABLE_SHARE_FOREIGN_KEY_INFO fk_c,
enum_fk_dml_type  dml_type,
uchar key_value,
int  key_len,
Foreign_key_chain chain,
int *  error 
)
static

Helper function to apply ON DELETE CASCADE to child table on DML operation.

Parameters
thdThread Handle.
table_cTABLE instance of a child table.
fk_cForeign key information.
dml_typeDML operation type.
key_valueKey value buffer.
key_lenLength of key value buffer.
chainForeign key chain.
[out]errorError value.
Returns
true On error.
false On success.

◆ on_delete_on_update_restrict_or_no_action()

static bool on_delete_on_update_restrict_or_no_action ( THD thd,
const TABLE table_c,
TABLE_SHARE_FOREIGN_KEY_INFO fk_c,
enum_fk_dml_type  dml_type 
)
static

Helper function to apply ON DELETE/ON UPDATE RESTRICT or NOACTION to child table on DML operation.

Note: ON DELETE|UPDATE SET DEFAULT also behaves like RESTRICT

Parameters
thdThread Handle.
table_cTABLE instance of a child table.
fk_cForeign key information.
dml_typeDML operation type.
Returns
true On error.
false On success.

◆ on_delete_on_update_set_null()

static bool on_delete_on_update_set_null ( THD thd,
const TABLE table_p,
TABLE table_c,
TABLE_SHARE_FOREIGN_KEY_INFO fk_c,
enum_fk_dml_type  dml_type,
uchar key_value,
int  key_len,
Foreign_key_chain chain,
int *  error 
)
static

Helper function to apply ON DELETE/ON UPDATE SET NULL to child table on DML operation.

Parameters
thdThread Handle.
table_pTABLE instance of a parent table.
table_cTABLE instance of a child table.
fk_cForeign key information.
dml_typeDML operation type.
key_valueKey value buffer.
key_lenLength of key value buffer.
chainForeign key chain.
[out]errorError value.
Returns
true On error.
false On success.

◆ on_update_cascade()

static bool on_update_cascade ( THD thd,
const TABLE table_p,
TABLE table_c,
TABLE_SHARE_FOREIGN_KEY_INFO fk_c,
KEY key_info_p,
uint  parent_key_idx,
KEY key_info_c,
uint  child_key_idx,
enum_fk_dml_type  dml_type,
uchar key_value,
int  key_len,
Foreign_key_chain chain,
int *  error 
)
static

Function to apply ON UPDATE CASCADE to child table on DML operation.

Parameters
thdThread Handle.
table_pTABLE instance of a parent table.
table_cTABLE instance of a child table.
fk_cForeign key information.
dml_typeDML operation type.
key_info_pParent table key information.
parent_key_idxParent table key index.
key_info_cChild table key information.
child_key_idxChild table key index.
key_valueKey value buffer.
key_lenLength of key value buffer.
chainForeign key chain.
[out]errorError value.
Returns
true On error.
false On success.

◆ open_table_for_fk()

static TABLE * open_table_for_fk ( THD thd,
const char *  db_name,
const char *  table_name 
)
static

Function to open table for foreign key validation.

Parameters
thdThread Handle.
db_nameDB name.
table_nameTable name.
Returns
TABLE* TABLE instance on success, nullptr otherwise.

◆ report_no_referenced_row_error()

static bool report_no_referenced_row_error ( THD thd,
const TABLE table_c,
TABLE_SHARE_FOREIGN_KEY_INFO fk 
)
inlinestatic

Reports ER_NO_REFERENCED_ROW_2 error with fk information.

Parameters
thdThread Handle.
table_cTABLE handle
fkForeign Key Information
Returns
true Propagates error

◆ report_row_referenced_error()

static bool report_row_referenced_error ( THD thd,
const TABLE table_c,
TABLE_SHARE_FOREIGN_KEY_INFO fk 
)
inlinestatic

Reports ER_ROW_IS_REFERENCED_2 error with fk information.

Parameters
thdThread Handle.
table_cTABLE handle
fkForeign Key Information
Returns
true Propagates error

◆ set_key_value_null()

static bool set_key_value_null ( TABLE table,
uint  num_key_cols,
LEX_CSTRING col_names 
)
static

Function to set the null value for key columns.

Parameters
tableTABLE instance of a table.
num_key_colsNumber of columns.
col_namesList of columns.
Returns
false On Success.
true On failure.

◆ set_updated_key_value()

static bool set_updated_key_value ( THD thd,
TABLE table_c,
int  child_key_idx,
const TABLE table_p,
int  parent_key_idx,
TABLE_SHARE_FOREIGN_KEY_INFO fk 
)
static

Function to copy value to child table columns during UPDATE CASCADE operation.

Parameters
thdThread Handle.
table_cTABLE instance of a child table.
child_key_idxIndex of key in the child table.
table_pTABLE instance of a parent table.
parent_key_idxIndex of key in the parent table.
fkForeign key information.
Returns
false On Success.
true On failure.

◆ skip_foreign_key_checks()

static bool skip_foreign_key_checks ( THD thd,
const TABLE table 
)
static

Helper function to skip foreign checks.

Parameters
thdThread Handle.
tableTABLE instance of a table.
Returns
true If foreign key check for a table should be skipped.
false Otherwise.

Variable Documentation

◆ FK_MAX_CASCADE_DEPTH

constexpr uint32_t FK_MAX_CASCADE_DEPTH = 15
constexpr

With the ON CASCADE DELETE/UPDATE clause, deleting from the parent table can trigger recursive cascading calls.

This defines the maximum number of such cascading deletes or updates allowed. If this limit is exceeded, the delete operation on the parent table will fail, and the user must drop the excessive foreign key constraint before proceeding.