From f0ee73699105cc50a543c13408ddc9bfb324523b Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Wed, 8 Jun 2005 19:31:34 +0400 Subject: [PATCH 1/9] Cleanup sql_prepare.cc --- sql/sql_prepare.cc | 312 ++++++++++++++++++++------------------------- 1 file changed, 136 insertions(+), 176 deletions(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 4440e542434..1d1ea37a15b 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -889,8 +889,8 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, tables global/local table list RETURN VALUE - FALSE OK - TRUE error + FALSE success + TRUE error, error message is set in THD */ static bool mysql_test_insert(Prepared_statement *stmt, @@ -905,11 +905,10 @@ static bool mysql_test_insert(Prepared_statement *stmt, LEX *lex= stmt->lex; List_iterator_fast its(values_list); List_item *values; - bool res; DBUG_ENTER("mysql_test_insert"); - if ((res= insert_precheck(thd, table_list))) - DBUG_RETURN(res); + if (insert_precheck(thd, table_list)) + goto error; /* open temporary memory pool for temporary data allocated by derived @@ -920,10 +919,7 @@ static bool mysql_test_insert(Prepared_statement *stmt, TL_WRITE_DELAYED as having two such locks can cause table corruption. */ if (open_normal_and_derived_tables(thd, table_list)) - { - DBUG_RETURN(TRUE); - } - + goto error; if ((values= its++)) { @@ -937,17 +933,14 @@ static bool mysql_test_insert(Prepared_statement *stmt, table_list->table->insert_values=(byte *)1; } - if ((res= mysql_prepare_insert(thd, table_list, table_list->table, - fields, values, update_fields, - update_values, duplic, - &unused_conds, FALSE))) + if (mysql_prepare_insert(thd, table_list, table_list->table, fields, + values, update_fields, update_values, duplic, + &unused_conds, FALSE)) goto error; value_count= values->elements; its.rewind(); - res= TRUE; - if (table_list->lock_type == TL_WRITE_DELAYED && !(table_list->table->file->table_flags() & HA_CAN_INSERT_DELAYED)) { @@ -968,12 +961,11 @@ static bool mysql_test_insert(Prepared_statement *stmt, goto error; } } + DBUG_RETURN(FALSE); - res= FALSE; error: - lex->unit.cleanup(); /* insert_values is cleared in open_table */ - DBUG_RETURN(res); + DBUG_RETURN(TRUE); } @@ -987,9 +979,10 @@ error: RETURN VALUE 0 success + 1 error, error message is set in THD 2 convert to multi_update - 1 error */ + static int mysql_test_update(Prepared_statement *stmt, TABLE_LIST *table_list) { @@ -1003,69 +996,60 @@ static int mysql_test_update(Prepared_statement *stmt, DBUG_ENTER("mysql_test_update"); if (update_precheck(thd, table_list)) - DBUG_RETURN(1); + goto error; - if (!open_tables(thd, &table_list, &table_count)) + if (open_tables(thd, &table_list, &table_count)) + goto error; + + if (table_list->multitable_view) { - if (table_list->multitable_view) - { - DBUG_ASSERT(table_list->view != 0); - DBUG_PRINT("info", ("Switch to multi-update")); - /* pass counter value */ - thd->lex->table_count= table_count; - /* convert to multiupdate */ - return 2; - } + DBUG_ASSERT(table_list->view != 0); + DBUG_PRINT("info", ("Switch to multi-update")); + /* pass counter value */ + thd->lex->table_count= table_count; + /* convert to multiupdate */ + DBUG_RETURN(2); + } - /* - thd->fill_derived_tables() is false here for sure (because it is - preparation of PS, so we even do not check it - */ - if (lock_tables(thd, table_list, table_count) || - mysql_handle_derived(thd->lex, &mysql_derived_prepare)) - DBUG_RETURN(1); + /* + thd->fill_derived_tables() is false here for sure (because it is + preparation of PS, so we even do not check it). + */ + if (lock_tables(thd, table_list, table_count) || + mysql_handle_derived(thd->lex, &mysql_derived_prepare)) + goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS /* TABLE_LIST contain right privilages request */ want_privilege= table_list->grant.want_privilege; #endif - if (!(res= mysql_prepare_update(thd, table_list, - &select->where, - select->order_list.elements, - (ORDER *) select->order_list.first))) - { + if (mysql_prepare_update(thd, table_list, &select->where, + select->order_list.elements, + (ORDER *) select->order_list.first)) + goto error; + #ifndef NO_EMBEDDED_ACCESS_CHECKS - table_list->grant.want_privilege= - table_list->table->grant.want_privilege= - want_privilege; + table_list->grant.want_privilege= want_privilege; + table_list->table->grant.want_privilege= want_privilege; #endif - thd->lex->select_lex.no_wrap_view_item= 1; - if (setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0)) - { - res= 1; - thd->lex->select_lex.no_wrap_view_item= 0; - } - else - { - thd->lex->select_lex.no_wrap_view_item= 0; + thd->lex->select_lex.no_wrap_view_item= 1; + res= setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0); + thd->lex->select_lex.no_wrap_view_item= 0; + if (res) + goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS - /* Check values */ - table_list->grant.want_privilege= - table_list->table->grant.want_privilege= - (SELECT_ACL & ~table_list->table->grant.privilege); + /* Check values */ + table_list->grant.want_privilege= + table_list->table->grant.want_privilege= + (SELECT_ACL & ~table_list->table->grant.privilege); #endif - if (setup_fields(thd, 0, table_list, - stmt->lex->value_list, 0, 0, 0)) - res= 1; - } - } - stmt->lex->unit.cleanup(); - } - else - res= 1; + if (setup_fields(thd, 0, table_list, stmt->lex->value_list, 0, 0, 0)) + goto error; /* TODO: here we should send types of placeholders to the client. */ - DBUG_RETURN(res); + DBUG_RETURN(0); +error: + DBUG_RETURN(1); } @@ -1079,33 +1063,29 @@ static int mysql_test_update(Prepared_statement *stmt, RETURN VALUE FALSE success - TRUE error + TRUE error, error message is set in THD */ -static int mysql_test_delete(Prepared_statement *stmt, - TABLE_LIST *table_list) + +static bool mysql_test_delete(Prepared_statement *stmt, + TABLE_LIST *table_list) { THD *thd= stmt->thd; LEX *lex= stmt->lex; DBUG_ENTER("mysql_test_delete"); - if (delete_precheck(thd, table_list)) - DBUG_RETURN(TRUE); + if (delete_precheck(thd, table_list) || + open_and_lock_tables(thd, table_list)) + goto error; - if (!open_and_lock_tables(thd, table_list)) + if (!table_list->table) { - bool res; - if (!table_list->table) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - table_list->view_db.str, table_list->view_name.str); - DBUG_RETURN(-1); - } - - res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where); - lex->unit.cleanup(); - DBUG_RETURN(res); + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + table_list->view_db.str, table_list->view_name.str); + goto error; } - /* TODO: here we should send types of placeholders to the client. */ + + DBUG_RETURN(mysql_prepare_delete(thd, table_list, &lex->select_lex.where)); +error: DBUG_RETURN(TRUE); } @@ -1125,13 +1105,12 @@ static int mysql_test_delete(Prepared_statement *stmt, TRUE error, sent to client */ -static int mysql_test_select(Prepared_statement *stmt, - TABLE_LIST *tables, bool text_protocol) +static bool mysql_test_select(Prepared_statement *stmt, + TABLE_LIST *tables, bool text_protocol) { THD *thd= stmt->thd; LEX *lex= stmt->lex; SELECT_LEX_UNIT *unit= &lex->unit; - bool result; DBUG_ENTER("mysql_test_select"); #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1139,19 +1118,20 @@ static int mysql_test_select(Prepared_statement *stmt, if (tables) { if (check_table_access(thd, privilege, tables,0)) - DBUG_RETURN(TRUE); + goto error; } else if (check_access(thd, privilege, any_db,0,0,0)) - DBUG_RETURN(TRUE); + goto error; #endif - result= TRUE; if (!lex->result && !(lex->result= new (stmt->mem_root) select_send)) - goto err; + { + my_error(ER_OUTOFMEMORY, MYF(0), sizeof(select_send)); + goto error; + } if (open_and_lock_tables(thd, tables)) - goto err; - + goto error; thd->used_tables= 0; // Updated by setup_fields @@ -1161,15 +1141,13 @@ static int mysql_test_select(Prepared_statement *stmt, usual, and we pass 0 as setup_tables_done_option */ if (unit->prepare(thd, 0, 0, "")) - { - goto err_prep; - } + goto error; if (!text_protocol) { if (lex->describe) { if (send_prep_stmt(stmt, 0) || thd->protocol->flush()) - goto err_prep; + goto error; } else { @@ -1179,7 +1157,7 @@ static int mysql_test_select(Prepared_statement *stmt, /* Change columns if a procedure like analyse() */ if (unit->last_procedure && unit->last_procedure->change_columns(fields)) - goto err_prep; + goto error; /* We can use lex->result as it should've been @@ -1188,15 +1166,12 @@ static int mysql_test_select(Prepared_statement *stmt, if (send_prep_stmt(stmt, lex->result->field_count(fields)) || lex->result->send_fields(fields, Protocol::SEND_EOF) || thd->protocol->flush()) - goto err_prep; + goto error; } } - result= FALSE; // ok - -err_prep: - unit->cleanup(); -err: - DBUG_RETURN(result); + DBUG_RETURN(FALSE); +error: + DBUG_RETURN(TRUE); } @@ -1211,26 +1186,22 @@ err: RETURN VALUE FALSE success - TRUE error, sent to client + TRUE error, error message is set in THD */ static bool mysql_test_do_fields(Prepared_statement *stmt, TABLE_LIST *tables, List *values) { - DBUG_ENTER("mysql_test_do_fields"); THD *thd= stmt->thd; - bool res; + + DBUG_ENTER("mysql_test_do_fields"); if (tables && check_table_access(thd, SELECT_ACL, tables, 0)) DBUG_RETURN(TRUE); if (open_and_lock_tables(thd, tables)) - { DBUG_RETURN(TRUE); - } - res= setup_fields(thd, 0, 0, *values, 0, 0, 0); - stmt->lex->unit.cleanup(); - DBUG_RETURN(res); + DBUG_RETURN(setup_fields(thd, 0, 0, *values, 0, 0, 0)); } @@ -1247,6 +1218,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt, FALSE success TRUE error */ + static bool mysql_test_set_fields(Prepared_statement *stmt, TABLE_LIST *tables, List *var_list) @@ -1255,25 +1227,19 @@ static bool mysql_test_set_fields(Prepared_statement *stmt, List_iterator_fast it(*var_list); THD *thd= stmt->thd; set_var_base *var; - bool res; - if (tables && check_table_access(thd, SELECT_ACL, tables, 0)) - DBUG_RETURN(TRUE); - - if ((res= open_and_lock_tables(thd, tables))) + if (tables && check_table_access(thd, SELECT_ACL, tables, 0) || + open_and_lock_tables(thd, tables)) goto error; + while ((var= it++)) { if (var->light_check(thd)) - { - stmt->lex->unit.cleanup(); - res= TRUE; goto error; - } } + DBUG_RETURN(FALSE); error: - stmt->lex->unit.cleanup(); - DBUG_RETURN(res); + DBUG_RETURN(TRUE); } @@ -1294,7 +1260,7 @@ error: RETURN VALUE FALSE success - TRUE error + TRUE error, error message is set in THD */ static bool select_like_stmt_test(Prepared_statement *stmt, @@ -1304,24 +1270,16 @@ static bool select_like_stmt_test(Prepared_statement *stmt, DBUG_ENTER("select_like_stmt_test"); THD *thd= stmt->thd; LEX *lex= stmt->lex; - bool res= FALSE; - if (specific_prepare && (res= (*specific_prepare)(thd))) - goto end; + if (specific_prepare && (*specific_prepare)(thd)) + DBUG_RETURN(TRUE); thd->used_tables= 0; // Updated by setup_fields - // JOIN::prepare calls - if (lex->unit.prepare(thd, 0, setup_tables_done_option, "")) - { - res= TRUE; - } -end: - lex->unit.cleanup(); - DBUG_RETURN(res); + /* Calls JOIN::prepare */ + DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option, "")); } - /* Check internal SELECT of the prepared command (with opening and locking tables used). @@ -1369,25 +1327,26 @@ select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt, tables list of tables queries RETURN VALUE - 0 success - 1 error, sent to client - -1 error, not sent to client + FALSE success + TRUE error, error message is set in THD */ -static int mysql_test_create_table(Prepared_statement *stmt) +static bool mysql_test_create_table(Prepared_statement *stmt) { DBUG_ENTER("mysql_test_create_table"); THD *thd= stmt->thd; LEX *lex= stmt->lex; SELECT_LEX *select_lex= &lex->select_lex; - int res= 0; + bool res= FALSE; /* Skip first table, which is the table we are creating */ bool link_to_local; TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local); TABLE_LIST *tables= lex->query_tables; - if (!(res= create_table_precheck(thd, tables, create_table)) && - select_lex->item_list.elements) + if (create_table_precheck(thd, tables, create_table)) + DBUG_RETURN(TRUE); + + if (select_lex->item_list.elements) { select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0); @@ -1437,32 +1396,35 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt, RETURN VALUE 0 success - 1 error, sent to client - -1 error, not sent to client + 1 error, error message in THD is set. */ -static int mysql_test_multidelete(Prepared_statement *stmt, + +static bool mysql_test_multidelete(Prepared_statement *stmt, TABLE_LIST *tables) { - int res; + uint fake_counter; + stmt->thd->lex->current_select= &stmt->thd->lex->select_lex; if (add_item_to_list(stmt->thd, new Item_null())) - return -1; + { + my_error(ER_OUTOFMEMORY, MYF(0), 0); + goto error; + } - uint fake_counter; - if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter))) - return res; - if ((res= select_like_stmt_test_with_open_n_lock(stmt, tables, - &mysql_multi_delete_prepare, - OPTION_SETUP_TABLES_DONE))) - return res; + if (multi_delete_precheck(stmt->thd, tables, &fake_counter) || + select_like_stmt_test_with_open_n_lock(stmt, tables, + &mysql_multi_delete_prepare, + OPTION_SETUP_TABLES_DONE)) + goto error; if (!tables->table) { my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), tables->view_db.str, tables->view_name.str); - return -1; + goto error; } - return 0; - + return FALSE; +error: + return TRUE; } @@ -1520,8 +1482,8 @@ static int mysql_test_insert_select(Prepared_statement *stmt, tables->table->insert_values=(byte *)1; } - if ((res= insert_precheck(stmt->thd, tables))) - return res; + if (insert_precheck(stmt->thd, tables)) + return 1; /* store it, because mysql_insert_select_prepare_tester change it */ first_local_table= (TABLE_LIST *)lex->select_lex.table_list.first; @@ -1552,12 +1514,12 @@ static int mysql_test_insert_select(Prepared_statement *stmt, by calling fix_fields. RETURN VALUE - 0 success - 1 error, sent to client + FALSE success, statement metadata is sent to client + TRUE error, error message is set (but not sent) */ -static int check_prepared_statement(Prepared_statement *stmt, - bool text_protocol) +static bool check_prepared_statement(Prepared_statement *stmt, + bool text_protocol) { THD *thd= stmt->thd; LEX *lex= stmt->lex; @@ -1583,7 +1545,7 @@ static int check_prepared_statement(Prepared_statement *stmt, case SQLCOM_UPDATE: res= mysql_test_update(stmt, tables); - /* mysql_test_update return 2 if we need to switch to multi-update */ + /* mysql_test_update returns 2 if we need to switch to multi-update */ if (res != 2) break; @@ -1599,7 +1561,7 @@ static int check_prepared_statement(Prepared_statement *stmt, if ((res= mysql_test_select(stmt, tables, text_protocol))) goto error; /* Statement and field info has already been sent */ - DBUG_RETURN(0); + DBUG_RETURN(FALSE); case SQLCOM_CREATE_TABLE: res= mysql_test_create_table(stmt); @@ -1650,18 +1612,15 @@ static int check_prepared_statement(Prepared_statement *stmt, break; default: - /* - All other is not supported yet - */ - res= -1; + /* All other statements are not supported yet. */ my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0)); goto error; } if (res == 0) - DBUG_RETURN(text_protocol? 0 : (send_prep_stmt(stmt, 0) || - thd->protocol->flush())); + DBUG_RETURN(text_protocol? FALSE : (send_prep_stmt(stmt, 0) || + thd->protocol->flush())); error: - DBUG_RETURN(1); + DBUG_RETURN(TRUE); } /* @@ -1803,6 +1762,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, thd->lex->sphead= NULL; } lex_end(lex); + lex->unit.cleanup(); close_thread_tables(thd); thd->restore_backup_statement(stmt, &thd->stmt_backup); cleanup_items(stmt->free_list); From 6c148a7969bb80b56166ff4d32ec7a90a7b27491 Mon Sep 17 00:00:00 2001 From: "hf@deer.(none)" <> Date: Wed, 8 Jun 2005 20:35:37 +0500 Subject: [PATCH 2/9] Fix for bug #9764 (DISTINCT IFNULL truncates data) --- mysql-test/r/create.result | 2 +- mysql-test/r/distinct.result | 8 ++++++++ mysql-test/t/distinct.test | 8 ++++++++ sql/item_cmpfunc.cc | 26 ++++++++++++-------------- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index be527630078..9d96cef345f 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -434,7 +434,7 @@ d date YES NULL e varchar(1) NO f datetime YES NULL g time YES NULL -h varbinary(23) NO +h longblob NO dd time YES NULL select * from t2; a b c d e f g h dd diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 955ea5b8673..3ad2b73f1d3 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -464,3 +464,11 @@ SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; html prod 1 0.0000 drop table t1; +create table t1 (id int, dsc varchar(50)); +insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three"); +select distinct id, IFNULL(dsc, '-') from t1; +id IFNULL(dsc, '-') +1 line number one +2 line number two +3 line number three +drop table t1; diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index a3862786cc3..057c9bd9239 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -332,3 +332,11 @@ CREATE TABLE t1 ( INSERT INTO t1 VALUES ('1',1,0); SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; drop table t1; + +# +# Bug 9784 DISTINCT IFNULL truncates data +# +create table t1 (id int, dsc varchar(50)); +insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three"); +select distinct id, IFNULL(dsc, '-') from t1; +drop table t1; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 28ab38c5aed..b5b37efaf07 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1109,12 +1109,14 @@ void Item_func_between::print(String *str) void Item_func_ifnull::fix_length_and_dec() { + agg_result_type(&hybrid_type, args, 2); maybe_null=args[1]->maybe_null; decimals= max(args[0]->decimals, args[1]->decimals); - max_length= (max(args[0]->max_length - args[0]->decimals, - args[1]->max_length - args[1]->decimals) + - decimals); - agg_result_type(&hybrid_type, args, 2); + max_length= (hybrid_type == DECIMAL_RESULT || hybrid_type == INT_RESULT) ? + (max(args[0]->max_length - args[0]->decimals, + args[1]->max_length - args[1]->decimals) + decimals) : + max(args[0]->max_length, args[1]->max_length); + switch (hybrid_type) { case STRING_RESULT: agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV); @@ -1225,16 +1227,7 @@ Item_func_if::fix_length_and_dec() { maybe_null=args[1]->maybe_null || args[2]->maybe_null; decimals= max(args[1]->decimals, args[2]->decimals); - if (decimals == NOT_FIXED_DEC) - { - max_length= max(args[1]->max_length, args[2]->max_length); - } - else - { - max_length= (max(args[1]->max_length - args[1]->decimals, - args[2]->max_length - args[2]->decimals) + - decimals); - } + enum Item_result arg1_type=args[1]->result_type(); enum Item_result arg2_type=args[2]->result_type(); bool null1=args[1]->const_item() && args[1]->null_value; @@ -1263,6 +1256,11 @@ Item_func_if::fix_length_and_dec() collation.set(&my_charset_bin); // Number } } + max_length= + (cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) ? + (max(args[1]->max_length - args[1]->decimals, + args[2]->max_length - args[2]->decimals) + decimals) : + max(args[1]->max_length, args[2]->max_length); } From a2bf13cde69eb1f8ad1189391311a192cd58559b Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Wed, 8 Jun 2005 19:57:26 +0400 Subject: [PATCH 3/9] Trim trailing spaces. --- sql/sql_prepare.cc | 208 ++++++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 1d1ea37a15b..cb96f57a58a 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -15,18 +15,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /********************************************************************** -This file contains the implementation of prepare and executes. +This file contains the implementation of prepare and executes. Prepare: - - Server gets the query from client with command 'COM_PREPARE'; + - Server gets the query from client with command 'COM_PREPARE'; in the following format: [COM_PREPARE:1] [query] - - Parse the query and recognize any parameter markers '?' and + - Parse the query and recognize any parameter markers '?' and store its information list in lex->param_list - - Allocate a new statement for this prepare; and keep this in + - Allocate a new statement for this prepare; and keep this in 'thd->prepared_statements' pool. - - Without executing the query, return back to client the total + - Without executing the query, return back to client the total number of parameters along with result-set metadata information (if any) in the following format: [STMT_ID:4] @@ -34,10 +34,10 @@ Prepare: [Param_count:2] [Columns meta info] (if Column_count > 0) [Params meta info] (if Param_count > 0 ) (TODO : 4.1.1) - + Prepare-execute: - - Server gets the command 'COM_EXECUTE' to execute the + - Server gets the command 'COM_EXECUTE' to execute the previously prepared query. If there is any param markers; then client will send the data in the following format: [COM_EXECUTE:1] @@ -45,12 +45,12 @@ Prepare-execute: [NULL_BITS:(param_count+7)/8)] [TYPES_SUPPLIED_BY_CLIENT(0/1):1] [[length]data] - [[length]data] .. [[length]data]. - (Note: Except for string/binary types; all other types will not be + [[length]data] .. [[length]data]. + (Note: Except for string/binary types; all other types will not be supplied with length field) - - Replace the param items with this new data. If it is a first execute + - Replace the param items with this new data. If it is a first execute or types altered by client; then setup the conversion routines. - - Execute the query without re-parsing and send back the results + - Execute the query without re-parsing and send back the results to client Long data handling: @@ -61,8 +61,8 @@ Long data handling: - data from the packet is appended to long data value buffer for this placeholder. - It's up to the client to check for read data ended. The server doesn't - care; and also server doesn't notify to the client that it got the - data or not; if there is any error; then during execute; the error + care; and also server doesn't notify to the client that it got the + data or not; if there is any error; then during execute; the error will be returned ***********************************************************************/ @@ -97,7 +97,7 @@ public: #else bool (*set_params_data)(Prepared_statement *st, String *expanded_query); #endif - bool (*set_params_from_vars)(Prepared_statement *stmt, + bool (*set_params_from_vars)(Prepared_statement *stmt, List& varnames, String *expanded_query); public: @@ -167,7 +167,7 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns) Send types and names of placeholders to the client XXX: fix this nasty upcast from List to List */ - DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) || + DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) || (stmt->param_count && stmt->thd->protocol_simple.send_fields((List *) &stmt->lex->param_list, @@ -220,7 +220,7 @@ static ulong get_param_length(uchar **packet, ulong len) } if (len < 5) return 0; - (*packet)+=9; // Must be 254 when here + (*packet)+=9; // Must be 254 when here /* In our client-server protocol all numbers bigger than 2^24 stored as 8 bytes with uint8korr. Here we always know that @@ -242,7 +242,7 @@ static ulong get_param_length(uchar **packet, ulong len) pos input data buffer len length of data in the buffer - All these functions read the data from pos, convert it to requested type + All these functions read the data from pos, convert it to requested type and assign to param; pos is advanced to predefined length. Make a note that the NULL handling is examined at first execution @@ -260,7 +260,7 @@ static void set_param_tiny(Item_param *param, uchar **pos, ulong len) return; #endif int8 value= (int8) **pos; - param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) : + param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) : (longlong) value, 4); *pos+= 1; } @@ -480,7 +480,7 @@ static void set_param_str(Item_param *param, uchar **pos, ulong len) } -#undef get_param_length +#undef get_param_length static void setup_one_conversion_function(THD *thd, Item_param *param, uchar param_type) @@ -583,12 +583,12 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, #ifndef EMBEDDED_LIBRARY /* - Update the parameter markers by reading data from client packet + Update the parameter markers by reading data from client packet and if binary/update log is set, generate the valid query. */ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, - uchar *read_pos, uchar *data_end, + uchar *read_pos, uchar *data_end, String *query) { THD *thd= stmt->thd; @@ -596,14 +596,14 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, Item_param **end= begin + stmt->param_count; uint32 length= 0; - String str; + String str; const String *res; - DBUG_ENTER("insert_params_withlog"); + DBUG_ENTER("insert_params_withlog"); if (query->copy(stmt->query, stmt->query_length, default_charset_info)) DBUG_RETURN(1); - + for (Item_param **it= begin; it < end; ++it) { Item_param *param= *it; @@ -624,7 +624,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, if (query->replace(param->pos_in_query+length, 1, *res)) DBUG_RETURN(1); - + length+= res->length()-1; } DBUG_RETURN(0); @@ -632,13 +632,13 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, static bool insert_params(Prepared_statement *stmt, uchar *null_array, - uchar *read_pos, uchar *data_end, + uchar *read_pos, uchar *data_end, String *expanded_query) { Item_param **begin= stmt->param_array; Item_param **end= begin + stmt->param_count; - DBUG_ENTER("insert_params"); + DBUG_ENTER("insert_params"); for (Item_param **it= begin; it < end; ++it) { @@ -672,7 +672,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt, if (*read_pos++) //types supplied / first execute { /* - First execute or types altered by the client, setup the + First execute or types altered by the client, setup the conversion routines for all parameters (one time) */ Item_param **it= stmt->param_array; @@ -720,8 +720,8 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query) uchar *buff= (uchar*) client_param->buffer; param->unsigned_flag= client_param->is_unsigned; param->set_param_func(param, &buff, - client_param->length ? - *client_param->length : + client_param->length ? + *client_param->length : client_param->buffer_length); } } @@ -747,7 +747,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query) if (query->copy(stmt->query, stmt->query_length, default_charset_info)) DBUG_RETURN(1); - + for (; it < end; ++it, ++client_param) { Item_param *param= *it; @@ -759,10 +759,10 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query) else { uchar *buff= (uchar*)client_param->buffer; - param->unsigned_flag= client_param->is_unsigned; + param->unsigned_flag= client_param->is_unsigned; param->set_param_func(param, &buff, - client_param->length ? - *client_param->length : + client_param->length ? + *client_param->length : client_param->buffer_length); } } @@ -881,12 +881,12 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, } /* - Validate INSERT statement: + Validate INSERT statement: SYNOPSIS mysql_test_insert() - stmt prepared statemen handler - tables global/local table list + stmt prepared statemen handler + tables global/local table list RETURN VALUE FALSE success @@ -895,7 +895,7 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, static bool mysql_test_insert(Prepared_statement *stmt, TABLE_LIST *table_list, - List &fields, + List &fields, List &values_list, List &update_fields, List &update_values, @@ -958,7 +958,7 @@ static bool mysql_test_insert(Prepared_statement *stmt, goto error; } if (setup_fields(thd, 0, table_list, *values, 0, 0, 0)) - goto error; + goto error; } } DBUG_RETURN(FALSE); @@ -974,8 +974,8 @@ error: SYNOPSIS mysql_test_update() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries RETURN VALUE 0 success @@ -991,7 +991,7 @@ static int mysql_test_update(Prepared_statement *stmt, uint table_count= 0; SELECT_LEX *select= &stmt->lex->select_lex; #ifndef NO_EMBEDDED_ACCESS_CHECKS - uint want_privilege; + uint want_privilege; #endif DBUG_ENTER("mysql_test_update"); @@ -1046,7 +1046,7 @@ static int mysql_test_update(Prepared_statement *stmt, #endif if (setup_fields(thd, 0, table_list, stmt->lex->value_list, 0, 0, 0)) goto error; - /* TODO: here we should send types of placeholders to the client. */ + /* TODO: here we should send types of placeholders to the client. */ DBUG_RETURN(0); error: DBUG_RETURN(1); @@ -1058,8 +1058,8 @@ error: SYNOPSIS mysql_test_delete() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries RETURN VALUE FALSE success @@ -1093,12 +1093,12 @@ error: /* Validate SELECT statement. In case of success, if this query is not EXPLAIN, send column list info - back to client. + back to client. SYNOPSIS mysql_test_select() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries RETURN VALUE FALSE success @@ -1180,9 +1180,9 @@ error: SYNOPSIS mysql_test_do_fields() - stmt prepared statemen handler - tables list of tables queries - values list of expressions + stmt prepared statemen handler + tables list of tables queries + values list of expressions RETURN VALUE FALSE success @@ -1190,8 +1190,8 @@ error: */ static bool mysql_test_do_fields(Prepared_statement *stmt, - TABLE_LIST *tables, - List *values) + TABLE_LIST *tables, + List *values) { THD *thd= stmt->thd; @@ -1210,9 +1210,9 @@ static bool mysql_test_do_fields(Prepared_statement *stmt, SYNOPSIS mysql_test_set_fields() - stmt prepared statemen handler - tables list of tables queries - values list of expressions + stmt prepared statemen handler + tables list of tables queries + values list of expressions RETURN VALUE FALSE success @@ -1323,8 +1323,8 @@ select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt, SYNOPSIS mysql_test_create_table() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries RETURN VALUE FALSE success @@ -1364,8 +1364,8 @@ static bool mysql_test_create_table(Prepared_statement *stmt) SYNOPSIS mysql_test_multiupdate() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries converted converted to multi-update from usual update RETURN VALUE @@ -1374,7 +1374,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt) */ static bool mysql_test_multiupdate(Prepared_statement *stmt, - TABLE_LIST *tables, + TABLE_LIST *tables, bool converted) { /* if we switched from normal update, rights are checked */ @@ -1391,8 +1391,8 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt, SYNOPSIS mysql_test_multidelete() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries RETURN VALUE 0 success @@ -1400,7 +1400,7 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt, */ static bool mysql_test_multidelete(Prepared_statement *stmt, - TABLE_LIST *tables) + TABLE_LIST *tables) { uint fake_counter; @@ -1419,7 +1419,7 @@ static bool mysql_test_multidelete(Prepared_statement *stmt, if (!tables->table) { my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - tables->view_db.str, tables->view_name.str); + tables->view_db.str, tables->view_name.str); goto error; } return FALSE; @@ -1460,8 +1460,8 @@ static bool mysql_insert_select_prepare_tester(THD *thd) SYNOPSIS mysql_test_insert_select() - stmt prepared statemen handler - tables list of tables of query + stmt prepared statemen handler + tables list of tables of query RETURN VALUE 0 success @@ -1470,7 +1470,7 @@ static bool mysql_insert_select_prepare_tester(THD *thd) */ static int mysql_test_insert_select(Prepared_statement *stmt, - TABLE_LIST *tables) + TABLE_LIST *tables) { int res; LEX *lex= stmt->lex; @@ -1538,9 +1538,9 @@ static bool check_prepared_statement(Prepared_statement *stmt, case SQLCOM_REPLACE: case SQLCOM_INSERT: res= mysql_test_insert(stmt, tables, lex->field_list, - lex->many_values, - select_lex->item_list, lex->value_list, - lex->duplicates); + lex->many_values, + select_lex->item_list, lex->value_list, + lex->duplicates); break; case SQLCOM_UPDATE: @@ -1566,7 +1566,7 @@ static bool check_prepared_statement(Prepared_statement *stmt, case SQLCOM_CREATE_TABLE: res= mysql_test_create_table(stmt); break; - + case SQLCOM_DO: res= mysql_test_do_fields(stmt, tables, lex->insert_list); break; @@ -1661,30 +1661,30 @@ static bool init_param_array(Prepared_statement *stmt) /* Given a query string with parameter markers, create a Prepared Statement from it and send PS info back to the client. - + SYNOPSIS mysql_stmt_prepare() - packet query to be prepared - packet_length query string length, including ignored trailing NULL or + packet query to be prepared + packet_length query string length, including ignored trailing NULL or quote char. name NULL or statement name. For unnamed statements binary PS - protocol is used, for named statements text protocol is + protocol is used, for named statements text protocol is used. RETURN FALSE OK, statement prepared successfully TRUE Error NOTES - This function parses the query and sends the total number of parameters - and resultset metadata information back to client (if any), without - executing the query i.e. without any log/disk writes. This allows the - queries to be re-executed without re-parsing during execute. + This function parses the query and sends the total number of parameters + and resultset metadata information back to client (if any), without + executing the query i.e. without any log/disk writes. This allows the + queries to be re-executed without re-parsing during execute. If parameter markers are found in the query, then store the information - using Item_param along with maintaining a list in lex->param_array, so - that a fast and direct retrieval can be made without going through all + using Item_param along with maintaining a list in lex->param_array, so + that a fast and direct retrieval can be made without going through all field items. - + */ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, @@ -1857,8 +1857,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex) } /* - TODO: When the new table structure is ready, then have a status bit - to indicate the table is altered, and re-do the setup_* + TODO: When the new table structure is ready, then have a status bit + to indicate the table is altered, and re-do the setup_* and open the tables back. */ /* @@ -1867,8 +1867,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex) they have their own table list). */ for (TABLE_LIST *tables= lex->query_tables; - tables; - tables= tables->next_global) + tables; + tables= tables->next_global) { /* Reset old pointers to TABLEs: they are not valid since the tables @@ -1899,10 +1899,10 @@ void reset_stmt_for_execute(THD *thd, LEX *lex) /* Clears parameters from data left from previous execution or long data - + SYNOPSIS reset_stmt_params() - stmt prepared statement for which parameters should be reset + stmt prepared statement for which parameters should be reset */ static void reset_stmt_params(Prepared_statement *stmt) @@ -1999,8 +1999,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) } #else /* - In embedded library we re-install conversion routines each time - we set params, and also we don't need to parse packet. + In embedded library we re-install conversion routines each time + we set params, and also we don't need to parse packet. So we do it in one function. */ if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query)) @@ -2163,9 +2163,9 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt, SYNOPSIS mysql_stmt_fetch() - thd Thread handler - packet Packet from client (with stmt_id & num_rows) - packet_length Length of packet + thd Thread handler + packet Packet from client (with stmt_id & num_rows) + packet_length Length of packet */ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) @@ -2192,7 +2192,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), QUERY_PRIOR); - thd->protocol= &thd->protocol_prep; // Switch to binary protocol + thd->protocol= &thd->protocol_prep; // Switch to binary protocol stmt->cursor->fetch(num_rows); thd->protocol= &thd->protocol_simple; // Use normal protocol @@ -2213,7 +2213,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) SYNOPSIS mysql_stmt_reset() thd Thread handle - packet Packet with stmt id + packet Packet with stmt id DESCRIPTION This function resets statement to the state it was right after prepare. @@ -2240,22 +2240,22 @@ void mysql_stmt_reset(THD *thd, char *packet) stmt->state= Item_arena::PREPARED; - /* - Clear parameters from data which could be set by + /* + Clear parameters from data which could be set by mysql_stmt_send_long_data() call. */ reset_stmt_params(stmt); mysql_reset_thd_for_next_command(thd); send_ok(thd); - + DBUG_VOID_RETURN; } /* Delete a prepared statement from memory. - Note: we don't send any reply to that command. + Note: we don't send any reply to that command. */ void mysql_stmt_free(THD *thd, char *packet) @@ -2280,9 +2280,9 @@ void mysql_stmt_free(THD *thd, char *packet) SYNOPSIS mysql_stmt_get_longdata() - thd Thread handle - pos String to append - packet_length Length of string + thd Thread handle + pos String to append + packet_length Length of string DESCRIPTION Get a part of a long data. @@ -2301,7 +2301,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) Prepared_statement *stmt; Item_param *param; char *packet_end= packet + packet_length - 1; - + DBUG_ENTER("mysql_stmt_get_longdata"); #ifndef EMBEDDED_LIBRARY From a881e00aafab62b969190597c436a3f99c2bdc78 Mon Sep 17 00:00:00 2001 From: "hf@deer.(none)" <> Date: Wed, 8 Jun 2005 21:56:22 +0500 Subject: [PATCH 4/9] Fix for bug #10896 (0.00 > -0.00) --- mysql-test/r/type_newdecimal.result | 11 +++++++++++ mysql-test/t/type_newdecimal.test | 11 +++++++++++ sql/my_decimal.h | 5 +++++ 3 files changed, 27 insertions(+) diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 09fbc6b8143..c0693d1585c 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -896,6 +896,8 @@ create table t1( d1 decimal(18) unsigned, d2 decimal(20) unsigned, d3 decimal (2 insert into t1 values(1,-1,-1); ERROR 22003: Out of range value adjusted for column 'd2' at row 1 drop table t1; +set sql_mode=''; +set @sav_dpi= @@div_precision_increment; set @@div_precision_increment=15; create table t1 (col1 int, col2 decimal(30,25), col3 numeric(30,25)); insert into t1 values (1,0.0123456789012345678912345,0.0123456789012345678912345); @@ -909,3 +911,12 @@ select 77777777/7777777; 77777777/7777777 10.000000900000090 drop table t1; +set div_precision_increment= @sav_dpi; +create table t1 (a decimal(4,2)); +insert into t1 values (0.00); +select * from t1 where a > -0.00; +a +select * from t1 where a = -0.00; +a +0.00 +drop table t1; diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 6bff6c22abc..d1d595285a2 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -934,10 +934,12 @@ create table t1( d1 decimal(18) unsigned, d2 decimal(20) unsigned, d3 decimal (2 --error 1264 insert into t1 values(1,-1,-1); drop table t1; +set sql_mode=''; # # Bug #8425 (insufficient precision of the division) # +set @sav_dpi= @@div_precision_increment; set @@div_precision_increment=15; create table t1 (col1 int, col2 decimal(30,25), col3 numeric(30,25)); insert into t1 values (1,0.0123456789012345678912345,0.0123456789012345678912345); @@ -945,4 +947,13 @@ select col2/9999999999 from t1 where col1=1; select 9999999999/col2 from t1 where col1=1; select 77777777/7777777; drop table t1; +set div_precision_increment= @sav_dpi; +# +# Bug #10896 (0.00 > -0.00) +# +create table t1 (a decimal(4,2)); +insert into t1 values (0.00); +select * from t1 where a > -0.00; +select * from t1 where a = -0.00; +drop table t1; diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 27fd33cffbe..b65e6aedaa2 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -290,6 +290,11 @@ int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d) inline void my_decimal_neg(decimal_t *arg) { + if (decimal_is_zero(arg)) + { + arg->sign= 0; + return; + } decimal_neg(arg); } From 5394a1a4bddc7fad8d8d490c5d1a902152916a2f Mon Sep 17 00:00:00 2001 From: "dlenev@brandersnatch.localdomain" <> Date: Thu, 9 Jun 2005 01:07:52 +0400 Subject: [PATCH 5/9] Fix for bug #11158 "Can't perform multi-delete in stored procedure". In order to make multi-delete SP friendly we need to have all table locks for the elements of main statement table list properly set at the end of parsing. Also performed small cleanup: We don't need relink_tables_for_multidelete() any longer since the only case now when TABLE_LIST::correspondent_table is non-zero are tables in auxilary table list of multi-delete and these tables are handled specially in mysql_multi_delete_prepare(). --- mysql-test/r/sp-threads.result | 15 +++++++++++ mysql-test/t/sp-threads.test | 26 ++++++++++++++++++ sql/mysql_priv.h | 3 ++- sql/sql_base.cc | 28 ------------------- sql/sql_lex.h | 7 ++++- sql/sql_parse.cc | 49 +++++++++++++++++++++------------- sql/sql_prepare.cc | 3 +-- sql/sql_yacc.yy | 9 ++++++- 8 files changed, 89 insertions(+), 51 deletions(-) diff --git a/mysql-test/r/sp-threads.result b/mysql-test/r/sp-threads.result index a081e520496..a9d50e6e697 100644 --- a/mysql-test/r/sp-threads.result +++ b/mysql-test/r/sp-threads.result @@ -40,3 +40,18 @@ Id User Host db Command Time State Info unlock tables; drop procedure bug9486; drop table t1, t2; +drop procedure if exists bug11158; +create procedure bug11158() delete t1 from t1, t2 where t1.id = t2.id; +create table t1 (id int, j int); +insert into t1 values (1, 1), (2, 2); +create table t2 (id int); +insert into t2 values (1); +call bug11158(); +select * from t1; +id j +2 2 +lock tables t2 read; +call bug11158(); +unlock tables; +drop procedure bug11158; +drop table t1, t2; diff --git a/mysql-test/t/sp-threads.test b/mysql-test/t/sp-threads.test index 608ac3e2ee7..8fec5d14bc1 100644 --- a/mysql-test/t/sp-threads.test +++ b/mysql-test/t/sp-threads.test @@ -84,6 +84,32 @@ reap; drop procedure bug9486; drop table t1, t2; +# +# BUG#11158: Can't perform multi-delete in stored procedure +# +--disable_warnings +drop procedure if exists bug11158; +--enable_warnings +create procedure bug11158() delete t1 from t1, t2 where t1.id = t2.id; +create table t1 (id int, j int); +insert into t1 values (1, 1), (2, 2); +create table t2 (id int); +insert into t2 values (1); +# Procedure should work and cause proper effect (delete only first row) +call bug11158(); +select * from t1; +# Also let us test that we obtain only read (and thus non exclusive) lock +# for table from which we are not going to delete rows. +connection con2root; +lock tables t2 read; +connection con1root; +call bug11158(); +connection con2root; +unlock tables; +connection con1root; +# Clean-up +drop procedure bug11158; +drop table t1, t2; # # BUG#NNNN: New bug synopsis diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index e8ec1b69959..58ac3f96833 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -480,7 +480,7 @@ bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list); bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc); bool multi_update_precheck(THD *thd, TABLE_LIST *tables); -bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count); +bool multi_delete_precheck(THD *thd, TABLE_LIST *tables); bool mysql_multi_update_prepare(THD *thd); bool mysql_multi_delete_prepare(THD *thd); bool mysql_insert_select_prepare(THD *thd); @@ -575,6 +575,7 @@ void mysql_init_query(THD *thd, uchar *buf, uint length); bool mysql_new_select(LEX *lex, bool move_down); void create_select_for_variable(const char *var_name); void mysql_init_multi_delete(LEX *lex); +bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void init_max_user_conn(void); void init_update_queries(void); void free_max_user_conn(void); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b5df0be1073..a1887996d00 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -42,7 +42,6 @@ static my_bool open_new_frm(const char *path, const char *alias, uint db_stat, uint prgflag, uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc, MEM_ROOT *mem_root); -static void relink_tables_for_multidelete(THD *thd); extern "C" byte *table_cache_key(const byte *record,uint *length, my_bool not_used __attribute__((unused))) @@ -2089,7 +2088,6 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) (thd->fill_derived_tables() && mysql_handle_derived(thd->lex, &mysql_derived_filling))) DBUG_RETURN(TRUE); /* purecov: inspected */ - relink_tables_for_multidelete(thd); DBUG_RETURN(0); } @@ -2119,36 +2117,10 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables) if (open_tables(thd, &tables, &counter) || mysql_handle_derived(thd->lex, &mysql_derived_prepare)) DBUG_RETURN(TRUE); /* purecov: inspected */ - relink_tables_for_multidelete(thd); // Not really needed, but DBUG_RETURN(0); } -/* - Let us propagate pointers to open tables from global table list - to table lists for multi-delete -*/ - -static void relink_tables_for_multidelete(THD *thd) -{ - if (thd->lex->all_selects_list->next_select_in_list()) - { - for (SELECT_LEX *sl= thd->lex->all_selects_list; - sl; - sl= sl->next_select_in_list()) - { - for (TABLE_LIST *cursor= (TABLE_LIST *) sl->table_list.first; - cursor; - cursor=cursor->next_local) - { - if (cursor->correspondent_table) - cursor->table= cursor->correspondent_table->table; - } - } - } -} - - /* Mark all real tables in the list as free for reuse. diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 5022392565c..f6ffc141444 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -750,7 +750,12 @@ typedef struct st_lex uint grant, grant_tot_col, which_columns; uint fk_delete_opt, fk_update_opt, fk_match_option; uint slave_thd_opt, start_transaction_opt; - uint table_count; /* used when usual update transformed in multiupdate */ + /* + In LEX representing update which were transformed to multi-update + stores total number of tables. For LEX representing multi-delete + holds number of tables from which we will delete records. + */ + uint table_count; uint8 describe; uint8 derived_tables; uint8 create_view_algorithm; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7d00cfa4c98..ba316e84c73 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3291,10 +3291,9 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first; - uint table_count; multi_delete *result; - if ((res= multi_delete_precheck(thd, all_tables, &table_count))) + if ((res= multi_delete_precheck(thd, all_tables))) break; /* condition will be TRUE on SP re-excuting */ @@ -3311,7 +3310,7 @@ end_with_restore_list: goto error; if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables, - table_count))) + lex->table_count))) { res= mysql_select(thd, &select_lex->ref_pointer_array, select_lex->get_table_list(), @@ -6799,23 +6798,19 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) multi_delete_precheck() thd Thread handler tables Global/local table list - table_count Pointer to table counter RETURN VALUE FALSE OK TRUE error */ -bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) +bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) { SELECT_LEX *select_lex= &thd->lex->select_lex; TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first; - TABLE_LIST *target_tbl; DBUG_ENTER("multi_delete_precheck"); - *table_count= 0; - /* sql_yacc guarantees that tables and aux_tables are not zero */ DBUG_ASSERT(aux_tables != 0); if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) || @@ -6828,9 +6823,35 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0)); DBUG_RETURN(TRUE); } - for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next_local) + DBUG_RETURN(FALSE); +} + + +/* + Link tables in auxilary table list of multi-delete with corresponding + elements in main table list, and set proper locks for them. + + SYNOPSIS + multi_delete_set_locks_and_link_aux_tables() + lex - pointer to LEX representing multi-delete + + RETURN VALUE + FALSE - success + TRUE - error +*/ + +bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) +{ + TABLE_LIST *tables= (TABLE_LIST*)lex->select_lex.table_list.first; + TABLE_LIST *target_tbl; + DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables"); + + lex->table_count= 0; + + for (target_tbl= (TABLE_LIST *)lex->auxilliary_table_list.first; + target_tbl; target_tbl= target_tbl->next_local) { - (*table_count)++; + lex->table_count++; /* All tables in aux_tables must be found in FROM PART */ TABLE_LIST *walk; for (walk= tables; walk; walk= walk->next_local) @@ -6848,14 +6869,6 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) } walk->lock_type= target_tbl->lock_type; target_tbl->correspondent_table= walk; // Remember corresponding table - - /* in case of subselects, we need to set lock_type in - * corresponding table in list of all tables */ - if (walk->correspondent_table) - { - target_tbl->correspondent_table= walk->correspondent_table; - walk->correspondent_table->lock_type= walk->lock_type; - } } DBUG_RETURN(FALSE); } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 1521b206e0d..759bf45da26 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1448,8 +1448,7 @@ static int mysql_test_multidelete(Prepared_statement *stmt, if (add_item_to_list(stmt->thd, new Item_null())) return -1; - uint fake_counter; - if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter))) + if ((res= multi_delete_precheck(stmt->thd, tables))) return res; if ((res= select_like_stmt_test_with_open_n_lock(stmt, tables, &mysql_multi_delete_prepare, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e0529da9302..e4f6b5a8513 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6132,10 +6132,17 @@ single_multi: | table_wild_list { mysql_init_multi_delete(Lex); } FROM join_table_list where_clause + { + if (multi_delete_set_locks_and_link_aux_tables(Lex)) + YYABORT; + } | FROM table_wild_list { mysql_init_multi_delete(Lex); } USING join_table_list where_clause - {} + { + if (multi_delete_set_locks_and_link_aux_tables(Lex)) + YYABORT; + } ; table_wild_list: From 9b2e653af0e34e2995fbac33b6ade81df86d4147 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Thu, 9 Jun 2005 01:46:30 +0400 Subject: [PATCH 6/9] Disable dynamic SQL in stored routines. This is to close Bug#10975, Bug#7115, Bug#10605 This feature will be implemented in a future release. --- mysql-test/r/sp-error.result | 14 ++++++++++++++ mysql-test/t/sp-error.test | 21 +++++++++++++++++++++ sql/sql_yacc.yy | 15 +++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 1dc97124a07..b6ba737a8ba 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -672,3 +672,17 @@ select default(t30.s1) from t30; end| drop procedure bug10969| drop table t1| +prepare stmt from "select 1"; +create procedure p() deallocate prepare stmt; +ERROR 0A000: DEALLOCATE is not allowed in stored procedures +create function f() returns int begin deallocate prepare stmt; +ERROR 0A000: DEALLOCATE is not allowed in stored procedures +create procedure p() prepare stmt from "select 1"; +ERROR 0A000: PREPARE is not allowed in stored procedures +create function f() returns int begin prepare stmt from "select 1"; +ERROR 0A000: PREPARE is not allowed in stored procedures +create procedure p() execute stmt; +ERROR 0A000: EXECUTE is not allowed in stored procedures +create function f() returns int begin execute stmt; +ERROR 0A000: EXECUTE is not allowed in stored procedures +deallocate prepare stmt; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 891e282e335..faf6d8b4de3 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -965,3 +965,24 @@ drop procedure bug10969| drop table t1| delimiter ;| + +# +# Bug#10975, #10605, #7115: Dynamic SQL by means of +# PREPARE/EXECUTE/DEALLOCATE is not supported yet. +# Check that an error message is returned. +# +prepare stmt from "select 1"; +--error ER_SP_BADSTATEMENT +create procedure p() deallocate prepare stmt; +--error ER_SP_BADSTATEMENT +create function f() returns int begin deallocate prepare stmt; +--error ER_SP_BADSTATEMENT +create procedure p() prepare stmt from "select 1"; +--error ER_SP_BADSTATEMENT +create function f() returns int begin prepare stmt from "select 1"; +--error ER_SP_BADSTATEMENT +create procedure p() execute stmt; +--error ER_SP_BADSTATEMENT +create function f() returns int begin execute stmt; +deallocate prepare stmt; + diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 719b42e890f..3c945570ac2 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -919,6 +919,11 @@ deallocate: yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "DEALLOCATE"); + YYABORT; + } lex->sql_command= SQLCOM_DEALLOCATE_PREPARE; lex->prepared_stmt_name= $3; }; @@ -939,6 +944,11 @@ prepare: yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "PREPARE"); + YYABORT; + } lex->sql_command= SQLCOM_PREPARE; lex->prepared_stmt_name= $2; }; @@ -969,6 +979,11 @@ execute: yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "EXECUTE"); + YYABORT; + } lex->sql_command= SQLCOM_EXECUTE; lex->prepared_stmt_name= $2; } From a5a13ea8c8a00927b15d760f94220c28986b75c1 Mon Sep 17 00:00:00 2001 From: "joreland@mysql.com" <> Date: Thu, 9 Jun 2005 08:07:48 +0200 Subject: [PATCH 7/9] ndb - autotest small script fixes - Don't use hostname -s as it's linux specific - Don't remove result unless scp worked --- ndb/test/run-test/ndb-autotest.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ndb/test/run-test/ndb-autotest.sh b/ndb/test/run-test/ndb-autotest.sh index 3ba4d1928d5..09087a8a8c7 100755 --- a/ndb/test/run-test/ndb-autotest.sh +++ b/ndb/test/run-test/ndb-autotest.sh @@ -13,7 +13,7 @@ save_args=$* VERSION="ndb-autotest.sh version 1.04" DATE=`date '+%Y-%m-%d'` -HOST=`hostname -s` +HOST=`hostname` export DATE HOST set -e @@ -330,7 +330,10 @@ start(){ tar cfz /tmp/res.$2.$$.tgz `basename $p2`/$DATE scp /tmp/res.$2.$$.tgz \ $result_host:$result_path/res.$DATE.$HOST.$2.$$.tgz - rm -f /tmp/res.$2.$$.tgz + if [ $? -eq 0 ] + then + rm -f /tmp/res.$2.$$.tgz + fi fi } From 14d74e75dbe5c081d77fc2f4e94f8cd4988ebebf Mon Sep 17 00:00:00 2001 From: "joreland@mysql.com" <> Date: Thu, 9 Jun 2005 15:39:14 +0200 Subject: [PATCH 8/9] bug#11205 - ndb - 4006 when starting scan --- mysql-test/r/ndb_subquery.result | 19 +++++ mysql-test/t/ndb_subquery.test | 23 ++++++ ndb/include/ndbapi/Ndb.hpp | 2 +- ndb/src/ndbapi/Ndb.cpp | 9 +++ ndb/src/ndbapi/NdbScanOperation.cpp | 4 + ndb/src/ndbapi/Ndbif.cpp | 8 +- ndb/src/ndbapi/Ndbinit.cpp | 2 +- ndb/src/ndbapi/Ndblist.cpp | 11 +-- ndb/test/ndbapi/testNdbApi.cpp | 102 ++++++++++++++++++++++++ ndb/test/run-test/daily-basic-tests.txt | 4 + sql/ha_ndbcluster.cc | 2 +- 11 files changed, 169 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/ndb_subquery.result b/mysql-test/r/ndb_subquery.result index f65f09b71b3..b19571b05c1 100644 --- a/mysql-test/r/ndb_subquery.result +++ b/mysql-test/r/ndb_subquery.result @@ -40,3 +40,22 @@ p u o 5 5 5 drop table t1; drop table t2; +create table t1 (p int not null primary key, u int not null) engine=ndb; +insert into t1 values (1,1),(2,2),(3,3); +create table t2 as +select t1.* +from t1 as t1, t1 as t2, t1 as t3, t1 as t4, t1 as t5, t1 as t6, t1 as t7, t1 as t8 +where t1.u = t2.u +and t2.u = t3.u +and t3.u = t4.u +and t4.u = t5.u +and t5.u = t6.u +and t6.u = t7.u +and t7.u = t8.u; +select * from t2 order by 1; +p u +1 1 +2 2 +3 3 +drop table t1; +drop table t2; diff --git a/mysql-test/t/ndb_subquery.test b/mysql-test/t/ndb_subquery.test index 9d3a256a263..095fdbcfa13 100644 --- a/mysql-test/t/ndb_subquery.test +++ b/mysql-test/t/ndb_subquery.test @@ -37,3 +37,26 @@ drop table t1; drop table t2; # bug#5367 ########## + +### +# bug#11205 +create table t1 (p int not null primary key, u int not null) engine=ndb; +insert into t1 values (1,1),(2,2),(3,3); + +create table t2 as +select t1.* +from t1 as t1, t1 as t2, t1 as t3, t1 as t4, t1 as t5, t1 as t6, t1 as t7, t1 as t8 +where t1.u = t2.u + and t2.u = t3.u + and t3.u = t4.u + and t4.u = t5.u + and t5.u = t6.u + and t6.u = t7.u + and t7.u = t8.u; + +select * from t2 order by 1; + +drop table t1; +drop table t2; + + diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp index 766409d64e2..0299d337757 100644 --- a/ndb/include/ndbapi/Ndb.hpp +++ b/ndb/include/ndbapi/Ndb.hpp @@ -1543,7 +1543,7 @@ private: Uint32 theNoOfPreparedTransactions; Uint32 theNoOfSentTransactions; Uint32 theNoOfCompletedTransactions; - Uint32 theNoOfAllocatedTransactions; + Uint32 theRemainingStartTransactions; Uint32 theMaxNoOfTransactions; Uint32 theMinNoOfEventsToWakeUp; diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index 1ae1030e463..43fb34b8b99 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -390,6 +390,14 @@ Ndb::startTransactionLocal(Uint32 aPriority, Uint32 nodeId) DBUG_ENTER("Ndb::startTransactionLocal"); DBUG_PRINT("enter", ("nodeid: %d", nodeId)); + if(unlikely(theRemainingStartTransactions == 0)) + { + theError.code = 4006; + DBUG_RETURN(0); + } + + theRemainingStartTransactions--; + NdbConnection* tConnection; Uint64 tFirstTransId = theFirstTransId; tConnection = doConnect(nodeId); @@ -446,6 +454,7 @@ Ndb::closeTransaction(NdbConnection* aConnection) CHECK_STATUS_MACRO_VOID; tCon = theTransactionList; + theRemainingStartTransactions++; DBUG_PRINT("info",("close trans: 0x%x transid: 0x%llx", aConnection, aConnection->getTransactionId())); diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index fc5a22cce17..4fee0e658f2 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -104,14 +104,17 @@ NdbScanOperation::init(const NdbTableImpl* tab, NdbConnection* myConnection) { m_transConnection = myConnection; //NdbConnection* aScanConnection = theNdb->startTransaction(myConnection); + theNdb->theRemainingStartTransactions++; // will be checked in hupp... NdbConnection* aScanConnection = theNdb->hupp(myConnection); if (!aScanConnection){ + theNdb->theRemainingStartTransactions--; setErrorCodeAbort(theNdb->getNdbError().code); return -1; } // NOTE! The hupped trans becomes the owner of the operation if(NdbOperation::init(tab, aScanConnection) != 0){ + theNdb->theRemainingStartTransactions--; return -1; } @@ -705,6 +708,7 @@ void NdbScanOperation::closeScan(bool forceSend, bool releaseOp) tCon->theScanningOp = 0; theNdb->closeTransaction(tCon); + theNdb->theRemainingStartTransactions--; } void diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp index 1caebe436ef..2d14e087f62 100644 --- a/ndb/src/ndbapi/Ndbif.cpp +++ b/ndb/src/ndbapi/Ndbif.cpp @@ -107,12 +107,10 @@ Ndb::init(int aMaxNoOfTransactions) goto error_handler; } - tMaxNoOfTransactions = aMaxNoOfTransactions * 3; - if (tMaxNoOfTransactions > 1024) { - tMaxNoOfTransactions = 1024; - }//if + + tMaxNoOfTransactions = aMaxNoOfTransactions; theMaxNoOfTransactions = tMaxNoOfTransactions; - + theRemainingStartTransactions= tMaxNoOfTransactions; thePreparedTransactionsArray = new NdbConnection* [tMaxNoOfTransactions]; theSentTransactionsArray = new NdbConnection* [tMaxNoOfTransactions]; theCompletedTransactionsArray = new NdbConnection* [tMaxNoOfTransactions]; diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index a11dd842495..43d4c7b0707 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -95,7 +95,7 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection, theNoOfPreparedTransactions= 0; theNoOfSentTransactions= 0; theNoOfCompletedTransactions= 0; - theNoOfAllocatedTransactions= 0; + theRemainingStartTransactions= 0; theMaxNoOfTransactions= 0; theMinNoOfEventsToWakeUp= 0; prefixEnd= NULL; diff --git a/ndb/src/ndbapi/Ndblist.cpp b/ndb/src/ndbapi/Ndblist.cpp index 5902aa413dc..4e6045f8058 100644 --- a/ndb/src/ndbapi/Ndblist.cpp +++ b/ndb/src/ndbapi/Ndblist.cpp @@ -94,7 +94,6 @@ Ndb::createConIdleList(int aNrOfCon) } tNdbCon->Status(NdbConnection::NotConnected); } - theNoOfAllocatedTransactions = aNrOfCon; return aNrOfCon; } @@ -194,14 +193,8 @@ Ndb::getNdbCon() { NdbConnection* tNdbCon; if ( theConIdleList == NULL ) { - if (theNoOfAllocatedTransactions < theMaxNoOfTransactions) { - tNdbCon = new NdbConnection(this); - if (tNdbCon == NULL) { - return NULL; - }//if - theNoOfAllocatedTransactions++; - } else { - ndbout << "theNoOfAllocatedTransactions = " << theNoOfAllocatedTransactions << " theMaxNoOfTransactions = " << theMaxNoOfTransactions << endl; + tNdbCon = new NdbConnection(this); + if (tNdbCon == NULL) { return NULL; }//if tNdbCon->next(NULL); diff --git a/ndb/test/ndbapi/testNdbApi.cpp b/ndb/test/ndbapi/testNdbApi.cpp index de731a5eeec..d38ac460dfb 100644 --- a/ndb/test/ndbapi/testNdbApi.cpp +++ b/ndb/test/ndbapi/testNdbApi.cpp @@ -1281,6 +1281,102 @@ int runBug_11133(NDBT_Context* ctx, NDBT_Step* step){ return result; } +int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){ + int result = NDBT_OK; + const Uint32 max= 5; + const NdbDictionary::Table* pTab = ctx->getTab(); + + Ndb* pNdb = new Ndb("TEST_DB"); + if (pNdb == NULL){ + ndbout << "pNdb == NULL" << endl; + return NDBT_FAILED; + } + if (pNdb->init(max)){ + ERR(pNdb->getNdbError()); + delete pNdb; + return NDBT_FAILED; + } + + NdbConnection* pCon = pNdb->startTransaction(); + if (pCon == NULL){ + pNdb->closeTransaction(pCon); + delete pNdb; + return NDBT_FAILED; + } + + Uint32 i; + Vector scans; + for(i = 0; i<10*max; i++) + { + NdbScanOperation* pOp = pCon->getNdbScanOperation(pTab->getName()); + if (pOp == NULL){ + ERR(pCon->getNdbError()); + pNdb->closeTransaction(pCon); + delete pNdb; + return NDBT_FAILED; + } + + NdbResultSet* rs; + if ((rs= pOp->readTuples()) == 0){ + pNdb->closeTransaction(pCon); + ERR(pOp->getNdbError()); + delete pNdb; + return NDBT_FAILED; + } + scans.push_back(rs); + } + + // Dont' call any equal or setValues + + // Execute should not work + int check = pCon->execute(NoCommit); + if (check == 0){ + ndbout << "execute worked" << endl; + } else { + ERR(pCon->getNdbError()); + } + + for(i= 0; inextResult()) == 0); + if(check != 1) + { + ERR(pOp->getOperation()->getNdbError()); + pNdb->closeTransaction(pCon); + delete pNdb; + return NDBT_FAILED; + } + } + + pNdb->closeTransaction(pCon); + + Vector cons; + for(i= 0; i<10*max; i++) + { + pCon= pNdb->startTransaction(); + if(pCon) + cons.push_back(pCon); + else + break; + } + + for(i= 0; iclose(); + } + + if(cons.size() != max) + { + result= NDBT_FAILED; + } + + delete pNdb; + + return result; +} + +template class Vector; NDBT_TESTSUITE(testNdbApi); @@ -1363,6 +1459,12 @@ TESTCASE("Bug_11133", INITIALIZER(runBug_11133); FINALIZER(runClearTable); } +TESTCASE("Scan_4006", + "Check that getNdbScanOperation does not get 4006\n"){ + INITIALIZER(runLoadTable); + INITIALIZER(runScan_4006); + FINALIZER(runClearTable); +} NDBT_TESTSUITE_END(testNdbApi); int main(int argc, const char** argv){ diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt index a28f8fe0bd0..9eb15a5c3d7 100644 --- a/ndb/test/run-test/daily-basic-tests.txt +++ b/ndb/test/run-test/daily-basic-tests.txt @@ -550,6 +550,10 @@ max-time: 500 cmd: testNdbApi args: -n Bug_11133 T1 +max-time: 500 +cmd: testNdbApi +args: -n Scan_4006 T1 + #max-time: 500 #cmd: testInterpreter #args: T1 diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index a0080af1dfb..18c061f7bec 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -41,7 +41,7 @@ static const int parallelism= 240; // Default value for max number of transactions // createable against NDB from this handler -static const int max_transactions= 256; +static const int max_transactions= 2; static const char *ha_ndb_ext=".ndb"; From b6fba9b40de7605b2074e393a2ef534de44e2411 Mon Sep 17 00:00:00 2001 From: "joreland@mysql.com" <> Date: Thu, 9 Jun 2005 16:11:34 +0200 Subject: [PATCH 9/9] merge --- ndb/test/ndbapi/testNdbApi.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/ndb/test/ndbapi/testNdbApi.cpp b/ndb/test/ndbapi/testNdbApi.cpp index 000fbcdd66a..137a1d51d82 100644 --- a/ndb/test/ndbapi/testNdbApi.cpp +++ b/ndb/test/ndbapi/testNdbApi.cpp @@ -1274,7 +1274,7 @@ int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){ const Uint32 max= 5; const NdbDictionary::Table* pTab = ctx->getTab(); - Ndb* pNdb = new Ndb("TEST_DB"); + Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; return NDBT_FAILED; @@ -1293,7 +1293,7 @@ int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){ } Uint32 i; - Vector scans; + Vector scans; for(i = 0; i<10*max; i++) { NdbScanOperation* pOp = pCon->getNdbScanOperation(pTab->getName()); @@ -1304,14 +1304,13 @@ int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - NdbResultSet* rs; - if ((rs= pOp->readTuples()) == 0){ + if (pOp->readTuples() != 0){ pNdb->closeTransaction(pCon); ERR(pOp->getNdbError()); delete pNdb; return NDBT_FAILED; } - scans.push_back(rs); + scans.push_back(pOp); } // Dont' call any equal or setValues @@ -1326,11 +1325,11 @@ int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){ for(i= 0; inextResult()) == 0); if(check != 1) { - ERR(pOp->getOperation()->getNdbError()); + ERR(pOp->getNdbError()); pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; @@ -1364,7 +1363,7 @@ int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){ return result; } -template class Vector; +template class Vector; NDBT_TESTSUITE(testNdbApi);