MDEV-35445 Disable foreign key column nullability check for strict sql mode

- MDEV-34392(commit cc810e64d4) adds
the check for nullability of foreign key column when foreign key
relation is of UPDATE_CASCADE or UPDATE SET NULL. This check
makes DDL fail when it violates foreign key nullability.
This patch basically does the nullability check for foreign key
column only for strict sql mode
This commit is contained in:
Thirunarayanan Balathandayuthapani 2025-01-21 18:52:33 +05:30
commit 0301ef38b4
9 changed files with 364 additions and 8 deletions

View file

@ -44,6 +44,7 @@ Created 1/8/1996 Heikki Tuuri
#include "dict0priv.h"
#include "fts0priv.h"
#include "srv0start.h"
#include "ha_innodb.h"
/*****************************************************************//**
Based on a table object, this function builds the entry to be inserted
@ -1890,6 +1891,7 @@ dict_create_add_foreigns_to_dictionary(
error = DB_SUCCESS;
bool strict_mode = thd_is_strict_mode(trx->mysql_thd);
for (dict_foreign_set::const_iterator it = local_fk_set.begin();
it != local_fk_set.end();
++it) {
@ -1897,7 +1899,7 @@ dict_create_add_foreigns_to_dictionary(
foreign = *it;
ut_ad(foreign->id != NULL);
if (!foreign->check_fk_constraint_valid()) {
if (strict_mode && !foreign->check_fk_constraint_valid()) {
error = DB_CANNOT_ADD_CONSTRAINT;
} else {
error = dict_create_add_foreign_to_dictionary(

View file

@ -4246,13 +4246,15 @@ declared as NOT NULL
@param n_drop_fk number of constraints that are being dropped
@param col_name modified column name
@param new_field_flags Modified field flags
@param strict_mode Whether the sql_mode is strict
@retval true Not allowed (will call my_error())
@retval false Allowed
*/
static
bool check_foreigns_nullability(const dict_table_t *user_table,
dict_foreign_t **drop_fk, ulint n_drop_fk,
const char *col_name, uint32_t new_field_flags)
const char *col_name, uint32_t new_field_flags,
bool strict_mode)
{
ut_ad(mutex_own(&dict_sys.mutex));
@ -4264,7 +4266,7 @@ bool check_foreigns_nullability(const dict_table_t *user_table,
if (innobase_dropping_foreign(foreign, drop_fk, n_drop_fk))
continue;
if (foreign->on_update_cascade_null(col_name))
if (strict_mode && foreign->on_update_cascade_null(col_name))
goto non_null_error;
if (foreign->type & (foreign->DELETE_SET_NULL |
@ -4286,7 +4288,7 @@ non_null_error:
{
for (dict_foreign_t *foreign : user_table->referenced_set)
{
if (foreign->on_update_cascade_not_null(col_name))
if (strict_mode && foreign->on_update_cascade_not_null(col_name))
{
char display_name[FN_REFLEN];
const int dblen= int(table_name_t(const_cast<char*>(foreign->
@ -4388,6 +4390,7 @@ column that is being dropped or modified to NOT NULL.
@param user_table InnoDB table as it is before the ALTER operation
@param drop_fk constraints being dropped
@param n_drop_fk number of constraints that are being dropped
@param strict_mode Whether the strict sql_mode is set
@retval true Not allowed (will call my_error())
@retval false Allowed
*/
@ -4399,7 +4402,8 @@ innobase_check_foreigns(
const TABLE* old_table,
const dict_table_t* user_table,
dict_foreign_t** drop_fk,
ulint n_drop_fk)
ulint n_drop_fk,
bool strict_mode)
{
for (Field** fp = old_table->field; *fp; fp++) {
ut_ad(!(*fp)->real_maybe_null()
@ -4424,7 +4428,8 @@ innobase_check_foreigns(
if (check_foreigns_nullability(user_table, drop_fk,
n_drop_fk,
(*fp)->field_name.str,
it->flags)) {
it->flags,
strict_mode)) {
return true;
}
}
@ -6462,7 +6467,8 @@ prepare_inplace_alter_table_dict(
if (new_clustered) {
if (innobase_check_foreigns(
ha_alter_info, old_table,
user_table, ctx->drop_fk, ctx->num_to_drop_fk)) {
user_table, ctx->drop_fk, ctx->num_to_drop_fk,
thd_is_strict_mode(ctx->trx->mysql_thd))) {
new_clustered_failed:
DBUG_ASSERT(ctx->trx != ctx->prebuilt->trx);
ctx->trx->rollback();