ha_innodb.cc:

  Raise maximum column prefix len to 767 bytes, so that MySQL can create a column prefix index of 255 UTF-8 characters (each takes 3 bytes at the maximum); add comments about why innobase_get_at_most_n_mbchars() works ok
dict0mem.h:
  Raise maximum column prefix len to 767 bytes, so that MySQL can create a column prefix index of 255 UTF-8 characters (each takes 3 bytes at the maximum)
row0mysql.c:
  If MySQL tries to create a column prefix index longer that 255 UTF-8 characters, give an error, and drop the table from the InnoDB internal data dictionary. MySQL did not drop the table there in its own error handling.
parent 092d1a50
...@@ -151,7 +151,12 @@ struct dict_col_struct{ ...@@ -151,7 +151,12 @@ struct dict_col_struct{
in some of the functions below */ in some of the functions below */
}; };
#define DICT_MAX_COL_PREFIX_LEN 512 /* DICT_MAX_COL_PREFIX_LEN is measured in bytes. Starting from 4.1.6, we
define max col prefix len as 3 * 256, so that one can create a column prefix
index on 256 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
/* Data structure for a field in an index */ /* Data structure for a field in an index */
struct dict_field_struct{ struct dict_field_struct{
...@@ -160,9 +165,13 @@ struct dict_field_struct{ ...@@ -160,9 +165,13 @@ struct dict_field_struct{
ulint order; /* flags for ordering this field: ulint order; /* flags for ordering this field:
DICT_DESCEND, ... */ DICT_DESCEND, ... */
ulint prefix_len; /* 0 or the length of the column ulint prefix_len; /* 0 or the length of the column
prefix in a MySQL index of type, e.g., prefix in bytes in a MySQL index of
INDEX (textcol(25)); must be smaller type, e.g., INDEX (textcol(25));
than DICT_MAX_COL_PREFIX_LEN */ must be smaller than
DICT_MAX_COL_PREFIX_LEN; NOTE that
in the UTF-8 charset, MySQL reserves
sets this to 3 * the prefix len in
UTF-8 chars */
}; };
/* Data structure for an index tree */ /* Data structure for an index tree */
......
...@@ -1630,6 +1630,8 @@ row_create_index_for_mysql( ...@@ -1630,6 +1630,8 @@ row_create_index_for_mysql(
trx->op_info = "creating index"; trx->op_info = "creating index";
trx_start_if_not_started(trx);
/* Check that the same column does not appear twice in the index. /* Check that the same column does not appear twice in the index.
Starting from 4.0.14, InnoDB should be able to cope with that, but Starting from 4.0.14, InnoDB should be able to cope with that, but
safer not to allow them. */ safer not to allow them. */
...@@ -1656,9 +1658,16 @@ row_create_index_for_mysql( ...@@ -1656,9 +1658,16 @@ row_create_index_for_mysql(
goto error_handling; goto error_handling;
} }
} }
}
trx_start_if_not_started(trx); /* Check also that prefix_len < DICT_MAX_COL_PREFIX_LEN */
if (dict_index_get_nth_field(index, i)->prefix_len
>= DICT_MAX_COL_PREFIX_LEN) {
err = DB_TOO_BIG_RECORD;
goto error_handling;
}
}
if (row_mysql_is_recovered_tmp_table(index->table_name)) { if (row_mysql_is_recovered_tmp_table(index->table_name)) {
......
...@@ -3525,10 +3525,6 @@ create_index( ...@@ -3525,10 +3525,6 @@ create_index(
prefix_len = 0; prefix_len = 0;
} }
if (prefix_len >= DICT_MAX_COL_PREFIX_LEN) {
DBUG_RETURN(-1);
}
/* 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': */
...@@ -5333,39 +5329,32 @@ innobase_get_at_most_n_mbchars( ...@@ -5333,39 +5329,32 @@ innobase_get_at_most_n_mbchars(
/* If the charset is multi-byte, then we must find the length of the /* If the charset is multi-byte, then we must find the length of the
first at most n chars in the string. If the string contains less first at most n chars in the string. If the string contains less
characters than n, then we return the length to the end of the last characters than n, then we return the length to the end of the last
full character. */ character. */
if (charset->mbmaxlen > 1) { if (charset->mbmaxlen > 1) {
/* ulint right_value; */
/* my_charpos() returns the byte length of the first n_chars /* my_charpos() returns the byte length of the first n_chars
characters, or the end of the last full character */ characters, or a value bigger than the length of str, if
there were not enough full characters in str.
char_length = my_charpos(charset, str, Why does the code below work:
str + data_len, n_chars); Suppose that we are looking for n UTF-8 characters.
/*################################################*/ 1) If the string is long enough, then the prefix contains at
/* TODO: my_charpos sometimes returns a non-sensical value least n complete UTF-8 characters + maybe some extra
that is BIGGER than data_len: try to fix this bug partly with characters + an incomplete UTF-8 character. No problem in
these heuristics. This is NOT a complete bug fix! */ this case. The function returns the pointer to the
end of the nth character.
2) If the string is not long enough, then the string contains
the complete value of a column, that is, only complete UTF-8
characters, and we can store in the column prefix index the
whole string. */
char_length = my_charpos(charset, str,
str + data_len, n_chars);
if (char_length > data_len) { if (char_length > data_len) {
char_length = data_len; char_length = data_len;
} }
/*################################################*/
/* printf("data_len %lu, n_chars %lu, char_len %lu\n",
data_len, n_chars, char_length);
if (data_len < n_chars) {
right_value = data_len;
} else {
right_value = n_chars;
}
if (right_value != char_length) {
printf("ERRRRRROOORRRRRRRRRRRR!!!!!!!!!\n");
}
*/
} else { } else {
if (data_len < prefix_len) { if (data_len < prefix_len) {
char_length = data_len; char_length = data_len;
......
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