Skip to content

Commit bfed2c7

Browse files
committed
MDEV-27753 Incorrect ENGINE type of table after crash for CONNECT table
whenever possible, partitioning should use the full partition plugin name, not the one byte legacy code. Normally, ha_partition can get the engine plugin from table_share->default_part_plugin. But in some cases, e.g. in DROP TABLE, the table isn't opened, table_share is NULL, and ha_partition has to parse the frm, much like dd_frm_type() does. temporary_tables.cc, sql_table.cc: When dropping a table, it must be deleted in the engine first, then frm file. Because frm can be the only true source of metadata that the engine might need for DROP. table.cc: when opening a partitioned table, if the engine for partitions is not found, do not fallback to MyISAM.
1 parent f217c76 commit bfed2c7

File tree

10 files changed

+159
-47
lines changed

10 files changed

+159
-47
lines changed

mysql-test/main/drop_bad_db_type.result

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,50 @@ SET debug_dbug='+d,unstable_db_type';
33
install soname 'ha_archive';
44
create table t1 (a int) engine=archive;
55
insert t1 values (1),(2),(3);
6+
create table t2 (a int) engine=archive partition by hash(a) partitions 3;
67
flush tables;
78
uninstall soname 'ha_archive';
8-
select table_schema, table_name from information_schema.tables where table_name like 't1';
9-
table_schematest
10-
table_namet1
11-
select table_schema, table_name, engine, version from information_schema.tables where table_name like 't1';
12-
table_schematest
13-
table_namet1
14-
engineARCHIVE
15-
versionNULL
9+
select table_schema, table_name from information_schema.tables where table_name like 't_' order by 1,2;
10+
table_schematable_name
11+
testt1
12+
test t2
13+
select table_schema, table_name, engine, version from information_schema.tables where table_name like 't_' order by 1,2;
14+
table_schematable_nameengine version
15+
test t1ARCHIVENULL
16+
test t2 NULLNULL
1617
Warnings:
17-
Level Warning
18-
Code 1286
19-
Message Unknown storage engine 'ARCHIVE'
20-
select table_schema, table_name, engine, row_format from information_schema.tables where table_name like 't1';
21-
table_schema test
22-
table_name t1
23-
engine ARCHIVE
24-
row_format NULL
18+
Warning 1033 Incorrect information in file: './test/t2.frm'
19+
Warning 1286 Unknown storage engine 'ARCHIVE'
20+
select table_schema, table_name, engine, row_format from information_schema.tables where table_name like 't_' order by 1,2;
21+
table_schema table_name engine row_format
22+
test t1 ARCHIVE NULL
23+
test t2 NULL NULL
2524
Warnings:
26-
Level Warning
27-
Code 1286
28-
Message Unknown storage engine 'ARCHIVE'
25+
Warning 1033 Incorrect information in file: './test/t2.frm'
26+
Warning 1286 Unknown storage engine 'ARCHIVE'
2927
install soname 'ha_archive';
28+
show create table t1;
29+
Table Create Table
30+
t1 CREATE TABLE `t1` (
31+
`a` int(11) DEFAULT NULL
32+
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1
33+
show create table t2;
34+
Table Create Table
35+
t2 CREATE TABLE `t2` (
36+
`a` int(11) DEFAULT NULL
37+
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1
38+
PARTITION BY HASH (`a`)
39+
PARTITIONS 3
3040
db.opt
3141
t1.ARZ
3242
t1.frm
43+
t2#P#p0.ARZ
44+
t2#P#p1.ARZ
45+
t2#P#p2.ARZ
46+
t2.frm
47+
t2.par
3348
drop table t1;
49+
drop table t2;
3450
db.opt
3551
uninstall soname 'ha_archive';
3652
SET debug_dbug=@saved_dbug;

mysql-test/main/drop_bad_db_type.test

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
--source include/have_partition.inc
22
--source include/have_debug.inc
33

44
if (!$HA_ARCHIVE_SO) {
@@ -13,18 +13,25 @@ SET debug_dbug='+d,unstable_db_type';
1313
install soname 'ha_archive';
1414
create table t1 (a int) engine=archive;
1515
insert t1 values (1),(2),(3);
16+
17+
create table t2 (a int) engine=archive partition by hash(a) partitions 3;
18+
1619
flush tables;
1720
uninstall soname 'ha_archive';
1821

19-
--vertical_results
20-
select table_schema, table_name from information_schema.tables where table_name like 't1';
21-
select table_schema, table_name, engine, version from information_schema.tables where table_name like 't1';
22-
select table_schema, table_name, engine, row_format from information_schema.tables where table_name like 't1';
23-
--horizontal_results
22+
select table_schema, table_name from information_schema.tables where table_name like 't_' order by 1,2;
23+
--replace_result $mysqld_datadir ./
24+
select table_schema, table_name, engine, version from information_schema.tables where table_name like 't_' order by 1,2;
25+
--replace_result $mysqld_datadir ./
26+
select table_schema, table_name, engine, row_format from information_schema.tables where table_name like 't_' order by 1,2;
2427

2528
install soname 'ha_archive';
29+
show create table t1;
30+
show create table t2;
31+
2632
--list_files $mysqld_datadir/test
2733
drop table t1;
34+
drop table t2;
2835
--list_files $mysqld_datadir/test
2936
uninstall soname 'ha_archive';
3037

mysql-test/main/partition_not_blackhole.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ SHOW TABLES;
99
Tables_in_test
1010
t1
1111
SHOW CREATE TABLE t1;
12-
ERROR HY000: Failed to read from the .par file
12+
ERROR HY000: Incorrect information in file: './test/t1.frm'
1313
DROP TABLE t1;
1414
ERROR HY000: Got error 1 "Operation not permitted" from storage engine partition
1515
t1.frm

mysql-test/main/partition_not_blackhole.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ let $MYSQLD_DATADIR= `SELECT @@datadir`;
1717
--copy_file std_data/parts/t1_blackhole.par $MYSQLD_DATADIR/test/t1.par
1818
SHOW TABLES;
1919
--replace_result $MYSQLD_DATADIR ./
20-
--error ER_FAILED_READ_FROM_PAR_FILE
20+
--error ER_NOT_FORM_FILE
2121
SHOW CREATE TABLE t1;
2222

2323
# The replace is needed for Solaris

sql/ha_partition.cc

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3059,11 +3059,12 @@ bool ha_partition::read_par_file(const char *name)
30593059
@retval true Failure
30603060
*/
30613061

3062-
bool ha_partition::setup_engine_array(MEM_ROOT *mem_root)
3062+
bool ha_partition::setup_engine_array(MEM_ROOT *mem_root,
3063+
handlerton* first_engine)
30633064
{
30643065
uint i;
30653066
uchar *buff;
3066-
handlerton **engine_array, *first_engine;
3067+
handlerton **engine_array;
30673068
enum legacy_db_type db_type, first_db_type;
30683069

30693070
DBUG_ASSERT(!m_file);
@@ -3073,11 +3074,8 @@ bool ha_partition::setup_engine_array(MEM_ROOT *mem_root)
30733074
DBUG_RETURN(true);
30743075

30753076
buff= (uchar *) (m_file_buffer + PAR_ENGINES_OFFSET);
3076-
first_db_type= (enum legacy_db_type) buff[0];
3077-
first_engine= ha_resolve_by_legacy_type(ha_thd(), first_db_type);
3078-
if (!first_engine)
3079-
goto err;
30803077

3078+
first_db_type= (enum legacy_db_type) buff[0];
30813079
if (!(m_engine_array= (plugin_ref*)
30823080
alloc_root(&m_mem_root, m_tot_parts * sizeof(plugin_ref))))
30833081
goto err;
@@ -3118,6 +3116,74 @@ bool ha_partition::setup_engine_array(MEM_ROOT *mem_root)
31183116
}
31193117

31203118

3119+
handlerton *ha_partition::get_def_part_engine(const char *name)
3120+
{
3121+
if (table_share)
3122+
{
3123+
if (table_share->default_part_plugin)
3124+
return plugin_data(table_share->default_part_plugin, handlerton *);
3125+
}
3126+
else
3127+
{
3128+
// DROP TABLE, for example
3129+
char buff[FN_REFLEN];
3130+
File file;
3131+
MY_STAT state;
3132+
uchar *frm_image= 0;
3133+
handlerton *hton= 0;
3134+
bool use_legacy_type= false;
3135+
3136+
fn_format(buff, name, "", reg_ext, MY_APPEND_EXT);
3137+
3138+
file= mysql_file_open(key_file_frm, buff, O_RDONLY | O_SHARE, MYF(0));
3139+
if (file < 0)
3140+
return NULL;
3141+
3142+
if (mysql_file_fstat(file, &state, MYF(MY_WME)))
3143+
goto err;
3144+
if (state.st_size <= 64)
3145+
goto err;
3146+
if (!(frm_image= (uchar*)my_malloc(state.st_size, MYF(MY_WME))))
3147+
goto err;
3148+
if (mysql_file_read(file, frm_image, state.st_size, MYF(MY_NABP)))
3149+
goto err;
3150+
3151+
if (frm_image[64] != '/')
3152+
{
3153+
const uchar *e2= frm_image + 64;
3154+
const uchar *e2end = e2 + uint2korr(frm_image + 4);
3155+
if (e2end > frm_image + state.st_size)
3156+
goto err;
3157+
while (e2 + 3 < e2end)
3158+
{
3159+
uchar type= *e2++;
3160+
size_t length= extra2_read_len(&e2, e2end);
3161+
if (!length)
3162+
goto err;
3163+
if (type == EXTRA2_DEFAULT_PART_ENGINE)
3164+
{
3165+
LEX_CSTRING name= { (char*)e2, length };
3166+
plugin_ref plugin= ha_resolve_by_name(ha_thd(), &name, false);
3167+
if (plugin)
3168+
hton= plugin_data(plugin, handlerton *);
3169+
goto err;
3170+
}
3171+
e2+= length;
3172+
}
3173+
}
3174+
use_legacy_type= true;
3175+
err:
3176+
my_free(frm_image);
3177+
mysql_file_close(file, MYF(0));
3178+
if (!use_legacy_type)
3179+
return hton;
3180+
}
3181+
3182+
return ha_resolve_by_legacy_type(ha_thd(),
3183+
(enum legacy_db_type)m_file_buffer[PAR_ENGINES_OFFSET]);
3184+
}
3185+
3186+
31213187
/**
31223188
Get info about partition engines and their names from the .par file
31233189
@@ -3145,7 +3211,11 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root,
31453211
if (read_par_file(name))
31463212
DBUG_RETURN(true);
31473213

3148-
if (!is_clone && setup_engine_array(mem_root))
3214+
handlerton *default_engine= get_def_part_engine(name);
3215+
if (!default_engine)
3216+
DBUG_RETURN(true);
3217+
3218+
if (!is_clone && setup_engine_array(mem_root, default_engine))
31493219
DBUG_RETURN(true);
31503220

31513221
DBUG_RETURN(false);

sql/ha_partition.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,8 +580,9 @@ class ha_partition :public handler
580580
And one method to read it in.
581581
*/
582582
bool create_handler_file(const char *name);
583-
bool setup_engine_array(MEM_ROOT *mem_root);
583+
bool setup_engine_array(MEM_ROOT *mem_root, handlerton *first_engine);
584584
bool read_par_file(const char *name);
585+
handlerton *get_def_part_engine(const char *name);
585586
bool get_from_handler_file(const char *name, MEM_ROOT *mem_root,
586587
bool is_clone);
587588
bool new_handlers_from_part_info(MEM_ROOT *mem_root);

sql/sql_table.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,15 +2802,13 @@ bool quick_rm_table(THD *thd, handlerton *base, const LEX_CSTRING *db,
28022802
const LEX_CSTRING *table_name, uint flags, const char *table_path)
28032803
{
28042804
char path[FN_REFLEN + 1];
2805+
const size_t pathmax = sizeof(path) - 1 - reg_ext_length;
28052806
int error= 0;
28062807
DBUG_ENTER("quick_rm_table");
28072808

28082809
size_t path_length= table_path ?
2809-
(strxnmov(path, sizeof(path) - 1, table_path, reg_ext, NullS) - path) :
2810-
build_table_filename(path, sizeof(path)-1, db->str, table_name->str, reg_ext, flags);
2811-
if (mysql_file_delete(key_file_frm, path, MYF(0)))
2812-
error= 1; /* purecov: inspected */
2813-
path[path_length - reg_ext_length]= '\0'; // Remove reg_ext
2810+
(strxnmov(path, pathmax, table_path, NullS) - path) :
2811+
build_table_filename(path, pathmax, db->str, table_name->str, "", flags);
28142812
if (flags & NO_HA_TABLE)
28152813
{
28162814
handler *file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base);
@@ -2822,6 +2820,10 @@ bool quick_rm_table(THD *thd, handlerton *base, const LEX_CSTRING *db,
28222820
if (!(flags & (FRM_ONLY|NO_HA_TABLE)))
28232821
error|= ha_delete_table(current_thd, base, path, db, table_name, 0);
28242822

2823+
memcpy(path + path_length, reg_ext, reg_ext_length + 1);
2824+
if (mysql_file_delete(key_file_frm, path, MYF(0)))
2825+
error= 1;
2826+
28252827
if (likely(error == 0))
28262828
{
28272829
PSI_CALL_drop_table_share(flags & FN_IS_TMP, db->str, (uint)db->length,

sql/table.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1370,7 +1370,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
13701370
if (frm_image[61] && !share->default_part_plugin)
13711371
{
13721372
enum legacy_db_type db_type= (enum legacy_db_type) (uint) frm_image[61];
1373-
share->default_part_plugin= ha_lock_engine(NULL, ha_checktype(thd, db_type));
1373+
share->default_part_plugin= ha_lock_engine(NULL, ha_checktype(thd, db_type, 1));
13741374
if (!share->default_part_plugin)
13751375
goto err;
13761376
}

sql/temporary_tables.cc

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -698,19 +698,20 @@ bool THD::rm_temporary_table(handlerton *base, const char *path)
698698
char frm_path[FN_REFLEN + 1];
699699

700700
strxnmov(frm_path, sizeof(frm_path) - 1, path, reg_ext, NullS);
701-
if (mysql_file_delete(key_file_frm, frm_path, MYF(0)))
702-
{
703-
error= true;
704-
}
705-
file= get_new_handler((TABLE_SHARE*) 0, current_thd->mem_root, base);
701+
702+
file= get_new_handler((TABLE_SHARE*) 0, mem_root, base);
706703
if (file && file->ha_delete_table(path))
707704
{
708705
error= true;
709706
sql_print_warning("Could not remove temporary table: '%s', error: %d",
710707
path, my_errno);
711708
}
712-
713709
delete file;
710+
711+
if (mysql_file_delete(key_file_frm, frm_path, MYF(0)))
712+
{
713+
error= true;
714+
}
714715
DBUG_RETURN(error);
715716
}
716717

sql/unireg.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,21 @@ enum extra2_field_flags {
188188
VERS_OPTIMIZED_UPDATE= 1 << INVISIBLE_MAX_BITS
189189
};
190190

191+
static inline size_t extra2_read_len(const uchar **extra2, const uchar *end)
192+
{
193+
size_t length= *(*extra2)++;
194+
if (length)
195+
return length;
196+
197+
if ((*extra2) + 2 >= end)
198+
return 0;
199+
length= uint2korr(*extra2);
200+
(*extra2)+= 2;
201+
if (length < 256 || *extra2 + length > end)
202+
return 0;
203+
return length;
204+
}
205+
191206
int rea_create_table(THD *thd, LEX_CUSTRING *frm,
192207
const char *path, const char *db, const char *table_name,
193208
HA_CREATE_INFO *create_info, handler *file,

0 commit comments

Comments
 (0)