From d39dc6a99914c3156f0a7675def62f6bd3ec1ecd Mon Sep 17 00:00:00 2001 From: "hf@deer.(none)" <> Date: Fri, 1 Oct 2004 20:49:36 +0500 Subject: [PATCH 1/9] Fix for bug #5730 (Query cache crashes mysql) here i deleted the recursion from the querycache's memory allocation --- sql/sql_cache.cc | 74 ++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 674452192f8..f69fb3085d3 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1953,55 +1953,55 @@ my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block, { ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) + ALIGN_SIZE(sizeof(Query_cache_result))); - ulong len= data_len + all_headers_len; - ulong align_len= ALIGN_SIZE(len); - DBUG_ENTER("Query_cache::allocate_data_chain"); - DBUG_PRINT("qcache", ("data_len %lu, all_headers_len %lu", - data_len, all_headers_len)); - ulong min_size = (first_block_arg ? get_min_first_result_data_size(): get_min_append_result_data_size()); - *result_block = allocate_block(max(min_size, align_len), - min_result_data_size == 0, - all_headers_len + min_result_data_size, - 1); - my_bool success = (*result_block != 0); - if (success) + Query_cache_block *prev_block= NULL; + Query_cache_block *new_block; + DBUG_ENTER("Query_cache::allocate_data_chain"); + DBUG_PRINT("qcache", ("data_len %lu, all_headers_len %lu", + data_len, all_headers_len)); + + do { - Query_cache_block *new_block= *result_block; + ulong len= data_len + all_headers_len; + ulong align_len= ALIGN_SIZE(len); + + if (!(new_block= allocate_block(max(min_size, align_len), + min_result_data_size == 0, + all_headers_len + min_result_data_size, + 1))) + { + DBUG_PRINT("warning", ("Can't allocate block for results")); + DBUG_RETURN(FALSE); + } + new_block->n_tables = 0; - new_block->used = 0; + new_block->used = min(len, new_block->length); new_block->type = Query_cache_block::RES_INCOMPLETE; new_block->next = new_block->prev = new_block; Query_cache_result *header = new_block->result(); header->parent(query_block); - if (new_block->length < len) - { - /* - We got less memory then we need (no big memory blocks) => - Continue to allocated more blocks until we got everything we need. - */ - Query_cache_block *next_block; - if ((success = allocate_data_chain(&next_block, - len - new_block->length, - query_block, first_block_arg))) - double_linked_list_join(new_block, next_block); - } - if (success) - { - new_block->used = min(len, new_block->length); - - DBUG_PRINT("qcache", ("Block len %lu used %lu", + DBUG_PRINT("qcache", ("Block len %lu used %lu", new_block->length, new_block->used)); - } + + if (prev_block) + double_linked_list_join(prev_block, new_block); else - DBUG_PRINT("warning", ("Can't allocate block for continue")); - } - else - DBUG_PRINT("warning", ("Can't allocate block for results")); - DBUG_RETURN(success); + *result_block= new_block; + if (new_block->length >= len) + break; + + /* + We got less memory then we need (no big memory blocks) => + Continue to allocated more blocks until we got everything we need. + */ + data_len= len - new_block->length; + prev_block= new_block; + } while(1); + + DBUG_RETURN(TRUE); } /***************************************************************************** From d4b3df6d310e524f804d3c5d4876c338b3a6bc2e Mon Sep 17 00:00:00 2001 From: "marko@hundin.mysql.fi" <> Date: Mon, 4 Oct 2004 20:38:23 +0300 Subject: [PATCH 2/9] InnoDB: Fix ALTER TABLE t DISCARD TABLESPACE (Bug #5851) --- innobase/include/ut0mem.h | 10 +++++++--- innobase/include/ut0mem.ic | 2 +- innobase/row/row0mysql.c | 4 ++-- innobase/ut/ut0mem.c | 8 ++++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/innobase/include/ut0mem.h b/innobase/include/ut0mem.h index 2e02b3f0b6b..73ecb25101a 100644 --- a/innobase/include/ut0mem.h +++ b/innobase/include/ut0mem.h @@ -117,7 +117,7 @@ int ut_strcmp(const void* str1, const void* str2); /************************************************************************** -Determine the length of a string when it is quoted with ut_strcpyq(). */ +Compute strlen(ut_strcpyq(str, q)). */ UNIV_INLINE ulint ut_strlenq( @@ -127,7 +127,9 @@ ut_strlenq( char q); /* in: the quote character */ /************************************************************************** -Make a quoted copy of a string. */ +Make a quoted copy of a NUL-terminated string. Leading and trailing +quotes will not be included; only embedded quotes will be escaped. +See also ut_strlenq() and ut_memcpyq(). */ char* ut_strcpyq( @@ -138,7 +140,9 @@ ut_strcpyq( const char* src); /* in: null-terminated string */ /************************************************************************** -Make a quoted copy of a fixed-length string. */ +Make a quoted copy of a fixed-length string. Leading and trailing +quotes will not be included; only embedded quotes will be escaped. +See also ut_strlenq() and ut_strcpyq(). */ char* ut_memcpyq( diff --git a/innobase/include/ut0mem.ic b/innobase/include/ut0mem.ic index 3bb30a80f22..76c721112a0 100644 --- a/innobase/include/ut0mem.ic +++ b/innobase/include/ut0mem.ic @@ -49,7 +49,7 @@ ut_strcmp(const void* str1, const void* str2) } /************************************************************************** -Determine the length of a string when it is quoted with ut_strcpyq(). */ +Compute strlen(ut_strcpyq(str, q)). */ UNIV_INLINE ulint ut_strlenq( diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 8f5d3a216bc..c796646fc37 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1988,9 +1988,9 @@ row_discard_tablespace_for_mysql( "new_id_high INT;\n" "table_name CHAR;\n" "BEGIN\n" - "table_name := "; + "table_name := '"; static const char discard_tablespace_proc2[] = - ";\n" + "';\n" "new_id_high := %lu;\n" "new_id_low := %lu;\n" "new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n" diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c index 09410e348c2..a6002d7fd83 100644 --- a/innobase/ut/ut0mem.c +++ b/innobase/ut/ut0mem.c @@ -313,7 +313,9 @@ ut_free_all_mem(void) } /************************************************************************** -Make a quoted copy of a string. */ +Make a quoted copy of a NUL-terminated string. Leading and trailing +quotes will not be included; only embedded quotes will be escaped. +See also ut_strlenq() and ut_memcpyq(). */ char* ut_strcpyq( @@ -333,7 +335,9 @@ ut_strcpyq( } /************************************************************************** -Make a quoted copy of a fixed-length string. */ +Make a quoted copy of a fixed-length string. Leading and trailing +quotes will not be included; only embedded quotes will be escaped. +See also ut_strlenq() and ut_strcpyq(). */ char* ut_memcpyq( From 3985d58ad2d0b44e47d0c476c3925c5fede6453c Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Tue, 5 Oct 2004 17:08:22 +0300 Subject: [PATCH 3/9] 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. --- innobase/include/dict0mem.h | 17 ++++++++++---- innobase/row/row0mysql.c | 13 +++++++++-- sql/ha_innodb.cc | 45 ++++++++++++++----------------------- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h index 3fc3e850987..2564fcfb97a 100644 --- a/innobase/include/dict0mem.h +++ b/innobase/include/dict0mem.h @@ -151,7 +151,12 @@ struct dict_col_struct{ 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 */ struct dict_field_struct{ @@ -160,9 +165,13 @@ struct dict_field_struct{ ulint order; /* flags for ordering this field: DICT_DESCEND, ... */ ulint prefix_len; /* 0 or the length of the column - prefix in a MySQL index of type, e.g., - INDEX (textcol(25)); must be smaller - than DICT_MAX_COL_PREFIX_LEN */ + 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 + in the UTF-8 charset, MySQL reserves + sets this to 3 * the prefix len in + UTF-8 chars */ }; /* Data structure for an index tree */ diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index c796646fc37..152bb0291c3 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1630,6 +1630,8 @@ row_create_index_for_mysql( trx->op_info = "creating index"; + trx_start_if_not_started(trx); + /* 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 safer not to allow them. */ @@ -1656,9 +1658,16 @@ row_create_index_for_mysql( goto error_handling; } } - } + + /* Check also that prefix_len < DICT_MAX_COL_PREFIX_LEN */ - trx_start_if_not_started(trx); + 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)) { diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 132bb835d82..f5da82a8a8c 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -3525,10 +3525,6 @@ create_index( prefix_len = 0; } - if (prefix_len >= DICT_MAX_COL_PREFIX_LEN) { - DBUG_RETURN(-1); - } - /* We assume all fields should be sorted in ascending order, hence the '0': */ @@ -5333,39 +5329,32 @@ innobase_get_at_most_n_mbchars( /* 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 characters than n, then we return the length to the end of the last - full character. */ + character. */ if (charset->mbmaxlen > 1) { -/* ulint right_value; */ - /* 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. + + Why does the code below work: + Suppose that we are looking for n UTF-8 characters. + + 1) If the string is long enough, then the prefix contains at + least n complete UTF-8 characters + maybe some extra + characters + an incomplete UTF-8 character. No problem in + 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); - - /*################################################*/ - /* TODO: my_charpos sometimes returns a non-sensical value - that is BIGGER than data_len: try to fix this bug partly with - these heuristics. This is NOT a complete bug fix! */ - if (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 { if (data_len < prefix_len) { char_length = data_len; From ebb425d9c9fed6cbdfde5f5f202efa7f5d2d2de3 Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Tue, 5 Oct 2004 15:18:32 +0000 Subject: [PATCH 4/9] more and better arbitration warnings for cluster config --- ndb/src/mgmsrv/ConfigInfo.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp index e8f768d1968..9629c5e8904 100644 --- a/ndb/src/mgmsrv/ConfigInfo.cpp +++ b/ndb/src/mgmsrv/ConfigInfo.cpp @@ -3501,6 +3501,8 @@ check_node_vs_replicas(Vector§ions, BaseString node_group_warning, arbitration_warning; const char *arbit_warn_fmt= "\n arbitrator with id %d and db node with id %d on same host %s"; + const char *arbit_warn_fmt2= + "\n arbitrator with id %d has no hostname specified"; ctx.m_userProperties.get("NoOfNodes", &n_nodes); for (i= 0, n= 0; n < n_nodes; i++){ @@ -3583,13 +3585,19 @@ check_node_vs_replicas(Vector§ions, arbitration_warning.appfmt(arbit_warn_fmt, i, ii, host); } } + else + { + arbitration_warning.appfmt(arbit_warn_fmt2, i); + } } } } if (db_host_count > 1 && node_group_warning.length() > 0) ndbout_c("Cluster configuration warning:\n%s",node_group_warning.c_str()); if (db_host_count > 1 && arbitration_warning.length() > 0) - ndbout_c("Cluster configuration warning:%s",arbitration_warning.c_str()); + ndbout_c("Cluster configuration warning:%s%s",arbitration_warning.c_str(), + "\n Running arbitrator on the same host as a database node may" + "\n cause complete cluster shutdown in case of host failure."); } return true; } From 5d2492c8559d6cc3c791c0bd65489c8f2300a8b8 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Tue, 5 Oct 2004 19:22:13 +0300 Subject: [PATCH 5/9] dict0mem.h: Fix typos in previous push --- innobase/include/dict0mem.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h index 2564fcfb97a..944fad1a8c8 100644 --- a/innobase/include/dict0mem.h +++ b/innobase/include/dict0mem.h @@ -152,8 +152,8 @@ struct dict_col_struct{ }; /* 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 +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. */ #define DICT_MAX_COL_PREFIX_LEN 768 @@ -169,9 +169,8 @@ struct dict_field_struct{ type, e.g., INDEX (textcol(25)); 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 */ + in the UTF-8 charset, MySQL sets this + to 3 * the prefix len in UTF-8 chars */ }; /* Data structure for an index tree */ From 3fc7640a199172446302a9550a1434f6ff8f07b0 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Tue, 5 Oct 2004 21:22:14 +0500 Subject: [PATCH 6/9] Bug #5832 SELECT doesn't return records in some cases --- mysql-test/r/bdb.result | 24 ++++++++++++++++++++++++ mysql-test/r/ctype_utf8.result | 24 ++++++++++++++++++++++++ mysql-test/t/bdb.test | 20 ++++++++++++++++++++ mysql-test/t/ctype_utf8.test | 20 ++++++++++++++++++++ sql/field.cc | 10 +++++++++- 5 files changed, 97 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result index 846adaf53ef..6da3dbb929d 100644 --- a/mysql-test/r/bdb.result +++ b/mysql-test/r/bdb.result @@ -1260,3 +1260,27 @@ a length(a) char_length(a) ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 510 255 drop table t1; SET NAMES latin1; +CREATE TABLE t1 ( +id int unsigned NOT NULL auto_increment, +list_id smallint unsigned NOT NULL, +term TEXT NOT NULL, +PRIMARY KEY(id), +INDEX(list_id, term(4)) +) ENGINE=BDB CHARSET=utf8; +INSERT INTO t1 SET list_id = 1, term = "letterc"; +INSERT INTO t1 SET list_id = 1, term = "letterb"; +INSERT INTO t1 SET list_id = 1, term = "lettera"; +INSERT INTO t1 SET list_id = 1, term = "letterd"; +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterc"); +id +1 +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterb"); +id +2 +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "lettera"); +id +3 +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterd"); +id +4 +DROP TABLE t1; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 0c9ea42a0f1..0b98d9432ae 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -726,3 +726,27 @@ length(subject) 3 432 DROP TABLE t1; +CREATE TABLE t1 ( +id int unsigned NOT NULL auto_increment, +list_id smallint unsigned NOT NULL, +term TEXT NOT NULL, +PRIMARY KEY(id), +INDEX(list_id, term(4)) +) ENGINE=MYISAM CHARSET=utf8; +INSERT INTO t1 SET list_id = 1, term = "letterc"; +INSERT INTO t1 SET list_id = 1, term = "letterb"; +INSERT INTO t1 SET list_id = 1, term = "lettera"; +INSERT INTO t1 SET list_id = 1, term = "letterd"; +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterc"); +id +1 +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterb"); +id +2 +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "lettera"); +id +3 +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterd"); +id +4 +DROP TABLE t1; diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test index 86214ecd5a8..069ec758ba2 100644 --- a/mysql-test/t/bdb.test +++ b/mysql-test/t/bdb.test @@ -909,3 +909,23 @@ insert into t1 values (@a); select a, length(a), char_length(a) from t1; drop table t1; SET NAMES latin1; + +# +# Bug #5832 SELECT doesn't return records in some cases +# +CREATE TABLE t1 ( + id int unsigned NOT NULL auto_increment, + list_id smallint unsigned NOT NULL, + term TEXT NOT NULL, + PRIMARY KEY(id), + INDEX(list_id, term(4)) +) ENGINE=BDB CHARSET=utf8; +INSERT INTO t1 SET list_id = 1, term = "letterc"; +INSERT INTO t1 SET list_id = 1, term = "letterb"; +INSERT INTO t1 SET list_id = 1, term = "lettera"; +INSERT INTO t1 SET list_id = 1, term = "letterd"; +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterc"); +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterb"); +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "lettera"); +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterd"); +DROP TABLE t1; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 40709443d62..4a8eb63ed36 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -572,3 +572,23 @@ INSERT INTO t1 VALUES ('aaa','bbb'); SELECT length(subject) FROM t1; SELECT length(subject) FROM t1 ORDER BY 1; DROP TABLE t1; + +# +# Bug #5832 SELECT doesn't return records in some cases +# +CREATE TABLE t1 ( + id int unsigned NOT NULL auto_increment, + list_id smallint unsigned NOT NULL, + term TEXT NOT NULL, + PRIMARY KEY(id), + INDEX(list_id, term(4)) +) ENGINE=MYISAM CHARSET=utf8; +INSERT INTO t1 SET list_id = 1, term = "letterc"; +INSERT INTO t1 SET list_id = 1, term = "letterb"; +INSERT INTO t1 SET list_id = 1, term = "lettera"; +INSERT INTO t1 SET list_id = 1, term = "letterd"; +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterc"); +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterb"); +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "lettera"); +SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterd"); +DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index eaa1ca2bcca..8c75bd2d4b5 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5077,6 +5077,11 @@ void Field_blob::get_key_image(char *buff,uint length, } #endif /*HAVE_SPATIAL*/ + get_ptr(&blob); + uint char_length= length / cs->mbmaxlen; + char_length= my_charpos(cs, blob, blob + length, char_length); + set_if_smaller(length, char_length); + if ((uint32) length > blob_length) { /* @@ -5087,7 +5092,6 @@ void Field_blob::get_key_image(char *buff,uint length, length=(uint) blob_length; } int2store(buff,length); - get_ptr(&blob); memcpy(buff+HA_KEY_BLOB_LENGTH, blob, length); } @@ -5103,6 +5107,10 @@ int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length) char *blob1; uint blob_length=get_length(ptr); memcpy_fixed(&blob1,ptr+packlength,sizeof(char*)); + CHARSET_INFO *cs= charset(); + uint char_length= max_key_length / cs->mbmaxlen; + char_length= my_charpos(cs, blob1, blob1+blob_length, char_length); + set_if_smaller(blob_length, char_length); return Field_blob::cmp(blob1,min(blob_length, max_key_length), (char*) key_ptr+HA_KEY_BLOB_LENGTH, uint2korr(key_ptr)); From eabec4c3ca1522e16bf0c3a49da0499c8d22cd31 Mon Sep 17 00:00:00 2001 From: "dlenev@brandersnatch.localdomain" <> Date: Tue, 5 Oct 2004 21:23:38 +0400 Subject: [PATCH 7/9] Fixed small bug in handling of pre-4.1 TIMESTAMP columns which was introduced during implementation of TIMESTAMP columns, which are able to store NULLs (Unfortunately it is impossible to write test case for this. Kudos to Holyfoot for noticing it!) --- sql/field.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sql/field.cc b/sql/field.cc index eaa1ca2bcca..b394a155ddb 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2970,6 +2970,14 @@ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const return TIMESTAMP_AUTO_SET_ON_INSERT; case TIMESTAMP_UN_FIELD: return TIMESTAMP_AUTO_SET_ON_UPDATE; + case TIMESTAMP_OLD_FIELD: + /* + Altough we can have several such columns in legacy tables this + function should be called only for first of them (i.e. the one + having auto-set property). + */ + DBUG_ASSERT(table->timestamp_field == this); + /* Fall-through */ case TIMESTAMP_DNUN_FIELD: return TIMESTAMP_AUTO_SET_ON_BOTH; default: From 884892a650992514c40dd652a4a8cf89e4f3a6f7 Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 6 Oct 2004 13:18:55 +0000 Subject: [PATCH 8/9] bug#5736, subqueries and not in and testcases --- mysql-test/r/ndb_subquery.result | 42 +++++++++++++++++++++++ mysql-test/t/ndb_subquery.test | 38 +++++++++++++++++++++ ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 25 +++++++++++--- sql/ha_ndbcluster.cc | 44 ++++++++++++++++++++++--- 4 files changed, 141 insertions(+), 8 deletions(-) create mode 100644 mysql-test/r/ndb_subquery.result create mode 100644 mysql-test/t/ndb_subquery.test diff --git a/mysql-test/r/ndb_subquery.result b/mysql-test/r/ndb_subquery.result new file mode 100644 index 00000000000..8c89805a765 --- /dev/null +++ b/mysql-test/r/ndb_subquery.result @@ -0,0 +1,42 @@ +drop table if exists t1; +drop table if exists t2; +create table t1 (p int not null primary key, u int not null, o int not null, +unique (u), key(o)) engine=ndb; +create table t2 (p int not null primary key, u int not null, o int not null, +unique (u), key(o)) engine=ndb; +insert into t1 values (1,1,1),(2,2,2),(3,3,3); +insert into t2 values (1,1,1),(2,2,2),(3,3,3), (4,4,4), (5,5,5); +explain select * from t2 where p NOT IN (select p from t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 Using index +select * from t2 where p NOT IN (select p from t1); +p u o +4 4 4 +5 5 5 +explain select * from t2 where p NOT IN (select u from t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where +2 DEPENDENT SUBQUERY t1 unique_subquery u u 4 func 1 Using index +select * from t2 where p NOT IN (select u from t1); +p u o +4 4 4 +5 5 5 +explain select * from t2 where p NOT IN (select o from t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where +2 DEPENDENT SUBQUERY t1 index_subquery o o 4 func 1 Using index +select * from t2 where p NOT IN (select o from t1); +p u o +4 4 4 +5 5 5 +explain select * from t2 where p NOT IN (select p+0 from t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where +select * from t2 where p NOT IN (select p+0 from t1); +p u o +4 4 4 +5 5 5 +drop table t1; +drop table t2; diff --git a/mysql-test/t/ndb_subquery.test b/mysql-test/t/ndb_subquery.test new file mode 100644 index 00000000000..e80d9b16b46 --- /dev/null +++ b/mysql-test/t/ndb_subquery.test @@ -0,0 +1,38 @@ +-- source include/have_ndb.inc + +--disable_warnings +drop table if exists t1; +drop table if exists t2; +--enable_warnings + +########## +# bug#5367 +create table t1 (p int not null primary key, u int not null, o int not null, +unique (u), key(o)) engine=ndb; + +create table t2 (p int not null primary key, u int not null, o int not null, +unique (u), key(o)) engine=ndb; + +insert into t1 values (1,1,1),(2,2,2),(3,3,3); +insert into t2 values (1,1,1),(2,2,2),(3,3,3), (4,4,4), (5,5,5); + +# Use pk +explain select * from t2 where p NOT IN (select p from t1); +select * from t2 where p NOT IN (select p from t1); + +# Use unique index +explain select * from t2 where p NOT IN (select u from t1); +select * from t2 where p NOT IN (select u from t1); + +# Use ordered index +explain select * from t2 where p NOT IN (select o from t1); +select * from t2 where p NOT IN (select o from t1); + +# Use scan +explain select * from t2 where p NOT IN (select p+0 from t1); +select * from t2 where p NOT IN (select p+0 from t1); + +drop table t1; +drop table t2; +# bug#5367 +########## diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 5b5578cb579..765d77d5dd6 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -1249,7 +1249,8 @@ void Dbtc::execTCRELEASEREQ(Signal* signal) jam(); signal->theData[0] = tuserpointer; signal->theData[1] = ZINVALID_CONNECTION; - sendSignal(tapiBlockref, GSN_TCRELEASEREF, signal, 2, JBB); + signal->theData[2] = __LINE__; + sendSignal(tapiBlockref, GSN_TCRELEASEREF, signal, 3, JBB); return; } else { jam(); @@ -1262,7 +1263,9 @@ void Dbtc::execTCRELEASEREQ(Signal* signal) sendSignal(tapiBlockref, GSN_TCRELEASECONF, signal, 1, JBB); } else { if (tapiBlockref == apiConnectptr.p->ndbapiBlockref) { - if (apiConnectptr.p->apiConnectstate == CS_CONNECTED) { + if (apiConnectptr.p->apiConnectstate == CS_CONNECTED || + (apiConnectptr.p->apiConnectstate == CS_ABORTING && + apiConnectptr.p->abortState == AS_IDLE)){ jam(); /* JUST REPLY OK */ releaseApiCon(signal, apiConnectptr.i); signal->theData[0] = tuserpointer; @@ -1272,14 +1275,19 @@ void Dbtc::execTCRELEASEREQ(Signal* signal) jam(); signal->theData[0] = tuserpointer; signal->theData[1] = ZINVALID_CONNECTION; + signal->theData[2] = __LINE__; + signal->theData[3] = apiConnectptr.p->apiConnectstate; sendSignal(tapiBlockref, - GSN_TCRELEASEREF, signal, 2, JBB); + GSN_TCRELEASEREF, signal, 4, JBB); } } else { jam(); signal->theData[0] = tuserpointer; signal->theData[1] = ZINVALID_CONNECTION; - sendSignal(tapiBlockref, GSN_TCRELEASEREF, signal, 2, JBB); + signal->theData[2] = __LINE__; + signal->theData[3] = tapiBlockref; + signal->theData[4] = apiConnectptr.p->ndbapiBlockref; + sendSignal(tapiBlockref, GSN_TCRELEASEREF, signal, 5, JBB); }//if }//if }//Dbtc::execTCRELEASEREQ() @@ -6037,6 +6045,7 @@ void Dbtc::timeOutFoundLab(Signal* signal, Uint32 TapiConPtr) << " - place: " << c_apiConTimer_line[apiConnectptr.i]); switch (apiConnectptr.p->apiConnectstate) { case CS_STARTED: + ndbrequire(c_apiConTimer_line[apiConnectptr.i] != 3615); if(apiConnectptr.p->lqhkeyreqrec == apiConnectptr.p->lqhkeyconfrec){ jam(); /* @@ -11359,6 +11368,7 @@ void Dbtc::execTCKEYCONF(Signal* signal) Uint32 Ttcindxrec = regApiPtr->tcindxrec; // Copy reply from TcKeyConf + ndbassert(regApiPtr->noIndexOp); regApiPtr->noIndexOp--; // Decrease count regApiPtr->tcIndxSendArray[Ttcindxrec] = indexOp->tcIndxReq.senderData; regApiPtr->tcIndxSendArray[Ttcindxrec + 1] = @@ -11417,6 +11427,12 @@ void Dbtc::execTCKEYREF(Signal* signal) abortErrorLab(signal); break; } + /** + * Increase count as it will be decreased below... + * (and the code is written to handle failing lookup on "real" table + * not lookup on index table) + */ + regApiPtr->noIndexOp++; // else continue } case(IOS_INDEX_OPERATION): { @@ -11426,6 +11442,7 @@ void Dbtc::execTCKEYREF(Signal* signal) TcIndxReq * const tcIndxReq = &indexOp->tcIndxReq; TcIndxRef * const tcIndxRef = (TcIndxRef *)signal->getDataPtrSend(); + ndbassert(regApiPtr->noIndexOp); regApiPtr->noIndexOp--; // Decrease count tcIndxRef->connectPtr = tcIndxReq->senderData; tcIndxRef->transId[0] = tcKeyRef->transId[0]; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 57232778d48..8faa0b33756 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2135,11 +2135,47 @@ int ha_ndbcluster::index_read(byte *buf, DBUG_PRINT("enter", ("active_index: %u, key_len: %u, find_flag: %d", active_index, key_len, find_flag)); + int error; + ndb_index_type type = get_index_type(active_index); + const KEY* key_info = table->key_info+active_index; + switch (type){ + case PRIMARY_KEY_ORDERED_INDEX: + case PRIMARY_KEY_INDEX: + if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len) + { + DBUG_RETURN(pk_read(key, key_len, buf)); + } + else if (type == PRIMARY_KEY_INDEX) + { + DBUG_RETURN(1); + } + break; + case UNIQUE_ORDERED_INDEX: + case UNIQUE_INDEX: + if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len) + { + DBUG_RETURN(unique_index_read(key, key_len, buf)); + } + else if (type == UNIQUE_INDEX) + { + DBUG_RETURN(1); + } + break; + case ORDERED_INDEX: + break; + default: + case UNDEFINED_INDEX: + DBUG_ASSERT(false); + return 1; + break; + } + key_range start_key; - start_key.key= key; - start_key.length= key_len; - start_key.flag= find_flag; - DBUG_RETURN(read_range_first_to_buf(&start_key, NULL, false, true, buf)); + start_key.key = key; + start_key.length = key_len; + start_key.flag = find_flag; + error= ordered_index_scan(&start_key, 0, true, buf); + DBUG_RETURN(error == HA_ERR_END_OF_FILE ? HA_ERR_KEY_NOT_FOUND : error); } From 66923bf9685734ebec22af1a2a9a63e68ccdc24b Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 6 Oct 2004 13:26:38 +0000 Subject: [PATCH 9/9] forgot to remove ndbrequire --- ndb/src/kernel/blocks/dbtc/DbtcMain.cpp | 1 - ndb/test/run-test/atrt-mysql-test-run | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 765d77d5dd6..d270c6acc61 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -6045,7 +6045,6 @@ void Dbtc::timeOutFoundLab(Signal* signal, Uint32 TapiConPtr) << " - place: " << c_apiConTimer_line[apiConnectptr.i]); switch (apiConnectptr.p->apiConnectstate) { case CS_STARTED: - ndbrequire(c_apiConTimer_line[apiConnectptr.i] != 3615); if(apiConnectptr.p->lqhkeyreqrec == apiConnectptr.p->lqhkeyconfrec){ jam(); /* diff --git a/ndb/test/run-test/atrt-mysql-test-run b/ndb/test/run-test/atrt-mysql-test-run index 7657140d0fa..dd7b709bd06 100755 --- a/ndb/test/run-test/atrt-mysql-test-run +++ b/ndb/test/run-test/atrt-mysql-test-run @@ -3,7 +3,7 @@ set -x p=`pwd` cd $MYSQL_BASE_DIR/mysql-test -./mysql-test-run --with-ndbcluster --ndbconnectstring=$NDB_CONNECTSTRING $* | tee $p/output.txt +./mysql-test-run --with-ndbcluster --ndb-connectstring=$NDB_CONNECTSTRING $* | tee $p/output.txt f=`grep -c fail $p/output.txt` o=`grep -c pass $p/output.txt`