From 32d280ba3202c416ecf3ad15f5d2a6316c7dd128 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 24 Apr 2007 18:42:46 +0500 Subject: [PATCH 1/6] bug #27405 (Partitioning InnoDB auto_increment bug) InnoDB engine changes internal auto_increment counter only after ha_innodb::write_row, so two threads can't simultaneously operate between ha_innodb::update_autoincrement and ha_innodb::write_row. So concurrent execution of ha_partition::write_row prevented sql/ha_partition.cc: use table_share->mutex to avoid concurrent write_row for AUTO_INCREMENTed table --- sql/ha_partition.cc | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 3c25dcd202f..5247e665b0f 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2647,6 +2647,7 @@ int ha_partition::write_row(byte * buf) uint32 part_id; int error; longlong func_value; + bool autoincrement_lock= false; #ifdef NOT_NEEDED byte *rec0= m_rec0; #endif @@ -2662,7 +2663,21 @@ int ha_partition::write_row(byte * buf) or a new row, then update the auto_increment value in the record. */ if (table->next_number_field && buf == table->record[0]) + { + /* + Some engines (InnoDB for example) can change autoincrement + counter only after 'table->write_row' operation. + So if another thread gets inside the ha_partition::write_row + before it is complete, it gets same auto_increment value, + which means DUP_KEY error (bug #27405) + Here we separate the access using table_share->mutex, and + use autoincrement_lock variable to avoid unnecessary locks. + Probably not an ideal solution. + */ + autoincrement_lock= true; + pthread_mutex_lock(&table_share->mutex); update_auto_increment(); + } my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); #ifdef NOT_NEEDED @@ -2683,11 +2698,15 @@ int ha_partition::write_row(byte * buf) if (unlikely(error)) { m_part_info->err_value= func_value; - DBUG_RETURN(error); + goto exit; } m_last_part= part_id; DBUG_PRINT("info", ("Insert in partition %d", part_id)); - DBUG_RETURN(m_file[part_id]->write_row(buf)); + error= m_file[part_id]->write_row(buf); +exit: + if (autoincrement_lock) + pthread_mutex_unlock(&table_share->mutex); + DBUG_RETURN(error); } From e34aa82da9eca8b219a88bc255938f2c7094567a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 14 Aug 2007 17:28:51 +0400 Subject: [PATCH 2/6] Bug#29948: Unchecked NULL pointer caused server crash. The cli_read_binary_rows function is used to fetch data from the server after a prepared statement execution. It accepts a statement handler and gets the connection handler from it. But when the auto-reconnect option is set the connection handler is reset to NULL after reconnection because the prepared statement is lost and the handler became useless. This case wasn't checked in the cli_read_binary_rows function and caused server crash. Now the cli_read_binary_rows function checks the connection handler to be not NULL and returns an error if it is. tests/mysql_client_test.c: Added a test case for the bug#29948: Unchecked NULL pointer caused server crash. libmysql/libmysql.c: Bug#29948: Unchecked NULL pointer caused server crash. Now the cli_read_binary_rows function checks the connection handler to be not NULL and returns an error if it is. --- libmysql/libmysql.c | 10 +++++- tests/mysql_client_test.c | 75 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 1a0aae414ed..85c56a7ea40 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -4679,9 +4679,17 @@ int cli_read_binary_rows(MYSQL_STMT *stmt) MYSQL *mysql= stmt->mysql; MYSQL_DATA *result= &stmt->result; MYSQL_ROWS *cur, **prev_ptr= &result->data; - NET *net = &mysql->net; + NET *net; + + if (!mysql) + { + set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate); + return 1; + } + DBUG_ENTER("cli_read_binary_rows"); + net = &mysql->net; mysql= mysql->last_used_con; while ((pkt_len= cli_safe_read(mysql)) != packet_error) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 75c86902972..ca76270d8b8 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -15735,6 +15735,80 @@ static void test_bug27592() } +static void test_bug29948() +{ + MYSQL *dbc=NULL; + MYSQL_STMT *stmt=NULL; + MYSQL_BIND bind; + + int res=0; + my_bool auto_reconnect=1, error=0, is_null=0; + char kill_buf[20]; + const char *query; + int buf; + unsigned long length; + + dbc = mysql_init(NULL); + DIE_UNLESS(dbc); + + mysql_options(dbc, MYSQL_OPT_RECONNECT, (char*)&auto_reconnect); + if (!mysql_real_connect(dbc, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, + (CLIENT_FOUND_ROWS | CLIENT_MULTI_STATEMENTS | + CLIENT_MULTI_RESULTS))) + { + printf("connection failed: %s (%d)", mysql_error(dbc), + mysql_errno(dbc)); + exit(1); + } + + bind.buffer_type= MYSQL_TYPE_LONG; + bind.buffer= (char *)&buf; + bind.is_null= &is_null; + bind.error= &error; + bind.length= &length; + + res= mysql_query(dbc, "DROP TABLE IF EXISTS t1"); + myquery(res); + res= mysql_query(dbc, "CREATE TABLE t1 (a INT)"); + myquery(res); + res= mysql_query(dbc, "INSERT INTO t1 VALUES(1)"); + myquery(res); + + stmt= mysql_stmt_init(dbc); + check_stmt(stmt); + + buf= CURSOR_TYPE_READ_ONLY; + res= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void *)&buf); + myquery(res); + + query= "SELECT * from t1 where a=?"; + res= mysql_stmt_prepare(stmt, query, strlen(query)); + myquery(res); + + res= mysql_stmt_bind_param(stmt, &bind); + myquery(res); + + res= mysql_stmt_execute(stmt); + check_execute(stmt, res); + + res= mysql_stmt_bind_result(stmt,&bind); + check_execute(stmt, res); + + sprintf(kill_buf, "kill %ld", dbc->thread_id); + mysql_query(dbc, kill_buf); + + res= mysql_stmt_store_result(stmt); + DIE_UNLESS(res); + + mysql_stmt_free_result(stmt); + mysql_stmt_close(stmt); + mysql_query(dbc, "DROP TABLE t1"); + mysql_close(dbc); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -16019,6 +16093,7 @@ static struct my_tests_st my_tests[]= { { "test_bug28505", test_bug28505 }, { "test_bug28934", test_bug28934 }, { "test_bug27592", test_bug27592 }, + { "test_bug29948", test_bug29948 }, { 0, 0 } }; From 01f8130aa68392d14f36cc17c01e1b349bf844f5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Aug 2007 09:23:44 +0200 Subject: [PATCH 3/6] bug#28570: handler::index_read() is called with different find_flag when ORDER BY is used The range analysis module did not correctly signal to the handler that a range represents a ref (EQ_RANGE flag). This causes non-range queries like SELECT ... FROM ... WHERE keypart_1=const, ..., keypart_n=const ORDER BY ... FOR UPDATE to wait for a lock unneccesarily if another running transaction uses SELECT ... FOR UPDATE on the same table. Fixed by setting EQ_RANGE for all range accesses that represent an equality predicate. mysql-test/r/innodb_mysql.result: bug#28570: Test Result mysql-test/t/innodb_mysql.test: bug#28570: Test Case sql/handler.cc: bug#28570: Updated comment sql/opt_range.cc: bug#28570: Removed the criterion that key has to be unique (HA_NOSAME) in order for the EQ_RANGE flag to be set. It is sufficient that the range represent a ref access. --- mysql-test/r/innodb_mysql.result | 18 ++++++++++++++++++ mysql-test/t/innodb_mysql.test | 29 +++++++++++++++++++++++++++++ sql/handler.cc | 3 ++- sql/opt_range.cc | 3 +-- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 5b3ca972467..0bb93318557 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1007,4 +1007,22 @@ CALL p1(); CALL p1(); DROP PROCEDURE p1; DROP TABLE t1; +CREATE TABLE t1 ( +a INT, +b INT, +KEY (b) +) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,10), (2,10), (2,20), (3,30); +START TRANSACTION; +SELECT * FROM t1 WHERE b=20 FOR UPDATE; +a b +2 20 +START TRANSACTION; +SELECT * FROM t1 WHERE b=10 ORDER BY A FOR UPDATE; +a b +1 10 +2 10 +ROLLBACK; +ROLLBACK; +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index 63431e10bbf..e27db9944fe 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -840,5 +840,34 @@ DISCONNECT con2; DROP PROCEDURE p1; DROP TABLE t1; +# +# Bug #28570: handler::index_read() is called with different find_flag when +# ORDER BY is used +# + +CREATE TABLE t1 ( + a INT, + b INT, + KEY (b) +) ENGINE=InnoDB; + +INSERT INTO t1 VALUES (1,10), (2,10), (2,20), (3,30); + +START TRANSACTION; +SELECT * FROM t1 WHERE b=20 FOR UPDATE; + +--connect (conn2, localhost, root,,test) + +# This statement gives a "failed: 1205: Lock wait timeout exceeded; try +# restarting transaction" message when the bug is present. +START TRANSACTION; +SELECT * FROM t1 WHERE b=10 ORDER BY A FOR UPDATE; +ROLLBACK; + +--disconnect conn2 +--connection default + +ROLLBACK; +DROP TABLE t1; --echo End of 5.0 tests diff --git a/sql/handler.cc b/sql/handler.cc index 8ef14ce8906..bfb7e8c369f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2610,7 +2610,8 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) read_range_first() start_key Start key. Is 0 if no min range end_key End key. Is 0 if no max range - eq_range_arg Set to 1 if start_key == end_key + eq_range_arg Set to 1 if start_key == end_key and the range endpoints + will not change during query execution. sorted Set to 1 if result should be sorted per key NOTES diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 247f0eada49..39f0321955d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -6369,8 +6369,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, range->min_key=range->max_key=(char*) ref->key_buff; range->min_length=range->max_length=ref->key_length; range->flag= ((ref->key_length == key_info->key_length && - (key_info->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == - HA_NOSAME) ? EQ_RANGE : 0); + (key_info->flags & HA_END_SPACE_KEY) == 0) ? EQ_RANGE : 0); if (!(quick->key_parts=key_part=(KEY_PART *) alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts))) From bbf2211bdcd43581b9ddf54f1bfc731384e289c7 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Aug 2007 18:21:58 +0400 Subject: [PATCH 4/6] mysql_client_test.c: Post fix for the bug#29948. tests/mysql_client_test.c: Post fix for the bug#29948. --- tests/mysql_client_test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index dd6b0b5585f..c335b0128f7 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -15746,7 +15746,7 @@ static void test_bug29948() char kill_buf[20]; const char *query; int buf; - unsigned long length; + unsigned long length, cursor_type; dbc = mysql_init(NULL); DIE_UNLESS(dbc); @@ -15779,8 +15779,8 @@ static void test_bug29948() stmt= mysql_stmt_init(dbc); check_stmt(stmt); - buf= CURSOR_TYPE_READ_ONLY; - res= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void *)&buf); + cursor_type= CURSOR_TYPE_READ_ONLY; + res= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void *)&cursor_type); myquery(res); query= "SELECT * from t1 where a=?"; From a8f8e5483e7925ce804c3900752f88fdf43cb3ee Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 15 Aug 2007 10:24:18 -0700 Subject: [PATCH 5/6] Fixed bug #30396. The bug caused memory corruption for some queries with top OR level in the WHERE condition if they contained equality predicates and other sargable predicates in disjunctive parts of the condition. The corruption happened because the upper bound of the memory allocated for KEY_FIELD and SARGABLE_PARAM internal structures containing info about potential lookup keys was calculated incorrectly in some cases. In particular it was calculated incorrectly when the WHERE condition was an OR formula with disjuncts being AND formulas including equalities and other sargable predicates. mysql-test/r/select.result: Added a test case for bug #30396. mysql-test/t/select.test: Added a test case for bug #30396. sql/item_cmpfunc.h: Removed max_members from the COND_EQUAL class as not useful anymore. sql/sql_base.cc: Added the max_equal_elems field to the st_select_lex structure. sql/sql_lex.cc: Added the max_equal_elems field to the st_select_lex structure. sql/sql_lex.h: Added the max_equal_elems field to the st_select_lex structure. The field contains the maximal number of elements in multiple equalities built for the query conditions. sql/sql_select.cc: Fixed bug #30396. The bug caused memory corruption for some queries with top OR level in the WHERE condition if they contained equality predicates and other sargable predicates in disjunctive parts of the condition. The corruption happened because the upper bound of the memory allocated for KEY_FIELD and SARGABLE_PARAM internal structures containing info about potential lookup keys was calculated incorrectly in some cases. In particular it was calculated incorrectly when the WHERE condition was an OR formula with disjuncts being AND formulas including equalities and other sargable predicates. The max_equal_elems field to the st_select_lex structure is used now to calculate the above mentioned upper bound. The field contains the maximal number of elements in multiple equalities built for the query conditions. --- mysql-test/r/select.result | 57 ++++++++++++++++++++++++++++++++++++ mysql-test/t/select.test | 60 ++++++++++++++++++++++++++++++++++++++ sql/item_cmpfunc.h | 1 - sql/sql_base.cc | 1 + sql/sql_lex.cc | 1 + sql/sql_lex.h | 3 +- sql/sql_select.cc | 38 ++++++++---------------- 7 files changed, 133 insertions(+), 28 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 5930c36029f..2cf1316bb47 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4005,4 +4005,61 @@ id select_type table type possible_keys key key_len ref rows Extra EXPLAIN SELECT c1 FROM t1 WHERE (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT (SELECT COUNT(c2))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) > 0; ERROR HY000: Too high level of nesting for select DROP TABLE t1; +CREATE TABLE t1 ( +c1 int(11) NOT NULL AUTO_INCREMENT, +c2 varchar(1000) DEFAULT NULL, +c3 bigint(20) DEFAULT NULL, +c4 bigint(20) DEFAULT NULL, +PRIMARY KEY (c1) +); +EXPLAIN EXTENDED +SELECT join_2.c1 +FROM +t1 AS join_0, +t1 AS join_1, +t1 AS join_2, +t1 AS join_3, +t1 AS join_4, +t1 AS join_5, +t1 AS join_6, +t1 AS join_7 +WHERE +join_0.c1=join_1.c1 AND +join_1.c1=join_2.c1 AND +join_2.c1=join_3.c1 AND +join_3.c1=join_4.c1 AND +join_4.c1=join_5.c1 AND +join_5.c1=join_6.c1 AND +join_6.c1=join_7.c1 +OR +join_0.c2 < '?' AND +join_1.c2 < '?' AND +join_2.c2 > '?' AND +join_2.c2 < '!' AND +join_3.c2 > '?' AND +join_4.c2 = '?' AND +join_5.c2 <> '?' AND +join_6.c2 <> '?' AND +join_7.c2 >= '?' AND +join_0.c1=join_1.c1 AND +join_1.c1=join_2.c1 AND +join_2.c1=join_3.c1 AND +join_3.c1=join_4.c1 AND +join_4.c1=join_5.c1 AND +join_5.c1=join_6.c1 AND +join_6.c1=join_7.c1 +GROUP BY +join_3.c1, +join_2.c1, +join_7.c1, +join_1.c1, +join_0.c1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select '0' AS `c1` from `test`.`t1` `join_0` join `test`.`t1` `join_1` join `test`.`t1` `join_2` join `test`.`t1` `join_3` join `test`.`t1` `join_4` join `test`.`t1` `join_5` join `test`.`t1` `join_6` join `test`.`t1` `join_7` where 0 group by '0','0','0','0','0' +SHOW WARNINGS; +Level Code Message +Note 1003 select '0' AS `c1` from `test`.`t1` `join_0` join `test`.`t1` `join_1` join `test`.`t1` `join_2` join `test`.`t1` `join_3` join `test`.`t1` `join_4` join `test`.`t1` `join_5` join `test`.`t1` `join_6` join `test`.`t1` `join_7` where 0 group by '0','0','0','0','0' +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 8bfa12539fa..abf55745080 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3400,4 +3400,64 @@ eval EXPLAIN SELECT c1 FROM t1 WHERE $q > 0; DROP TABLE t1; +# +# Bug #30396: crash for a join with equalities and sargable predicates +# in disjunctive parts of the WHERE condition +# + +CREATE TABLE t1 ( + c1 int(11) NOT NULL AUTO_INCREMENT, + c2 varchar(1000) DEFAULT NULL, + c3 bigint(20) DEFAULT NULL, + c4 bigint(20) DEFAULT NULL, + PRIMARY KEY (c1) +); + +EXPLAIN EXTENDED +SELECT join_2.c1 +FROM + t1 AS join_0, + t1 AS join_1, + t1 AS join_2, + t1 AS join_3, + t1 AS join_4, + t1 AS join_5, + t1 AS join_6, + t1 AS join_7 +WHERE + join_0.c1=join_1.c1 AND + join_1.c1=join_2.c1 AND + join_2.c1=join_3.c1 AND + join_3.c1=join_4.c1 AND + join_4.c1=join_5.c1 AND + join_5.c1=join_6.c1 AND + join_6.c1=join_7.c1 + OR + join_0.c2 < '?' AND + join_1.c2 < '?' AND + join_2.c2 > '?' AND + join_2.c2 < '!' AND + join_3.c2 > '?' AND + join_4.c2 = '?' AND + join_5.c2 <> '?' AND + join_6.c2 <> '?' AND + join_7.c2 >= '?' AND + join_0.c1=join_1.c1 AND + join_1.c1=join_2.c1 AND + join_2.c1=join_3.c1 AND + join_3.c1=join_4.c1 AND + join_4.c1=join_5.c1 AND + join_5.c1=join_6.c1 AND + join_6.c1=join_7.c1 +GROUP BY + join_3.c1, + join_2.c1, + join_7.c1, + join_1.c1, + join_0.c1; + +SHOW WARNINGS; + +DROP TABLE t1; + --echo End of 5.0 tests diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 9afc0507817..7b6eaef08ec 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1506,7 +1506,6 @@ public: the current and level */ COND_EQUAL() { - max_members= 0; upper_levels= 0; } }; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1c01248c283..e8562cdffbd 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5611,6 +5611,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, thd->set_query_id=1; select_lex->cond_count= 0; select_lex->between_count= 0; + select_lex->max_equal_elems= 0; for (table= tables; table; table= table->next_local) { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 7911da69862..d11c2b21635 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1183,6 +1183,7 @@ void st_select_lex::init_query() */ parent_lex->push_context(&context); cond_count= between_count= with_wild= 0; + max_equal_elems= 0; conds_processed_with_permanent_arena= 0; ref_pointer_array= 0; select_n_where_fields= 0; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index b9c6abd2b06..94015a9fe07 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -533,7 +533,8 @@ public: */ uint select_n_having_items; uint cond_count; /* number of arguments of and/or/xor in where/having/on */ - uint between_count; /* number of between predicates in where/having/on */ + uint between_count; /* number of between predicates in where/having/on */ + uint max_equal_elems; /* maximal number of elements in multiple equalities */ /* Number of fields used in select list or where clause of current select and all inner subselects. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ac8dc84f118..b7846a7433d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3524,10 +3524,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, uint and_level,i,found_eq_constant; KEY_FIELD *key_fields, *end, *field; uint sz; - uint m= 1; - - if (cond_equal && cond_equal->max_members) - m= cond_equal->max_members; + uint m= max(select_lex->max_equal_elems,1); /* We use the same piece of memory to store both KEY_FIELD @@ -3547,7 +3544,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, it is considered as sargable only for its first argument. Multiple equality can add elements that are filled after substitution of field arguments by equal fields. There - can be not more than cond_equal->max_members such substitutions. + can be not more than select_lex->max_equal_elems such + substitutions. */ sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))* (((thd->lex->current_select->cond_count+1)*2 + @@ -7189,8 +7187,7 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal, just an argument of a comparison predicate. The function also determines the maximum number of members in equality lists of each Item_cond_and object assigning it to - cond_equal->max_members of this object and updating accordingly - the upper levels COND_EQUAL structures. + thd->lex->current_select->max_equal_elems. NOTES Multiple equality predicate =(f1,..fn) is equivalent to the conjuction of @@ -7235,7 +7232,6 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, COND_EQUAL *inherited) { Item_equal *item_equal; - uint members; COND_EQUAL cond_equal; cond_equal.upper_levels= inherited; @@ -7273,19 +7269,8 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, { item_equal->fix_length_and_dec(); item_equal->update_used_tables(); - members= item_equal->members(); - if (cond_equal.max_members < members) - cond_equal.max_members= members; - } - members= cond_equal.max_members; - if (inherited && inherited->max_members < members) - { - do - { - inherited->max_members= members; - inherited= inherited->upper_levels; - } - while (inherited); + set_if_bigger(thd->lex->current_select->max_equal_elems, + item_equal->members()); } ((Item_cond_and*)cond)->cond_equal= cond_equal; @@ -7340,10 +7325,12 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, { item_equal->fix_length_and_dec(); item_equal->update_used_tables(); - return item_equal; } else - return eq_list.pop(); + item_equal= (Item_equal *) eq_list.pop(); + set_if_bigger(thd->lex->current_select->max_equal_elems, + item_equal->members()); + return item_equal; } else { @@ -7359,9 +7346,8 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, { item_equal->fix_length_and_dec(); item_equal->update_used_tables(); - members= item_equal->members(); - if (cond_equal.max_members < members) - cond_equal.max_members= members; + set_if_bigger(thd->lex->current_select->max_equal_elems, + item_equal->members()); } and_cond->cond_equal= cond_equal; args->concat((List *)&cond_equal.current_level); From 0d9046ecaf3107371e0b2a59792104385da74349 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 16 Aug 2007 19:27:44 -0700 Subject: [PATCH 6/6] Post-merge fix. --- mysql-test/r/select.result | 4 +-- tests/mysql_client_test.c | 73 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index f1bfbec1555..48e8bf933e1 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4039,8 +4039,8 @@ join_2.c1, join_7.c1, join_1.c1, join_0.c1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables Warnings: Note 1003 select '0' AS `c1` from `test`.`t1` `join_0` join `test`.`t1` `join_1` join `test`.`t1` `join_2` join `test`.`t1` `join_3` join `test`.`t1` `join_4` join `test`.`t1` `join_5` join `test`.`t1` `join_6` join `test`.`t1` `join_7` where 0 group by '0','0','0','0','0' SHOW WARNINGS; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 3656364820e..a6ad0d5bc80 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -16269,6 +16269,78 @@ static void test_bug27592() DBUG_VOID_RETURN; } +static void test_bug29948() +{ + MYSQL *dbc=NULL; + MYSQL_STMT *stmt=NULL; + MYSQL_BIND bind; + + int res=0; + my_bool auto_reconnect=1, error=0, is_null=0; + char kill_buf[20]; + const char *query; + int buf; + unsigned long length, cursor_type; + + dbc = mysql_init(NULL); + DIE_UNLESS(dbc); + + mysql_options(dbc, MYSQL_OPT_RECONNECT, (char*)&auto_reconnect); + if (!mysql_real_connect(dbc, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, + (CLIENT_FOUND_ROWS | CLIENT_MULTI_STATEMENTS | + CLIENT_MULTI_RESULTS))) + { + printf("connection failed: %s (%d)", mysql_error(dbc), + mysql_errno(dbc)); + exit(1); + } + + bind.buffer_type= MYSQL_TYPE_LONG; + bind.buffer= (char *)&buf; + bind.is_null= &is_null; + bind.error= &error; + bind.length= &length; + + res= mysql_query(dbc, "DROP TABLE IF EXISTS t1"); + myquery(res); + res= mysql_query(dbc, "CREATE TABLE t1 (a INT)"); + myquery(res); + res= mysql_query(dbc, "INSERT INTO t1 VALUES(1)"); + myquery(res); + + stmt= mysql_stmt_init(dbc); + check_stmt(stmt); + + cursor_type= CURSOR_TYPE_READ_ONLY; + res= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void *)&cursor_type); + myquery(res); + + query= "SELECT * from t1 where a=?"; + res= mysql_stmt_prepare(stmt, query, strlen(query)); + myquery(res); + + res= mysql_stmt_bind_param(stmt, &bind); + myquery(res); + + res= mysql_stmt_execute(stmt); + check_execute(stmt, res); + + res= mysql_stmt_bind_result(stmt,&bind); + check_execute(stmt, res); + + sprintf(kill_buf, "kill %ld", dbc->thread_id); + mysql_query(dbc, kill_buf); + + res= mysql_stmt_store_result(stmt); + DIE_UNLESS(res); + + mysql_stmt_free_result(stmt); + mysql_stmt_close(stmt); + mysql_query(dbc, "DROP TABLE t1"); + mysql_close(dbc); +} /* @@ -16670,6 +16742,7 @@ static struct my_tests_st my_tests[]= { { "test_bug28505", test_bug28505 }, { "test_bug28934", test_bug28934 }, { "test_bug27592", test_bug27592 }, + { "test_bug29948", test_bug29948 }, { "test_bug29687", test_bug29687 }, { "test_bug29692", test_bug29692 }, { "test_bug29306", test_bug29306 },