mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
InnoDB: Fix bug #13315, index columns having a maximum length of 767.
innobase/data/data0data.c: Adapt to DICT_MAX_COL_PREFIX_LEN rename. innobase/dict/dict0dict.c: Adapt to DICT_MAX_COL_PREFIX_LEN rename. innobase/include/dict0mem.h: Rename DICT_MAX_COL_PREFIX_LEN to DICT_MAX_INDEX_COL_LEN. innobase/include/row0mysql.h: Add field_lengths parameter to row_create_index_for_mysql. innobase/rem/rem0rec.c: Adapt to DICT_MAX_COL_PREFIX_LEN rename. innobase/row/row0mysql.c: Add field_lengths parameter to row_create_index_for_mysql and use it to check for too long index columns. mysql-test/r/innodb.result: New tests. mysql-test/t/innodb.test: New tests. sql/ha_innodb.cc: Create temporary field_lengths buffer and pass it to row_create_index_for_mysql.
This commit is contained in:
parent
d2fc3bd424
commit
6fbbb1d5be
9 changed files with 131 additions and 23 deletions
|
@ -561,12 +561,12 @@ dtuple_convert_big_rec(
|
|||
}
|
||||
|
||||
/* 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
|
||||
+ DICT_MAX_COL_PREFIX_LEN) {
|
||||
+ DICT_MAX_INDEX_COL_LEN) {
|
||||
/* Cannot shorten more */
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
@ -588,10 +588,10 @@ dtuple_convert_big_rec(
|
|||
dfield = dtuple_get_nth_field(entry, 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
|
||||
- DICT_MAX_COL_PREFIX_LEN;
|
||||
- DICT_MAX_INDEX_COL_LEN;
|
||||
|
||||
vector->fields[n_fields].data = mem_heap_alloc(heap,
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -152,12 +152,12 @@ struct dict_col_struct{
|
|||
in some of the functions below */
|
||||
};
|
||||
|
||||
/* DICT_MAX_COL_PREFIX_LEN is measured in bytes. Starting from 4.1.6, we
|
||||
set max col prefix len to < 3 * 256, so that one can create a column prefix
|
||||
index on 255 characters of a TEXT field also in the UTF-8 charset. In that
|
||||
charset, a character may take at most 3 bytes. */
|
||||
/* DICT_MAX_INDEX_COL_LEN is measured in bytes and is the max index column
|
||||
length + 1. Starting from 4.1.6, we set it to < 3 * 256, so that one can
|
||||
create a column prefix index on 255 characters of a TEXT field also in the
|
||||
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 */
|
||||
struct dict_field_struct{
|
||||
|
@ -169,12 +169,12 @@ struct dict_field_struct{
|
|||
prefix in bytes in a MySQL index of
|
||||
type, e.g., INDEX (textcol(25));
|
||||
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
|
||||
to 3 * the prefix len in UTF-8 chars */
|
||||
ulint fixed_len; /* 0 or the fixed length of the
|
||||
column if smaller than
|
||||
DICT_MAX_COL_PREFIX_LEN */
|
||||
DICT_MAX_INDEX_COL_LEN */
|
||||
ulint fixed_offs; /* offset to the field, or
|
||||
ULINT_UNDEFINED if it is not fixed
|
||||
within the record (due to preceding
|
||||
|
|
|
@ -335,8 +335,14 @@ int
|
|||
row_create_index_for_mysql(
|
||||
/*=======================*/
|
||||
/* out: error number or DB_SUCCESS */
|
||||
dict_index_t* index, /* in: index defintion */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
dict_index_t* index, /* in: index definition */
|
||||
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
|
||||
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) {
|
||||
/* fixed-length fields cannot be external
|
||||
(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().) */
|
||||
ut_ad(i != ith);
|
||||
continue;
|
||||
|
|
|
@ -1973,13 +1973,20 @@ row_create_index_for_mysql(
|
|||
/*=======================*/
|
||||
/* out: error number or DB_SUCCESS */
|
||||
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;
|
||||
mem_heap_t* heap;
|
||||
que_thr_t* thr;
|
||||
ulint err;
|
||||
ulint i, j;
|
||||
ulint len;
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
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
|
||||
>= DICT_MAX_COL_PREFIX_LEN) {
|
||||
len = dict_index_get_nth_field(index, i)->prefix_len;
|
||||
|
||||
if (field_lengths) {
|
||||
len = ut_max(len, field_lengths[i]);
|
||||
}
|
||||
|
||||
if (len >= DICT_MAX_INDEX_COL_LEN) {
|
||||
err = DB_TOO_BIG_RECORD;
|
||||
|
||||
goto error_handling;
|
||||
|
|
|
@ -2559,3 +2559,37 @@ FOREIGN KEY (b) REFERENCES test.t1(id)
|
|||
) ENGINE=InnoDB;
|
||||
Got one of the listed errors
|
||||
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)
|
||||
) ENGINE=InnoDB;
|
||||
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,7 +4492,8 @@ create_index(
|
|||
ulint is_unsigned;
|
||||
ulint i;
|
||||
ulint j;
|
||||
|
||||
ulint* field_lengths;
|
||||
|
||||
DBUG_ENTER("create_index");
|
||||
|
||||
key = form->key_info + key_num;
|
||||
|
@ -4514,6 +4515,10 @@ create_index(
|
|||
|
||||
index = dict_mem_index_create((char*) table_name, key->name, 0,
|
||||
ind_type, n_fields);
|
||||
|
||||
field_lengths = (ulint*) my_malloc(sizeof(ulint) * n_fields,
|
||||
MYF(MY_FAE));
|
||||
|
||||
for (i = 0; i < n_fields; i++) {
|
||||
key_part = key->key_part + i;
|
||||
|
||||
|
@ -4568,6 +4573,8 @@ create_index(
|
|||
prefix_len = 0;
|
||||
}
|
||||
|
||||
field_lengths[i] = key_part->length;
|
||||
|
||||
/* We assume all fields should be sorted in ascending
|
||||
order, hence the '0': */
|
||||
|
||||
|
@ -4576,10 +4583,12 @@ create_index(
|
|||
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);
|
||||
|
||||
my_free((gptr) field_lengths, MYF(0));
|
||||
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
@ -4602,7 +4611,7 @@ create_clustered_index_when_no_primary(
|
|||
index = dict_mem_index_create((char*) table_name,
|
||||
(char*) "GEN_CLUST_INDEX",
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue