diff options
author | Alexander Barkov <bar@mariadb.com> | 2023-03-14 05:29:04 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2023-03-14 10:04:07 +0400 |
commit | bf15c8600ac924924a305e40d1dd159564efe7d5 (patch) | |
tree | d683d687d7912b8feb1e77568bc1a8b933b5c7ef | |
parent | d77aaa6994b30660bd8788d3415ae4a44f55d9a0 (diff) | |
download | mariadb-git-bf15c8600ac924924a305e40d1dd159564efe7d5.tar.gz |
MDEV-30805 SIGSEGV in my_convert and UBSAN: member access within null pointer of type 'const struct MY_CHARSET_HANDLER' in my_convertbb-11.0-bar-MDEV-30805
-rw-r--r-- | mysql-test/main/partition_utf8-debug.result | 2 | ||||
-rw-r--r-- | sql/field.h | 10 | ||||
-rw-r--r-- | sql/json_table.cc | 5 | ||||
-rw-r--r-- | sql/sql_table.cc | 221 | ||||
-rw-r--r-- | sql/sql_type.cc | 42 | ||||
-rw-r--r-- | sql/sql_type.h | 27 | ||||
-rw-r--r-- | sql/sql_type_fixedbin.h | 4 | ||||
-rw-r--r-- | sql/sql_type_geom.cc | 3 | ||||
-rw-r--r-- | sql/sql_type_geom.h | 3 |
9 files changed, 180 insertions, 137 deletions
diff --git a/mysql-test/main/partition_utf8-debug.result b/mysql-test/main/partition_utf8-debug.result index db1396198ab..2b4982a3dcc 100644 --- a/mysql-test/main/partition_utf8-debug.result +++ b/mysql-test/main/partition_utf8-debug.result @@ -77,7 +77,7 @@ CREATE OR REPLACE TABLE t1 (a DATE) CHARACTER SET utf8 PARTITION BY LIST COLUMNS (a) (PARTITION p0 VALUES IN (FROM_DAYS(100))); Warnings: Note 1003 PARTITION BY LIST COLUMNS(`a`) -(PARTITION `p0` VALUES IN (_utf8mb3 0x303030302d30302d3030) ENGINE = MyISAM) +(PARTITION `p0` VALUES IN (_latin1 0x303030302d30302d3030) ENGINE = MyISAM) SELECT PARTITION_DESCRIPTION FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='t1'; PARTITION_DESCRIPTION '0000-00-00' diff --git a/sql/field.h b/sql/field.h index 13d80099124..d4b59a88f59 100644 --- a/sql/field.h +++ b/sql/field.h @@ -5377,7 +5377,7 @@ public: bool sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root); bool prepare_stage1(THD *thd, MEM_ROOT *mem_root, - handler *file, ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr); void prepare_stage1_simple(CHARSET_INFO *cs) { @@ -5385,11 +5385,9 @@ public: create_length_to_internal_length_simple(); } bool prepare_stage1_typelib(THD *thd, MEM_ROOT *mem_root, - handler *file, ulonglong table_flags); - bool prepare_stage1_string(THD *thd, MEM_ROOT *mem_root, - handler *file, ulonglong table_flags); - bool prepare_stage1_bit(THD *thd, MEM_ROOT *mem_root, - handler *file, ulonglong table_flags); + column_definition_type_t deftype); + bool prepare_stage1_string(THD *thd, MEM_ROOT *mem_root); + bool prepare_stage1_bit(THD *thd, MEM_ROOT *mem_root); bool bulk_alter(const Column_derived_attributes *derived_attr, const Column_bulk_alter_attributes *bulk_attr) diff --git a/sql/json_table.cc b/sql/json_table.cc index d404a54bc3f..ded221269ad 100644 --- a/sql/json_table.cc +++ b/sql/json_table.cc @@ -792,8 +792,9 @@ bool Create_json_table::add_json_table_fields(THD *thd, TABLE *table, */ sql_f->length= sql_f->char_length; - if (sql_f->prepare_stage1(thd, thd->mem_root, table->file, - table->file->ha_table_flags(), &da)) + if (sql_f->prepare_stage1(thd, thd->mem_root, + COLUMN_DEFINITION_TABLE_FIELD, + &da)) goto err_exit; while ((jc2= it2++) != jc) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 94371b53303..26a58e66ffe 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2396,17 +2396,16 @@ static void check_duplicate_key(THD *thd, const Key *key, const KEY *key_info, bool Column_definition::prepare_stage1_typelib(THD *thd, MEM_ROOT *mem_root, - handler *file, - ulonglong table_flags) + column_definition_type_t deftype) { /* Pass the last parameter to prepare_interval_field() as follows: - - If we are preparing for an SP variable (file is NULL), we pass "false", + - If we are preparing for an SP variable, we pass "false", to force allocation and full copying of TYPELIB values on the given mem_root, even if no character set conversion is needed. This is needed because a life cycle of an SP variable is longer than the current query. - - If we are preparing for a CREATE TABLE, (file != NULL), we pass "true". + - If we are preparing for a CREATE TABLE, we pass "true". This will create the typelib in runtime memory - we will free the occupied memory at the same time when we free this sql_field -- at the end of execution. @@ -2414,11 +2413,11 @@ bool Column_definition::prepare_stage1_typelib(THD *thd, values in "interval" in cases when no character conversion is needed, to avoid extra copying. */ - if (prepare_interval_field(mem_root, file != NULL)) + if (prepare_interval_field(mem_root, + deftype == COLUMN_DEFINITION_TABLE_FIELD)) return true; // E.g. wrong values with commas: SET('a,b') create_length_to_internal_length_typelib(); - DBUG_ASSERT(file || !default_value); // SP variables have no default_value if (default_value && default_value->expr->basic_const_item()) { if ((charset != default_value->expr->collation.collation && @@ -2431,14 +2430,11 @@ bool Column_definition::prepare_stage1_typelib(THD *thd, bool Column_definition::prepare_stage1_string(THD *thd, - MEM_ROOT *mem_root, - handler *file, - ulonglong table_flags) + MEM_ROOT *mem_root) { create_length_to_internal_length_string(); if (prepare_blob_field(thd)) return true; - DBUG_ASSERT(file || !default_value); // SP variables have no default_value /* Convert the default value from client character set into the column character set if necessary. @@ -2458,13 +2454,9 @@ bool Column_definition::prepare_stage1_string(THD *thd, bool Column_definition::prepare_stage1_bit(THD *thd, - MEM_ROOT *mem_root, - handler *file, - ulonglong table_flags) + MEM_ROOT *mem_root) { pack_flag= FIELDFLAG_NUMBER; - if (!(table_flags & HA_CAN_BIT_FIELD)) - pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR; create_length_to_internal_length_bit(); return false; } @@ -2472,14 +2464,15 @@ bool Column_definition::prepare_stage1_bit(THD *thd, bool Column_definition::prepare_stage1(THD *thd, MEM_ROOT *mem_root, - handler *file, - ulonglong table_flags, + column_definition_type_t deftype, const Column_derived_attributes *derived_attr) { + // SP variables have no default_value + DBUG_ASSERT(deftype == COLUMN_DEFINITION_TABLE_FIELD || !default_value); + return type_handler()->Column_definition_prepare_stage1(thd, mem_root, - this, file, - table_flags, + this, deftype, derived_attr); } @@ -2703,10 +2696,77 @@ key_add_part_check_null(const handler *file, KEY *key_info, /* - Preparation for table creation + Prepare for a table creation. + Stage 1: prepare the field list. +*/ +static bool mysql_prepare_create_table_stage1(THD *thd, + HA_CREATE_INFO *create_info, + Alter_info *alter_info) +{ + DBUG_ENTER("mysql_prepare_create_table_stage1"); + const Column_derived_attributes dattr(create_info->default_table_charset); + const Column_bulk_alter_attributes + battr(create_info->alter_table_convert_to_charset); + Create_field *sql_field; + List_iterator_fast<Create_field> it(alter_info->create_list); + + DBUG_EXECUTE_IF("test_pseudo_invisible",{ + mysql_add_invisible_field(thd, &alter_info->create_list, + "invisible", &type_handler_slong, INVISIBLE_SYSTEM, + new (thd->mem_root)Item_int(thd, 9)); + }); + DBUG_EXECUTE_IF("test_completely_invisible",{ + mysql_add_invisible_field(thd, &alter_info->create_list, + "invisible", &type_handler_slong, INVISIBLE_FULL, + new (thd->mem_root)Item_int(thd, 9)); + }); + DBUG_EXECUTE_IF("test_invisible_index",{ + LEX_CSTRING temp; + temp.str= "invisible"; + temp.length= strlen("invisible"); + mysql_add_invisible_index(thd, &alter_info->key_list + , &temp, Key::MULTIPLE); + }); + + + for ( ; (sql_field=it++) ; ) + { + /* Virtual fields are always NULL */ + if (sql_field->vcol_info) + sql_field->flags&= ~NOT_NULL_FLAG; + + /* + Initialize length from its original value (number of characters), + which was set in the parser. This is necessary if we're + executing a prepared statement for the second time. + */ + sql_field->length= sql_field->char_length; + + if (sql_field->bulk_alter(&dattr, &battr)) + DBUG_RETURN(true); + + if (sql_field->prepare_stage1(thd, thd->mem_root, + COLUMN_DEFINITION_TABLE_FIELD, + &dattr)) + DBUG_RETURN(true); + + DBUG_ASSERT(sql_field->charset); + + if (check_column_name(sql_field->field_name.str)) + { + my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name.str); + DBUG_RETURN(TRUE); + } + } + DBUG_RETURN(false); +} + + +/* + Preparation for table creation, final stage. SYNOPSIS - mysql_prepare_create_table() + mysql_prepare_create_table_finalize() thd Thread object. create_info Create information (like MAX_ROWS). alter_info List of columns and indexes to create @@ -2729,11 +2789,12 @@ key_add_part_check_null(const handler *file, KEY *key_info, */ static int -mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, - Alter_info *alter_info, uint *db_options, - handler *file, KEY **key_info_buffer, - uint *key_count, int create_table_mode, - const LEX_CSTRING db, const LEX_CSTRING table_name) +mysql_prepare_create_table_finalize(THD *thd, HA_CREATE_INFO *create_info, + Alter_info *alter_info, uint *db_options, + handler *file, KEY **key_info_buffer, + uint *key_count, int create_table_mode, + const LEX_CSTRING db, + const LEX_CSTRING table_name) { const char *key_name; Create_field *sql_field,*dup_field; @@ -2749,28 +2810,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, bool tmp_table= create_table_mode == C_ALTER_TABLE; const bool create_simple= thd->lex->create_simple(); bool is_hash_field_needed= false; - const Column_derived_attributes dattr(create_info->default_table_charset); - const Column_bulk_alter_attributes - battr(create_info->alter_table_convert_to_charset); DBUG_ENTER("mysql_prepare_create_table"); - DBUG_EXECUTE_IF("test_pseudo_invisible",{ - mysql_add_invisible_field(thd, &alter_info->create_list, - "invisible", &type_handler_slong, INVISIBLE_SYSTEM, - new (thd->mem_root)Item_int(thd, 9)); - }); - DBUG_EXECUTE_IF("test_completely_invisible",{ - mysql_add_invisible_field(thd, &alter_info->create_list, - "invisible", &type_handler_slong, INVISIBLE_FULL, - new (thd->mem_root)Item_int(thd, 9)); - }); - DBUG_EXECUTE_IF("test_invisible_index",{ - LEX_CSTRING temp; - temp.str= "invisible"; - temp.length= strlen("invisible"); - mysql_add_invisible_index(thd, &alter_info->key_list - , &temp, Key::MULTIPLE); - }); LEX_CSTRING* connect_string = &create_info->connect_string; if (connect_string->length != 0 && connect_string->length > CONNECT_STRING_MAXLEN && @@ -2805,42 +2846,16 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(TRUE); } + for (field_no=0; (sql_field=it++) ; field_no++) { - /* Virtual fields are always NULL */ - if (sql_field->vcol_info) - sql_field->flags&= ~NOT_NULL_FLAG; - - /* - Initialize length from its original value (number of characters), - which was set in the parser. This is necessary if we're - executing a prepared statement for the second time. - */ - sql_field->length= sql_field->char_length; - - if (sql_field->bulk_alter(&dattr, &battr)) - DBUG_RETURN(true); - - if (sql_field->prepare_stage1(thd, thd->mem_root, - file, file->ha_table_flags(), - &dattr)) - DBUG_RETURN(true); - - DBUG_ASSERT(sql_field->charset); + if (!(sql_field->flags & NOT_NULL_FLAG)) + null_fields++; if (sql_field->real_field_type() == MYSQL_TYPE_BIT && file->ha_table_flags() & HA_CAN_BIT_FIELD) total_uneven_bit_length+= sql_field->length & 7; - if (!(sql_field->flags & NOT_NULL_FLAG)) - null_fields++; - - if (check_column_name(sql_field->field_name.str)) - { - my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name.str); - DBUG_RETURN(TRUE); - } - /* Check if we have used the same field name before */ for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++) { @@ -3829,6 +3844,49 @@ without_overlaps_err: DBUG_RETURN(FALSE); } + +/* + Preparation for table creation + + SYNOPSIS + mysql_prepare_create_table() + thd Thread object. + create_info Create information (like MAX_ROWS). + alter_info List of columns and indexes to create + db_options INOUT Table options (like HA_OPTION_PACK_RECORD). + file The handler for the new table. + key_info_buffer OUT An array of KEY structs for the indexes. + key_count OUT The number of elements in the array. + create_table_mode C_ORDINARY_CREATE, C_ALTER_TABLE, + C_CREATE_SELECT, C_ASSISTED_DISCOVERY + + DESCRIPTION + Prepares the table and key structures for table creation. + + NOTES + sets create_info->varchar if the table has a varchar + + RETURN VALUES + FALSE OK + TRUE error +*/ + +static int +mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, + Alter_info *alter_info, uint *db_options, + handler *file, KEY **key_info_buffer, + uint *key_count, int create_table_mode, + const LEX_CSTRING db, + const LEX_CSTRING table_name) +{ + return mysql_prepare_create_table_stage1(thd, create_info, alter_info) || + mysql_prepare_create_table_finalize(thd, create_info, alter_info, + db_options, file, key_info_buffer, + key_count, create_table_mode, + db, table_name); +} + + /** check comment length of table, column, index and partition @@ -3957,7 +4015,8 @@ bool Column_definition::prepare_blob_field(THD *thd) bool Column_definition::sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root) { const Column_derived_attributes dattr(thd->variables.collation_database); - return prepare_stage1(thd, mem_root, NULL, HA_CAN_GEOMETRY, &dattr) || + return prepare_stage1(thd, mem_root, + COLUMN_DEFINITION_ROUTINE_LOCAL, &dattr) || prepare_stage2(NULL, HA_CAN_GEOMETRY); } @@ -4052,6 +4111,9 @@ handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db, DBUG_RETURN(NULL); } + if (mysql_prepare_create_table_stage1(thd, create_info, alter_info)) + DBUG_RETURN(NULL); + db_options= create_info->table_options_with_row_type(); if (unlikely(!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, @@ -4268,9 +4330,10 @@ handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db, } #endif - if (mysql_prepare_create_table(thd, create_info, alter_info, &db_options, - file, key_info, key_count, - create_table_mode, db, table_name)) + if (mysql_prepare_create_table_finalize(thd, create_info, + alter_info, &db_options, + file, key_info, key_count, + create_table_mode, db, table_name)) goto err; create_info->table_options=db_options; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 3759c0ba02f..213de62705f 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -3008,8 +3008,7 @@ bool Type_handler:: Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *def, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const @@ -3022,8 +3021,7 @@ bool Type_handler_null:: Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *def, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const @@ -3037,8 +3035,7 @@ bool Type_handler_row:: Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *def, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const @@ -3052,8 +3049,7 @@ bool Type_handler_temporal_result:: Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *def, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const @@ -3067,8 +3063,7 @@ bool Type_handler_numeric:: Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *def, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const @@ -3081,8 +3076,7 @@ bool Type_handler_newdecimal:: Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *def, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const @@ -3096,28 +3090,26 @@ bool Type_handler_bit:: Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *def, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const { def->charset= &my_charset_numeric; - return def->prepare_stage1_bit(thd, mem_root, file, table_flags); + return def->prepare_stage1_bit(thd, mem_root); } bool Type_handler_typelib:: Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *def, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const { return def->prepare_charset_for_string(derived_attr) || - def->prepare_stage1_typelib(thd, mem_root, file, table_flags); + def->prepare_stage1_typelib(thd, mem_root, type); } @@ -3125,14 +3117,13 @@ bool Type_handler_string_result:: Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *def, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const { return def->prepare_charset_for_string(derived_attr) || - def->prepare_stage1_string(thd, mem_root, file, table_flags); + def->prepare_stage1_string(thd, mem_root); } @@ -3343,10 +3334,11 @@ bool Type_handler_bit:: handler *file, ulonglong table_flags) const { - /* - We have sql_field->pack_flag already set here, see - mysql_prepare_create_table(). - */ + if (!(table_flags & HA_CAN_BIT_FIELD)) + { + def->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR; + def->create_length_to_internal_length_bit(); + } return false; } diff --git a/sql/sql_type.h b/sql/sql_type.h index 741e0c9bb96..d931c7ffb6d 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -3962,8 +3962,7 @@ public: virtual bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const; @@ -4441,8 +4440,7 @@ public: bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const override; @@ -4756,8 +4754,7 @@ public: bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const override; @@ -5310,8 +5307,7 @@ public: bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const override; @@ -5414,8 +5410,7 @@ public: bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const override; @@ -5947,8 +5942,7 @@ public: bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const override; @@ -6791,8 +6785,7 @@ public: bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const override; @@ -6849,8 +6842,7 @@ public: bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const override; @@ -7286,8 +7278,7 @@ public: bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const override; diff --git a/sql/sql_type_fixedbin.h b/sql/sql_type_fixedbin.h index 223bf2cf398..c1be1c9ccba 100644 --- a/sql/sql_type_fixedbin.h +++ b/sql/sql_type_fixedbin.h @@ -382,8 +382,8 @@ public: } bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, - Column_definition *def, handler *file, - ulonglong table_flags, + Column_definition *def, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const override { diff --git a/sql/sql_type_geom.cc b/sql/sql_type_geom.cc index 5732ae47217..3bdc34b4d65 100644 --- a/sql/sql_type_geom.cc +++ b/sql/sql_type_geom.cc @@ -280,8 +280,7 @@ bool Type_handler_geometry:: Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *def, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const { diff --git a/sql/sql_type_geom.h b/sql/sql_type_geom.h index 3bc25808bc3..db951297519 100644 --- a/sql/sql_type_geom.h +++ b/sql/sql_type_geom.h @@ -108,8 +108,7 @@ public: bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, - handler *file, - ulonglong table_flags, + column_definition_type_t type, const Column_derived_attributes *derived_attr) const override; |