Commit e6b32615 authored by osku@127.(none)'s avatar osku@127.(none)

InnoDB: Fix bug #13315, index columns having a maximum length of 767.

parent 306dcf06
...@@ -561,12 +561,12 @@ dtuple_convert_big_rec( ...@@ -561,12 +561,12 @@ dtuple_convert_big_rec(
} }
/* We do not store externally fields which are smaller than /* We do not store externally fields which are smaller than
DICT_MAX_COL_PREFIX_LEN */ DICT_MAX_INDEX_COL_LEN */
ut_a(DICT_MAX_COL_PREFIX_LEN > REC_1BYTE_OFFS_LIMIT); ut_a(DICT_MAX_INDEX_COL_LEN > REC_1BYTE_OFFS_LIMIT);
if (longest < BTR_EXTERN_FIELD_REF_SIZE + 10 if (longest < BTR_EXTERN_FIELD_REF_SIZE + 10
+ DICT_MAX_COL_PREFIX_LEN) { + DICT_MAX_INDEX_COL_LEN) {
/* Cannot shorten more */ /* Cannot shorten more */
mem_heap_free(heap); mem_heap_free(heap);
...@@ -588,10 +588,10 @@ dtuple_convert_big_rec( ...@@ -588,10 +588,10 @@ dtuple_convert_big_rec(
dfield = dtuple_get_nth_field(entry, longest_i); dfield = dtuple_get_nth_field(entry, longest_i);
vector->fields[n_fields].field_no = longest_i; vector->fields[n_fields].field_no = longest_i;
ut_a(dfield->len > DICT_MAX_COL_PREFIX_LEN); ut_a(dfield->len > DICT_MAX_INDEX_COL_LEN);
vector->fields[n_fields].len = dfield->len vector->fields[n_fields].len = dfield->len
- DICT_MAX_COL_PREFIX_LEN; - DICT_MAX_INDEX_COL_LEN;
vector->fields[n_fields].data = mem_heap_alloc(heap, vector->fields[n_fields].data = mem_heap_alloc(heap,
vector->fields[n_fields].len); vector->fields[n_fields].len);
......
...@@ -1625,7 +1625,7 @@ dict_index_add_col( ...@@ -1625,7 +1625,7 @@ dict_index_add_col(
variable-length fields, so that the extern flag can be embedded in variable-length fields, so that the extern flag can be embedded in
the length word. */ the length word. */
if (field->fixed_len > DICT_MAX_COL_PREFIX_LEN) { if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
field->fixed_len = 0; field->fixed_len = 0;
} }
......
...@@ -152,12 +152,12 @@ struct dict_col_struct{ ...@@ -152,12 +152,12 @@ struct dict_col_struct{
in some of the functions below */ in some of the functions below */
}; };
/* DICT_MAX_COL_PREFIX_LEN is measured in bytes. Starting from 4.1.6, we /* DICT_MAX_INDEX_COL_LEN is measured in bytes and is the max index column
set max col prefix len to < 3 * 256, so that one can create a column prefix length + 1. Starting from 4.1.6, we set it to < 3 * 256, so that one can
index on 255 characters of a TEXT field also in the UTF-8 charset. In that create a column prefix index on 255 characters of a TEXT field also in the
charset, a character may take at most 3 bytes. */ UTF-8 charset. In that charset, a character may take at most 3 bytes. */
#define DICT_MAX_COL_PREFIX_LEN 768 #define DICT_MAX_INDEX_COL_LEN 768
/* Data structure for a field in an index */ /* Data structure for a field in an index */
struct dict_field_struct{ struct dict_field_struct{
...@@ -169,12 +169,12 @@ struct dict_field_struct{ ...@@ -169,12 +169,12 @@ struct dict_field_struct{
prefix in bytes in a MySQL index of prefix in bytes in a MySQL index of
type, e.g., INDEX (textcol(25)); type, e.g., INDEX (textcol(25));
must be smaller than must be smaller than
DICT_MAX_COL_PREFIX_LEN; NOTE that DICT_MAX_INDEX_COL_LEN; NOTE that
in the UTF-8 charset, MySQL sets this in the UTF-8 charset, MySQL sets this
to 3 * the prefix len in UTF-8 chars */ to 3 * the prefix len in UTF-8 chars */
ulint fixed_len; /* 0 or the fixed length of the ulint fixed_len; /* 0 or the fixed length of the
column if smaller than column if smaller than
DICT_MAX_COL_PREFIX_LEN */ DICT_MAX_INDEX_COL_LEN */
ulint fixed_offs; /* offset to the field, or ulint fixed_offs; /* offset to the field, or
ULINT_UNDEFINED if it is not fixed ULINT_UNDEFINED if it is not fixed
within the record (due to preceding within the record (due to preceding
......
...@@ -335,8 +335,14 @@ int ...@@ -335,8 +335,14 @@ int
row_create_index_for_mysql( row_create_index_for_mysql(
/*=======================*/ /*=======================*/
/* out: error number or DB_SUCCESS */ /* out: error number or DB_SUCCESS */
dict_index_t* index, /* in: index defintion */ dict_index_t* index, /* in: index definition */
trx_t* trx); /* in: transaction handle */ trx_t* trx, /* in: transaction handle */
const ulint* field_lengths); /* in: if not NULL, must contain
dict_index_get_n_fields(index)
actual field lengths for the
index columns, which are
then checked for not being too
large. */
/************************************************************************* /*************************************************************************
Scans a table create SQL string and adds to the data dictionary Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function the foreign key constraints declared in the string. This function
......
...@@ -621,7 +621,7 @@ rec_set_nth_field_extern_bit_new( ...@@ -621,7 +621,7 @@ rec_set_nth_field_extern_bit_new(
if (field->fixed_len) { if (field->fixed_len) {
/* fixed-length fields cannot be external /* fixed-length fields cannot be external
(Fixed-length fields longer than (Fixed-length fields longer than
DICT_MAX_COL_PREFIX_LEN will be treated as DICT_MAX_INDEX_COL_LEN will be treated as
variable-length ones in dict_index_add_col().) */ variable-length ones in dict_index_add_col().) */
ut_ad(i != ith); ut_ad(i != ith);
continue; continue;
......
...@@ -1973,13 +1973,20 @@ row_create_index_for_mysql( ...@@ -1973,13 +1973,20 @@ row_create_index_for_mysql(
/*=======================*/ /*=======================*/
/* out: error number or DB_SUCCESS */ /* out: error number or DB_SUCCESS */
dict_index_t* index, /* in: index definition */ dict_index_t* index, /* in: index definition */
trx_t* trx) /* in: transaction handle */ trx_t* trx, /* in: transaction handle */
const ulint* field_lengths) /* in: if not NULL, must contain
dict_index_get_n_fields(index)
actual field lengths for the
index columns, which are
then checked for not being too
large. */
{ {
ind_node_t* node; ind_node_t* node;
mem_heap_t* heap; mem_heap_t* heap;
que_thr_t* thr; que_thr_t* thr;
ulint err; ulint err;
ulint i, j; ulint i, j;
ulint len;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX)); ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
...@@ -2018,10 +2025,16 @@ row_create_index_for_mysql( ...@@ -2018,10 +2025,16 @@ row_create_index_for_mysql(
} }
} }
/* Check also that prefix_len < DICT_MAX_COL_PREFIX_LEN */ /* Check also that prefix_len and actual length
< DICT_MAX_INDEX_COL_LEN */
len = dict_index_get_nth_field(index, i)->prefix_len;
if (field_lengths) {
len = ut_max(len, field_lengths[i]);
}
if (dict_index_get_nth_field(index, i)->prefix_len if (len >= DICT_MAX_INDEX_COL_LEN) {
>= DICT_MAX_COL_PREFIX_LEN) {
err = DB_TOO_BIG_RECORD; err = DB_TOO_BIG_RECORD;
goto error_handling; goto error_handling;
......
...@@ -2559,3 +2559,37 @@ FOREIGN KEY (b) REFERENCES test.t1(id) ...@@ -2559,3 +2559,37 @@ FOREIGN KEY (b) REFERENCES test.t1(id)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
Got one of the listed errors Got one of the listed errors
DROP TABLE t1; DROP TABLE t1;
create table t1 (col1 varchar(2000), index (col1(767)))
character set = latin1 engine = innodb;
create table t2 (col1 char(255), index (col1))
character set = latin1 engine = innodb;
create table t3 (col1 binary(255), index (col1))
character set = latin1 engine = innodb;
create table t4 (col1 varchar(767), index (col1))
character set = latin1 engine = innodb;
create table t5 (col1 varchar(767) primary key)
character set = latin1 engine = innodb;
create table t6 (col1 varbinary(767) primary key)
character set = latin1 engine = innodb;
create table t7 (col1 text, index(col1(767)))
character set = latin1 engine = innodb;
create table t8 (col1 blob, index(col1(767)))
character set = latin1 engine = innodb;
create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2))
character set = latin1 engine = innodb;
drop table t1, t2, t3, t4, t5, t6, t7, t8, t9;
create table t1 (col1 varchar(768), index (col1))
character set = latin1 engine = innodb;
ERROR HY000: Can't create table './test/t1.frm' (errno: 139)
create table t2 (col1 varchar(768) primary key)
character set = latin1 engine = innodb;
ERROR HY000: Can't create table './test/t2.frm' (errno: 139)
create table t3 (col1 varbinary(768) primary key)
character set = latin1 engine = innodb;
ERROR HY000: Can't create table './test/t3.frm' (errno: 139)
create table t4 (col1 text, index(col1(768)))
character set = latin1 engine = innodb;
ERROR HY000: Can't create table './test/t4.frm' (errno: 139)
create table t5 (col1 blob, index(col1(768)))
character set = latin1 engine = innodb;
ERROR HY000: Can't create table './test/t5.frm' (errno: 139)
...@@ -1482,3 +1482,49 @@ CREATE TEMPORARY TABLE t2 ...@@ -1482,3 +1482,49 @@ CREATE TEMPORARY TABLE t2
FOREIGN KEY (b) REFERENCES test.t1(id) FOREIGN KEY (b) REFERENCES test.t1(id)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
DROP TABLE t1; DROP TABLE t1;
#
# Test that index column max sizes are checked (bug #13315)
#
# prefix index
create table t1 (col1 varchar(2000), index (col1(767)))
character set = latin1 engine = innodb;
# normal indexes
create table t2 (col1 char(255), index (col1))
character set = latin1 engine = innodb;
create table t3 (col1 binary(255), index (col1))
character set = latin1 engine = innodb;
create table t4 (col1 varchar(767), index (col1))
character set = latin1 engine = innodb;
create table t5 (col1 varchar(767) primary key)
character set = latin1 engine = innodb;
create table t6 (col1 varbinary(767) primary key)
character set = latin1 engine = innodb;
create table t7 (col1 text, index(col1(767)))
character set = latin1 engine = innodb;
create table t8 (col1 blob, index(col1(767)))
character set = latin1 engine = innodb;
# multi-column indexes are allowed to be longer
create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2))
character set = latin1 engine = innodb;
drop table t1, t2, t3, t4, t5, t6, t7, t8, t9;
--error 1005
create table t1 (col1 varchar(768), index (col1))
character set = latin1 engine = innodb;
--error 1005
create table t2 (col1 varchar(768) primary key)
character set = latin1 engine = innodb;
--error 1005
create table t3 (col1 varbinary(768) primary key)
character set = latin1 engine = innodb;
--error 1005
create table t4 (col1 text, index(col1(768)))
character set = latin1 engine = innodb;
--error 1005
create table t5 (col1 blob, index(col1(768)))
character set = latin1 engine = innodb;
...@@ -4492,6 +4492,7 @@ create_index( ...@@ -4492,6 +4492,7 @@ create_index(
ulint is_unsigned; ulint is_unsigned;
ulint i; ulint i;
ulint j; ulint j;
ulint* field_lengths;
DBUG_ENTER("create_index"); DBUG_ENTER("create_index");
...@@ -4514,6 +4515,10 @@ create_index( ...@@ -4514,6 +4515,10 @@ create_index(
index = dict_mem_index_create((char*) table_name, key->name, 0, index = dict_mem_index_create((char*) table_name, key->name, 0,
ind_type, n_fields); ind_type, n_fields);
field_lengths = (ulint*) my_malloc(sizeof(ulint) * n_fields,
MYF(MY_FAE));
for (i = 0; i < n_fields; i++) { for (i = 0; i < n_fields; i++) {
key_part = key->key_part + i; key_part = key->key_part + i;
...@@ -4568,6 +4573,8 @@ create_index( ...@@ -4568,6 +4573,8 @@ create_index(
prefix_len = 0; prefix_len = 0;
} }
field_lengths[i] = key_part->length;
/* We assume all fields should be sorted in ascending /* We assume all fields should be sorted in ascending
order, hence the '0': */ order, hence the '0': */
...@@ -4576,10 +4583,12 @@ create_index( ...@@ -4576,10 +4583,12 @@ create_index(
0, prefix_len); 0, prefix_len);
} }
error = row_create_index_for_mysql(index, trx); error = row_create_index_for_mysql(index, trx, field_lengths);
error = convert_error_code_to_mysql(error, NULL); error = convert_error_code_to_mysql(error, NULL);
my_free((gptr) field_lengths, MYF(0));
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -4602,7 +4611,7 @@ create_clustered_index_when_no_primary( ...@@ -4602,7 +4611,7 @@ create_clustered_index_when_no_primary(
index = dict_mem_index_create((char*) table_name, index = dict_mem_index_create((char*) table_name,
(char*) "GEN_CLUST_INDEX", (char*) "GEN_CLUST_INDEX",
0, DICT_CLUSTERED, 0); 0, DICT_CLUSTERED, 0);
error = row_create_index_for_mysql(index, trx); error = row_create_index_for_mysql(index, trx, NULL);
error = convert_error_code_to_mysql(error, NULL); error = convert_error_code_to_mysql(error, 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