Commit 3b074d7b authored by marko's avatar marko

Fix a severe bug that was introduced in r1422 when fixing Bug #21101.

When creating an index containing a too long record, InnoDB would
dereference a NULL pointer when trying to determine the maximum row length.

innodb_check_for_record_too_big_error(): Replace the dict_table_t*
parameter with a Boolean flag.  There is not always a dict_table_t object
when this function is called.

page_get_free_space_of_empty_noninline(): Move the definition and
declaration from row0mysql (!) to page0page.  Make the signature
identical with page_get_free_space_of_empty().

create_clustered_index_when_no_primary(): Add the parameter "comp".
Remove unnecessary casts.
parent b5bb1096
...@@ -4510,17 +4510,17 @@ ha_innobase::position( ...@@ -4510,17 +4510,17 @@ ha_innobase::position(
/********************************************************************* /*********************************************************************
If it's a DB_TOO_BIG_RECORD error then set a suitable message to If it's a DB_TOO_BIG_RECORD error then set a suitable message to
return to the client.*/ return to the client.*/
static inline
void void
innodb_check_for_record_too_big_error( innodb_check_for_record_too_big_error(
/*==================================*/ /*==================================*/
dict_table_t* table, /* in: table to check */ ulint comp, /* in: ROW_FORMAT: nonzero=COMPACT, 0=REDUNDANT */
int error) /* in: error code to check */ int error) /* in: error code to check */
{ {
if (error == (int)DB_TOO_BIG_RECORD) { if (error == (int)DB_TOO_BIG_RECORD) {
ulint max_row_size; ulint max_row_size;
max_row_size = page_get_free_space_of_empty_noninline(table); max_row_size = page_get_free_space_of_empty_noninline(comp);
my_error(ER_TOO_BIG_ROWSIZE, MYF(0), max_row_size); my_error(ER_TOO_BIG_ROWSIZE, MYF(0), max_row_size);
} }
...@@ -4634,9 +4634,8 @@ create_table_def( ...@@ -4634,9 +4634,8 @@ create_table_def(
error = row_create_table_for_mysql(table, trx); error = row_create_table_for_mysql(table, trx);
/* We need access to the table and so we do the error checking innodb_check_for_record_too_big_error(dict_table_is_comp(table),
and set the error message here, before the error translation.*/ error);
innodb_check_for_record_too_big_error(table, error);
error = convert_error_code_to_mysql(error, NULL); error = convert_error_code_to_mysql(error, NULL);
...@@ -4760,9 +4759,8 @@ create_index( ...@@ -4760,9 +4759,8 @@ create_index(
sure we don't create too long indexes. */ sure we don't create too long indexes. */
error = row_create_index_for_mysql(index, trx, field_lengths); error = row_create_index_for_mysql(index, trx, field_lengths);
/* We need access to the table and so we do the error checking innodb_check_for_record_too_big_error(form->s->row_type
and set the error message here, before the error translation.*/ != ROW_TYPE_REDUNDANT, error);
innodb_check_for_record_too_big_error(index->table, error);
error = convert_error_code_to_mysql(error, NULL); error = convert_error_code_to_mysql(error, NULL);
...@@ -4779,6 +4777,8 @@ int ...@@ -4779,6 +4777,8 @@ int
create_clustered_index_when_no_primary( create_clustered_index_when_no_primary(
/*===================================*/ /*===================================*/
trx_t* trx, /* in: InnoDB transaction handle */ trx_t* trx, /* in: InnoDB transaction handle */
ulint comp, /* in: ROW_FORMAT:
nonzero=COMPACT, 0=REDUNDANT */
const char* table_name) /* in: table name */ const char* table_name) /* in: table name */
{ {
dict_index_t* index; dict_index_t* index;
...@@ -4787,13 +4787,11 @@ create_clustered_index_when_no_primary( ...@@ -4787,13 +4787,11 @@ create_clustered_index_when_no_primary(
/* We pass 0 as the space id, and determine at a lower level the space /* We pass 0 as the space id, and determine at a lower level the space
id where to store the table */ id where to store the table */
index = dict_mem_index_create((char*) table_name, index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX",
(char*) "GEN_CLUST_INDEX", 0, DICT_CLUSTERED, 0); 0, DICT_CLUSTERED, 0);
error = row_create_index_for_mysql(index, trx, NULL); error = row_create_index_for_mysql(index, trx, NULL);
/* We need access to the table and so we do the error checking innodb_check_for_record_too_big_error(comp, error);
and set the error message here, before the error translation.*/
innodb_check_for_record_too_big_error(index->table, error);
error = convert_error_code_to_mysql(error, NULL); error = convert_error_code_to_mysql(error, NULL);
...@@ -4924,8 +4922,9 @@ ha_innobase::create( ...@@ -4924,8 +4922,9 @@ ha_innobase::create(
order the rows by their row id which is internally generated order the rows by their row id which is internally generated
by InnoDB */ by InnoDB */
error = create_clustered_index_when_no_primary(trx, error = create_clustered_index_when_no_primary(
norm_name); trx, form->s->row_type != ROW_TYPE_REDUNDANT,
norm_name);
if (error) { if (error) {
goto cleanup; goto cleanup;
} }
......
...@@ -531,6 +531,15 @@ page_get_free_space_of_empty( ...@@ -531,6 +531,15 @@ page_get_free_space_of_empty(
/* out: free space */ /* out: free space */
ulint comp) /* in: nonzero=compact page format */ ulint comp) /* in: nonzero=compact page format */
__attribute__((const)); __attribute__((const));
/*****************************************************************
Calculates free space if a page is emptied. */
ulint
page_get_free_space_of_empty_noninline(
/*===================================*/
/* out: free space */
ulint comp) /* in: nonzero=compact page format */
__attribute__((const));
/**************************************************************** /****************************************************************
Returns the sum of the sizes of the records in the record list Returns the sum of the sizes of the records in the record list
excluding the infimum and supremum records. */ excluding the infimum and supremum records. */
......
...@@ -460,19 +460,6 @@ row_check_table_for_mysql( ...@@ -460,19 +460,6 @@ row_check_table_for_mysql(
/* out: DB_ERROR or DB_SUCCESS */ /* out: DB_ERROR or DB_SUCCESS */
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
handle */ handle */
/*************************************************************************
Get the min of the maximum possible row sizes. */
ulint
page_get_free_space_of_empty_noninline(
/*===================================*/
/* out: The (approx) maximum size
of a row, this is a conservative
estimate, since the size can be
slightly larger depending upon
the ROW_FORMAT setting.*/
dict_table_t* table); /* in: table for which max record
size required.*/
/* A struct describing a place for an individual column in the MySQL /* A struct describing a place for an individual column in the MySQL
row format which is presented to the table handler in ha_innobase. row format which is presented to the table handler in ha_innobase.
......
...@@ -209,6 +209,18 @@ page_set_max_trx_id( ...@@ -209,6 +209,18 @@ page_set_max_trx_id(
} }
} }
/*****************************************************************
Calculates free space if a page is emptied. */
ulint
page_get_free_space_of_empty_noninline(
/*===================================*/
/* out: free space */
ulint comp) /* in: nonzero=compact page format */
{
return(page_get_free_space_of_empty(comp));
}
/**************************************************************** /****************************************************************
Allocates a block of memory from an index page. */ Allocates a block of memory from an index page. */
......
...@@ -4059,25 +4059,3 @@ row_check_table_for_mysql( ...@@ -4059,25 +4059,3 @@ row_check_table_for_mysql(
return(ret); return(ret);
} }
/*************************************************************************
Get the maximum row size. */
ulint
page_get_free_space_of_empty_noninline(
/*===================================*/
/* out: The (approx) maximum size
of a row, this is a conservative
estimate, since the size can be
slightly larger depending upon
the ROW_FORMAT setting.*/
dict_table_t* table) /* in: table for which max record
size is required.*/
{
ibool compact;
compact = dict_table_is_comp(table);
return(page_get_free_space_of_empty(compact) / 2);
}
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