1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-30555 The server does not detect changes in NULL-ability of system table columns

Introduce CAN_BE_NULL annotation into Table_check_intact checks.
By default columns are considered NOT NULL, nullable
columns must be explicitly marked with CAN_BE_NULL.

All TABLE_FIELD_TYPE arrays are fixed as above.

Assisted-By: Claude:claude-4.6-sonnet
This commit is contained in:
Sergei Golubchik
2026-05-04 23:42:21 +02:00
parent 49987de410
commit 659cfc9b1c
11 changed files with 83 additions and 34 deletions

View File

@@ -279,9 +279,9 @@ event CREATE TABLE `event` (
# Emulate that tables were created with utf8mb4 by an older version
ALTER TABLE mysql.proc MODIFY db CHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
MODIFY name CHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
MODIFY specific_name CHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
MODIFY specific_name CHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
MODIFY definer VARCHAR(384) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
MODIFY comment TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
MODIFY comment TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
MODIFY character_set_client CHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
MODIFY collation_connection CHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
MODIFY db_collation CHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;

View File

@@ -24,9 +24,9 @@ SHOW CREATE TABLE mysql.event;
ALTER TABLE mysql.proc MODIFY db CHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
MODIFY name CHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
MODIFY specific_name CHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
MODIFY specific_name CHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
MODIFY definer VARCHAR(384) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
MODIFY comment TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
MODIFY comment TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
MODIFY character_set_client CHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
MODIFY collation_connection CHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
MODIFY db_collation CHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;

View File

@@ -190,7 +190,7 @@ CREATE TABLE mysql.proc LIKE proc_backup;
CREATE DATABASE db1;
CREATE PROCEDURE db1.p1() SET @foo = 10;
# Modify a field of the table.
ALTER TABLE mysql.proc MODIFY comment CHAR (32);
ALTER TABLE mysql.proc MODIFY comment CHAR (32) not null;
DROP DATABASE db1;
Warnings:
Error 1728 Cannot load from mysql.proc. The table is probably corrupted

View File

@@ -275,7 +275,7 @@ CREATE DATABASE db1;
CREATE PROCEDURE db1.p1() SET @foo = 10;
--echo # Modify a field of the table.
ALTER TABLE mysql.proc MODIFY comment CHAR (32);
ALTER TABLE mysql.proc MODIFY comment CHAR (32) not null;
# This should not fail even if mysql.proc is invalid.
DROP DATABASE db1;

View File

@@ -2776,4 +2776,17 @@ SET @@SESSION.OPTIMIZER_SWITCH="in_to_exists=OFF,materialization=OFF";
ERROR HY000: At least one of the 'in_to_exists' or 'materialization' optimizer_switch flags must be 'on'
PREPARE stmt FROM @cmd;
set @@SESSION.OPTIMIZER_SWITCH=@old_optimizer_switch;
# End of 10.2 Test
# End of 10.2 tests
#
# MDEV-30555 The server does not detect changes in NULL-ability of system table columns
#
call mtr.add_suppression("Incorrect definition of table mysql\\.proc");
RENAME TABLE mysql.proc TO proc_backup;
CREATE TABLE mysql.proc LIKE proc_backup;
ALTER TABLE mysql.proc MODIFY definer
varchar(384) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL;
CREATE PROCEDURE p1() SET @x = 1;
ERROR HY000: Cannot load from mysql.proc. The table is probably corrupted
DROP TABLE mysql.proc;
RENAME TABLE proc_backup TO mysql.proc;
# End of 10.11 tests

View File

@@ -3611,4 +3611,24 @@ PREPARE stmt FROM @cmd;
set @@SESSION.OPTIMIZER_SWITCH=@old_optimizer_switch;
--echo # End of 10.2 Test
--echo # End of 10.2 tests
--echo #
--echo # MDEV-30555 The server does not detect changes in NULL-ability of system table columns
--echo #
call mtr.add_suppression("Incorrect definition of table mysql\\.proc");
RENAME TABLE mysql.proc TO proc_backup;
CREATE TABLE mysql.proc LIKE proc_backup;
ALTER TABLE mysql.proc MODIFY definer
varchar(384) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL;
--error ER_CANNOT_LOAD_FROM_TABLE_V2
CREATE PROCEDURE p1() SET @x = 1;
DROP TABLE mysql.proc;
RENAME TABLE proc_backup TO mysql.proc;
--echo # End of 10.11 tests

View File

@@ -62,12 +62,12 @@ const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] =
},
{
{ STRING_WITH_LEN("execute_at") },
{ STRING_WITH_LEN("datetime") },
{ STRING_WITH_LEN("datetime") + CAN_BE_NULL },
{NULL, 0}
},
{
{ STRING_WITH_LEN("interval_value") },
{ STRING_WITH_LEN("int(11)") },
{ STRING_WITH_LEN("int(11)") + CAN_BE_NULL },
{NULL, 0}
},
{
@@ -76,7 +76,7 @@ const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] =
"'HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR',"
"'DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND',"
"'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND',"
"'SECOND_MICROSECOND')") },
"'SECOND_MICROSECOND')") + CAN_BE_NULL },
{NULL, 0}
},
{
@@ -91,17 +91,17 @@ const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] =
},
{
{ STRING_WITH_LEN("last_executed") },
{ STRING_WITH_LEN("datetime") },
{ STRING_WITH_LEN("datetime") + CAN_BE_NULL },
{NULL, 0}
},
{
{ STRING_WITH_LEN("starts") },
{ STRING_WITH_LEN("datetime") },
{ STRING_WITH_LEN("datetime") + CAN_BE_NULL },
{NULL, 0}
},
{
{ STRING_WITH_LEN("ends") },
{ STRING_WITH_LEN("datetime") },
{ STRING_WITH_LEN("datetime") + CAN_BE_NULL },
{NULL, 0}
},
{
@@ -145,22 +145,22 @@ const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] =
},
{
{ STRING_WITH_LEN("character_set_client") },
{ STRING_WITH_LEN("char(32)") },
{ STRING_WITH_LEN("char(32)") + CAN_BE_NULL },
{ STRING_WITH_LEN("utf8mb") }
},
{
{ STRING_WITH_LEN("collation_connection") },
{ STRING_WITH_LEN("char(") },
{ STRING_WITH_LEN("char(") + CAN_BE_NULL },
{ STRING_WITH_LEN("utf8mb") }
},
{
{ STRING_WITH_LEN("db_collation") },
{ STRING_WITH_LEN("char(") },
{ STRING_WITH_LEN("char(") + CAN_BE_NULL },
{ STRING_WITH_LEN("utf8mb") }
},
{
{ STRING_WITH_LEN("body_utf8") },
{ STRING_WITH_LEN("longblob") },
{ STRING_WITH_LEN("longblob") + CAN_BE_NULL },
{ NULL, 0 }
}
};

View File

@@ -212,22 +212,22 @@ TABLE_FIELD_TYPE proc_table_fields[MYSQL_PROC_FIELD_COUNT] =
},
{
{ STRING_WITH_LEN("character_set_client") },
{ STRING_WITH_LEN("char(32)") },
{ STRING_WITH_LEN("char(32)") + CAN_BE_NULL },
{ STRING_WITH_LEN("utf8mb") }
},
{
{ STRING_WITH_LEN("collation_connection") },
{ STRING_WITH_LEN("char(") },
{ STRING_WITH_LEN("char(") + CAN_BE_NULL },
{ STRING_WITH_LEN("utf8mb") }
},
{
{ STRING_WITH_LEN("db_collation") },
{ STRING_WITH_LEN("char(") },
{ STRING_WITH_LEN("char(") + CAN_BE_NULL },
{ STRING_WITH_LEN("utf8mb") }
},
{
{ STRING_WITH_LEN("body_utf8") },
{ STRING_WITH_LEN("longblob") },
{ STRING_WITH_LEN("longblob") + CAN_BE_NULL },
{ NULL, 0 }
},
{

View File

@@ -154,7 +154,7 @@ TABLE_FIELD_TYPE table_stat_fields[TABLE_STAT_N_FIELDS] =
},
{
{ STRING_WITH_LEN("cardinality") },
{ STRING_WITH_LEN("bigint(21)") },
{ STRING_WITH_LEN("bigint(21)") + CAN_BE_NULL },
{ NULL, 0 }
},
};
@@ -182,42 +182,42 @@ TABLE_FIELD_TYPE column_stat_fields[COLUMN_STAT_N_FIELDS] =
},
{
{ STRING_WITH_LEN("min_value") },
{ STRING_WITH_LEN("varbinary(255)") },
{ STRING_WITH_LEN("varbinary(255)") + CAN_BE_NULL },
{ NULL, 0 }
},
{
{ STRING_WITH_LEN("max_value") },
{ STRING_WITH_LEN("varbinary(255)") },
{ STRING_WITH_LEN("varbinary(255)") + CAN_BE_NULL },
{ NULL, 0 }
},
{
{ STRING_WITH_LEN("nulls_ratio") },
{ STRING_WITH_LEN("decimal(12,4)") },
{ STRING_WITH_LEN("decimal(12,4)") + CAN_BE_NULL },
{ NULL, 0 }
},
{
{ STRING_WITH_LEN("avg_length") },
{ STRING_WITH_LEN("decimal(12,4)") },
{ STRING_WITH_LEN("decimal(12,4)") + CAN_BE_NULL },
{ NULL, 0 }
},
{
{ STRING_WITH_LEN("avg_frequency") },
{ STRING_WITH_LEN("decimal(12,4)") },
{ STRING_WITH_LEN("decimal(12,4)") + CAN_BE_NULL },
{ NULL, 0 }
},
{
{ STRING_WITH_LEN("hist_size") },
{ STRING_WITH_LEN("tinyint(3)") },
{ STRING_WITH_LEN("tinyint(3)") + CAN_BE_NULL },
{ NULL, 0 }
},
{
{ STRING_WITH_LEN("hist_type") },
{ STRING_WITH_LEN("enum('SINGLE_PREC_HB','DOUBLE_PREC_HB','JSON_HB')") },
{ STRING_WITH_LEN("enum('SINGLE_PREC_HB','DOUBLE_PREC_HB','JSON_HB')") + CAN_BE_NULL },
{ STRING_WITH_LEN("utf8mb3") }
},
{
{ STRING_WITH_LEN("histogram") },
{ STRING_WITH_LEN("longblob") },
{ STRING_WITH_LEN("longblob") + CAN_BE_NULL },
{ NULL, 0 }
}
};
@@ -250,7 +250,7 @@ TABLE_FIELD_TYPE index_stat_fields[INDEX_STAT_N_FIELDS] =
},
{
{ STRING_WITH_LEN("avg_frequency") },
{ STRING_WITH_LEN("decimal(12,4)") },
{ STRING_WITH_LEN("decimal(12,4)") + CAN_BE_NULL },
{ NULL, 0 }
}
};

View File

@@ -5486,8 +5486,8 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def)
the new table definition is backward compatible with the
original one.
*/
if (strncmp(sql_type.c_ptr_safe(), field_def->type.str,
field_def->type.length - 1))
size_t type_len= field_def->type.length & ~CAN_BE_NULL;
if (strncmp(sql_type.c_ptr_safe(), field_def->type.str, type_len - 1))
{
report_error(0, "Incorrect definition of table %s.%s: "
"expected column '%s' at position %d to have type "
@@ -5520,6 +5520,16 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def)
field->charset()->cs_name.str);
error= TRUE;
}
bool col_can_be_null= field_def->type.length & CAN_BE_NULL;
if (col_can_be_null != field->real_maybe_null())
{
report_error(0, "Incorrect definition of table %s.%s: "
"expected column '%s' at position %d to be %s.",
table->s->db.str, table->alias.c_ptr(),
field_def->name.str, i,
col_can_be_null ? "nullable" : "NOT NULL");
error= TRUE;
}
}
else
{

View File

@@ -542,6 +542,12 @@ TABLE_CATEGORY get_table_category(const Lex_ident_db &db,
const Lex_ident_table &name);
/*
Set this bit in TABLE_FIELD_TYPE::type.length to mark a column as nullable.
The actual type string length is type.length & ~CAN_BE_NULL.
*/
#define CAN_BE_NULL (1UL << 31)
typedef struct st_table_field_type
{
LEX_CSTRING name;