Commit d1a80e6a authored by Jimmy Yang's avatar Jimmy Yang

Fix Bug #12885783 - BLOCK LOADING TABLE WITH LARGE COLLATION NUMBER

FROM 5.6 SERVER

rb://747 approved by Marko
parent 10e7b948
...@@ -25,6 +25,7 @@ Created 4/24/1996 Heikki Tuuri ...@@ -25,6 +25,7 @@ Created 4/24/1996 Heikki Tuuri
#include "rem0cmp.h" #include "rem0cmp.h"
#include "srv0start.h" #include "srv0start.h"
#include "srv0srv.h" #include "srv0srv.h"
#include "db0err.h"
/******************************************************************** /********************************************************************
Returns TRUE if index's i'th column's name is 'name' .*/ Returns TRUE if index's i'th column's name is 'name' .*/
...@@ -329,7 +330,7 @@ dict_check_tablespaces_and_store_max_id( ...@@ -329,7 +330,7 @@ dict_check_tablespaces_and_store_max_id(
/************************************************************************ /************************************************************************
Loads definitions for table columns. */ Loads definitions for table columns. */
static static
void ulint
dict_load_columns( dict_load_columns(
/*==============*/ /*==============*/
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
...@@ -350,6 +351,7 @@ dict_load_columns( ...@@ -350,6 +351,7 @@ dict_load_columns(
ulint col_len; ulint col_len;
ulint i; ulint i;
mtr_t mtr; mtr_t mtr;
ulint err = DB_SUCCESS;
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
...@@ -397,6 +399,30 @@ dict_load_columns( ...@@ -397,6 +399,30 @@ dict_load_columns(
field = rec_get_nth_field_old(rec, 6, &len); field = rec_get_nth_field_old(rec, 6, &len);
prtype = mach_read_from_4(field); prtype = mach_read_from_4(field);
/* We can rely on dtype_get_charset_coll() to check
charset collation number exceed limit, since it comes
with a smaller mask. We have to do the check explicitly
here */
if (((prtype >> 16) & LARGE_CHAR_COLL_PRTYPE_MASK)
> MAX_CHAR_COLL_NUM) {
fprintf(stderr, "InnoDB: Error: load column"
" '%s' for table '%s' failed.\n"
"InnoDB: column '%s' has a charset"
" collation number of %lu, exceeds"
" maximum value %lu supported\n",
name, name, table->name,
(ulong) ((prtype >> 16)
& LARGE_CHAR_COLL_PRTYPE_MASK),
(ulong) MAX_CHAR_COLL_NUM);
err = DB_CORRUPTION;
/* If the force recovery flag is not set, it will
stop loading and exit */
if (!srv_force_recovery) {
goto func_exit;
}
}
if (dtype_get_charset_coll(prtype) == 0 if (dtype_get_charset_coll(prtype) == 0
&& dtype_is_string_type(mtype)) { && dtype_is_string_type(mtype)) {
/* The table was created with < 4.1.2. */ /* The table was created with < 4.1.2. */
...@@ -428,8 +454,11 @@ dict_load_columns( ...@@ -428,8 +454,11 @@ dict_load_columns(
btr_pcur_move_to_next_user_rec(&pcur, &mtr); btr_pcur_move_to_next_user_rec(&pcur, &mtr);
} }
func_exit:
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
return(err);
} }
/************************************************************************ /************************************************************************
...@@ -899,7 +928,12 @@ dict_load_table( ...@@ -899,7 +928,12 @@ dict_load_table(
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
dict_load_columns(table, heap); err = dict_load_columns(table, heap);
if (err != DB_SUCCESS && !srv_force_recovery) {
table = NULL;
goto func_exit;
}
dict_table_add_to_cache(table, heap); dict_table_add_to_cache(table, heap);
...@@ -961,6 +995,8 @@ dict_load_table( ...@@ -961,6 +995,8 @@ dict_load_table(
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
} }
#endif /* 0 */ #endif /* 0 */
func_exit:
mem_heap_free(heap); mem_heap_free(heap);
return(table); return(table);
......
...@@ -5336,13 +5336,14 @@ create_table_def( ...@@ -5336,13 +5336,14 @@ create_table_def(
charset_no = (ulint)field->charset()->number; charset_no = (ulint)field->charset()->number;
ut_a(charset_no < 256); /* in data0type.h we assume /* in data0type.h we assume
that the number fits in one that the number fits in one byte */
byte */ ut_a(charset_no <= MAX_CHAR_COLL_NUM);
} }
ut_a(field->type() < 256); /* we assume in dtype_form_prtype() /* we assume in dtype_form_prtype() that this fits in
that this fits in one byte */ one byte */
ut_a(field->type() <= MAX_CHAR_COLL_NUM);
col_len = field->pack_length(); col_len = field->pack_length();
/* The MySQL pack length contains 1 or 2 bytes length field /* The MySQL pack length contains 1 or 2 bytes length field
......
...@@ -149,6 +149,15 @@ SQL null*/ ...@@ -149,6 +149,15 @@ SQL null*/
store the charset-collation number; one byte is left unused, though */ store the charset-collation number; one byte is left unused, though */
#define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6 #define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6
/* We support 8 bits (up to 255) collation number until 5.6.3, in which
the collation number is extended to 32767 */
#define MAX_CHAR_COLL_NUM 255
/* Mask to get the large charset-collation number in PRTYPE
This is used to mainly block loading tables with large charset-collation
value with database from 5.6 */
#define LARGE_CHAR_COLL_PRTYPE_MASK 0xFFFFUL
/************************************************************************* /*************************************************************************
Gets the MySQL type code from a dtype. */ Gets the MySQL type code from a dtype. */
UNIV_INLINE UNIV_INLINE
......
...@@ -272,7 +272,7 @@ dtype_new_store_for_order_and_null_size( ...@@ -272,7 +272,7 @@ dtype_new_store_for_order_and_null_size(
mach_write_to_2(buf + 2, len & 0xFFFFUL); mach_write_to_2(buf + 2, len & 0xFFFFUL);
ut_ad(dtype_get_charset_coll(type->prtype) < 256); ut_ad(dtype_get_charset_coll(type->prtype) <= MAX_CHAR_COLL_NUM);
mach_write_to_2(buf + 4, dtype_get_charset_coll(type->prtype)); mach_write_to_2(buf + 4, dtype_get_charset_coll(type->prtype));
if (type->prtype & DATA_NOT_NULL) { if (type->prtype & DATA_NOT_NULL) {
...@@ -339,12 +339,10 @@ dtype_new_read_for_order_and_null_size( ...@@ -339,12 +339,10 @@ dtype_new_read_for_order_and_null_size(
type->len = mach_read_from_2(buf + 2); type->len = mach_read_from_2(buf + 2);
mach_read_from_2(buf + 4);
charset_coll = mach_read_from_2(buf + 4) & 0x7fff; charset_coll = mach_read_from_2(buf + 4) & 0x7fff;
if (dtype_is_string_type(type->mtype)) { if (dtype_is_string_type(type->mtype)) {
ut_a(charset_coll < 256); ut_a(charset_coll <= MAX_CHAR_COLL_NUM);
if (charset_coll == 0) { if (charset_coll == 0) {
/* This insert buffer record was inserted with MySQL /* This insert buffer record was inserted with MySQL
......
2011-09-08 The InnoDB Team
* dict/dict0load.c, handler/ha_innodb.cc, include/data0type.h
include/data0type.ic:
Fix Bug##12885783 - BLOCK LOADING TABLE WITH LARGE COLLATION
NUMBER FROM 5.6 SERVER
2011-09-06 The InnoDB Team 2011-09-06 The InnoDB Team
* buf/buf0buddy.c: * buf/buf0buddy.c:
......
...@@ -40,6 +40,7 @@ Created 4/24/1996 Heikki Tuuri ...@@ -40,6 +40,7 @@ Created 4/24/1996 Heikki Tuuri
#include "rem0cmp.h" #include "rem0cmp.h"
#include "srv0start.h" #include "srv0start.h"
#include "srv0srv.h" #include "srv0srv.h"
#include "db0err.h"
/****************************************************************//** /****************************************************************//**
Compare the name of an index column. Compare the name of an index column.
...@@ -449,7 +450,7 @@ dict_check_tablespaces_and_store_max_id( ...@@ -449,7 +450,7 @@ dict_check_tablespaces_and_store_max_id(
/********************************************************************//** /********************************************************************//**
Loads definitions for table columns. */ Loads definitions for table columns. */
static static
void enum db_err
dict_load_columns( dict_load_columns(
/*==============*/ /*==============*/
dict_table_t* table, /*!< in: table */ dict_table_t* table, /*!< in: table */
...@@ -470,6 +471,7 @@ dict_load_columns( ...@@ -470,6 +471,7 @@ dict_load_columns(
ulint col_len; ulint col_len;
ulint i; ulint i;
mtr_t mtr; mtr_t mtr;
enum db_err err = DB_SUCCESS;
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
...@@ -517,6 +519,30 @@ dict_load_columns( ...@@ -517,6 +519,30 @@ dict_load_columns(
field = rec_get_nth_field_old(rec, 6, &len); field = rec_get_nth_field_old(rec, 6, &len);
prtype = mach_read_from_4(field); prtype = mach_read_from_4(field);
/* We can rely on dtype_get_charset_coll() to check
charset collation number exceed limit, since it comes
with a smaller mask. We have to do the check explicitly
here */
if (((prtype >> 16) & LARGE_CHAR_COLL_PRTYPE_MASK)
> MAX_CHAR_COLL_NUM) {
fprintf(stderr, "InnoDB: Error: load column"
" '%s' for table '%s' failed.\n"
"InnoDB: column '%s' has a charset"
" collation number of %lu, exceeds"
" maximum value %lu supported\n",
name, name, table->name,
(ulong) ((prtype >> 16)
& LARGE_CHAR_COLL_PRTYPE_MASK),
(ulong) MAX_CHAR_COLL_NUM);
err = DB_CORRUPTION;
/* If the force recovery flag is not set, it will
stop loading and exit */
if (!srv_force_recovery) {
goto func_exit;
}
}
if (dtype_get_charset_coll(prtype) == 0 if (dtype_get_charset_coll(prtype) == 0
&& dtype_is_string_type(mtype)) { && dtype_is_string_type(mtype)) {
/* The table was created with < 4.1.2. */ /* The table was created with < 4.1.2. */
...@@ -548,8 +574,11 @@ dict_load_columns( ...@@ -548,8 +574,11 @@ dict_load_columns(
btr_pcur_move_to_next_user_rec(&pcur, &mtr); btr_pcur_move_to_next_user_rec(&pcur, &mtr);
} }
func_exit:
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
return(err);
} }
/********************************************************************//** /********************************************************************//**
...@@ -1044,7 +1073,12 @@ dict_load_table( ...@@ -1044,7 +1073,12 @@ dict_load_table(
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
dict_load_columns(table, heap); err = dict_load_columns(table, heap);
if (err != DB_SUCCESS && !srv_force_recovery) {
table = NULL;
goto func_exit;
}
dict_table_add_to_cache(table, heap); dict_table_add_to_cache(table, heap);
...@@ -1106,6 +1140,8 @@ dict_load_table( ...@@ -1106,6 +1140,8 @@ dict_load_table(
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
} }
#endif /* 0 */ #endif /* 0 */
func_exit:
mem_heap_free(heap); mem_heap_free(heap);
return(table); return(table);
......
...@@ -6086,7 +6086,7 @@ create_table_def( ...@@ -6086,7 +6086,7 @@ create_table_def(
charset_no = (ulint)field->charset()->number; charset_no = (ulint)field->charset()->number;
if (UNIV_UNLIKELY(charset_no >= 256)) { if (UNIV_UNLIKELY(charset_no > MAX_CHAR_COLL_NUM)) {
/* in data0type.h we assume that the /* in data0type.h we assume that the
number fits in one byte in prtype */ number fits in one byte in prtype */
push_warning_printf( push_warning_printf(
...@@ -6101,8 +6101,9 @@ create_table_def( ...@@ -6101,8 +6101,9 @@ create_table_def(
} }
} }
ut_a(field->type() < 256); /* we assume in dtype_form_prtype() /* we assume in dtype_form_prtype() that this fits in
that this fits in one byte */ one byte */
ut_a(field->type() <= MAX_CHAR_COLL_NUM);
col_len = field->pack_length(); col_len = field->pack_length();
/* The MySQL pack length contains 1 or 2 bytes length field /* The MySQL pack length contains 1 or 2 bytes length field
......
...@@ -168,6 +168,15 @@ SQL null*/ ...@@ -168,6 +168,15 @@ SQL null*/
store the charset-collation number; one byte is left unused, though */ store the charset-collation number; one byte is left unused, though */
#define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6 #define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6
/* We support 8 bits (up to 255) collation number until 5.6.3, in which
the collation number is extended to 32767 */
#define MAX_CHAR_COLL_NUM 255
/* Mask to get the large charset-collation number in PRTYPE
This is used to mainly block loading tables with large charset-collation
value with database from 5.6 */
#define LARGE_CHAR_COLL_PRTYPE_MASK 0xFFFFUL
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/*********************************************************************//** /*********************************************************************//**
Gets the MySQL type code from a dtype. Gets the MySQL type code from a dtype.
......
...@@ -306,7 +306,7 @@ dtype_new_store_for_order_and_null_size( ...@@ -306,7 +306,7 @@ dtype_new_store_for_order_and_null_size(
mach_write_to_2(buf + 2, len & 0xFFFFUL); mach_write_to_2(buf + 2, len & 0xFFFFUL);
ut_ad(dtype_get_charset_coll(type->prtype) < 256); ut_ad(dtype_get_charset_coll(type->prtype) <= MAX_CHAR_COLL_NUM);
mach_write_to_2(buf + 4, dtype_get_charset_coll(type->prtype)); mach_write_to_2(buf + 4, dtype_get_charset_coll(type->prtype));
if (type->prtype & DATA_NOT_NULL) { if (type->prtype & DATA_NOT_NULL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment