mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
InnoDB: Fix bug #13315, index columns having a maximum length of 767.
This commit is contained in:
@@ -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(
|
|||||||
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(
|
|||||||
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{
|
|||||||
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{
|
|||||||
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
|
|||||||
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(
|
|||||||
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(
|
|||||||
/*=======================*/
|
/*=======================*/
|
||||||
/* 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(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check also that prefix_len < DICT_MAX_COL_PREFIX_LEN */
|
/* Check also that prefix_len and actual length
|
||||||
|
< DICT_MAX_INDEX_COL_LEN */
|
||||||
|
|
||||||
if (dict_index_get_nth_field(index, i)->prefix_len
|
len = dict_index_get_nth_field(index, i)->prefix_len;
|
||||||
>= DICT_MAX_COL_PREFIX_LEN) {
|
|
||||||
|
if (field_lengths) {
|
||||||
|
len = ut_max(len, field_lengths[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= DICT_MAX_INDEX_COL_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)
|
|||||||
) 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
|
|||||||
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(
|
|||||||
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(
|
|||||||
|
|
||||||
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(
|
|||||||
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(
|
|||||||
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(
|
|||||||
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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user