Commit 2e34a089 authored by unknown's avatar unknown

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.
parent b2f7c99d
......@@ -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 */
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
>= DICT_MAX_COL_PREFIX_LEN) {
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,6 +4492,7 @@ create_index(
ulint is_unsigned;
ulint i;
ulint j;
ulint* field_lengths;
DBUG_ENTER("create_index");
......@@ -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);
......
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