From 5b01a77c9c92dff6020c58d8c24f22f7659d3f16 Mon Sep 17 00:00:00 2001 From: "dkatz@damien-katzs-computer.local" <> Date: Mon, 22 Oct 2007 15:16:43 -0400 Subject: [PATCH 02/29] Bug #31332 --event-scheduler option misbehaving Changed the behaviour of the --event-scheduler option when used without an arguments. It now turns the option on. --- mysql-test/r/events_bugs.result | 4 ++++ mysql-test/t/events_bugs-master.opt | 1 + mysql-test/t/events_bugs.test | 15 +++++++++++++++ sql/events.cc | 2 +- 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 mysql-test/t/events_bugs-master.opt diff --git a/mysql-test/r/events_bugs.result b/mysql-test/r/events_bugs.result index b6b77101874..b0de2358777 100644 --- a/mysql-test/r/events_bugs.result +++ b/mysql-test/r/events_bugs.result @@ -3,6 +3,10 @@ drop database if exists mysqltest_db1; drop database if exists mysqltest_db2; create database events_test; use events_test; +select * from information_schema.global_variables where variable_name like 'event_scheduler'; +VARIABLE_NAME VARIABLE_VALUE +EVENT_SCHEDULER ON +SET GLOBAL event_scheduler = 'OFF'; CREATE EVENT lower_case ON SCHEDULE EVERY 1 MINUTE DO SELECT 1; CREATE EVENT Lower_case ON SCHEDULE EVERY 2 MINUTE DO SELECT 2; ERROR HY000: Event 'Lower_case' already exists diff --git a/mysql-test/t/events_bugs-master.opt b/mysql-test/t/events_bugs-master.opt new file mode 100644 index 00000000000..f93413a61e5 --- /dev/null +++ b/mysql-test/t/events_bugs-master.opt @@ -0,0 +1 @@ +--event-scheduler diff --git a/mysql-test/t/events_bugs.test b/mysql-test/t/events_bugs.test index ebd86f3a3d2..efdb67349ec 100644 --- a/mysql-test/t/events_bugs.test +++ b/mysql-test/t/events_bugs.test @@ -9,6 +9,21 @@ drop database if exists mysqltest_db2; create database events_test; use events_test; +# +# START: Bug #31332 --event-scheduler option misbehaving +# + +# NOTE!! this test must come first! It's testing that the --event-scheduler +# option with no argument in events_bugs-master.opt turns the scheduler on. + +select * from information_schema.global_variables where variable_name like 'event_scheduler'; + +SET GLOBAL event_scheduler = 'OFF'; + +# +# END: Bug #31332 +# + # # START - 16415: Events: event names are case sensitive # diff --git a/sql/events.cc b/sql/events.cc index 1bfbc5d6645..67249b40c79 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -146,7 +146,7 @@ bool Events::set_opt_event_scheduler(char *argument) { if (argument == NULL) - opt_event_scheduler= Events::EVENTS_DISABLED; + opt_event_scheduler= Events::EVENTS_ON; else { int type; From 5f33524d247729b31326f07ecf06c1325da44979 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Mon, 12 Nov 2007 14:44:17 +0300 Subject: [PATCH 03/29] Fix for a BUG#31898: 16M memory allocations for user variables in stored procedure. The problem was that MySQL used unnecessarily large amounts of memory if user variables were used as an argument to CONCAT or CONCAT_WS -- 16M per each user variable used. Technically, it happened because MySQL used the following allocation strategy for string functions to avoid multiple realloc() calls: in the virtual operation fix_length_and_dec() the attribute max_length was calculated as a sum of max_length values for each argument. Although this approach worked well for small (or fixed) data types, there could be a problem if there as a user variable among the arguments of a string function -- max_length of the function would be 16M (as the max_length of a user variable is 16M). Both CONCAT() and CONCAT_WS() functions suffer from this problem. The fix is to do not use meta-data for allocating memory. The following strategy is proposed instead: allocate the exact length of the result string at the first record, double the amount of memory allocated when it is required. No test case for this bug because there is no way to test memory consumption in a robust way with our test suite. --- sql/item_strfunc.cc | 60 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 03c65c9d654..a7624c5bbcd 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -356,10 +356,35 @@ String *Item_func_concat::val_str(String *str) } else { // Two big const strings - if (tmp_value.alloc(max_length) || - tmp_value.copy(*res) || - tmp_value.append(*res2)) + /* + NOTE: We should be prudent in the initial allocation unit -- the + size of the arguments is a function of data distribution, which + can be any. Instead of overcommitting at the first row, we grow + the allocated amount by the factor of 2. This ensures that no + more than 25% of memory will be overcommitted on average. + */ + + uint concat_len= res->length() + res2->length(); + + if (tmp_value.alloced_length() < concat_len) + { + if (tmp_value.alloced_length() == 0) + { + if (tmp_value.alloc(concat_len)) + goto null; + } + else + { + uint new_len = max(tmp_value.alloced_length() * 2, concat_len); + + if (tmp_value.realloc(new_len)) + goto null; + } + } + + if (tmp_value.copy(*res) || tmp_value.append(*res2)) goto null; + res= &tmp_value; use_as_buff=str; } @@ -679,8 +704,33 @@ String *Item_func_concat_ws::val_str(String *str) } else { // Two big const strings - if (tmp_value.alloc(max_length) || - tmp_value.copy(*res) || + /* + NOTE: We should be prudent in the initial allocation unit -- the + size of the arguments is a function of data distribution, which can + be any. Instead of overcommitting at the first row, we grow the + allocated amount by the factor of 2. This ensures that no more than + 25% of memory will be overcommitted on average. + */ + + uint concat_len= res->length() + sep_str->length() + res2->length(); + + if (tmp_value.alloced_length() < concat_len) + { + if (tmp_value.alloced_length() == 0) + { + if (tmp_value.alloc(concat_len)) + goto null; + } + else + { + uint new_len = max(tmp_value.alloced_length() * 2, concat_len); + + if (tmp_value.realloc(new_len)) + goto null; + } + } + + if (tmp_value.copy(*res) || tmp_value.append(*sep_str) || tmp_value.append(*res2)) goto null; From 99d33cd67a0d0e3224ae653692d6f73a6aedb1ac Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Mon, 12 Nov 2007 17:26:32 +0300 Subject: [PATCH 04/29] A patch for BUG#32172: information_schema test fails with wait_condition timeout. The problem was that the event thread didn't manage to execute the event in 30 seconds on highly-loaded box. The fix is to increase timeout. This is a fix for the test suite. --- mysql-test/t/information_schema.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 1987d9d5773..55334916913 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1142,6 +1142,7 @@ END$$ DELIMITER ;$$ +let $wait_timeout= 300; let $wait_condition=select count(*) = 0 from information_schema.events where event_name='event_status'; --source include/wait_condition.inc From 2ed0d9ea21120bf193f1a0189d61c211f33f17df Mon Sep 17 00:00:00 2001 From: "dkatz@damien-katzs-computer.local" <> Date: Wed, 14 Nov 2007 16:12:46 -0500 Subject: [PATCH 05/29] Bug#28785 thread-handling not displayed properly in SHOW VARIABLES --- mysql-test/r/no-threads.result | 3 +++ mysql-test/t/no-threads.test | 1 + sql/mysqld.cc | 5 +++-- sql/scheduler.h | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/no-threads.result b/mysql-test/r/no-threads.result index 50e52138be8..aefecd0f7bc 100644 --- a/mysql-test/r/no-threads.result +++ b/mysql-test/r/no-threads.result @@ -4,3 +4,6 @@ select 1+1; select 1+2; 1+2 3 +SHOW GLOBAL VARIABLES LIKE 'thread_handling'; +Variable_name Value +thread_handling no-threads diff --git a/mysql-test/t/no-threads.test b/mysql-test/t/no-threads.test index 806cf24e961..31ea6406ee9 100644 --- a/mysql-test/t/no-threads.test +++ b/mysql-test/t/no-threads.test @@ -3,3 +3,4 @@ # select 1+1; select 1+2; +SHOW GLOBAL VARIABLES LIKE 'thread_handling'; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4cf6e05751f..f65fee872ed 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7745,12 +7745,13 @@ mysqld_get_one_option(int optid, break; } case OPT_ONE_THREAD: - global_system_variables.thread_handling= 2; + global_system_variables.thread_handling= + SCHEDULER_ONE_THREAD_PER_CONNECTION; break; case OPT_THREAD_HANDLING: { global_system_variables.thread_handling= - find_type_or_exit(argument, &thread_handling_typelib, opt->name); + find_type_or_exit(argument, &thread_handling_typelib, opt->name)-1; break; } case OPT_FT_BOOLEAN_SYNTAX: diff --git a/sql/scheduler.h b/sql/scheduler.h index 8351cefda4c..46bbd300cbb 100644 --- a/sql/scheduler.h +++ b/sql/scheduler.h @@ -40,7 +40,7 @@ public: enum scheduler_types { - SCHEDULER_ONE_THREAD_PER_CONNECTION=1, + SCHEDULER_ONE_THREAD_PER_CONNECTION=0, SCHEDULER_NO_THREADS, SCHEDULER_POOL_OF_THREADS }; From e8343ca83df952a0901a5a1621130c4f89920f8b Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Thu, 15 Nov 2007 15:35:35 +0300 Subject: [PATCH 06/29] A patch for BUG#19723: kill of active connection yields different error code depending on platform. On Mac OS X, KILL statement issued to kill the current connection would return a different error code and message than on other platforms ('MySQL server has gone away' instead of 'Shutdown in progress'). The reason for this difference was that on Mac OS X we have macro SIGNAL_WITH_VIO_CLOSE defined. This macro forces KILL implementation to close the communication socket of the thread that is being killed. SIGNAL_WITH_VIO_CLOSE macro is defined on platforms where just sending a signal is not a reliable mechanism to interrupt the thread from sleeping on a blocking system call. In a nutshell, closing the socket is a hack to work around an operating system bug and awake the blocked thread no matter what. However, if the thread that is being killed is the same thread that issued KILL statement, closing the socket leads to a prematurely lost connection. At the same time it is not necessary to close the socket in this case, since the thread in question is not inside a blocking system call. The fix, therefore, is to not close the socket if the thread that is being killed is the same that issued KILL statement, even with defined SIGNAL_WITH_VIO_CLOSE. --- mysql-test/r/kill.result | 9 +++++++++ mysql-test/t/kill.test | 16 ++++++++++++++++ sql/sql_class.cc | 15 ++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result index a08be429a83..8376eb7c0de 100644 --- a/mysql-test/r/kill.result +++ b/mysql-test/r/kill.result @@ -125,3 +125,12 @@ drop function bug27563; drop procedure proc27563; PREPARE stmt FROM 'EXPLAIN SELECT * FROM t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40 WHERE a1=a2 AND a2=a3 AND a3=a4 AND a4=a5 AND a5=a6 AND a6=a7 AND a7=a8 AND a8=a9 AND a9=a10 AND a10=a11 AND a11=a12 AND a12=a13 AND a13=a14 AND a14=a15 AND a15=a16 AND a16=a17 AND a17=a18 AND a18=a19 AND a19=a20 AND a20=a21 AND a21=a22 AND a22=a23 AND a23=a24 AND a24=a25 AND a25=a26 AND a26=a27 AND a27=a28 AND a28=a29 AND a29=a30 AND a30=a31 AND a31=a32 AND a32=a33 AND a33=a34 AND a34=a35 AND a35=a36 AND a36=a37 AND a37=a38 AND a38=a39 AND a39=a40 '; EXECUTE stmt; +# +# Bug#19723: kill of active connection yields different error code +# depending on platform. +# + +# Connection: con2. +KILL CONNECTION_ID(); +SELECT 1; +ERROR HY000: Lost connection to MySQL server during query diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test index 5d5095f7d61..219412e5afa 100644 --- a/mysql-test/t/kill.test +++ b/mysql-test/t/kill.test @@ -304,3 +304,19 @@ while ($i) dec $i ; } --enable_query_log + +########################################################################### + +--echo # +--echo # Bug#19723: kill of active connection yields different error code +--echo # depending on platform. +--echo # + +--echo +--echo # Connection: con2. +--connection con2 + +KILL CONNECTION_ID(); + +--error 2013 +SELECT 1; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a904023cbff..368ed897a4d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -818,7 +818,20 @@ void THD::awake(THD::killed_state state_to_set) if (!slave_thread) thread_scheduler.post_kill_notification(this); #ifdef SIGNAL_WITH_VIO_CLOSE - close_active_vio(); + if (this != current_thd) + { + /* + In addition to a signal, let's close the socket of the thread that + is being killed. This is to make sure it does not block if the + signal is lost. This needs to be done only on platforms where + signals are not a reliable interruption mechanism. + + If we're killing ourselves, we know that we're not blocked, so this + hack is not used. + */ + + close_active_vio(); + } #endif } if (mysys_var) From 55cb6d64c3f9d22cb04bfab18cb26b6b5356df97 Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Fri, 16 Nov 2007 10:43:59 +0100 Subject: [PATCH 07/29] Bug#32429 ssl_cipher setting in my.cnf not read by libmysqlclient --- sql-common/client.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql-common/client.c b/sql-common/client.c index cb1d224ef2e..1fc73549520 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1085,11 +1085,16 @@ void mysql_read_default_options(struct st_mysql_options *options, my_free(options->ssl_capath, MYF(MY_ALLOW_ZERO_PTR)); options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME)); break; + case 26: /* ssl_cipher */ + my_free(options->ssl_cipher, MYF(MY_ALLOW_ZERO_PTR)); + options->ssl_cipher= my_strdup(opt_arg, MYF(MY_WME)); + break; #else case 13: /* Ignore SSL options */ case 14: case 15: case 16: + case 26: break; #endif /* HAVE_OPENSSL */ case 17: /* charset-lib */ From 1794242b24cc0f958af48db9019d95aed06cf589 Mon Sep 17 00:00:00 2001 From: "thek@adventure.(none)" <> Date: Mon, 19 Nov 2007 17:59:44 +0100 Subject: [PATCH 08/29] Bug #31153 calling stored procedure crashes server if available memory is low When the server was out of memory it crashed because of invalid memory access. This patch adds detection for failed memory allocations and make the server output a proper error message. --- sql/mysqld.cc | 14 ++++- sql/sp_head.cc | 38 +++++++++--- sql/sp_head.h | 6 +- sql/sql_base.cc | 3 +- sql/sql_lex.h | 5 +- sql/sql_prepare.cc | 2 +- sql/sql_yacc.yy | 149 +++++++++++++++++++++++++++++++++++---------- 7 files changed, 168 insertions(+), 49 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 08c2b60fa79..89d7f3272ad 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2489,7 +2489,12 @@ static int my_message_sql(uint error, const char *str, myf MyFlags) thd->query_error= 1; // needed to catch query errors during replication if (!thd->no_warnings_for_error) + { + thd->no_warnings_for_error= TRUE; push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str); + thd->no_warnings_for_error= FALSE; + } + /* thd->lex->current_select == 0 if lex structure is not inited (not query command (COM_QUERY)) @@ -4295,8 +4300,13 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused))) sock == unix_sock ? VIO_LOCALHOST: 0)) || my_net_init(&thd->net,vio_tmp)) { - if (vio_tmp) - vio_delete(vio_tmp); + /* + Only delete the temporary vio if we didn't already attach it to the + NET object. The destructor in THD will delete any initialized net + structure. + */ + if (vio_tmp && thd->net.vio != vio_tmp) + vio_delete(vio_tmp); else { (void) shutdown(new_sock, SHUT_RDWR); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 5ad6625efb8..3049ae5ccd3 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -411,14 +411,16 @@ check_routine_name(LEX_STRING ident) */ void * -sp_head::operator new(size_t size) +sp_head::operator new(size_t size) throw() { DBUG_ENTER("sp_head::operator new"); MEM_ROOT own_root; sp_head *sp; - init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC); + init_sql_alloc(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC); sp= (sp_head *) alloc_root(&own_root, size); + if (sp == NULL) + return NULL; sp->main_mem_root= own_root; DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root)); DBUG_RETURN(sp); @@ -429,6 +431,10 @@ sp_head::operator delete(void *ptr, size_t size) { DBUG_ENTER("sp_head::operator delete"); MEM_ROOT own_root; + + if (ptr == NULL) + DBUG_VOID_RETURN; + sp_head *sp= (sp_head *) ptr; /* Make a copy of main_mem_root as free_root will free the sp */ @@ -472,6 +478,9 @@ sp_head::init(LEX *lex) lex->spcont= m_pcont= new sp_pcontext(); + if (!lex->spcont) + DBUG_VOID_RETURN; + /* Altough trg_table_fields list is used only in triggers we init for all types of stored procedures to simplify reset_lex()/restore_lex() code. @@ -973,7 +982,7 @@ sp_head::execute(THD *thd) DBUG_RETURN(TRUE); /* init per-instruction memroot */ - init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0); + init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0); DBUG_ASSERT(!(m_flags & IS_INVOKED)); m_flags|= IS_INVOKED; @@ -1795,16 +1804,29 @@ sp_head::execute_procedure(THD *thd, List *args) } -// Reset lex during parsing, before we parse a sub statement. -void +/** + @brief Reset lex during parsing, before we parse a sub statement. + + @param thd Thread handler. + + @return Error state + @retval true An error occurred. + @retval false Success. +*/ + +bool sp_head::reset_lex(THD *thd) { DBUG_ENTER("sp_head::reset_lex"); LEX *sublex; LEX *oldlex= thd->lex; + sublex= new (thd->mem_root)st_lex_local; + if (sublex == 0) + DBUG_RETURN(TRUE); + + thd->lex= sublex; (void)m_lex.push_front(oldlex); - thd->lex= sublex= new st_lex; /* Reset most stuff. */ lex_start(thd); @@ -1827,7 +1849,7 @@ sp_head::reset_lex(THD *thd) sublex->interval_list.empty(); sublex->type= 0; - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } // Restore lex during parsing, after we have parsed a sub statement. @@ -3703,7 +3725,7 @@ sp_add_to_query_tables(THD *thd, LEX *lex, if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST)))) { - my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST)); + thd->fatal_error(); return NULL; } table->db_length= strlen(db); diff --git a/sql/sp_head.h b/sql/sp_head.h index ebe40ce9c87..cb243dd2503 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -191,10 +191,10 @@ public: Security_context m_security_ctx; static void * - operator new(size_t size); + operator new(size_t size) throw (); static void - operator delete(void *ptr, size_t size); + operator delete(void *ptr, size_t size) throw (); sp_head(); @@ -254,7 +254,7 @@ public: } // Resets lex in 'thd' and keeps a copy of the old one. - void + bool reset_lex(THD *thd); // Restores lex in 'thd' from our copy, but keeps some status from the diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 289924ff418..7ceed4e15d2 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -80,7 +80,6 @@ bool Prelock_error_handler::safely_trapped_errors() return ((m_handled_errors > 0) && (m_unhandled_errors == 0)); } - TABLE *unused_tables; /* Used by mysql_test */ HASH open_cache; /* Used by mysql_test */ @@ -2643,7 +2642,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) temporary mem_root for new .frm parsing. TODO: variables for size */ - init_alloc_root(&new_frm_mem, 8024, 8024); + init_sql_alloc(&new_frm_mem, 8024, 8024); thd->current_tablenr= 0; restart: diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ce56be79744..f216f51b0e4 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1283,11 +1283,11 @@ typedef struct st_lex : public Query_tables_list struct st_lex_local: public st_lex { - static void *operator new(size_t size) + static void *operator new(size_t size) throw() { return (void*) sql_alloc((uint) size); } - static void *operator new(size_t size, MEM_ROOT *mem_root) + static void *operator new(size_t size, MEM_ROOT *mem_root) throw() { return (void*) alloc_root(mem_root, (uint) size); } @@ -1303,3 +1303,4 @@ extern void lex_start(THD *thd); extern void lex_end(LEX *lex); extern int MYSQLlex(void *arg, void *yythd); extern char *skip_rear_comments(CHARSET_INFO *cs, char *begin, char *end); + diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index af3da834a7a..74cbd2c5505 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2659,7 +2659,7 @@ Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg) last_errno(0), flags((uint) IS_IN_USE) { - init_alloc_root(&main_mem_root, thd_arg->variables.query_alloc_block_size, + init_sql_alloc(&main_mem_root, thd_arg->variables.query_alloc_block_size, thd_arg->variables.query_prealloc_size); *last_error= '\0'; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 553cc6d24d5..3140ae4f7e3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1628,6 +1628,8 @@ create_function_tail: } /* Order is important here: new - reset - init */ sp= new sp_head(); + if (sp == NULL) + MYSQL_YYABORT; sp->reset_thd_mem_root(thd); sp->init(lex); sp->init_sp_name(thd, lex->spname); @@ -1929,7 +1931,8 @@ sp_decl: { LEX *lex= Lex; - lex->sphead->reset_lex(YYTHD); + if (lex->sphead->reset_lex(YYTHD)) + MYSQL_YYABORT; lex->spcont->declare_var_boundary($2); } type @@ -1937,6 +1940,10 @@ sp_decl: { LEX *lex= Lex; sp_pcontext *pctx= lex->spcont; + if (pctx == 0) + { + MYSQL_YYABORT; + } uint num_vars= pctx->context_var_count(); enum enum_field_types var_type= (enum enum_field_types) $4; Item *dflt_value_item= $5; @@ -2022,12 +2029,15 @@ sp_decl: { i= new sp_instr_hreturn(sp->instructions(), ctx, ctx->current_var_count()); + if (i == NULL ) + MYSQL_YYABORT; sp->add_instr(i); } else { /* EXIT or UNDO handler, just jump to the end of the block */ i= new sp_instr_hreturn(sp->instructions(), ctx, 0); - + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */ } @@ -2055,7 +2065,9 @@ sp_decl: } i= new sp_instr_cpush(sp->instructions(), ctx, $5, ctx->current_cursor_count()); - sp->add_instr(i); + if ( i==NULL ) + MYSQL_YYABORT; + sp->add_instr(i); ctx->push_cursor(&$2); $$.vars= $$.conds= $$.hndlrs= 0; $$.curs= 1; @@ -2064,7 +2076,8 @@ sp_decl: sp_cursor_stmt: { - Lex->sphead->reset_lex(YYTHD); + if(Lex->sphead->reset_lex(YYTHD)) + MYSQL_YYABORT; /* We use statement here just be able to get a better error message. Using 'select' works too, but will then @@ -2230,7 +2243,8 @@ sp_proc_stmt: LEX *lex= thd->lex; Lex_input_stream *lip= thd->m_lip; - lex->sphead->reset_lex(thd); + if (lex->sphead->reset_lex(thd)) + MYSQL_YYABORT; lex->sphead->m_tmp_query= lip->tok_start; } statement @@ -2255,9 +2269,10 @@ sp_proc_stmt: lex->var_list.is_empty()); if (lex->sql_command != SQLCOM_SET_OPTION) { - sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(), + sp_instr_stmt *i= new sp_instr_stmt(sp->instructions(), lex->spcont, lex); - + if (i == NULL) + MYSQL_YYABORT; /* Extract the query statement from the tokenizer. The end is either lex->ptr, if there was no lookahead, @@ -2275,7 +2290,10 @@ sp_proc_stmt: sp->restore_lex(thd); } | RETURN_SYM - { Lex->sphead->reset_lex(YYTHD); } + { + if(Lex->sphead->reset_lex(YYTHD)) + MYSQL_YYABORT; + } expr { LEX *lex= Lex; @@ -2292,6 +2310,8 @@ sp_proc_stmt: i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3, sp->m_return_field_def.sql_type, lex); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); sp->m_flags|= sp_head::HAS_RETURN; } @@ -2334,12 +2354,23 @@ sp_proc_stmt: uint n; n= ctx->diff_handlers(lab->ctx, TRUE); /* Exclusive the dest. */ + if (n) - sp->add_instr(new sp_instr_hpop(ip++, ctx, n)); + { + sp_instr_hpop *hpop= new sp_instr_hpop(ip++, ctx, n); + if (hpop == NULL) + MYSQL_YYABORT; + sp->add_instr(hpop); + } n= ctx->diff_cursors(lab->ctx, TRUE); /* Exclusive the dest. */ if (n) - sp->add_instr(new sp_instr_cpop(ip++, ctx, n)); + { + sp_instr_cpop *cpop= new sp_instr_cpop(ip++, ctx, n); + sp->add_instr(cpop); + } i= new sp_instr_jump(ip, ctx); + if (i == NULL) + MYSQL_YYABORT; sp->push_backpatch(i, lab); /* Jumping forward */ sp->add_instr(i); } @@ -2364,11 +2395,19 @@ sp_proc_stmt: n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */ if (n) - sp->add_instr(new sp_instr_hpop(ip++, ctx, n)); + { + sp_instr_hpop *hpop= new sp_instr_hpop(ip++, ctx, n); + sp->add_instr(hpop); + } n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */ if (n) - sp->add_instr(new sp_instr_cpop(ip++, ctx, n)); + { + sp_instr_cpop *cpop= new sp_instr_cpop(ip++, ctx, n); + sp->add_instr(cpop); + } i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */ + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); } } @@ -2385,6 +2424,8 @@ sp_proc_stmt: MYSQL_YYABORT; } i= new sp_instr_copen(sp->instructions(), lex->spcont, offset); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); } | FETCH_SYM sp_opt_fetch_noise ident INTO @@ -2400,6 +2441,8 @@ sp_proc_stmt: MYSQL_YYABORT; } i= new sp_instr_cfetch(sp->instructions(), lex->spcont, offset); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); } sp_fetch_list @@ -2417,6 +2460,8 @@ sp_proc_stmt: MYSQL_YYABORT; } i= new sp_instr_cclose(sp->instructions(), lex->spcont, offset); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); } ; @@ -2472,7 +2517,10 @@ sp_fetch_list: ; sp_if: - { Lex->sphead->reset_lex(YYTHD); } + { + if (Lex->sphead->reset_lex(YYTHD)) + MYSQL_YYABORT; + } expr THEN_SYM { LEX *lex= Lex; @@ -2481,7 +2529,8 @@ sp_if: uint ip= sp->instructions(); sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx, $2, lex); - + if (i == NULL) + MYSQL_YYABORT; sp->push_backpatch(i, ctx->push_label((char *)"", 0)); sp->add_cont_backpatch(i); sp->add_instr(i); @@ -2493,7 +2542,8 @@ sp_if: sp_pcontext *ctx= Lex->spcont; uint ip= sp->instructions(); sp_instr_jump *i = new sp_instr_jump(ip, ctx); - + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); sp->backpatch(ctx->pop_label()); sp->push_backpatch(i, ctx->push_label((char *)"", 0)); @@ -2522,7 +2572,8 @@ simple_case_stmt: { LEX *lex= Lex; case_stmt_action_case(lex); - lex->sphead->reset_lex(YYTHD); /* For expr $3 */ + if (lex->sphead->reset_lex(YYTHD)) + MYSQL_YYABORT; /* For expr $3 */ } expr { @@ -2571,7 +2622,8 @@ searched_when_clause_list: simple_when_clause: WHEN_SYM { - Lex->sphead->reset_lex(YYTHD); /* For expr $3 */ + if (Lex->sphead->reset_lex(YYTHD)) + MYSQL_YYABORT; /* For expr $3 */ } expr { @@ -2592,7 +2644,8 @@ simple_when_clause: searched_when_clause: WHEN_SYM { - Lex->sphead->reset_lex(YYTHD); /* For expr $3 */ + if (Lex->sphead->reset_lex(YYTHD)) + MYSQL_YYABORT; /* For expr $3 */ } expr { @@ -2616,6 +2669,8 @@ else_clause_opt: uint ip= sp->instructions(); sp_instr_error *i= new sp_instr_error(ip, lex->spcont, ER_SP_CASE_NOT_FOUND); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); } | ELSE sp_proc_stmts1 @@ -2685,11 +2740,21 @@ sp_unlabeled_control: sp->backpatch(ctx->last_label()); /* We always have a label */ if ($3.hndlrs) - sp->add_instr(new sp_instr_hpop(sp->instructions(), ctx, - $3.hndlrs)); + { + sp_instr_hpop *hpop= new sp_instr_hpop(sp->instructions(), ctx, + $3.hndlrs); + if (hpop == NULL) + MYSQL_YYABORT; + sp->add_instr(hpop); + } if ($3.curs) - sp->add_instr(new sp_instr_cpop(sp->instructions(), ctx, - $3.curs)); + { + sp_instr_cpop *cpop= new sp_instr_cpop(sp->instructions(), ctx, + $3.curs); + if (cpop == NULL) + MYSQL_YYABORT; + sp->add_instr(cpop); + } lex->spcont= ctx->pop_context(); } | LOOP_SYM @@ -2699,11 +2764,15 @@ sp_unlabeled_control: uint ip= lex->sphead->instructions(); sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */ sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip); - + if (i == NULL) + MYSQL_YYABORT; lex->sphead->add_instr(i); } | WHILE_SYM - { Lex->sphead->reset_lex(YYTHD); } + { + if (Lex->sphead->reset_lex(YYTHD)) + MYSQL_YYABORT; + } expr DO_SYM { LEX *lex= Lex; @@ -2711,7 +2780,8 @@ sp_unlabeled_control: uint ip= sp->instructions(); sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont, $3, lex); - + if (i == NULL) + MYSQL_YYABORT; /* Jumping forward */ sp->push_backpatch(i, lex->spcont->last_label()); sp->new_cont_backpatch(i); @@ -2724,12 +2794,16 @@ sp_unlabeled_control: uint ip= lex->sphead->instructions(); sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */ sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip); - + if (i == NULL) + MYSQL_YYABORT; lex->sphead->add_instr(i); lex->sphead->do_cont_backpatch(); } | REPEAT_SYM sp_proc_stmts1 UNTIL_SYM - { Lex->sphead->reset_lex(YYTHD); } + { + if (Lex->sphead->reset_lex(YYTHD)) + MYSQL_YYABORT; + } expr END REPEAT_SYM { LEX *lex= Lex; @@ -2738,6 +2812,8 @@ sp_unlabeled_control: sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont, $5, lab->ip, lex); + if (i == NULL) + MYSQL_YYABORT; lex->sphead->add_instr(i); lex->sphead->restore_lex(YYTHD); /* We can shortcut the cont_backpatch here */ @@ -4271,6 +4347,8 @@ select_init2: select_part2 { LEX *lex= Lex; + if (lex == NULL) + MYSQL_YYABORT; SELECT_LEX * sel= lex->current_select; if (lex->current_select->set_braces(0)) { @@ -4624,6 +4702,8 @@ predicate: $7->push_front($5); $7->push_front($1); Item_func_in *item = new (YYTHD->mem_root) Item_func_in(*$7); + if (item == NULL) + MYSQL_YYABORT; item->negate(); $$= item; } @@ -5084,7 +5164,8 @@ simple_expr: { LEX *lex= Lex; sp_name *name= new sp_name($1, $3, true); - + if (name == NULL) + MYSQL_YYABORT; name->init_qname(YYTHD); sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION); if ($5) @@ -5199,8 +5280,9 @@ simple_expr: if (lex->copy_db_to(&db.str, &db.length)) MYSQL_YYABORT; sp_name *name= new sp_name(db, $1, false); - if (name) - name->init_qname(thd); + if (name == NULL) + MYSQL_YYABORT; + name->init_qname(thd); sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION); if ($4) @@ -8422,7 +8504,8 @@ option_type_value: QQ: May be we should simply prohibit group assignments in SP? */ - Lex->sphead->reset_lex(thd); + if (Lex->sphead->reset_lex(thd)) + MYSQL_YYABORT; lex= thd->lex; /* Set new LEX as if we at start of set rule. */ @@ -8587,6 +8670,8 @@ sys_option_value: it= spv->dflt; else it= new Item_null(); + if (it == NULL) + MYSQL_YYABORT; sp_set= new sp_instr_set(lex->sphead->instructions(), ctx, spv->offset, it, spv->type, lex, TRUE); lex->sphead->add_instr(sp_set); @@ -9832,6 +9917,8 @@ sp_tail: /* Order is important here: new - reset - init */ sp= new sp_head(); + if (sp == NULL) + MYSQL_YYABORT; sp->reset_thd_mem_root(YYTHD); sp->init(lex); sp->m_type= TYPE_ENUM_PROCEDURE; From 94e6e4ff4451b9fc7e48bdaf26183ce057f40eed Mon Sep 17 00:00:00 2001 From: "davi@endora.local" <> Date: Tue, 20 Nov 2007 15:17:53 -0200 Subject: [PATCH 09/29] Bug#31397 Inconsistent drop table behavior of handler tables. The problem is that DROP TABLE and other DDL statements failed to automatically close handlers associated with tables that were marked for reopen (FLUSH TABLES). The current implementation fails to properly discard handlers of dropped tables (that were marked for reopen) because it searches on the open handler tables list and using the current alias of the table being dropped. The problem is that it must not use the open handler tables list to search because the table might have been closed (marked for reopen) by a flush tables command and also it must not use the current table alias at all since multiple different aliases may be associated with a single table. This is specially visible when a user has two open handlers (using alias) of a same table and a flush tables command is issued before the table is dropped (see test case). Scanning the handler table list is also useless for dropping handlers associated with temporary tables, because temporary tables are not kept in the THD::handler_tables list. The solution is to simple scan the handlers hash table searching for, and deleting all handlers with matching table names if the reopen flag is not passed to the flush function, indicating that the handlers should be deleted. All matching handlers are deleted even if the associated the table is not open. --- mysql-test/include/handler.inc | 94 +++++++++++ mysql-test/r/handler_innodb.result | 91 +++++++++++ mysql-test/r/handler_myisam.result | 91 +++++++++++ sql/mysql_priv.h | 9 +- sql/sql_base.cc | 8 +- sql/sql_class.cc | 4 +- sql/sql_handler.cc | 249 +++++++++++++---------------- sql/sql_rename.cc | 2 + sql/sql_table.cc | 18 +-- 9 files changed, 401 insertions(+), 165 deletions(-) diff --git a/mysql-test/include/handler.inc b/mysql-test/include/handler.inc index 79e21382d4c..485b2e881d3 100644 --- a/mysql-test/include/handler.inc +++ b/mysql-test/include/handler.inc @@ -598,3 +598,97 @@ handler a2 read a last; handler a2 read a prev; handler a2 close; drop table t1; + +# +# Bug#31397 Inconsistent drop table behavior of handler tables. +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings +create table t1 (a int); +handler t1 open as t1_alias; +drop table t1; +create table t1 (a int); +handler t1 open as t1_alias; +flush tables; +drop table t1; +create table t1 (a int); +handler t1 open as t1_alias; +handler t1_alias close; +drop table t1; +create table t1 (a int); +handler t1 open as t1_alias; +handler t1_alias read first; +drop table t1; +--error ER_UNKNOWN_TABLE +handler t1_alias read next; + +# Test that temporary tables associated with handlers are properly dropped. + +create table t1 (a int); +create temporary table t2 (a int, key(a)); +handler t1 open as a1; +handler t2 open as a2; +handler a2 read a first; +drop table t1, t2; +--error ER_UNKNOWN_TABLE +handler a2 read a next; +--error ER_UNKNOWN_TABLE +handler a1 close; + +# Alter table drop handlers + +create table t1 (a int, key(a)); +create table t2 like t1; +handler t1 open as a1; +handler t2 open as a2; +handler a1 read a first; +handler a2 read a first; +alter table t1 add b int; +--error ER_UNKNOWN_TABLE +handler a1 close; +handler a2 close; +drop table t1, t2; + +# Rename table drop handlers + +create table t1 (a int, key(a)); +handler t1 open as a1; +handler a1 read a first; +rename table t1 to t2; +--error ER_UNKNOWN_TABLE +handler a1 read a first; +drop table t2; + +# Optimize table drop handlers + +create table t1 (a int, key(a)); +create table t2 like t1; +handler t1 open as a1; +handler t2 open as a2; +handler a1 read a first; +handler a2 read a first; +optimize table t1; +--error ER_UNKNOWN_TABLE +handler a1 close; +handler a2 close; +drop table t1, t2; + +# Flush tables causes handlers reopen + +create table t1 (a int, b char(1), key a(a), key b(a,b)); +insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"), + (5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j"); +handler t1 open; +handler t1 read a first; +handler t1 read a next; +flush tables; +handler t1 read a next; +handler t1 read a next; +flush tables with read lock; +handler t1 read a next; +unlock tables; +drop table t1; +--error ER_UNKNOWN_TABLE +handler t1 read a next; diff --git a/mysql-test/r/handler_innodb.result b/mysql-test/r/handler_innodb.result index d9a1a0aa12b..9d269f78d10 100644 --- a/mysql-test/r/handler_innodb.result +++ b/mysql-test/r/handler_innodb.result @@ -637,3 +637,94 @@ a b 8 i handler a2 close; drop table t1; +drop table if exists t1,t2; +create table t1 (a int); +handler t1 open as t1_alias; +drop table t1; +create table t1 (a int); +handler t1 open as t1_alias; +flush tables; +drop table t1; +create table t1 (a int); +handler t1 open as t1_alias; +handler t1_alias close; +drop table t1; +create table t1 (a int); +handler t1 open as t1_alias; +handler t1_alias read first; +a +drop table t1; +handler t1_alias read next; +ERROR 42S02: Unknown table 't1_alias' in HANDLER +create table t1 (a int); +create temporary table t2 (a int, key(a)); +handler t1 open as a1; +handler t2 open as a2; +handler a2 read a first; +a +drop table t1, t2; +handler a2 read a next; +ERROR 42S02: Unknown table 'a2' in HANDLER +handler a1 close; +ERROR 42S02: Unknown table 'a1' in HANDLER +create table t1 (a int, key(a)); +create table t2 like t1; +handler t1 open as a1; +handler t2 open as a2; +handler a1 read a first; +a +handler a2 read a first; +a +alter table t1 add b int; +handler a1 close; +ERROR 42S02: Unknown table 'a1' in HANDLER +handler a2 close; +drop table t1, t2; +create table t1 (a int, key(a)); +handler t1 open as a1; +handler a1 read a first; +a +rename table t1 to t2; +handler a1 read a first; +ERROR 42S02: Unknown table 'a1' in HANDLER +drop table t2; +create table t1 (a int, key(a)); +create table t2 like t1; +handler t1 open as a1; +handler t2 open as a2; +handler a1 read a first; +a +handler a2 read a first; +a +optimize table t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +handler a1 close; +ERROR 42S02: Unknown table 'a1' in HANDLER +handler a2 close; +drop table t1, t2; +create table t1 (a int, b char(1), key a(a), key b(a,b)); +insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"), +(5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j"); +handler t1 open; +handler t1 read a first; +a b +0 a +handler t1 read a next; +a b +1 b +flush tables; +handler t1 read a next; +a b +0 a +handler t1 read a next; +a b +1 b +flush tables with read lock; +handler t1 read a next; +a b +0 a +unlock tables; +drop table t1; +handler t1 read a next; +ERROR 42S02: Unknown table 't1' in HANDLER diff --git a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result index b42fdc864fe..0b27b07c4d2 100644 --- a/mysql-test/r/handler_myisam.result +++ b/mysql-test/r/handler_myisam.result @@ -637,3 +637,94 @@ a b 8 i handler a2 close; drop table t1; +drop table if exists t1,t2; +create table t1 (a int); +handler t1 open as t1_alias; +drop table t1; +create table t1 (a int); +handler t1 open as t1_alias; +flush tables; +drop table t1; +create table t1 (a int); +handler t1 open as t1_alias; +handler t1_alias close; +drop table t1; +create table t1 (a int); +handler t1 open as t1_alias; +handler t1_alias read first; +a +drop table t1; +handler t1_alias read next; +ERROR 42S02: Unknown table 't1_alias' in HANDLER +create table t1 (a int); +create temporary table t2 (a int, key(a)); +handler t1 open as a1; +handler t2 open as a2; +handler a2 read a first; +a +drop table t1, t2; +handler a2 read a next; +ERROR 42S02: Unknown table 'a2' in HANDLER +handler a1 close; +ERROR 42S02: Unknown table 'a1' in HANDLER +create table t1 (a int, key(a)); +create table t2 like t1; +handler t1 open as a1; +handler t2 open as a2; +handler a1 read a first; +a +handler a2 read a first; +a +alter table t1 add b int; +handler a1 close; +ERROR 42S02: Unknown table 'a1' in HANDLER +handler a2 close; +drop table t1, t2; +create table t1 (a int, key(a)); +handler t1 open as a1; +handler a1 read a first; +a +rename table t1 to t2; +handler a1 read a first; +ERROR 42S02: Unknown table 'a1' in HANDLER +drop table t2; +create table t1 (a int, key(a)); +create table t2 like t1; +handler t1 open as a1; +handler t2 open as a2; +handler a1 read a first; +a +handler a2 read a first; +a +optimize table t1; +Table Op Msg_type Msg_text +test.t1 optimize status Table is already up to date +handler a1 close; +ERROR 42S02: Unknown table 'a1' in HANDLER +handler a2 close; +drop table t1, t2; +create table t1 (a int, b char(1), key a(a), key b(a,b)); +insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"), +(5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j"); +handler t1 open; +handler t1 read a first; +a b +0 a +handler t1 read a next; +a b +1 b +flush tables; +handler t1 read a next; +a b +0 a +handler t1 read a next; +a b +1 b +flush tables with read lock; +handler t1 read a next; +a b +0 a +unlock tables; +drop table t1; +handler t1 read a next; +ERROR 42S02: Unknown table 't1' in HANDLER diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 12838317646..f19e11357cd 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1289,12 +1289,9 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen); bool mysql_ha_close(THD *thd, TABLE_LIST *tables); bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, List *,enum ha_rkey_function,Item *,ha_rows,ha_rows); -int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, - bool is_locked); -/* mysql_ha_flush mode_flags bits */ -#define MYSQL_HA_CLOSE_FINAL 0x00 -#define MYSQL_HA_REOPEN_ON_USAGE 0x01 -#define MYSQL_HA_FLUSH_ALL 0x02 +void mysql_ha_flush(THD *thd); +void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables); +void mysql_ha_cleanup(THD *thd); /* sql_base.cc */ #define TMP_TABLE_KEY_EXTRA 8 diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 66d0cda2155..5e2b0285a1c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -929,8 +929,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, thd->proc_info="Flushing tables"; close_old_data_files(thd,thd->open_tables,1,1); - mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL, - TRUE); + mysql_ha_flush(thd); + bool found=1; /* Wait until all threads has closed all the tables we had locked */ DBUG_PRINT("info", @@ -2516,7 +2516,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, deadlock may occur. */ if (thd->handler_tables) - mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); + mysql_ha_flush(thd); /* Actually try to find the table in the open_cache. @@ -3136,7 +3136,7 @@ bool wait_for_tables(THD *thd) { thd->some_tables_deleted=0; close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0); - mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); + mysql_ha_flush(thd); if (!table_is_used(thd->open_tables,1)) break; (void) pthread_cond_wait(&COND_refresh,&LOCK_open); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a904023cbff..a8bac731b87 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -678,9 +678,7 @@ void THD::cleanup(void) lock=locked_tables; locked_tables=0; close_thread_tables(this); } - mysql_ha_flush(this, (TABLE_LIST*) 0, - MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL, FALSE); - hash_free(&handler_tables_hash); + mysql_ha_cleanup(this); delete_dynamic(&user_var_events); hash_free(&user_vars); close_temporary_tables(this); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 19a99f9d12b..31d6b28a73c 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -65,9 +65,6 @@ static enum enum_ha_read_modes rkey_to_rnext[]= { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV }; -static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags); - - /* Get hash key and hash key length. @@ -119,13 +116,15 @@ static void mysql_ha_hash_free(TABLE_LIST *tables) @param thd Thread identifier. @param tables A list of tables with the first entry to close. + @param is_locked If LOCK_open is locked. @note Though this function takes a list of tables, only the first list entry will be closed. - @note Broadcasts refresh if it closed the table. + @note Broadcasts refresh if it closed a table with old version. */ -static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables) +static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables, + bool is_locked) { TABLE **table_ptr; @@ -143,13 +142,15 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables) if (*table_ptr) { (*table_ptr)->file->ha_index_or_rnd_end(); - VOID(pthread_mutex_lock(&LOCK_open)); + if (! is_locked) + VOID(pthread_mutex_lock(&LOCK_open)); if (close_thread_table(thd, table_ptr)) { /* Tell threads waiting for refresh that something has happened */ broadcast_refresh(); } - VOID(pthread_mutex_unlock(&LOCK_open)); + if (! is_locked) + VOID(pthread_mutex_unlock(&LOCK_open)); } else if (tables->table) { @@ -305,7 +306,7 @@ err: if (hash_tables) my_free((char*) hash_tables, MYF(0)); if (tables->table) - mysql_ha_close_table(thd, tables); + mysql_ha_close_table(thd, tables, FALSE); DBUG_PRINT("exit",("ERROR")); DBUG_RETURN(TRUE); } @@ -339,7 +340,7 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables) (uchar*) tables->alias, strlen(tables->alias) + 1))) { - mysql_ha_close_table(thd, hash_tables); + mysql_ha_close_table(thd, hash_tables, FALSE); hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables); } else @@ -478,7 +479,7 @@ retry: if (need_reopen) { - mysql_ha_close_table(thd, tables); + mysql_ha_close_table(thd, tables, FALSE); hash_tables->table= NULL; /* The lock might have been aborted, we need to manually reset @@ -669,163 +670,131 @@ err0: } -/* - Flush (close) a list of HANDLER tables. +/** + Scan the handler tables hash for matching tables. - SYNOPSIS - mysql_ha_flush() - thd Thread identifier. - tables The list of tables to close. If NULL, - close all HANDLER tables [marked as flushed]. - mode_flags MYSQL_HA_CLOSE_FINAL finally close the table. - MYSQL_HA_REOPEN_ON_USAGE mark for reopen. - MYSQL_HA_FLUSH_ALL flush all tables, not only - those marked for flush. - is_locked If LOCK_open is locked. + @param thd Thread identifier. + @param tables The list of tables to remove. - DESCRIPTION - The list of HANDLER tables may be NULL, in which case all HANDLER - tables are closed (if MYSQL_HA_FLUSH_ALL) is set. - If 'tables' is NULL and MYSQL_HA_FLUSH_ALL is not set, - all HANDLER tables marked for flush are closed. - Broadcasts refresh for every table closed. - - NOTE - Since mysql_ha_flush() is called when the base table has to be closed, - we compare real table names, not aliases. Hence, database names matter. - - RETURN - 0 ok + @return Pointer to head of linked list (TABLE_LIST::next_local) of matching + TABLE_LIST elements from handler_tables_hash. Otherwise, NULL if no + table was matched. */ -int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, - bool is_locked) +static TABLE_LIST *mysql_ha_find(THD *thd, TABLE_LIST *tables) { - TABLE_LIST *tmp_tables; - TABLE **table_ptr; - bool did_lock= FALSE; - DBUG_ENTER("mysql_ha_flush"); - DBUG_PRINT("enter", ("tables: 0x%lx mode_flags: 0x%02x", - (long) tables, mode_flags)); + TABLE_LIST *hash_tables, *head= NULL, *first= tables; + DBUG_ENTER("mysql_ha_find"); - if (tables) + /* search for all handlers with matching table names */ + for (uint i= 0; i < thd->handler_tables_hash.records; i++) { - /* Close all tables in the list. */ - for (tmp_tables= tables ; tmp_tables; tmp_tables= tmp_tables->next_local) + hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i); + for (tables= first; tables; tables= tables->next_local) { - DBUG_PRINT("info-in-tables-list",("'%s'.'%s' as '%s'", - tmp_tables->db, tmp_tables->table_name, - tmp_tables->alias)); - /* Close all currently open handler tables with the same base table. */ - table_ptr= &(thd->handler_tables); - while (*table_ptr) - { - if ((!*tmp_tables->db || - !my_strcasecmp(&my_charset_latin1, (*table_ptr)->s->db.str, - tmp_tables->db)) && - ! my_strcasecmp(&my_charset_latin1, - (*table_ptr)->s->table_name.str, - tmp_tables->table_name)) - { - DBUG_PRINT("info",("*table_ptr '%s'.'%s' as '%s'", - (*table_ptr)->s->db.str, - (*table_ptr)->s->table_name.str, - (*table_ptr)->alias)); - /* The first time it is required, lock for close_thread_table(). */ - if (! did_lock && ! is_locked) - { - VOID(pthread_mutex_lock(&LOCK_open)); - did_lock= TRUE; - } - mysql_ha_flush_table(thd, table_ptr, mode_flags); - continue; - } - table_ptr= &(*table_ptr)->next; - } - /* end of handler_tables list */ + if ((! *tables->db || + ! my_strcasecmp(&my_charset_latin1, hash_tables->db, tables->db)) && + ! my_strcasecmp(&my_charset_latin1, hash_tables->table_name, + tables->table_name)) + break; } - /* end of flush tables list */ - } - else - { - /* Close all currently open tables [which are marked for flush]. */ - table_ptr= &(thd->handler_tables); - while (*table_ptr) + if (tables) { - if ((mode_flags & MYSQL_HA_FLUSH_ALL) || - (*table_ptr)->needs_reopen_or_name_lock()) - { - /* The first time it is required, lock for close_thread_table(). */ - if (! did_lock && ! is_locked) - { - VOID(pthread_mutex_lock(&LOCK_open)); - did_lock= TRUE; - } - mysql_ha_flush_table(thd, table_ptr, mode_flags); - continue; - } - table_ptr= &(*table_ptr)->next; + hash_tables->next_local= head; + head= hash_tables; } } - /* Release the lock if it was taken by this function. */ - if (did_lock) - VOID(pthread_mutex_unlock(&LOCK_open)); - - DBUG_RETURN(0); + DBUG_RETURN(head); } -/* - Flush (close) a table. - SYNOPSIS - mysql_ha_flush_table() - thd Thread identifier. - table The table to close. - mode_flags MYSQL_HA_CLOSE_FINAL finally close the table. - MYSQL_HA_REOPEN_ON_USAGE mark for reopen. +/** + Remove matching tables from the HANDLER's hash table. - DESCRIPTION - Broadcasts refresh if it closed the table. - The caller must lock LOCK_open. + @param thd Thread identifier. + @param tables The list of tables to remove. - RETURN - 0 ok + @note Broadcasts refresh if it closed a table with old version. */ -static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) +void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables) { - TABLE_LIST *hash_tables; - TABLE *table= *table_ptr; - DBUG_ENTER("mysql_ha_flush_table"); - DBUG_PRINT("enter",("'%s'.'%s' as '%s' flags: 0x%02x", - table->s->db.str, table->s->table_name.str, - table->alias, mode_flags)); + TABLE_LIST *hash_tables, *next; + DBUG_ENTER("mysql_ha_rm_tables"); - if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, - (uchar*) table->alias, - strlen(table->alias) + 1))) + safe_mutex_assert_not_owner(&LOCK_open); + + DBUG_ASSERT(tables); + + hash_tables= mysql_ha_find(thd, tables); + + while (hash_tables) { - if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE)) - { - /* This is a final close. Remove from hash. */ - hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables); - } - else + next= hash_tables->next_local; + if (hash_tables->table) + mysql_ha_close_table(thd, hash_tables, FALSE); + hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables); + hash_tables= next; + } + + DBUG_VOID_RETURN; +} + + +/** + Flush (close and mark for re-open) all tables that should be should + be reopen. + + @param thd Thread identifier. + + @note Broadcasts refresh if it closed a table with old version. +*/ + +void mysql_ha_flush(THD *thd) +{ + TABLE_LIST *hash_tables; + DBUG_ENTER("mysql_ha_flush"); + + safe_mutex_assert_owner(&LOCK_open); + + for (uint i= 0; i < thd->handler_tables_hash.records; i++) + { + hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i); + if (hash_tables->table && hash_tables->table->needs_reopen_or_name_lock()) { + mysql_ha_close_table(thd, hash_tables, TRUE); /* Mark table as closed, ready for re-open. */ hash_tables->table= NULL; } - } - - safe_mutex_assert_owner(&LOCK_open); - (*table_ptr)->file->ha_index_or_rnd_end(); - safe_mutex_assert_owner(&LOCK_open); - if (close_thread_table(thd, table_ptr)) - { - /* Tell threads waiting for refresh that something has happened */ - broadcast_refresh(); } - DBUG_RETURN(0); + DBUG_VOID_RETURN; } + + +/** + Close all HANDLER's tables. + + @param thd Thread identifier. + + @note Broadcasts refresh if it closed a table with old version. +*/ + +void mysql_ha_cleanup(THD *thd) +{ + TABLE_LIST *hash_tables; + DBUG_ENTER("mysql_ha_cleanup"); + + for (uint i= 0; i < thd->handler_tables_hash.records; i++) + { + hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i); + if (hash_tables->table) + mysql_ha_close_table(thd, hash_tables, FALSE); + } + + hash_free(&thd->handler_tables_hash); + + DBUG_VOID_RETURN; +} + diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 750bcd50479..66d89edc146 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -51,6 +51,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) DBUG_RETURN(1); } + mysql_ha_rm_tables(thd, table_list); + if (wait_if_global_read_lock(thd,0,1)) DBUG_RETURN(1); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index bf4a02ae5cc..9d26273e809 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1521,6 +1521,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, built_query.append("DROP TABLE "); } + mysql_ha_rm_tables(thd, tables); + pthread_mutex_lock(&LOCK_open); /* @@ -1562,8 +1564,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, handlerton *table_type; enum legacy_db_type frm_db_type; - mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL, 1); - error= drop_temporary_table(thd, table); switch (error) { @@ -1572,13 +1572,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, tmp_table_deleted= 1; continue; case -1: - // table already in use - /* - XXX: This branch should never be taken outside of SF, trigger or - prelocked mode. - - DBUG_ASSERT(thd->in_sub_stmt); - */ + DBUG_ASSERT(thd->in_sub_stmt); error= 1; goto err_with_placeholders; default: @@ -4025,7 +4019,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); - mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL, FALSE); + mysql_ha_rm_tables(thd, tables); + for (table= tables; table; table= table->next_local) { char table_name[NAME_LEN*2+2]; @@ -5766,8 +5761,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, build_table_filename(reg_path, sizeof(reg_path), db, table_name, reg_ext, 0); build_table_filename(path, sizeof(path), db, table_name, "", 0); - - mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL, FALSE); + mysql_ha_rm_tables(thd, table_list); /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ if (alter_info->tablespace_op != NO_TABLESPACE_OP) From d06b46e83fcbbf1d04e28db0ae734e3d1230abf2 Mon Sep 17 00:00:00 2001 From: "davi@endora.local" <> Date: Tue, 20 Nov 2007 17:45:49 -0200 Subject: [PATCH 10/29] This issue was fixed in Bug 30904 which includes a similar test case. --- mysql-test/t/sp_notembedded.test | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/mysql-test/t/sp_notembedded.test b/mysql-test/t/sp_notembedded.test index b5037b469ae..4a747b9c614 100644 --- a/mysql-test/t/sp_notembedded.test +++ b/mysql-test/t/sp_notembedded.test @@ -45,27 +45,9 @@ call bug4902_2()| call bug4902_2()| drop procedure bug4902_2| - -# Disable until bug#17244 is fixed ---disable_parsing # -# BUG#5278: Stored procedure packets out of order if SET PASSWORD. +# BUG#3583: query cache doesn't work for stored procedures # ---disable_warnings -drop function if exists bug5278| ---enable_warnings -create function bug5278 () returns char -begin - SET PASSWORD FOR 'bob'@'%.loc.gov' = PASSWORD('newpass'); - return 'okay'; -end| - ---error 1133 -select bug5278()| ---error 1133 -select bug5278()| -drop function bug5278| ---enable_parsing --disable_warnings drop table if exists t1| @@ -74,9 +56,6 @@ create table t1 ( id char(16) not null default '', data int not null )| -# -# BUG#3583: query cache doesn't work for stored procedures -# --disable_warnings drop procedure if exists bug3583| --enable_warnings From 04bf5743b4bbe67429f9ef6442f1b3e00e4bb45b Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Thu, 22 Nov 2007 03:48:51 +0300 Subject: [PATCH 11/29] Update the failing kill test in the team tree. --- mysql-test/r/kill.result | 4 +++- mysql-test/t/kill.test | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result index 8376eb7c0de..3ea5bbd20bc 100644 --- a/mysql-test/r/kill.result +++ b/mysql-test/r/kill.result @@ -132,5 +132,7 @@ EXECUTE stmt; # Connection: con2. KILL CONNECTION_ID(); +# CR_SERVER_LOST, CR_SERVER_GONE_ERROR, depending on the timing +# of close of the connection socket SELECT 1; -ERROR HY000: Lost connection to MySQL server during query +Got one of the listed errors diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test index 219412e5afa..3da4232502d 100644 --- a/mysql-test/t/kill.test +++ b/mysql-test/t/kill.test @@ -318,5 +318,7 @@ while ($i) KILL CONNECTION_ID(); ---error 2013 +--echo # CR_SERVER_LOST, CR_SERVER_GONE_ERROR, depending on the timing +--echo # of close of the connection socket +--error 2013, 2006 SELECT 1; From c9d81cabd3e384f7936c29eecc347cd66df58ced Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Thu, 22 Nov 2007 14:48:03 +0300 Subject: [PATCH 12/29] Add a test case for Bug#29817. The bug was fixed by the patch for Bug#28318. --- mysql-test/r/skip_grants.result | 6 ++++++ mysql-test/t/skip_grants.test | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/mysql-test/r/skip_grants.result b/mysql-test/r/skip_grants.result index 6bb8cbea2f1..38e017af7ad 100644 --- a/mysql-test/r/skip_grants.result +++ b/mysql-test/r/skip_grants.result @@ -72,3 +72,9 @@ count(*) select count(*) from information_schema.USER_PRIVILEGES; count(*) 0 +# +# Bug#29817 Queries with UDF fail with non-descriptive error +# if mysql.proc is missing +# +select no_such_function(1); +ERROR 42000: FUNCTION test.no_such_function does not exist diff --git a/mysql-test/t/skip_grants.test b/mysql-test/t/skip_grants.test index 5e0fc65bc34..8e543b9e38c 100644 --- a/mysql-test/t/skip_grants.test +++ b/mysql-test/t/skip_grants.test @@ -122,3 +122,9 @@ select count(*) from information_schema.COLUMN_PRIVILEGES; select count(*) from information_schema.SCHEMA_PRIVILEGES; select count(*) from information_schema.TABLE_PRIVILEGES; select count(*) from information_schema.USER_PRIVILEGES; +--echo # +--echo # Bug#29817 Queries with UDF fail with non-descriptive error +--echo # if mysql.proc is missing +--echo # +--error ER_SP_DOES_NOT_EXIST +select no_such_function(1); From 351c47415314cad3623be6689e4205bc6f31ca0c Mon Sep 17 00:00:00 2001 From: "davi@endora.local" <> Date: Thu, 22 Nov 2007 10:18:19 -0200 Subject: [PATCH 13/29] Bug#32528 Global read lock with a low priority write lock causes a server crash FLUSH TABLES WITH READ LOCK fails to properly detect write locked tables when running under low priority updates. The problem is that when trying to aspire a global read lock, the reload_acl_and_cache() function fails to properly check if the thread has a low priority write lock, which later my cause a server crash or deadlock. The solution is to simple check if the thread has any type of the possible exclusive write locks. --- mysql-test/r/flush.result | 17 +++++++++++++++++ mysql-test/t/flush.test | 31 +++++++++++++++++++++++++++++++ sql/sql_parse.cc | 2 +- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result index 7eb7fd16edb..ce64e09c1d3 100644 --- a/mysql-test/r/flush.result +++ b/mysql-test/r/flush.result @@ -55,3 +55,20 @@ flush tables with read lock; insert into t2 values(1); unlock tables; drop table t1, t2; +drop table if exists t1, t2; +set session low_priority_updates=1; +create table t1 (a int); +create table t2 (b int); +lock tables t1 write; +flush tables with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +unlock tables; +lock tables t1 read, t2 write; +flush tables with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +unlock tables; +lock tables t1 read; +flush tables with read lock; +unlock tables; +drop table t1, t2; +set session low_priority_updates=default; diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test index 3a4f2f2f5f2..72efa8a2ee6 100644 --- a/mysql-test/t/flush.test +++ b/mysql-test/t/flush.test @@ -133,4 +133,35 @@ disconnect con3; connection default; drop table t1, t2; +# +# Bug#32528 Global read lock with a low priority write lock causes a server crash +# + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + +set session low_priority_updates=1; + +create table t1 (a int); +create table t2 (b int); + +lock tables t1 write; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +flush tables with read lock; +unlock tables; + +lock tables t1 read, t2 write; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +flush tables with read lock; +unlock tables; + +lock tables t1 read; +flush tables with read lock; +unlock tables; + +drop table t1, t2; + +set session low_priority_updates=default; + # End of 5.0 tests diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0a8b92d28c0..e587a9f3561 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7054,7 +7054,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, for (; lock_p < end_p; lock_p++) { - if ((*lock_p)->type == TL_WRITE) + if ((*lock_p)->type >= TL_WRITE_ALLOW_WRITE) { my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); return 1; From 95bfde3d016b244d9d2cd8077401ece526484919 Mon Sep 17 00:00:00 2001 From: "thek@adventure.(none)" <> Date: Mon, 26 Nov 2007 15:44:05 +0100 Subject: [PATCH 14/29] Bug #32436 KILL QUERY completely deadlocks mysqld Sending several "KILL QUERY" statements to target a connection running "SELECT SLEEP" could freeze the server. The locking order in Item_func_sleep was wrong and this could lead to a dead lock. This patch solves the issue by resolving the locking order properly. --- sql/item_func.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sql/item_func.cc b/sql/item_func.cc index d03d497dfd0..a0824f2a146 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3732,13 +3732,12 @@ longlong Item_func_sleep::val_int() break; error= 0; } - + pthread_mutex_unlock(&LOCK_user_locks); pthread_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; pthread_mutex_unlock(&thd->mysys_var->mutex); - pthread_mutex_unlock(&LOCK_user_locks); pthread_cond_destroy(&cond); return test(!error); // Return 1 killed From cdad8669dfcc82515a83e188627d58f702a54aa5 Mon Sep 17 00:00:00 2001 From: "davi@mysql.com/endora.local" <> Date: Mon, 26 Nov 2007 14:09:37 -0200 Subject: [PATCH 15/29] Bug#29592 SQL Injection issue Remove the mysql_odbc_escape_string() function. The function has multi-byte character escaping issues, doesn't honor the NO_BACKSLASH_ESCAPES mode and is not used anymore by the Connector/ODBC as of 3.51.17. --- include/mysql.h | 10 - include/mysql_h.ic | 816 ++++++++++++++++++++-------------------- libmysql/libmysql.c | 72 ---- libmysql/libmysql.def | 1 - libmysqld/libmysqld.def | 1 - 5 files changed, 407 insertions(+), 493 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index b3e0dc45496..f2303abb241 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -550,16 +550,6 @@ unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); void STDCALL mysql_debug(const char *debug); -char * STDCALL mysql_odbc_escape_string(MYSQL *mysql, - char *to, - unsigned long to_length, - const char *from, - unsigned long from_length, - void *param, - char * - (*extend_buffer) - (void *, char *to, - unsigned long *length)); void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int STDCALL mysql_thread_safe(void); my_bool STDCALL mysql_embedded(void); diff --git a/include/mysql_h.ic b/include/mysql_h.ic index 5a9daee6f9f..1d4f3ce2758 100644 --- a/include/mysql_h.ic +++ b/include/mysql_h.ic @@ -32,65 +32,65 @@ enum mysql_option; enum mysql_protocol_type; enum mysql_rpl_type; enum mysql_status; -# 134 "mysql.h" +# 138 "mysql.h" typedef struct st_mysql_rows MYSQL_ROWS; -# 24 "my_list.h" +# 23 "my_list.h" typedef struct st_list LIST; -# 35 "my_alloc.h" +# 34 "my_alloc.h" typedef struct st_mem_root MEM_ROOT; -# 251 "mysql.h" +# 255 "mysql.h" typedef struct st_mysql MYSQL; -# 653 "mysql.h" +# 647 "mysql.h" typedef struct st_mysql_bind MYSQL_BIND; -# 93 "mysql.h" +# 97 "mysql.h" typedef struct st_mysql_field MYSQL_FIELD; -# 117 "mysql.h" +# 121 "mysql.h" typedef unsigned int MYSQL_FIELD_OFFSET; -# 340 "mysql.h" +# 344 "mysql.h" typedef struct st_mysql_manager MYSQL_MANAGER; -# 354 "mysql.h" +# 358 "mysql.h" typedef struct st_mysql_parameters MYSQL_PARAMETERS; -# 309 "mysql.h" +# 313 "mysql.h" typedef struct st_mysql_res MYSQL_RES; -# 116 "mysql.h" +# 120 "mysql.h" typedef char * * MYSQL_ROW; -# 140 "mysql.h" -typedef MYSQL_ROWS * MYSQL_ROW_OFFSET; -# 681 "mysql.h" -typedef struct st_mysql_stmt MYSQL_STMT; -# 236 "mysql.h" -typedef struct character_set MY_CHARSET_INFO; -# 180 "mysql_com.h" -typedef struct st_net NET; -# 23 "typelib.h" -typedef struct st_typelib TYPELIB; -# 170 "mysql_com.h" -typedef struct st_vio Vio; -# 57 "mysql.h" -typedef char * gptr; -# 29 "my_list.h" -typedef int (* list_walk_action)(void *, void *); -# 48 "mysql.h" -typedef char my_bool; -# 63 "mysql.h" -typedef int my_socket; -# 125 "mysql.h" -typedef unsigned long long int my_ulonglong; # 144 "mysql.h" +typedef MYSQL_ROWS * MYSQL_ROW_OFFSET; +# 675 "mysql.h" +typedef struct st_mysql_stmt MYSQL_STMT; +# 240 "mysql.h" +typedef struct character_set MY_CHARSET_INFO; +# 179 "mysql_com.h" +typedef struct st_net NET; +# 22 "typelib.h" +typedef struct st_typelib TYPELIB; +# 169 "mysql_com.h" +typedef struct st_vio Vio; +# 60 "mysql.h" +typedef char * gptr; +# 28 "my_list.h" +typedef int (* list_walk_action)(void *, void *); +# 51 "mysql.h" +typedef char my_bool; +# 66 "mysql.h" +typedef int my_socket; +# 129 "mysql.h" +typedef unsigned long long int my_ulonglong; +# 148 "mysql.h" typedef struct embedded_query_result EMBEDDED_QUERY_RESULT; -# 145 "mysql.h" +# 149 "mysql.h" typedef struct st_mysql_data MYSQL_DATA; -# 750 "mysql.h" +# 744 "mysql.h" typedef struct st_mysql_methods MYSQL_METHODS; -# 48 "mysql_time.h" +# 47 "mysql_time.h" typedef struct st_mysql_time MYSQL_TIME; -# 371 "mysql_com.h" +# 375 "mysql_com.h" typedef struct st_udf_args UDF_ARGS; -# 384 "mysql_com.h" +# 388 "mysql_com.h" typedef struct st_udf_init UDF_INIT; -# 27 "my_alloc.h" +# 26 "my_alloc.h" typedef struct st_used_mem USED_MEM; -# 236 "mysql.h" +# 240 "mysql.h" struct __attribute__((aligned(__alignof__(unsigned int)), aligned(__alignof__(void *)))) character_set { unsigned int number; @@ -102,7 +102,7 @@ struct __attribute__((aligned(__alignof__(unsigned int)), aligned(__alignof__(vo unsigned int mbminlen; unsigned int mbmaxlen; }; -# 357 "mysql_com.h" +# 361 "mysql_com.h" struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof__(double)))) rand_struct { unsigned long int seed1; @@ -110,14 +110,14 @@ struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof unsigned long int max_value; double max_value_dbl; }; -# 24 "my_list.h" +# 23 "my_list.h" struct __attribute__((aligned(__alignof__(void *)))) st_list { struct st_list * prev; struct st_list * next; void * data; }; -# 35 "my_alloc.h" +# 34 "my_alloc.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned int)))) st_mem_root { USED_MEM * free; @@ -129,7 +129,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned unsigned int first_block_usage; void (* error_handler)(void); }; -# 251 "mysql.h" +# 255 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long long int)))) st_mysql { NET net; @@ -173,7 +173,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned void * thd; my_bool * unbuffered_fetch_owner; }; -# 653 "mysql.h" +# 647 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_bind { unsigned long int * length; @@ -195,7 +195,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned void (* fetch_result)(struct st_mysql_bind *, MYSQL_FIELD *, unsigned char * * row); void (* skip_result)(struct st_mysql_bind *, MYSQL_FIELD *, unsigned char * * row); }; -# 145 "mysql.h" +# 149 "mysql.h" struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__alignof__(void *)))) st_mysql_data { my_ulonglong rows; @@ -204,7 +204,7 @@ struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__al MEM_ROOT alloc; struct embedded_query_result * embedded_info; }; -# 93 "mysql.h" +# 97 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_field { char * name; @@ -228,7 +228,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned unsigned int charsetnr; enum enum_field_types type; }; -# 340 "mysql.h" +# 344 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_manager { NET net; @@ -246,7 +246,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned int net_buf_size; char last_error[256]; }; -# 750 "mysql.h" +# 744 "mysql.h" struct __attribute__((aligned(__alignof__(void *)))) st_mysql_methods { my_bool (* read_query_result)(MYSQL * mysql); @@ -266,7 +266,7 @@ struct __attribute__((aligned(__alignof__(void *)))) st_mysql_methods int (* read_change_user_result)(MYSQL * mysql, char * buff, char const * passwd); int (* read_rows_from_cursor)(MYSQL_STMT * stmt); }; -# 167 "mysql.h" +# 171 "mysql.h" struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof__(void *)))) st_mysql_options { unsigned int connect_timeout; @@ -309,13 +309,13 @@ struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof int (* local_infile_error)(void *, char *, unsigned int); void * local_infile_userdata; }; -# 354 "mysql.h" +# 358 "mysql.h" struct __attribute__((aligned(__alignof__(void *)))) st_mysql_parameters { unsigned long int * p_max_allowed_packet; unsigned long int * p_net_buffer_length; }; -# 309 "mysql.h" +# 313 "mysql.h" struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__alignof__(void *)))) st_mysql_res { my_ulonglong row_count; @@ -333,14 +333,14 @@ struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__al my_bool unbuffered_fetch_cancelled; struct st_mysql_methods const * methods; }; -# 134 "mysql.h" +# 138 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_rows { struct st_mysql_rows * next; MYSQL_ROW data; unsigned long int length; }; -# 681 "mysql.h" +# 675 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long long int)))) st_mysql_stmt { MEM_ROOT mem_root; @@ -370,7 +370,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned my_bool unbuffered_fetch_cancelled; my_bool update_max_length; }; -# 48 "mysql_time.h" +# 47 "mysql_time.h" struct __attribute__((aligned(__alignof__(unsigned long int)))) st_mysql_time { unsigned int year; @@ -383,7 +383,7 @@ struct __attribute__((aligned(__alignof__(unsigned long int)))) st_mysql_time my_bool neg; enum enum_mysql_timestamp_type time_type; }; -# 180 "mysql_com.h" +# 179 "mysql_com.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_net { Vio * vio; @@ -419,7 +419,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned my_bool report_error; my_bool return_errno; }; -# 23 "typelib.h" +# 22 "typelib.h" struct __attribute__((aligned(__alignof__(unsigned int)), aligned(__alignof__(void *)))) st_typelib { unsigned int count; @@ -427,7 +427,7 @@ struct __attribute__((aligned(__alignof__(unsigned int)), aligned(__alignof__(vo char const * * type_names; unsigned int * type_lengths; }; -# 371 "mysql_com.h" +# 375 "mysql_com.h" struct __attribute__((aligned(__alignof__(unsigned int)), aligned(__alignof__(void *)))) st_udf_args { unsigned int arg_count; @@ -438,7 +438,7 @@ struct __attribute__((aligned(__alignof__(unsigned int)), aligned(__alignof__(vo char * * attributes; unsigned long int * attribute_lengths; }; -# 384 "mysql_com.h" +# 388 "mysql_com.h" struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof__(void *)))) st_udf_init { my_bool maybe_null; @@ -447,14 +447,14 @@ struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof char * ptr; my_bool const_item; }; -# 27 "my_alloc.h" +# 26 "my_alloc.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned int)))) st_used_mem { struct st_used_mem * next; unsigned int left; unsigned int size; }; -# 368 "mysql_com.h" +# 372 "mysql_com.h" enum Item_result { STRING_RESULT = 0, @@ -463,7 +463,7 @@ enum Item_result ROW_RESULT = 3, DECIMAL_RESULT = 4, }; -# 314 "mysql_com.h" +# 313 "mysql_com.h" enum enum_cursor_type { CURSOR_TYPE_NO_CURSOR = 0, @@ -471,7 +471,7 @@ enum enum_cursor_type CURSOR_TYPE_FOR_UPDATE = 2, CURSOR_TYPE_SCROLLABLE = 4, }; -# 227 "mysql_com.h" +# 226 "mysql_com.h" enum enum_field_types { MYSQL_TYPE_DECIMAL = 0, @@ -502,13 +502,13 @@ enum enum_field_types MYSQL_TYPE_STRING = 254, MYSQL_TYPE_GEOMETRY = 255, }; -# 324 "mysql_com.h" +# 323 "mysql_com.h" enum enum_mysql_set_option { MYSQL_OPTION_MULTI_STATEMENTS_ON = 0, MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1, }; -# 583 "mysql.h" +# 577 "mysql.h" enum enum_mysql_stmt_state { MYSQL_STMT_INIT_DONE = 1, @@ -516,7 +516,7 @@ enum enum_mysql_stmt_state MYSQL_STMT_EXECUTE_DONE = 3, MYSQL_STMT_FETCH_DONE = 4, }; -# 29 "mysql_time.h" +# 28 "mysql_time.h" enum enum_mysql_timestamp_type { MYSQL_TIMESTAMP_NONE = -(2), @@ -525,7 +525,7 @@ enum enum_mysql_timestamp_type MYSQL_TIMESTAMP_DATETIME = 1, MYSQL_TIMESTAMP_TIME = 2, }; -# 52 "mysql_com.h" +# 51 "mysql_com.h" enum enum_server_command { COM_SLEEP = 0, @@ -559,14 +559,14 @@ enum enum_server_command COM_STMT_FETCH = 28, COM_END = 29, }; -# 727 "mysql.h" +# 721 "mysql.h" enum enum_stmt_attr_type { STMT_ATTR_UPDATE_MAX_LENGTH = 0, STMT_ATTR_CURSOR_TYPE = 1, STMT_ATTR_PREFETCH_ROWS = 2, }; -# 289 "mysql_com.h" +# 288 "mysql_com.h" enum mysql_enum_shutdown_level { SHUTDOWN_DEFAULT = 0, @@ -578,7 +578,7 @@ enum mysql_enum_shutdown_level KILL_QUERY = 254, KILL_CONNECTION = 255, }; -# 154 "mysql.h" +# 158 "mysql.h" enum mysql_option { MYSQL_OPT_CONNECT_TIMEOUT = 0, @@ -604,7 +604,7 @@ enum mysql_option MYSQL_OPT_RECONNECT = 20, MYSQL_OPT_SSL_VERIFY_SERVER_CERT = 21, }; -# 221 "mysql.h" +# 225 "mysql.h" enum mysql_protocol_type { MYSQL_PROTOCOL_DEFAULT = 0, @@ -613,357 +613,355 @@ enum mysql_protocol_type MYSQL_PROTOCOL_PIPE = 3, MYSQL_PROTOCOL_MEMORY = 4, }; -# 231 "mysql.h" +# 235 "mysql.h" enum mysql_rpl_type { MYSQL_RPL_MASTER = 0, MYSQL_RPL_SLAVE = 1, MYSQL_RPL_ADMIN = 2, }; -# 216 "mysql.h" +# 220 "mysql.h" enum mysql_status { MYSQL_STATUS_READY = 0, MYSQL_STATUS_GET_RESULT = 1, MYSQL_STATUS_USE_RESULT = 2, }; -# 423 "mysql_com.h" -extern my_bool check_scramble(char const * reply, char const * message, unsigned char const * hash_stage2); -# 416 "mysql_com.h" -extern my_bool check_scramble_323(char const *, char const * message, unsigned long int * salt); -# 33 "typelib.h" -extern TYPELIB * copy_typelib(MEM_ROOT * root, TYPELIB * from); -# 411 "mysql_com.h" -extern void create_random_string(char * to, unsigned int, struct rand_struct * rand_st); -# 30 "typelib.h" -extern int find_type(char * x, TYPELIB * typelib, unsigned int); -# 425 "mysql_com.h" -extern void get_salt_from_password(unsigned char * res, char const * password); -# 418 "mysql_com.h" -extern void get_salt_from_password_323(unsigned long int * res, char const * password); -# 431 "mysql_com.h" -extern char * get_tty_password(char * opt_message); -# 32 "typelib.h" -extern char const * get_type(TYPELIB * typelib, unsigned int); -# 413 "mysql_com.h" -extern void hash_password(unsigned long int * to, char const * password, unsigned int); -# 31 "my_list.h" -extern LIST * list_add(LIST * root, LIST * element); -# 33 "my_list.h" -extern LIST * list_cons(void * data, LIST * root); -# 32 "my_list.h" -extern LIST * list_delete(LIST * root, LIST * element); -# 35 "my_list.h" -extern void list_free(LIST * root, unsigned int); -# 36 "my_list.h" -extern unsigned int list_length(LIST *); -# 34 "my_list.h" -extern LIST * list_reverse(LIST * root); -# 37 "my_list.h" -extern int list_walk(LIST *, list_walk_action, gptr); -# 440 "mysql_com.h" -extern int load_defaults(char const * conf_file, char const * * groups, int * argc, char * * * argv); -# 426 "mysql_com.h" -extern void make_password_from_salt(char * to, unsigned char const * hash_stage2); -# 419 "mysql_com.h" -extern void make_password_from_salt_323(char * to, unsigned long int const * salt); -# 421 "mysql_com.h" -extern void make_scrambled_password(char * to, char const * password); -# 414 "mysql_com.h" -extern void make_scrambled_password_323(char * to, char const * password); -# 31 "typelib.h" -extern void make_type(char * to, unsigned int, TYPELIB * typelib); -# 437 "mysql_com.h" -extern int modify_defaults_file(char const * file_location, char const * option, char const * option_value, char const * section_name, int); -# 354 "mysql_com.h" -extern int my_connect(my_socket, struct sockaddr const * name, unsigned int, unsigned int); -# 436 "mysql_com.h" -extern my_bool my_init(void); -# 336 "mysql_com.h" -extern my_bool my_net_init(NET * net, Vio * vio); -# 337 "mysql_com.h" -extern void my_net_local_init(NET * net); -# 347 "mysql_com.h" -extern unsigned long int my_net_read(NET * net); -# 342 "mysql_com.h" -extern my_bool my_net_write(NET * net, char const * packet, unsigned long int); -# 410 "mysql_com.h" -extern double my_rnd(struct rand_struct *); -# 443 "mysql_com.h" -extern void my_thread_end(void); -# 442 "mysql_com.h" -extern my_bool my_thread_init(void); -# 559 "mysql.h" -extern void myodbc_remove_escape(MYSQL * mysql, char * name); -# 501 "mysql.h" -extern int mysql_add_slave(MYSQL * mysql, char const * host, unsigned int, char const * user, char const * passwd); -# 410 "mysql.h" -extern my_ulonglong mysql_affected_rows(MYSQL * mysql); -# 823 "mysql.h" -extern my_bool mysql_autocommit(MYSQL * mysql, my_bool); -# 426 "mysql.h" -extern my_bool mysql_change_user(MYSQL * mysql, char const * user, char const * passwd, char const * db); -# 418 "mysql.h" -extern char const * mysql_character_set_name(MYSQL * mysql); -# 826 "mysql.h" -extern void mysql_close(MYSQL * sock); -# 821 "mysql.h" -extern my_bool mysql_commit(MYSQL * mysql); -# 530 "mysql.h" -extern void mysql_data_seek(MYSQL_RES * result, my_ulonglong); -# 548 "mysql.h" -extern void mysql_debug(char const * debug); -# 487 "mysql.h" -extern void mysql_disable_reads_from_master(MYSQL * mysql); -# 481 "mysql.h" -extern void mysql_disable_rpl_parse(MYSQL * mysql); -# 509 "mysql.h" -extern int mysql_dump_debug_info(MYSQL * mysql); -# 561 "mysql.h" -extern my_bool mysql_embedded(void); -# 486 "mysql.h" -extern void mysql_enable_reads_from_master(MYSQL * mysql); -# 480 "mysql.h" -extern void mysql_enable_rpl_parse(MYSQL * mysql); -# 402 "mysql.h" -extern my_bool mysql_eof(MYSQL_RES * res); -# 412 "mysql.h" -extern unsigned int mysql_errno(MYSQL * mysql); -# 432 "mysql_com.h" -extern char const * mysql_errno_to_sqlstate(unsigned int); -# 413 "mysql.h" -extern char const * mysql_error(MYSQL * mysql); -# 541 "mysql.h" -extern unsigned long int mysql_escape_string(char * to, char const * from, unsigned long int); -# 538 "mysql.h" -extern MYSQL_FIELD * mysql_fetch_field(MYSQL_RES * result); -# 403 "mysql.h" -extern MYSQL_FIELD * mysql_fetch_field_direct(MYSQL_RES * res, unsigned int); -# 405 "mysql.h" -extern MYSQL_FIELD * mysql_fetch_fields(MYSQL_RES * res); -# 537 "mysql.h" -extern unsigned long int * mysql_fetch_lengths(MYSQL_RES * result); -# 536 "mysql.h" -extern MYSQL_ROW mysql_fetch_row(MYSQL_RES * result); -# 409 "mysql.h" -extern unsigned int mysql_field_count(MYSQL * mysql); -# 534 "mysql.h" -extern MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES * result, MYSQL_FIELD_OFFSET); -# 407 "mysql.h" -extern MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES * res); -# 529 "mysql.h" -extern void mysql_free_result(MYSQL_RES * result); -# 454 "mysql.h" -extern void mysql_get_character_set_info(MYSQL * mysql, MY_CHARSET_INFO * charset); -# 519 "mysql.h" -extern char const * mysql_get_client_info(void); -# 520 "mysql.h" -extern unsigned long int mysql_get_client_version(void); -# 521 "mysql.h" -extern char const * mysql_get_host_info(MYSQL * mysql); -# 384 "mysql.h" -extern MYSQL_PARAMETERS * mysql_get_parameters(void); -# 523 "mysql.h" -extern unsigned int mysql_get_proto_info(MYSQL * mysql); -# 518 "mysql.h" -extern char const * mysql_get_server_info(MYSQL * mysql); -# 522 "mysql.h" -extern unsigned long int mysql_get_server_version(MYSQL * mysql); -# 425 "mysql.h" -extern char const * mysql_get_ssl_cipher(MYSQL * mysql); -# 543 "mysql.h" -extern unsigned long int mysql_hex_string(char * to, char const * from, unsigned long int); -# 416 "mysql.h" -extern char const * mysql_info(MYSQL * mysql); -# 421 "mysql.h" -extern MYSQL * mysql_init(MYSQL * mysql); -# 411 "mysql.h" -extern my_ulonglong mysql_insert_id(MYSQL * mysql); -# 512 "mysql.h" -extern int mysql_kill(MYSQL * mysql, unsigned long int); -# 524 "mysql.h" -extern MYSQL_RES * mysql_list_dbs(MYSQL * mysql, char const * wild); -# 539 "mysql.h" -extern MYSQL_RES * mysql_list_fields(MYSQL * mysql, char const * table, char const * wild); -# 526 "mysql.h" -extern MYSQL_RES * mysql_list_processes(MYSQL * mysql); -# 525 "mysql.h" -extern MYSQL_RES * mysql_list_tables(MYSQL * mysql, char const * wild); -# 568 "mysql.h" -extern void mysql_manager_close(MYSQL_MANAGER * con); -# 569 "mysql.h" -extern int mysql_manager_command(MYSQL_MANAGER * con, char const * cmd, int); -# 563 "mysql.h" -extern MYSQL_MANAGER * mysql_manager_connect(MYSQL_MANAGER * con, char const * host, char const * user, char const * passwd, unsigned int); -# 571 "mysql.h" -extern int mysql_manager_fetch_line(MYSQL_MANAGER * con, char * res_buf, int); -# 562 "mysql.h" -extern MYSQL_MANAGER * mysql_manager_init(MYSQL_MANAGER * con); -# 445 "mysql.h" -extern my_bool mysql_master_query(MYSQL * mysql, char const * q, unsigned long int); -# 447 "mysql.h" -extern my_bool mysql_master_send_query(MYSQL * mysql, char const * q, unsigned long int); -# 824 "mysql.h" -extern my_bool mysql_more_results(MYSQL * mysql); -# 825 "mysql.h" -extern int mysql_next_result(MYSQL * mysql); -# 401 "mysql.h" -extern unsigned int mysql_num_fields(MYSQL_RES * res); -# 400 "mysql.h" -extern my_ulonglong mysql_num_rows(MYSQL_RES * res); -# 549 "mysql.h" -extern char * mysql_odbc_escape_string(MYSQL * mysql, char * to, unsigned long int, char const * from, unsigned long int, void * param, char * (* extend_buffer)(void *, char * to, unsigned long int * length)); -# 527 "mysql.h" -extern int mysql_options(MYSQL * mysql, enum mysql_option, char const * arg); -# 516 "mysql.h" -extern int mysql_ping(MYSQL * mysql); -# 75 "mysql.h" -extern unsigned int mysql_port; -# 436 "mysql.h" -extern int mysql_query(MYSQL * mysql, char const * q); -# 574 "mysql.h" -extern my_bool mysql_read_query_result(MYSQL * mysql); -# 489 "mysql.h" -extern my_bool mysql_reads_from_master_enabled(MYSQL * mysql); -# 428 "mysql.h" -extern MYSQL * mysql_real_connect(MYSQL * mysql, char const * host, char const * user, char const * passwd, char const * db, unsigned int, char const * unix_socket, unsigned long int); -# 545 "mysql.h" -extern unsigned long int mysql_real_escape_string(MYSQL * mysql, char * to, char const * from, unsigned long int); -# 439 "mysql.h" -extern int mysql_real_query(MYSQL * mysql, char const * q, unsigned long int); -# 510 "mysql.h" -extern int mysql_refresh(MYSQL * mysql, unsigned int); -# 822 "mysql.h" -extern my_bool mysql_rollback(MYSQL * mysql); -# 532 "mysql.h" -extern MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES * result, MYSQL_ROW_OFFSET); -# 406 "mysql.h" -extern MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES * res); -# 483 "mysql.h" -extern int mysql_rpl_parse_enabled(MYSQL * mysql); -# 494 "mysql.h" -extern my_bool mysql_rpl_probe(MYSQL * mysql); -# 491 "mysql.h" -extern enum mysql_rpl_type mysql_rpl_query_type(char const * q, int); -# 435 "mysql.h" -extern int mysql_select_db(MYSQL * mysql, char const * db); -# 437 "mysql.h" -extern int mysql_send_query(MYSQL * mysql, char const * q, unsigned long int); -# 371 "mysql.h" -extern void mysql_server_end(void); -# 370 "mysql.h" -extern int mysql_server_init(int, char * * argv, char * * groups); -# 419 "mysql.h" -extern int mysql_set_character_set(MYSQL * mysql, char const * csname); -# 472 "mysql.h" -extern void mysql_set_local_infile_default(MYSQL * mysql); -# 461 "mysql.h" -extern void mysql_set_local_infile_handler(MYSQL * mysql, int (* local_infile_init)(void * *, char const *, void *), int (* local_infile_read)(void *, char *, unsigned int), void (* local_infile_end)(void), int (* local_infile_error)(void *, char *, unsigned int), void *); -# 497 "mysql.h" -extern int mysql_set_master(MYSQL * mysql, char const * host, unsigned int, char const * user, char const * passwd); -# 513 "mysql.h" -extern int mysql_set_server_option(MYSQL * mysql, enum enum_mysql_set_option); -# 506 "mysql.h" -extern int mysql_shutdown(MYSQL * mysql, enum mysql_enum_shutdown_level); -# 450 "mysql.h" -extern my_bool mysql_slave_query(MYSQL * mysql, char const * q, unsigned long int); -# 452 "mysql.h" -extern my_bool mysql_slave_send_query(MYSQL * mysql, char const * q, unsigned long int); -# 414 "mysql.h" -extern char const * mysql_sqlstate(MYSQL * mysql); -# 422 "mysql.h" -extern my_bool mysql_ssl_set(MYSQL * mysql, char const * key, char const * cert, char const * ca, char const * capath, char const * cipher); -# 517 "mysql.h" -extern char const * mysql_stat(MYSQL * mysql); -# 817 "mysql.h" -extern my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT * stmt); -# 795 "mysql.h" -extern my_bool mysql_stmt_attr_get(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void * attr); -# 792 "mysql.h" -extern my_bool mysql_stmt_attr_set(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void const * attr); -# 798 "mysql.h" -extern my_bool mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); -# 799 "mysql.h" -extern my_bool mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); -# 800 "mysql.h" -extern my_bool mysql_stmt_close(MYSQL_STMT * stmt); -# 815 "mysql.h" -extern void mysql_stmt_data_seek(MYSQL_STMT * stmt, my_ulonglong); -# 809 "mysql.h" -extern unsigned int mysql_stmt_errno(MYSQL_STMT * stmt); -# 810 "mysql.h" -extern char const * mysql_stmt_error(MYSQL_STMT * stmt); -# 785 "mysql.h" -extern int mysql_stmt_execute(MYSQL_STMT * stmt); -# 786 "mysql.h" -extern int mysql_stmt_fetch(MYSQL_STMT * stmt); -# 787 "mysql.h" -extern int mysql_stmt_fetch_column(MYSQL_STMT * stmt, MYSQL_BIND * bind, unsigned int, unsigned long int); -# 819 "mysql.h" -extern unsigned int mysql_stmt_field_count(MYSQL_STMT * stmt); -# 802 "mysql.h" -extern my_bool mysql_stmt_free_result(MYSQL_STMT * stmt); -# 782 "mysql.h" -extern MYSQL_STMT * mysql_stmt_init(MYSQL * mysql); -# 818 "mysql.h" -extern my_ulonglong mysql_stmt_insert_id(MYSQL_STMT * stmt); -# 816 "mysql.h" -extern my_ulonglong mysql_stmt_num_rows(MYSQL_STMT * stmt); -# 791 "mysql.h" -extern unsigned long int mysql_stmt_param_count(MYSQL_STMT * stmt); -# 808 "mysql.h" -extern MYSQL_RES * mysql_stmt_param_metadata(MYSQL_STMT * stmt); -# 783 "mysql.h" -extern int mysql_stmt_prepare(MYSQL_STMT * stmt, char const * query, unsigned long int); -# 801 "mysql.h" -extern my_bool mysql_stmt_reset(MYSQL_STMT * stmt); -# 807 "mysql.h" -extern MYSQL_RES * mysql_stmt_result_metadata(MYSQL_STMT * stmt); -# 812 "mysql.h" -extern MYSQL_ROW_OFFSET mysql_stmt_row_seek(MYSQL_STMT * stmt, MYSQL_ROW_OFFSET); -# 814 "mysql.h" -extern MYSQL_ROW_OFFSET mysql_stmt_row_tell(MYSQL_STMT * stmt); -# 803 "mysql.h" -extern my_bool mysql_stmt_send_long_data(MYSQL_STMT * stmt, unsigned int, char const * data, unsigned long int); -# 811 "mysql.h" -extern char const * mysql_stmt_sqlstate(MYSQL_STMT * stmt); -# 790 "mysql.h" -extern int mysql_stmt_store_result(MYSQL_STMT * stmt); -# 441 "mysql.h" -extern MYSQL_RES * mysql_store_result(MYSQL * mysql); -# 393 "mysql.h" -extern void mysql_thread_end(void); -# 417 "mysql.h" -extern unsigned long int mysql_thread_id(MYSQL * mysql); -# 392 "mysql.h" -extern my_bool mysql_thread_init(void); -# 560 "mysql.h" -extern unsigned int mysql_thread_safe(void); -# 76 "mysql.h" -extern char * mysql_unix_port; -# 442 "mysql.h" -extern MYSQL_RES * mysql_use_result(MYSQL * mysql); -# 415 "mysql.h" -extern unsigned int mysql_warning_count(MYSQL * mysql); -# 339 "mysql_com.h" -extern void net_clear(NET * net); -# 338 "mysql_com.h" -extern void net_end(NET * net); -# 341 "mysql_com.h" -extern my_bool net_flush(NET * net); -# 346 "mysql_com.h" -extern int net_real_write(NET * net, char const * packet, unsigned long int); -# 340 "mysql_com.h" -extern my_bool net_realloc(NET * net, unsigned long int); -# 343 "mysql_com.h" -extern my_bool net_write_command(NET * net, unsigned char, char const * header, unsigned long int, char const * packet, unsigned long int); # 427 "mysql_com.h" -extern char * octet2hex(char * to, char const * str, unsigned int); -# 408 "mysql_com.h" -extern void randominit(struct rand_struct *, unsigned long int, unsigned long int); -# 422 "mysql_com.h" -extern void scramble(char * to, char const * message, char const * password); +extern my_bool check_scramble(char const * reply, char const * message, unsigned char const * hash_stage2); +# 420 "mysql_com.h" +extern my_bool check_scramble_323(char const *, char const * message, unsigned long int * salt); +# 32 "typelib.h" +extern TYPELIB * copy_typelib(MEM_ROOT * root, TYPELIB * from); # 415 "mysql_com.h" +extern void create_random_string(char * to, unsigned int, struct rand_struct * rand_st); +# 29 "typelib.h" +extern int find_type(char * x, TYPELIB * typelib, unsigned int); +# 429 "mysql_com.h" +extern void get_salt_from_password(unsigned char * res, char const * password); +# 422 "mysql_com.h" +extern void get_salt_from_password_323(unsigned long int * res, char const * password); +# 435 "mysql_com.h" +extern char * get_tty_password(char * opt_message); +# 31 "typelib.h" +extern char const * get_type(TYPELIB * typelib, unsigned int); +# 417 "mysql_com.h" +extern void hash_password(unsigned long int * to, char const * password, unsigned int); +# 30 "my_list.h" +extern LIST * list_add(LIST * root, LIST * element); +# 32 "my_list.h" +extern LIST * list_cons(void * data, LIST * root); +# 31 "my_list.h" +extern LIST * list_delete(LIST * root, LIST * element); +# 34 "my_list.h" +extern void list_free(LIST * root, unsigned int); +# 35 "my_list.h" +extern unsigned int list_length(LIST *); +# 33 "my_list.h" +extern LIST * list_reverse(LIST * root); +# 36 "my_list.h" +extern int list_walk(LIST *, list_walk_action, gptr); +# 444 "mysql_com.h" +extern int load_defaults(char const * conf_file, char const * * groups, int * argc, char * * * argv); +# 430 "mysql_com.h" +extern void make_password_from_salt(char * to, unsigned char const * hash_stage2); +# 423 "mysql_com.h" +extern void make_password_from_salt_323(char * to, unsigned long int const * salt); +# 425 "mysql_com.h" +extern void make_scrambled_password(char * to, char const * password); +# 418 "mysql_com.h" +extern void make_scrambled_password_323(char * to, char const * password); +# 30 "typelib.h" +extern void make_type(char * to, unsigned int, TYPELIB * typelib); +# 441 "mysql_com.h" +extern int modify_defaults_file(char const * file_location, char const * option, char const * option_value, char const * section_name, int); +# 358 "mysql_com.h" +extern int my_connect(my_socket, struct sockaddr const * name, unsigned int, unsigned int); +# 440 "mysql_com.h" +extern my_bool my_init(void); +# 335 "mysql_com.h" +extern my_bool my_net_init(NET * net, Vio * vio); +# 336 "mysql_com.h" +extern void my_net_local_init(NET * net); +# 346 "mysql_com.h" +extern unsigned long int my_net_read(NET * net); +# 341 "mysql_com.h" +extern my_bool my_net_write(NET * net, char const * packet, unsigned long int); +# 414 "mysql_com.h" +extern double my_rnd(struct rand_struct *); +# 447 "mysql_com.h" +extern void my_thread_end(void); +# 446 "mysql_com.h" +extern my_bool my_thread_init(void); +# 553 "mysql.h" +extern void myodbc_remove_escape(MYSQL * mysql, char * name); +# 505 "mysql.h" +extern int mysql_add_slave(MYSQL * mysql, char const * host, unsigned int, char const * user, char const * passwd); +# 414 "mysql.h" +extern my_ulonglong mysql_affected_rows(MYSQL * mysql); +# 817 "mysql.h" +extern my_bool mysql_autocommit(MYSQL * mysql, my_bool); +# 430 "mysql.h" +extern my_bool mysql_change_user(MYSQL * mysql, char const * user, char const * passwd, char const * db); +# 422 "mysql.h" +extern char const * mysql_character_set_name(MYSQL * mysql); +# 820 "mysql.h" +extern void mysql_close(MYSQL * sock); +# 815 "mysql.h" +extern my_bool mysql_commit(MYSQL * mysql); +# 534 "mysql.h" +extern void mysql_data_seek(MYSQL_RES * result, my_ulonglong); +# 552 "mysql.h" +extern void mysql_debug(char const * debug); +# 491 "mysql.h" +extern void mysql_disable_reads_from_master(MYSQL * mysql); +# 485 "mysql.h" +extern void mysql_disable_rpl_parse(MYSQL * mysql); +# 513 "mysql.h" +extern int mysql_dump_debug_info(MYSQL * mysql); +# 555 "mysql.h" +extern my_bool mysql_embedded(void); +# 490 "mysql.h" +extern void mysql_enable_reads_from_master(MYSQL * mysql); +# 484 "mysql.h" +extern void mysql_enable_rpl_parse(MYSQL * mysql); +# 406 "mysql.h" +extern my_bool mysql_eof(MYSQL_RES * res); +# 416 "mysql.h" +extern unsigned int mysql_errno(MYSQL * mysql); +# 436 "mysql_com.h" +extern char const * mysql_errno_to_sqlstate(unsigned int); +# 417 "mysql.h" +extern char const * mysql_error(MYSQL * mysql); +# 545 "mysql.h" +extern unsigned long int mysql_escape_string(char * to, char const * from, unsigned long int); +# 542 "mysql.h" +extern MYSQL_FIELD * mysql_fetch_field(MYSQL_RES * result); +# 407 "mysql.h" +extern MYSQL_FIELD * mysql_fetch_field_direct(MYSQL_RES * res, unsigned int); +# 409 "mysql.h" +extern MYSQL_FIELD * mysql_fetch_fields(MYSQL_RES * res); +# 541 "mysql.h" +extern unsigned long int * mysql_fetch_lengths(MYSQL_RES * result); +# 540 "mysql.h" +extern MYSQL_ROW mysql_fetch_row(MYSQL_RES * result); +# 413 "mysql.h" +extern unsigned int mysql_field_count(MYSQL * mysql); +# 538 "mysql.h" +extern MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES * result, MYSQL_FIELD_OFFSET); +# 411 "mysql.h" +extern MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES * res); +# 533 "mysql.h" +extern void mysql_free_result(MYSQL_RES * result); +# 458 "mysql.h" +extern void mysql_get_character_set_info(MYSQL * mysql, MY_CHARSET_INFO * charset); +# 523 "mysql.h" +extern char const * mysql_get_client_info(void); +# 524 "mysql.h" +extern unsigned long int mysql_get_client_version(void); +# 525 "mysql.h" +extern char const * mysql_get_host_info(MYSQL * mysql); +# 388 "mysql.h" +extern MYSQL_PARAMETERS * mysql_get_parameters(void); +# 527 "mysql.h" +extern unsigned int mysql_get_proto_info(MYSQL * mysql); +# 522 "mysql.h" +extern char const * mysql_get_server_info(MYSQL * mysql); +# 526 "mysql.h" +extern unsigned long int mysql_get_server_version(MYSQL * mysql); +# 429 "mysql.h" +extern char const * mysql_get_ssl_cipher(MYSQL * mysql); +# 547 "mysql.h" +extern unsigned long int mysql_hex_string(char * to, char const * from, unsigned long int); +# 420 "mysql.h" +extern char const * mysql_info(MYSQL * mysql); +# 425 "mysql.h" +extern MYSQL * mysql_init(MYSQL * mysql); +# 415 "mysql.h" +extern my_ulonglong mysql_insert_id(MYSQL * mysql); +# 516 "mysql.h" +extern int mysql_kill(MYSQL * mysql, unsigned long int); +# 528 "mysql.h" +extern MYSQL_RES * mysql_list_dbs(MYSQL * mysql, char const * wild); +# 543 "mysql.h" +extern MYSQL_RES * mysql_list_fields(MYSQL * mysql, char const * table, char const * wild); +# 530 "mysql.h" +extern MYSQL_RES * mysql_list_processes(MYSQL * mysql); +# 529 "mysql.h" +extern MYSQL_RES * mysql_list_tables(MYSQL * mysql, char const * wild); +# 562 "mysql.h" +extern void mysql_manager_close(MYSQL_MANAGER * con); +# 563 "mysql.h" +extern int mysql_manager_command(MYSQL_MANAGER * con, char const * cmd, int); +# 557 "mysql.h" +extern MYSQL_MANAGER * mysql_manager_connect(MYSQL_MANAGER * con, char const * host, char const * user, char const * passwd, unsigned int); +# 565 "mysql.h" +extern int mysql_manager_fetch_line(MYSQL_MANAGER * con, char * res_buf, int); +# 556 "mysql.h" +extern MYSQL_MANAGER * mysql_manager_init(MYSQL_MANAGER * con); +# 449 "mysql.h" +extern my_bool mysql_master_query(MYSQL * mysql, char const * q, unsigned long int); +# 451 "mysql.h" +extern my_bool mysql_master_send_query(MYSQL * mysql, char const * q, unsigned long int); +# 818 "mysql.h" +extern my_bool mysql_more_results(MYSQL * mysql); +# 819 "mysql.h" +extern int mysql_next_result(MYSQL * mysql); +# 405 "mysql.h" +extern unsigned int mysql_num_fields(MYSQL_RES * res); +# 404 "mysql.h" +extern my_ulonglong mysql_num_rows(MYSQL_RES * res); +# 531 "mysql.h" +extern int mysql_options(MYSQL * mysql, enum mysql_option, char const * arg); +# 520 "mysql.h" +extern int mysql_ping(MYSQL * mysql); +# 78 "mysql.h" +extern unsigned int mysql_port; +# 440 "mysql.h" +extern int mysql_query(MYSQL * mysql, char const * q); +# 568 "mysql.h" +extern my_bool mysql_read_query_result(MYSQL * mysql); +# 493 "mysql.h" +extern my_bool mysql_reads_from_master_enabled(MYSQL * mysql); +# 432 "mysql.h" +extern MYSQL * mysql_real_connect(MYSQL * mysql, char const * host, char const * user, char const * passwd, char const * db, unsigned int, char const * unix_socket, unsigned long int); +# 549 "mysql.h" +extern unsigned long int mysql_real_escape_string(MYSQL * mysql, char * to, char const * from, unsigned long int); +# 443 "mysql.h" +extern int mysql_real_query(MYSQL * mysql, char const * q, unsigned long int); +# 514 "mysql.h" +extern int mysql_refresh(MYSQL * mysql, unsigned int); +# 816 "mysql.h" +extern my_bool mysql_rollback(MYSQL * mysql); +# 536 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES * result, MYSQL_ROW_OFFSET); +# 410 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES * res); +# 487 "mysql.h" +extern int mysql_rpl_parse_enabled(MYSQL * mysql); +# 498 "mysql.h" +extern my_bool mysql_rpl_probe(MYSQL * mysql); +# 495 "mysql.h" +extern enum mysql_rpl_type mysql_rpl_query_type(char const * q, int); +# 439 "mysql.h" +extern int mysql_select_db(MYSQL * mysql, char const * db); +# 441 "mysql.h" +extern int mysql_send_query(MYSQL * mysql, char const * q, unsigned long int); +# 375 "mysql.h" +extern void mysql_server_end(void); +# 374 "mysql.h" +extern int mysql_server_init(int, char * * argv, char * * groups); +# 423 "mysql.h" +extern int mysql_set_character_set(MYSQL * mysql, char const * csname); +# 476 "mysql.h" +extern void mysql_set_local_infile_default(MYSQL * mysql); +# 465 "mysql.h" +extern void mysql_set_local_infile_handler(MYSQL * mysql, int (* local_infile_init)(void * *, char const *, void *), int (* local_infile_read)(void *, char *, unsigned int), void (* local_infile_end)(void), int (* local_infile_error)(void *, char *, unsigned int), void *); +# 501 "mysql.h" +extern int mysql_set_master(MYSQL * mysql, char const * host, unsigned int, char const * user, char const * passwd); +# 517 "mysql.h" +extern int mysql_set_server_option(MYSQL * mysql, enum enum_mysql_set_option); +# 510 "mysql.h" +extern int mysql_shutdown(MYSQL * mysql, enum mysql_enum_shutdown_level); +# 454 "mysql.h" +extern my_bool mysql_slave_query(MYSQL * mysql, char const * q, unsigned long int); +# 456 "mysql.h" +extern my_bool mysql_slave_send_query(MYSQL * mysql, char const * q, unsigned long int); +# 418 "mysql.h" +extern char const * mysql_sqlstate(MYSQL * mysql); +# 426 "mysql.h" +extern my_bool mysql_ssl_set(MYSQL * mysql, char const * key, char const * cert, char const * ca, char const * capath, char const * cipher); +# 521 "mysql.h" +extern char const * mysql_stat(MYSQL * mysql); +# 811 "mysql.h" +extern my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT * stmt); +# 789 "mysql.h" +extern my_bool mysql_stmt_attr_get(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void * attr); +# 786 "mysql.h" +extern my_bool mysql_stmt_attr_set(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void const * attr); +# 792 "mysql.h" +extern my_bool mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +# 793 "mysql.h" +extern my_bool mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +# 794 "mysql.h" +extern my_bool mysql_stmt_close(MYSQL_STMT * stmt); +# 809 "mysql.h" +extern void mysql_stmt_data_seek(MYSQL_STMT * stmt, my_ulonglong); +# 803 "mysql.h" +extern unsigned int mysql_stmt_errno(MYSQL_STMT * stmt); +# 804 "mysql.h" +extern char const * mysql_stmt_error(MYSQL_STMT * stmt); +# 779 "mysql.h" +extern int mysql_stmt_execute(MYSQL_STMT * stmt); +# 780 "mysql.h" +extern int mysql_stmt_fetch(MYSQL_STMT * stmt); +# 781 "mysql.h" +extern int mysql_stmt_fetch_column(MYSQL_STMT * stmt, MYSQL_BIND * bind_arg, unsigned int, unsigned long int); +# 813 "mysql.h" +extern unsigned int mysql_stmt_field_count(MYSQL_STMT * stmt); +# 796 "mysql.h" +extern my_bool mysql_stmt_free_result(MYSQL_STMT * stmt); +# 776 "mysql.h" +extern MYSQL_STMT * mysql_stmt_init(MYSQL * mysql); +# 812 "mysql.h" +extern my_ulonglong mysql_stmt_insert_id(MYSQL_STMT * stmt); +# 810 "mysql.h" +extern my_ulonglong mysql_stmt_num_rows(MYSQL_STMT * stmt); +# 785 "mysql.h" +extern unsigned long int mysql_stmt_param_count(MYSQL_STMT * stmt); +# 802 "mysql.h" +extern MYSQL_RES * mysql_stmt_param_metadata(MYSQL_STMT * stmt); +# 777 "mysql.h" +extern int mysql_stmt_prepare(MYSQL_STMT * stmt, char const * query, unsigned long int); +# 795 "mysql.h" +extern my_bool mysql_stmt_reset(MYSQL_STMT * stmt); +# 801 "mysql.h" +extern MYSQL_RES * mysql_stmt_result_metadata(MYSQL_STMT * stmt); +# 806 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_stmt_row_seek(MYSQL_STMT * stmt, MYSQL_ROW_OFFSET); +# 808 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_stmt_row_tell(MYSQL_STMT * stmt); +# 797 "mysql.h" +extern my_bool mysql_stmt_send_long_data(MYSQL_STMT * stmt, unsigned int, char const * data, unsigned long int); +# 805 "mysql.h" +extern char const * mysql_stmt_sqlstate(MYSQL_STMT * stmt); +# 784 "mysql.h" +extern int mysql_stmt_store_result(MYSQL_STMT * stmt); +# 445 "mysql.h" +extern MYSQL_RES * mysql_store_result(MYSQL * mysql); +# 397 "mysql.h" +extern void mysql_thread_end(void); +# 421 "mysql.h" +extern unsigned long int mysql_thread_id(MYSQL * mysql); +# 396 "mysql.h" +extern my_bool mysql_thread_init(void); +# 554 "mysql.h" +extern unsigned int mysql_thread_safe(void); +# 79 "mysql.h" +extern char * mysql_unix_port; +# 446 "mysql.h" +extern MYSQL_RES * mysql_use_result(MYSQL * mysql); +# 419 "mysql.h" +extern unsigned int mysql_warning_count(MYSQL * mysql); +# 338 "mysql_com.h" +extern void net_clear(NET * net); +# 337 "mysql_com.h" +extern void net_end(NET * net); +# 340 "mysql_com.h" +extern my_bool net_flush(NET * net); +# 345 "mysql_com.h" +extern int net_real_write(NET * net, char const * packet, unsigned long int); +# 339 "mysql_com.h" +extern my_bool net_realloc(NET * net, unsigned long int); +# 342 "mysql_com.h" +extern my_bool net_write_command(NET * net, unsigned char, char const * header, unsigned long int, char const * packet, unsigned long int); +# 431 "mysql_com.h" +extern char * octet2hex(char * to, char const * str, unsigned int); +# 412 "mysql_com.h" +extern void randominit(struct rand_struct *, unsigned long int, unsigned long int); +# 426 "mysql_com.h" +extern void scramble(char * to, char const * message, char const * password); +# 419 "mysql_com.h" extern void scramble_323(char * to, char const * message, char const * password); -# 35 "typelib.h" +# 34 "typelib.h" extern TYPELIB sql_protocol_typelib; diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 85509b49fdd..4afc3ec5925 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1617,78 +1617,6 @@ mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, return escape_string_for_mysql(mysql->charset, to, 0, from, length); } - -char * STDCALL -mysql_odbc_escape_string(MYSQL *mysql, - char *to, ulong to_length, - const char *from, ulong from_length, - void *param, - char * (*extend_buffer) - (void *, char *, ulong *)) -{ - char *to_end=to+to_length-5; - const char *end; -#ifdef USE_MB - my_bool use_mb_flag=use_mb(mysql->charset); -#endif - - for (end=from+from_length; from != end ; from++) - { - if (to >= to_end) - { - to_length = (ulong) (end-from)+512; /* We want this much more */ - if (!(to=(*extend_buffer)(param, to, &to_length))) - return to; - to_end=to+to_length-5; - } -#ifdef USE_MB - { - int l; - if (use_mb_flag && (l = my_ismbchar(mysql->charset, from, end))) - { - while (l--) - *to++ = *from++; - from--; - continue; - } - } -#endif - switch (*from) { - case 0: /* Must be escaped for 'mysql' */ - *to++= '\\'; - *to++= '0'; - break; - case '\n': /* Must be escaped for logs */ - *to++= '\\'; - *to++= 'n'; - break; - case '\r': - *to++= '\\'; - *to++= 'r'; - break; - case '\\': - *to++= '\\'; - *to++= '\\'; - break; - case '\'': - *to++= '\\'; - *to++= '\''; - break; - case '"': /* Better safe than sorry */ - *to++= '\\'; - *to++= '"'; - break; - case '\032': /* This gives problems on Win32 */ - *to++= '\\'; - *to++= 'Z'; - break; - default: - *to++= *from; - } - } - return to; -} - void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name) { diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 8c6b71d9553..81f86dc8726 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -78,7 +78,6 @@ EXPORTS mysql_next_result mysql_num_fields mysql_num_rows - mysql_odbc_escape_string mysql_options mysql_stmt_param_count mysql_stmt_param_metadata diff --git a/libmysqld/libmysqld.def b/libmysqld/libmysqld.def index 8829112fefd..8aed164a30e 100644 --- a/libmysqld/libmysqld.def +++ b/libmysqld/libmysqld.def @@ -71,7 +71,6 @@ EXPORTS mysql_next_result mysql_num_fields mysql_num_rows - mysql_odbc_escape_string mysql_options mysql_ping mysql_query From 345650212c9113e5c966307259db8698fced7bf7 Mon Sep 17 00:00:00 2001 From: "thek@adventure.(none)" <> Date: Mon, 26 Nov 2007 19:09:40 +0100 Subject: [PATCH 16/29] Bug#16470 crash on grant if old grant tables Loading 4.1 into 5.0 or 5.1 failed silently because procs_priv table missing. This caused the server to crash on any attempt to store new grants because of uninitialized structures. This patch breaks up the grant loading function into two phases to allow for procs_priv table to fail with an warning instead of crashing the server. --- mysql-test/r/grant.result | 19 +++ mysql-test/t/grant.test | 20 +++ sql/sql_acl.cc | 322 ++++++++++++++++++++++++-------------- sql/sql_parse.cc | 31 ++-- 4 files changed, 260 insertions(+), 132 deletions(-) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 0d4dad39882..7a7e90b2280 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1223,3 +1223,22 @@ drop user юзер_юзер@localhost; grant select on test.* to очень_длинный_юзер@localhost; ERROR HY000: String 'очень_длинный_юзер' is too long for user name (should be no longer than 16) set names default; +FLUSH PRIVILEGES without procs_priv table. +RENAME TABLE mysql.procs_priv TO mysql.procs_gone; +FLUSH PRIVILEGES; +Warnings: +Error 1146 Table 'mysql.procs_priv' doesn't exist +Error 1547 Cannot load from mysql.mysql.procs_priv. The table is probably corrupted +Assigning privileges without procs_priv table. +CREATE DATABASE mysqltest1; +CREATE PROCEDURE mysqltest1.test() SQL SECURITY DEFINER +SELECT 1; +GRANT EXECUTE ON FUNCTION mysqltest1.test TO mysqltest_1@localhost; +ERROR 42S02: Table 'mysql.procs_priv' doesn't exist +GRANT ALL PRIVILEGES ON test.* TO mysqltest_1@localhost; +CALL mysqltest1.test(); +1 +1 +DROP DATABASE mysqltest1; +RENAME TABLE mysql.procs_gone TO mysql.procs_priv; +FLUSH PRIVILEGES; diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index e33712e1ebf..8e060ef5ca9 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -1274,3 +1274,23 @@ drop user юзер_юзер@localhost; --error ER_WRONG_STRING_LENGTH grant select on test.* to очень_длинный_юзер@localhost; set names default; + + +# +# Bug #16470 crash on grant if old grant tables +# +--echo FLUSH PRIVILEGES without procs_priv table. +RENAME TABLE mysql.procs_priv TO mysql.procs_gone; +FLUSH PRIVILEGES; +--echo Assigning privileges without procs_priv table. +CREATE DATABASE mysqltest1; +CREATE PROCEDURE mysqltest1.test() SQL SECURITY DEFINER + SELECT 1; +--error ER_NO_SUCH_TABLE +GRANT EXECUTE ON FUNCTION mysqltest1.test TO mysqltest_1@localhost; +GRANT ALL PRIVILEGES ON test.* TO mysqltest_1@localhost; +CALL mysqltest1.test(); +DROP DATABASE mysqltest1; +RENAME TABLE mysql.procs_gone TO mysql.procs_priv; +FLUSH PRIVILEGES; + diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 7e017d7d028..39df07a0cfa 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3471,16 +3471,13 @@ void grant_free(void) } -/* - Initialize structures responsible for table/column-level privilege checking - and load information for them from tables in the 'mysql' database. +/** + @brief Initialize structures responsible for table/column-level privilege + checking and load information for them from tables in the 'mysql' database. - SYNOPSIS - grant_init() - - RETURN VALUES - 0 ok - 1 Could not initialize grant's + @return Error status + @retval 0 OK + @retval 1 Could not initialize grant subsystem. */ my_bool grant_init() @@ -3501,50 +3498,136 @@ my_bool grant_init() } -/* - Initialize structures responsible for table/column-level privilege - checking and load information about grants from open privilege tables. +/** + @brief Helper function to grant_reload_procs_priv - SYNOPSIS - grant_load() - thd Current thread - tables List containing open "mysql.tables_priv" and - "mysql.columns_priv" tables. + Reads the procs_priv table into memory hash. - RETURN VALUES - FALSE - success - TRUE - error + @param table A pointer to the procs_priv table structure. + + @see grant_reload + @see grant_reload_procs_priv + + @return Error state + @retval TRUE An error occurred + @retval FALSE Success +*/ + +static my_bool grant_load_procs_priv(TABLE *p_table) +{ + MEM_ROOT *memex_ptr; + my_bool return_val= 1; + bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; + MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, + THR_MALLOC); + DBUG_ENTER("grant_load"); + (void) hash_init(&proc_priv_hash,system_charset_info, + 0,0,0, (hash_get_key) get_grant_table, + 0,0); + (void) hash_init(&func_priv_hash,system_charset_info, + 0,0,0, (hash_get_key) get_grant_table, + 0,0); + p_table->file->ha_index_init(0, 1); + p_table->use_all_columns(); + + if (!p_table->file->index_first(p_table->record[0])) + { + memex_ptr= &memex; + my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr); + do + { + GRANT_NAME *mem_check; + HASH *hash; + if (!(mem_check=new (memex_ptr) GRANT_NAME(p_table))) + { + /* This could only happen if we are out memory */ + goto end_unlock; + } + + if (check_no_resolve) + { + if (hostname_requires_resolving(mem_check->host.hostname)) + { + sql_print_warning("'procs_priv' entry '%s %s@%s' " + "ignored in --skip-name-resolve mode.", + mem_check->tname, mem_check->user, + mem_check->host.hostname ? + mem_check->host.hostname : ""); + continue; + } + } + if (p_table->field[4]->val_int() == TYPE_ENUM_PROCEDURE) + { + hash= &proc_priv_hash; + } + else + if (p_table->field[4]->val_int() == TYPE_ENUM_FUNCTION) + { + hash= &func_priv_hash; + } + else + { + sql_print_warning("'procs_priv' entry '%s' " + "ignored, bad routine type", + mem_check->tname); + continue; + } + + mem_check->privs= fix_rights_for_procedure(mem_check->privs); + if (! mem_check->ok()) + delete mem_check; + else if (my_hash_insert(hash, (uchar*) mem_check)) + { + delete mem_check; + goto end_unlock; + } + } + while (!p_table->file->index_next(p_table->record[0])); + } + /* Return ok */ + return_val= 0; + +end_unlock: + p_table->file->ha_index_end(); + my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr); + DBUG_RETURN(return_val); +} + + +/** + @brief Initialize structures responsible for table/column-level privilege + checking and load information about grants from open privilege tables. + + @param thd Current thread + @param tables List containing open "mysql.tables_priv" and + "mysql.columns_priv" tables. + + @see grant_reload + + @return Error state + @retval FALSE Success + @retval TRUE Error */ static my_bool grant_load(TABLE_LIST *tables) { MEM_ROOT *memex_ptr; my_bool return_val= 1; - TABLE *t_table, *c_table, *p_table; + TABLE *t_table= 0, *c_table= 0; bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC); DBUG_ENTER("grant_load"); - (void) hash_init(&column_priv_hash,system_charset_info, - 0,0,0, (hash_get_key) get_grant_table, - (hash_free_key) free_grant_table,0); - (void) hash_init(&proc_priv_hash,system_charset_info, - 0,0,0, (hash_get_key) get_grant_table, - 0,0); - (void) hash_init(&func_priv_hash,system_charset_info, - 0,0,0, (hash_get_key) get_grant_table, - 0,0); - init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); + 0,0,0, (hash_get_key) get_grant_table, + (hash_free_key) free_grant_table,0); t_table = tables[0].table; c_table = tables[1].table; - p_table= tables[2].table; t_table->file->ha_index_init(0, 1); - p_table->file->ha_index_init(0, 1); t_table->use_all_columns(); c_table->use_all_columns(); - p_table->use_all_columns(); + if (!t_table->file->index_first(t_table->record[0])) { memex_ptr= &memex; @@ -3582,92 +3665,91 @@ static my_bool grant_load(TABLE_LIST *tables) } while (!t_table->file->index_next(t_table->record[0])); } - if (!p_table->file->index_first(p_table->record[0])) - { - memex_ptr= &memex; - my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr); - do - { - GRANT_NAME *mem_check; - HASH *hash; - if (!(mem_check=new (&memex) GRANT_NAME(p_table))) - { - /* This could only happen if we are out memory */ - goto end_unlock; - } - if (check_no_resolve) - { - if (hostname_requires_resolving(mem_check->host.hostname)) - { - sql_print_warning("'procs_priv' entry '%s %s@%s' " - "ignored in --skip-name-resolve mode.", - mem_check->tname, mem_check->user, - mem_check->host.hostname ? - mem_check->host.hostname : ""); - continue; - } - } - if (p_table->field[4]->val_int() == TYPE_ENUM_PROCEDURE) - { - hash= &proc_priv_hash; - } - else - if (p_table->field[4]->val_int() == TYPE_ENUM_FUNCTION) - { - hash= &func_priv_hash; - } - else - { - sql_print_warning("'procs_priv' entry '%s' " - "ignored, bad routine type", - mem_check->tname); - continue; - } - - mem_check->privs= fix_rights_for_procedure(mem_check->privs); - if (! mem_check->ok()) - delete mem_check; - else if (my_hash_insert(hash, (uchar*) mem_check)) - { - delete mem_check; - goto end_unlock; - } - } - while (!p_table->file->index_next(p_table->record[0])); - } return_val=0; // Return ok end_unlock: t_table->file->ha_index_end(); - p_table->file->ha_index_end(); my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr); DBUG_RETURN(return_val); } -/* - Reload information about table and column level privileges if possible. +/** + @brief Helper function to grant_reload. Reloads procs_priv table is it + exists. - SYNOPSIS - grant_reload() - thd Current thread + @param thd A pointer to the thread handler object. - NOTES - Locked tables are checked by acl_reload() and doesn't have to be checked - in this call. - This function is also used for initialization of structures responsible - for table/column-level privilege checking. + @see grant_reload - RETURN VALUE - FALSE Success - TRUE Error + @return Error state + @retval FALSE Success + @retval TRUE An error has occurred. +*/ + +static my_bool grant_reload_procs_priv(THD *thd) +{ + HASH old_proc_priv_hash, old_func_priv_hash; + TABLE_LIST table; + my_bool return_val= FALSE; + DBUG_ENTER("grant_reload_procs_priv"); + + bzero((char*) &table, sizeof(table)); + table.alias= table.table_name= (char*) "procs_priv"; + table.db= (char *) "mysql"; + table.lock_type= TL_READ; + + if (simple_open_n_lock_tables(thd, &table)) + { + close_thread_tables(thd); + DBUG_RETURN(TRUE); + } + + /* Save a copy of the current hash if we need to undo the grant load */ + old_proc_priv_hash= proc_priv_hash; + old_func_priv_hash= func_priv_hash; + + rw_wrlock(&LOCK_grant); + if ((return_val= grant_load_procs_priv(table.table))) + { + /* Error; Reverting to old hash */ + DBUG_PRINT("error",("Reverting to old privileges")); + grant_free(); + proc_priv_hash= old_proc_priv_hash; + func_priv_hash= old_func_priv_hash; + } + else + { + hash_free(&old_proc_priv_hash); + hash_free(&old_func_priv_hash); + } + rw_unlock(&LOCK_grant); + + close_thread_tables(thd); + DBUG_RETURN(return_val); +} + + +/** + @brief Reload information about table and column level privileges if possible + + @param thd Current thread + + Locked tables are checked by acl_reload() and doesn't have to be checked + in this call. + This function is also used for initialization of structures responsible + for table/column-level privilege checking. + + @return Error state + @retval FALSE Success + @retval TRUE Error */ my_bool grant_reload(THD *thd) { - TABLE_LIST tables[3]; - HASH old_column_priv_hash, old_proc_priv_hash, old_func_priv_hash; + TABLE_LIST tables[2]; + HASH old_column_priv_hash; MEM_ROOT old_mem; my_bool return_val= 1; DBUG_ENTER("grant_reload"); @@ -3679,11 +3761,9 @@ my_bool grant_reload(THD *thd) bzero((char*) tables, sizeof(tables)); tables[0].alias= tables[0].table_name= (char*) "tables_priv"; tables[1].alias= tables[1].table_name= (char*) "columns_priv"; - tables[2].alias= tables[2].table_name= (char*) "procs_priv"; - tables[0].db= tables[1].db= tables[2].db= (char *) "mysql"; + tables[0].db= tables[1].db= (char *) "mysql"; tables[0].next_local= tables[0].next_global= tables+1; - tables[1].next_local= tables[1].next_global= tables+2; - tables[0].lock_type= tables[1].lock_type= tables[2].lock_type= TL_READ; + tables[0].lock_type= tables[1].lock_type= TL_READ; /* To avoid deadlocks we should obtain table locks before @@ -3693,35 +3773,45 @@ my_bool grant_reload(THD *thd) goto end; rw_wrlock(&LOCK_grant); - grant_version++; old_column_priv_hash= column_priv_hash; - old_proc_priv_hash= proc_priv_hash; - old_func_priv_hash= func_priv_hash; + + /* + Create a new memory pool but save the current memory pool to make an undo + opertion possible in case of failure. + */ old_mem= memex; + init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); if ((return_val= grant_load(tables))) { // Error. Revert to old hash DBUG_PRINT("error",("Reverting to old privileges")); grant_free(); /* purecov: deadcode */ column_priv_hash= old_column_priv_hash; /* purecov: deadcode */ - proc_priv_hash= old_proc_priv_hash; - func_priv_hash= old_func_priv_hash; memex= old_mem; /* purecov: deadcode */ } else { hash_free(&old_column_priv_hash); - hash_free(&old_proc_priv_hash); - hash_free(&old_func_priv_hash); free_root(&old_mem,MYF(0)); } rw_unlock(&LOCK_grant); -end: close_thread_tables(thd); + + /* + It is ok failing to load procs_priv table because we may be + working with 4.1 privilege tables. + */ + if (grant_reload_procs_priv(thd)) + my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "mysql.procs_priv"); + + rw_wrlock(&LOCK_grant); + grant_version++; + rw_unlock(&LOCK_grant); + +end: DBUG_RETURN(return_val); } - /**************************************************************************** Check table level grants diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 695e923e816..4e4b30adb3b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6293,24 +6293,23 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List *using_fields, } -/* - Reload/resets privileges and the different caches. +/** + @brief Reload/resets privileges and the different caches. - SYNOPSIS - reload_acl_and_cache() - thd Thread handler (can be NULL!) - options What should be reset/reloaded (tables, privileges, - slave...) - tables Tables to flush (if any) - write_to_binlog Depending on 'options', it may be very bad to write the - query to the binlog (e.g. FLUSH SLAVE); this is a - pointer where reload_acl_and_cache() will put 0 if - it thinks we really should not write to the binlog. - Otherwise it will put 1. + @param thd Thread handler (can be NULL!) + @param options What should be reset/reloaded (tables, privileges, slave...) + @param tables Tables to flush (if any) + @param write_to_binlog True if we can write to the binlog. - RETURN - 0 ok - !=0 error. thd->killed or thd->net.report_error is set + @note Depending on 'options', it may be very bad to write the + query to the binlog (e.g. FLUSH SLAVE); this is a + pointer where reload_acl_and_cache() will put 0 if + it thinks we really should not write to the binlog. + Otherwise it will put 1. + + @return Error status code + @retval 0 Ok + @retval !=0 Error; thd->killed or thd->net.report_error is set */ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, From 906697768cb5928be9eaeedbf2ac0df8ac612109 Mon Sep 17 00:00:00 2001 From: "thek@adventure.(none)" <> Date: Wed, 28 Nov 2007 09:03:21 +0100 Subject: [PATCH 17/29] Error number increased; fixing broken number. --- mysql-test/r/grant.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 34f6e0b4379..0d40778d5f2 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1231,7 +1231,7 @@ RENAME TABLE mysql.procs_priv TO mysql.procs_gone; FLUSH PRIVILEGES; Warnings: Error 1146 Table 'mysql.procs_priv' doesn't exist -Error 1547 Cannot load from mysql.mysql.procs_priv. The table is probably corrupted +Error 1548 Cannot load from mysql.mysql.procs_priv. The table is probably corrupted Assigning privileges without procs_priv table. CREATE DATABASE mysqltest1; CREATE PROCEDURE mysqltest1.test() SQL SECURITY DEFINER From bd3f76d767e7dc78a73d68501271dcae9b0853aa Mon Sep 17 00:00:00 2001 From: "davi@mysql.com/endora.local" <> Date: Wed, 28 Nov 2007 10:18:01 -0200 Subject: [PATCH 18/29] Bug#31479 Bad lock interaction if CREATE TABLE LIKE is killed Kill of a CREATE TABLE source_table LIKE statement waiting for a name-lock on the source table causes a bad lock interaction. The mysql_create_like_table() has a bug that if the connection is killed while waiting for the name-lock on the source table, it will jump to the wrong error path and try to unlock the source table and LOCK_open, but both weren't locked. The solution is to simple return when the name lock request is killed, it's safe to do so because no lock was acquired and no cleanup is needed. Original bug report also contains description of other problems related to this scenario but they either already fixed in 5.1 or will be addressed separately (see bug report for details). --- mysql-test/r/lock_multi.result | 11 +++++++++++ mysql-test/t/lock_multi.test | 32 ++++++++++++++++++++++++++++++++ sql/sql_table.cc | 2 +- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index af49e1a27dc..079f92ca420 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -88,3 +88,14 @@ alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // unlock tables; drop table t1; +drop table if exists t1; +create table t1 (a int); +connection: locker +lock tables t1 read; +connection: writer +create table t2 like t1;; +connection: default +kill query +ERROR 70100: Query execution was interrupted +unlock tables; +drop table t1; diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index d670bb55a18..649c1a4efbd 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -249,4 +249,36 @@ reap; connection locker; drop table t1; +# +# Bug#31479 Bad lock interaction if CREATE TABLE LIKE is killed +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +--echo connection: locker +connection locker; +lock tables t1 read; +--echo connection: writer +connection writer; +let $ID= `select connection_id()`; +--send create table t2 like t1; +--echo connection: default +connection default; +let $show_type= open tables where in_use=2 and name_locked=1; +let $show_pattern= '%t1%2%1'; +--source include/wait_show_pattern.inc +--echo kill query +disable_query_log; +eval kill query $ID; +enable_query_log; +connection writer; +--error ER_QUERY_INTERRUPTED +--reap +connection locker; +unlock tables; +connection default; +drop table t1; + # End of 5.0 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 0838b805b35..de7ccb7b86f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2761,7 +2761,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST *src_table, operations on the target table. */ if (lock_and_wait_for_table_name(thd, src_table)) - goto err; + DBUG_RETURN(res); pthread_mutex_lock(&LOCK_open); From fce47dbc9a4b3d3d630fce55c6cb535030397ab9 Mon Sep 17 00:00:00 2001 From: "malff@lambda.hsd1.co.comcast.net." <> Date: Wed, 28 Nov 2007 08:41:45 -0700 Subject: [PATCH 19/29] Manual merge --- sql/sql_table.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 862a36f8876..0e670ba1f30 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1558,9 +1558,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, /* Don't give warnings for not found errors, as we already generate notes */ thd->no_warnings_for_error= 1; - /* Remove the tables from the HANDLER list, if they are in it. */ - mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL, 1); - for (table= tables; table; table= table->next_local) { char *db=table->db; From d179bb64c261a02a21ffcc50bed8bc93dba606cf Mon Sep 17 00:00:00 2001 From: "davi@mysql.com/endora.local" <> Date: Thu, 29 Nov 2007 09:42:26 -0200 Subject: [PATCH 20/29] Bug#23713 LOCK TABLES + CREATE TRIGGER + FLUSH TABLES WITH READ LOCK = deadlock This bug is actually two bugs in one, one of which is CREATE TRIGGER under LOCK TABLES and the other is CREATE TRIGGER under LOCK TABLES simultaneous to a FLUSH TABLES WITH READ LOCK (global read lock). Both situations could lead to a server crash or deadlock. The first problem arises from the fact that when under LOCK TABLES, if the table is in the set of locked tables, the table is already open and it doesn't need to be reopened (not a placeholder). Also in this case, if the table is not write locked, a exclusive lock can't be acquired because of a possible deadlock with another thread also holding a (read) lock on the table. The second issue arises from the fact that one should never wait for a global read lock if it's holding any locked tables, because the global read lock is waiting for these tables and this leads to a circular wait deadlock. The solution for the first case is to check if the table is write locked and upgraded the write lock to a exclusive lock and fail otherwise for non write locked tables. Grabbin the exclusive lock in this case also means to ensure that the table is opened only by the calling thread. The second issue is partly fixed by not waiting for the global read lock if the thread is holding any locked tables. The second issue is only partly addressed in this patch because it turned out to be much wider and also affects other DDL statements. Reported as Bug#32395 --- mysql-test/r/trigger.result | 35 ++++++++++ ...rant.result => trigger_notembedded.result} | 1 + mysql-test/t/trigger.test | 47 +++++++++++++ ...er-grant.test => trigger_notembedded.test} | 34 ++++++++++ sql/mysql_priv.h | 6 +- sql/sql_base.cc | 42 +++++++++++- sql/sql_handler.cc | 7 +- sql/sql_rename.cc | 2 +- sql/sql_table.cc | 12 ++-- sql/sql_trigger.cc | 68 ++++++++++--------- 10 files changed, 207 insertions(+), 47 deletions(-) rename mysql-test/r/{trigger-grant.result => trigger_notembedded.result} (99%) rename mysql-test/t/{trigger-grant.test => trigger_notembedded.test} (96%) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index d322d4cda76..8b384dfdc4e 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -1981,4 +1981,39 @@ drop table table_25411_b; DROP TRIGGER IF EXISTS trg; SHOW CREATE TRIGGER trg; ERROR HY000: Trigger does not exist +drop table if exists t1; +create table t1 (i int, j int); +create trigger t1_bi before insert on t1 for each row begin end; +create trigger t1_bi before insert on t1 for each row begin end; +ERROR 42000: This version of MySQL doesn't yet support 'multiple triggers with the same action time and event for one table' +drop trigger t1_bi; +drop trigger t1_bi; +ERROR HY000: Trigger does not exist +lock tables t1 read; +create trigger t1_bi before insert on t1 for each row begin end; +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +create trigger t1_bi before insert on t1 for each row begin end; +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +drop trigger t1_bi; +ERROR HY000: Trigger does not exist +unlock tables; +create trigger t1_bi before insert on t1 for each row begin end; +lock tables t1 read; +create trigger t1_bi before insert on t1 for each row begin end; +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +drop trigger t1_bi; +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +unlock tables; +drop trigger t1_bi; +lock tables t1 write; +create trigger b1_bi before insert on t1 for each row set new.i = new.i + 10; +insert into t1 values (10, 10); +drop trigger b1_bi; +insert into t1 values (10, 10); +select * from t1; +i j +20 10 +10 10 +unlock tables; +drop table t1; End of 5.1 tests. diff --git a/mysql-test/r/trigger-grant.result b/mysql-test/r/trigger_notembedded.result similarity index 99% rename from mysql-test/r/trigger-grant.result rename to mysql-test/r/trigger_notembedded.result index 14b8c98f2fa..d56f83993a6 100644 --- a/mysql-test/r/trigger-grant.result +++ b/mysql-test/r/trigger_notembedded.result @@ -448,3 +448,4 @@ DROP TABLE t1; DROP DATABASE mysqltest_db1; USE test; End of 5.0 tests. +End of 5.1 tests. diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index e1037d8bf9c..1aeac91e5ad 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -2257,4 +2257,51 @@ DROP TRIGGER IF EXISTS trg; --error ER_TRG_DOES_NOT_EXIST SHOW CREATE TRIGGER trg; +# +# Bug#23713 LOCK TABLES + CREATE TRIGGER + FLUSH TABLES WITH READ LOCK = deadlock +# +# Test of trigger creation and removal under LOCK TABLES +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (i int, j int); + +create trigger t1_bi before insert on t1 for each row begin end; +--error ER_NOT_SUPPORTED_YET +create trigger t1_bi before insert on t1 for each row begin end; +drop trigger t1_bi; +--error ER_TRG_DOES_NOT_EXIST +drop trigger t1_bi; + +lock tables t1 read; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +create trigger t1_bi before insert on t1 for each row begin end; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +create trigger t1_bi before insert on t1 for each row begin end; +--error ER_TRG_DOES_NOT_EXIST +drop trigger t1_bi; +unlock tables; + +create trigger t1_bi before insert on t1 for each row begin end; +lock tables t1 read; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +create trigger t1_bi before insert on t1 for each row begin end; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +drop trigger t1_bi; +unlock tables; +drop trigger t1_bi; + +lock tables t1 write; +create trigger b1_bi before insert on t1 for each row set new.i = new.i + 10; +insert into t1 values (10, 10); +drop trigger b1_bi; +insert into t1 values (10, 10); +select * from t1; +unlock tables; + +drop table t1; + --echo End of 5.1 tests. diff --git a/mysql-test/t/trigger-grant.test b/mysql-test/t/trigger_notembedded.test similarity index 96% rename from mysql-test/t/trigger-grant.test rename to mysql-test/t/trigger_notembedded.test index 8145212ed5b..748ae6e1c27 100644 --- a/mysql-test/t/trigger-grant.test +++ b/mysql-test/t/trigger_notembedded.test @@ -875,3 +875,37 @@ DROP DATABASE mysqltest_db1; USE test; --echo End of 5.0 tests. + +# +# Bug#23713 LOCK TABLES + CREATE TRIGGER + FLUSH TABLES WITH READ LOCK = deadlock +# + +# Test temporarily disable due to Bug#32395 +--disable_parsing +create table t1 (i int); +connect (flush,localhost,root,,test,,); +connection default; +--echo connection: default +lock tables t1 write; +connection flush; +--echo connection: flush +--send flush tables with read lock; +connection default; +--echo connection: default +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Flushing tables"; +--source include/wait_condition.inc +create trigger t1_bi before insert on t1 for each row begin end; +unlock tables; +connection flush; +--echo connection: flush +--reap +unlock tables; +connection default; +select * from t1; +drop table t1; +disconnect flush; +--enable_parsing + +--echo End of 5.1 tests. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8a0993d4f14..cafb7487e35 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -978,7 +978,8 @@ bool check_dup(const char *db, const char *name, TABLE_LIST *tables); bool compare_record(TABLE *table); bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name); - +void wait_while_table_is_used(THD *thd, TABLE *table, + enum ha_extra_function function); bool table_cache_init(void); void table_cache_free(void); bool table_def_init(void); @@ -1141,6 +1142,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update, uint lock_flags); TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem, bool *refresh, uint flags); +bool name_lock_locked_table(THD *thd, TABLE_LIST *tables); bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in); TABLE *table_cache_insert_placeholder(THD *thd, const char *key, uint key_length); @@ -1292,7 +1294,7 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables); bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, List *,enum ha_rkey_function,Item *,ha_rows,ha_rows); void mysql_ha_flush(THD *thd); -void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables); +void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked); void mysql_ha_cleanup(THD *thd); /* sql_base.cc */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3cc8a685aa9..ba8b7fc1330 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2199,6 +2199,41 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond) } +/** + Exclusively name-lock a table that is already write-locked by the + current thread. + + @param thd current thread context + @param tables able list containing one table to open. + + @return FALSE on success, TRUE otherwise. +*/ + +bool name_lock_locked_table(THD *thd, TABLE_LIST *tables) +{ + DBUG_ENTER("name_lock_locked_table"); + + /* Under LOCK TABLES we must only accept write locked tables. */ + tables->table= find_locked_table(thd, tables->db, tables->table_name); + + if (!tables->table) + my_error(ER_TABLE_NOT_LOCKED, MYF(0), tables->alias); + else if (tables->table->reginfo.lock_type < TL_WRITE_LOW_PRIORITY) + my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), tables->alias); + else + { + /* + Ensures that table is opened only by this thread and that no + other statement will open this table. + */ + wait_while_table_is_used(thd, tables->table, HA_EXTRA_FORCE_REOPEN); + DBUG_RETURN(FALSE); + } + + DBUG_RETURN(TRUE); +} + + /* Open table which is already name-locked by this thread. @@ -3118,6 +3153,9 @@ bool reopen_table(TABLE *table) then there is only one table open and locked. This means that the function probably has to be adjusted before it can be used anywhere outside ALTER TABLE. + + @note Must not use TABLE_SHARE::table_name/db of the table being closed, + the strings are used in a loop even after the share may be freed. */ void close_data_files_and_morph_locks(THD *thd, const char *db, @@ -3387,8 +3425,8 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) @param send_refresh Should we awake waiters even if we didn't close any tables? */ -void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, - bool send_refresh) +static void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, + bool send_refresh) { bool found= send_refresh; DBUG_ENTER("close_old_data_files"); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 31d6b28a73c..a4ba6f1140b 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -714,17 +714,16 @@ static TABLE_LIST *mysql_ha_find(THD *thd, TABLE_LIST *tables) @param thd Thread identifier. @param tables The list of tables to remove. + @param is_locked If LOCK_open is locked. @note Broadcasts refresh if it closed a table with old version. */ -void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables) +void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked) { TABLE_LIST *hash_tables, *next; DBUG_ENTER("mysql_ha_rm_tables"); - safe_mutex_assert_not_owner(&LOCK_open); - DBUG_ASSERT(tables); hash_tables= mysql_ha_find(thd, tables); @@ -733,7 +732,7 @@ void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables) { next= hash_tables->next_local; if (hash_tables->table) - mysql_ha_close_table(thd, hash_tables, FALSE); + mysql_ha_close_table(thd, hash_tables, is_locked); hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables); hash_tables= next; } diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 66d89edc146..9dd8e1b70d4 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -51,7 +51,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) DBUG_RETURN(1); } - mysql_ha_rm_tables(thd, table_list); + mysql_ha_rm_tables(thd, table_list, FALSE); if (wait_if_global_read_lock(thd,0,1)) DBUG_RETURN(1); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 0e670ba1f30..c618d170fb7 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1521,7 +1521,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, built_query.append("DROP TABLE "); } - mysql_ha_rm_tables(thd, tables); + mysql_ha_rm_tables(thd, tables, FALSE); pthread_mutex_lock(&LOCK_open); @@ -3705,14 +3705,16 @@ mysql_rename_table(handlerton *base, const char *old_db, Win32 clients must also have a WRITE LOCK on the table ! */ -static void wait_while_table_is_used(THD *thd,TABLE *table, - enum ha_extra_function function) +void wait_while_table_is_used(THD *thd, TABLE *table, + enum ha_extra_function function) { DBUG_ENTER("wait_while_table_is_used"); DBUG_PRINT("enter", ("table: '%s' share: 0x%lx db_stat: %u version: %lu", table->s->table_name.str, (ulong) table->s, table->db_stat, table->s->version)); + safe_mutex_assert_owner(&LOCK_open); + VOID(table->file->extra(function)); /* Mark all tables that are in use as 'old' */ mysql_lock_abort(thd, table, TRUE); /* end threads waiting on lock */ @@ -4031,7 +4033,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); - mysql_ha_rm_tables(thd, tables); + mysql_ha_rm_tables(thd, tables, FALSE); for (table= tables; table; table= table->next_local) { @@ -5795,7 +5797,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, build_table_filename(reg_path, sizeof(reg_path), db, table_name, reg_ext, 0); build_table_filename(path, sizeof(path), db, table_name, "", 0); - mysql_ha_rm_tables(thd, table_list); + mysql_ha_rm_tables(thd, table_list, FALSE); /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ if (alter_info->tablespace_op != NO_TABLESPACE_OP) diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 3129bd81572..b421f57b7ab 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -323,6 +323,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) TABLE *table; bool result= TRUE; String stmt_query; + bool need_start_waiting= FALSE; DBUG_ENTER("mysql_create_or_drop_trigger"); @@ -374,10 +375,12 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) /* We don't want perform our operations while global read lock is held so we have to wait until its end and then prevent it from occurring - again until we are done. (Acquiring LOCK_open is not enough because - global read lock is held without holding LOCK_open). + again until we are done, unless we are under lock tables. (Acquiring + LOCK_open is not enough because global read lock is held without holding + LOCK_open). */ - if (wait_if_global_read_lock(thd, 0, 1)) + if (!thd->locked_tables && + !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) DBUG_RETURN(TRUE); VOID(pthread_mutex_lock(&LOCK_open)); @@ -433,35 +436,25 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) goto end; } - if (lock_table_names(thd, tables)) - goto end; + /* We also don't allow creation of triggers on views. */ + tables->required_type= FRMTYPE_TABLE; - /* - If the table is under LOCK TABLES, lock_table_names() does not set - tables->table. Find the table in open_tables. - */ - if (!tables->table && thd->locked_tables) + /* Keep consistent with respect to other DDL statements */ + mysql_ha_rm_tables(thd, tables, TRUE); + + if (thd->locked_tables) { - for (table= thd->open_tables; - table && (strcmp(table->s->table_name.str, tables->table_name) || - strcmp(table->s->db.str, tables->db)); - table= table->next) {} - tables->table= table; + /* Table must be write locked */ + if (name_lock_locked_table(thd, tables)) + goto end; } - if (!tables->table) + else { - /* purecov: begin inspected */ - my_error(ER_TABLE_NOT_LOCKED, MYF(0), tables->alias); - goto end; - /* purecov: end */ - } - - /* No need to reopen the table if it is locked with LOCK TABLES. */ - if (!thd->locked_tables || (tables->table->in_use != thd)) - { - /* We also don't allow creation of triggers on views. */ - tables->required_type= FRMTYPE_TABLE; + /* Grab the name lock and insert the placeholder*/ + if (lock_table_names(thd, tables)) + goto end; + /* Convert the placeholder to a real table */ if (reopen_name_locked_table(thd, tables, TRUE)) { unlock_table_name(thd, tables); @@ -489,13 +482,20 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) /* Under LOCK TABLES we must reopen the table to activate the trigger. */ if (!result && thd->locked_tables) { - /* - Must not use table->s->db.str or table->s->table_name.str here. - The strings are used in a loop even after the share may be freed. - */ + /* Make table suitable for reopening */ close_data_files_and_morph_locks(thd, tables->db, tables->table_name); thd->in_lock_tables= 1; - result= reopen_tables(thd, 1, 0); + if (reopen_tables(thd, 1, 1)) + { + /* To be safe remove this table from the set of LOCKED TABLES */ + unlink_open_table(thd, tables->table, FALSE); + + /* + Ignore reopen_tables errors for now. It's better not leave master/slave + in a inconsistent state. + */ + thd->clear_error(); + } thd->in_lock_tables= 0; } @@ -507,7 +507,9 @@ end: } VOID(pthread_mutex_unlock(&LOCK_open)); - start_waiting_global_read_lock(thd); + + if (need_start_waiting) + start_waiting_global_read_lock(thd); if (!result) send_ok(thd); From a1666e067adcac4e04afef256e52233916101e00 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@ibm." <> Date: Fri, 30 Nov 2007 12:14:07 +0300 Subject: [PATCH 21/29] A test case for BUG#26676: VIEW using old table schema in a session. The following clarification should be made in The Manual: Standard SQL is quite clear that, if new columns are added to a table after a view on that table is created with "select *", the new columns will not become part of the view. In all cases, the view definition (view structure) is frozen at CREATE time, so changes to the underlying tables do not affect the view structure. --- mysql-test/r/view.result | 43 +++++++++++++++++++++++++++++++++ mysql-test/t/view.test | 51 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 60c3ff68e67..2971af7347d 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -3617,4 +3617,47 @@ DROP TABLE `t-2`; DROP VIEW `v-2`; DROP DATABASE `d-1`; USE test; + +# +# Bug#26676: VIEW using old table schema in a session. +# + +DROP VIEW IF EXISTS v1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(c1 INT, c2 INT); +INSERT INTO t1 VALUES (1, 2), (3, 4); + +SELECT * FROM t1; +c1 c2 +1 2 +3 4 + +CREATE VIEW v1 AS SELECT * FROM t1; + +SELECT * FROM v1; +c1 c2 +1 2 +3 4 + +ALTER TABLE t1 ADD COLUMN c3 INT AFTER c2; + +SELECT * FROM t1; +c1 c2 c3 +1 2 NULL +3 4 NULL + +SELECT * FROM v1; +c1 c2 +1 2 +3 4 + +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`c1` AS `c1`,`t1`.`c2` AS `c2` from `t1` latin1 latin1_swedish_ci + +DROP VIEW v1; +DROP TABLE t1; + +# End of test case for Bug#26676. + End of 5.1 tests. diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index e388aa61803..7f769c50449 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -3475,4 +3475,55 @@ DROP VIEW `v-2`; DROP DATABASE `d-1`; USE test; +--echo +--echo # +--echo # Bug#26676: VIEW using old table schema in a session. +--echo # +--echo + +--disable_warnings +DROP VIEW IF EXISTS v1; +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1(c1 INT, c2 INT); +INSERT INTO t1 VALUES (1, 2), (3, 4); + +--echo + +SELECT * FROM t1; + +--echo + +CREATE VIEW v1 AS SELECT * FROM t1; + +--echo + +SELECT * FROM v1; + +--echo + +ALTER TABLE t1 ADD COLUMN c3 INT AFTER c2; + +--echo + +SELECT * FROM t1; + +--echo + +SELECT * FROM v1; + +--echo + +SHOW CREATE VIEW v1; + +--echo + +DROP VIEW v1; +DROP TABLE t1; + +--echo +--echo # End of test case for Bug#26676. +--echo + --echo End of 5.1 tests. From ee9bafc1c5021d92cdadb690970ab01ccfce7c27 Mon Sep 17 00:00:00 2001 From: "davi@mysql.com/endora.local" <> Date: Fri, 30 Nov 2007 09:34:25 -0200 Subject: [PATCH 22/29] Bug#22312 Syntax error in expression with INTERVAL() Parser rejects valid INTERVAL() expressions when associated with arithmetic operators. The problem is the way in which the expression and interval grammar rules were organized caused shift/reduce conflicts. The solution is to tweak the interval rules to avoid shift/reduce conflicts by removing the broken interval_expr rule and explicitly specify it's content where necessary. Original fix by Davi Arnaut, revised and improved rules by Marc Alff --- mysql-test/r/parser.result | 43 ++++++++++++++++++++++++++++ mysql-test/t/parser.test | 28 +++++++++++++++++++ sql/sql_yacc.yy | 57 ++++++++++++++++++++------------------ 3 files changed, 101 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/parser.result b/mysql-test/r/parser.result index 76326f65f08..ef53f227ec0 100644 --- a/mysql-test/r/parser.result +++ b/mysql-test/r/parser.result @@ -484,3 +484,46 @@ select atan(10, 20 "p2"); ERROR 42000: Incorrect parameters in the call to native function 'atan' select atan(10 AS p1, 20 AS p2); ERROR 42000: Incorrect parameters in the call to native function 'atan' +DROP TABLE IF EXISTS t1; +SELECT STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL 10 MINUTE; +STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL 10 MINUTE +NULL +SELECT STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL (INTERVAL(1,2,3) + 1) MINUTE; +STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL (INTERVAL(1,2,3) + 1) MINUTE +NULL +SELECT "1997-12-31 23:59:59" + INTERVAL 1 SECOND; +"1997-12-31 23:59:59" + INTERVAL 1 SECOND +1998-01-01 00:00:00 +SELECT 1 + INTERVAL(1,0,1,2) + 1; +1 + INTERVAL(1,0,1,2) + 1 +4 +SELECT INTERVAL(1^1,0,1,2) + 1; +INTERVAL(1^1,0,1,2) + 1 +2 +SELECT INTERVAL(1,0+1,2,3) * 5.5; +INTERVAL(1,0+1,2,3) * 5.5 +5.5 +SELECT INTERVAL(3,3,1+3,4+4) / 0.5; +INTERVAL(3,3,1+3,4+4) / 0.5 +2.0000 +SELECT (INTERVAL(1,0,1,2) + 5) * 7 + INTERVAL(1,0,1,2) / 2; +(INTERVAL(1,0,1,2) + 5) * 7 + INTERVAL(1,0,1,2) / 2 +50.0000 +SELECT INTERVAL(1,0,1,2) + 1, 5 * INTERVAL(1,0,1,2); +INTERVAL(1,0,1,2) + 1 5 * INTERVAL(1,0,1,2) +3 10 +SELECT INTERVAL(0,(1*5)/2) + INTERVAL(5,4,3); +INTERVAL(0,(1*5)/2) + INTERVAL(5,4,3) +2 +SELECT 1^1 + INTERVAL 1+1 SECOND & 1 + INTERVAL 1+1 SECOND; +1^1 + INTERVAL 1+1 SECOND & 1 + INTERVAL 1+1 SECOND +NULL +SELECT 1%2 - INTERVAL 1^1 SECOND | 1%2 - INTERVAL 1^1 SECOND; +1%2 - INTERVAL 1^1 SECOND | 1%2 - INTERVAL 1^1 SECOND +NULL +CREATE TABLE t1 (a INT, b DATETIME); +INSERT INTO t1 VALUES (INTERVAL(3,2,1) + 1, "1997-12-31 23:59:59" + INTERVAL 1 SECOND); +SELECT * FROM t1 WHERE a = INTERVAL(3,2,1) + 1; +a b +3 1998-01-01 00:00:00 +DROP TABLE t1; diff --git a/mysql-test/t/parser.test b/mysql-test/t/parser.test index 79c9129bb74..9170308a4f2 100644 --- a/mysql-test/t/parser.test +++ b/mysql-test/t/parser.test @@ -629,3 +629,31 @@ select atan(10, 20 "p2"); -- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT select atan(10 AS p1, 20 AS p2); +# +# Bug#22312 Syntax error in expression with INTERVAL() +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +SELECT STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL 10 MINUTE; +SELECT STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL (INTERVAL(1,2,3) + 1) MINUTE; +SELECT "1997-12-31 23:59:59" + INTERVAL 1 SECOND; +SELECT 1 + INTERVAL(1,0,1,2) + 1; +SELECT INTERVAL(1^1,0,1,2) + 1; +SELECT INTERVAL(1,0+1,2,3) * 5.5; +SELECT INTERVAL(3,3,1+3,4+4) / 0.5; +SELECT (INTERVAL(1,0,1,2) + 5) * 7 + INTERVAL(1,0,1,2) / 2; +SELECT INTERVAL(1,0,1,2) + 1, 5 * INTERVAL(1,0,1,2); +SELECT INTERVAL(0,(1*5)/2) + INTERVAL(5,4,3); + +--disable_warnings +SELECT 1^1 + INTERVAL 1+1 SECOND & 1 + INTERVAL 1+1 SECOND; +SELECT 1%2 - INTERVAL 1^1 SECOND | 1%2 - INTERVAL 1^1 SECOND; +--enable_warnings + +CREATE TABLE t1 (a INT, b DATETIME); +INSERT INTO t1 VALUES (INTERVAL(3,2,1) + 1, "1997-12-31 23:59:59" + INTERVAL 1 SECOND); +SELECT * FROM t1 WHERE a = INTERVAL(3,2,1) + 1; +DROP TABLE t1; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 5de142ca83a..80e354aef98 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -508,10 +508,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 280 shift/reduce conflicts. + Currently there are 177 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 280 +%expect 177 /* Comments for TOKENS. @@ -1157,7 +1157,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); variable variable_aux bool_pri predicate bit_expr table_wild simple_expr udf_expr - expr_or_default set_expr_or_default interval_expr + expr_or_default set_expr_or_default param_marker geometry_function signed_literal now_or_signed_literal opt_escape sp_opt_default @@ -6569,10 +6569,10 @@ bit_expr: { $$= new Item_func_plus($1,$3); } | bit_expr '-' bit_expr %prec '-' { $$= new Item_func_minus($1,$3); } - | bit_expr '+' interval_expr interval %prec '+' - { $$= new Item_date_add_interval($1,$3,$4,0); } - | bit_expr '-' interval_expr interval %prec '-' - { $$= new Item_date_add_interval($1,$3,$4,1); } + | bit_expr '+' INTERVAL_SYM expr interval %prec '+' + { $$= new Item_date_add_interval($1,$4,$5,0); } + | bit_expr '-' INTERVAL_SYM expr interval %prec '-' + { $$= new Item_date_add_interval($1,$4,$5,1); } | bit_expr '*' bit_expr %prec '*' { $$= new Item_func_mul($1,$3); } | bit_expr '/' bit_expr %prec '/' @@ -6622,11 +6622,6 @@ all_or_any: | ANY_SYM { $$ = 0; } ; -interval_expr: - INTERVAL_SYM expr %prec INTERVAL_SYM - { $$=$2; } - ; - simple_expr: simple_ident | function_call_keyword @@ -6722,18 +6717,9 @@ simple_expr: $$= new (YYTHD->mem_root) Item_insert_value(Lex->current_context(), $3); } - | interval_expr interval '+' expr + | INTERVAL_SYM expr interval '+' expr %prec INTERVAL_SYM /* we cannot put interval before - */ - { $$= new (YYTHD->mem_root) Item_date_add_interval($4,$1,$2,0); } - | interval_expr - { - if ($1->type() != Item::ROW_ITEM) - { - my_parse_error(ER(ER_SYNTAX_ERROR)); - MYSQL_YYABORT; - } - $$= new (YYTHD->mem_root) Item_func_interval((Item_row *)$1); - } + { $$= new (YYTHD->mem_root) Item_date_add_interval($5,$2,$3,0); } ; /* @@ -6761,6 +6747,23 @@ function_call_keyword: { $$= new (YYTHD->mem_root) Item_func_hour($3); } | INSERT '(' expr ',' expr ',' expr ',' expr ')' { $$= new (YYTHD->mem_root) Item_func_insert($3,$5,$7,$9); } + | INTERVAL_SYM '(' expr ',' expr ')' %prec INTERVAL_SYM + { + THD *thd= YYTHD; + List *list= new (thd->mem_root) List; + list->push_front($5); + list->push_front($3); + Item_row *item= new (thd->mem_root) Item_row(*list); + $$= new (thd->mem_root) Item_func_interval(item); + } + | INTERVAL_SYM '(' expr ',' expr ',' expr_list ')' %prec INTERVAL_SYM + { + THD *thd= YYTHD; + $7->push_front($5); + $7->push_front($3); + Item_row *item= new (thd->mem_root) Item_row(*$7); + $$= new (thd->mem_root) Item_func_interval(item); + } | LEFT '(' expr ',' expr ')' { $$= new (YYTHD->mem_root) Item_func_left($3,$5); } | MINUTE_SYM '(' expr ')' @@ -6838,10 +6841,10 @@ function_call_nonkeyword: $$= new (YYTHD->mem_root) Item_func_curtime_local($3); Lex->safe_to_cache_query=0; } - | DATE_ADD_INTERVAL '(' expr ',' interval_expr interval ')' - { $$= new (YYTHD->mem_root) Item_date_add_interval($3,$5,$6,0); } - | DATE_SUB_INTERVAL '(' expr ',' interval_expr interval ')' - { $$= new (YYTHD->mem_root) Item_date_add_interval($3,$5,$6,1); } + | DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' %prec INTERVAL_SYM + { $$= new (YYTHD->mem_root) Item_date_add_interval($3,$6,$7,0); } + | DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' %prec INTERVAL_SYM + { $$= new (YYTHD->mem_root) Item_date_add_interval($3,$6,$7,1); } | EXTRACT_SYM '(' interval FROM expr ')' { $$=new (YYTHD->mem_root) Item_extract( $3, $5); } | GET_FORMAT '(' date_time_type ',' expr ')' From 609a1d0d2dd087ca30c1eb4f79ee96c8fece8b80 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@ibm." <> Date: Fri, 30 Nov 2007 14:49:34 +0300 Subject: [PATCH 23/29] BUG#32723 (grant3.test fails) can not be reproduced. Enabling the test case. --- mysql-test/t/disabled.def | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 3746d20ebd8..0b0231e0ff0 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -19,7 +19,6 @@ events : Bug#32664 events.test fails randomly events_scheduling : Bug#29830 Test case 'events_scheduling' fails on Mac OS X and Windows lowercase_table3 : Bug#32667 lowercase_table3.test reports to error log kill : Bug#29149: Test "kill" fails on Windows -grant3 : Bug#32723: grant3.test fails innodb_mysql : Bug#32724: innodb_mysql.test fails randomly wait_timeout : Bug#32801 wait_timeout.test fails randomly kill : Bug#29149 Test "kill" fails on Windows From 8377c71f413b6087ace9eef3ea1cf412b93c74ff Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@ibm." <> Date: Fri, 30 Nov 2007 16:12:20 +0300 Subject: [PATCH 24/29] A patch for BUG#32148: killing a query may be ineffective. The problem was that THD::killed was reset after a command was read from the socket, but before it was actually handled. That lead to a race: if another KILL statement was issued for this connection in the middle of reading from the socket and processing a command, THD::killed state would be cleaned. The fix is to move this cleanup into net_send_error() function. A sample test case exists in binlog_killed.test: - connection 1: start a new transaction on table t1; - connection 2: send query to the server (w/o waiting for the result) to update data in table t1 -- this query will be blocked since there is unfinished transaction; - connection 1: kill query in connection 2 and finish the transaction; - connection 2: get result of the previous query -- it should be the "query-killed" error. This test however contains race condition, which can not be fixed with the current protocol: there is no way to guarantee, that the server will receive and start processing the query in connection 2 (which is intended to get blocked) before the KILL command (sent in the connection 1) will arrive. In other words, there is no way to ensure that the following sequence will not happen: - connection 1: start a new transaction on table t1; - connection 1: kill query in connection 2 and finish the transaction; - connection 2: send query to the server (w/o waiting for the result) to update data in table t1 -- this query will be blocked since there is unfinished transaction; - connection 2: get result of the previous query -- the query will succeed. So, there is no test case for this bug, since it's impossible to write a reliable test case under the current circumstances. --- sql/protocol.cc | 6 ++++++ sql/sql_parse.cc | 7 +------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/sql/protocol.cc b/sql/protocol.cc index bf8faec006a..713f4ed3d25 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -76,6 +76,12 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) DBUG_ASSERT(!thd->spcont); + if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) + { + thd->killed= THD::NOT_KILLED; + thd->mysys_var->abort= 0; + } + if (net && net->no_send_error) { thd->clear_error(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a43d8335b9e..df425557bdf 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -788,12 +788,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, NET *net= &thd->net; bool error= 0; DBUG_ENTER("dispatch_command"); - - if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) - { - thd->killed= THD::NOT_KILLED; - thd->mysys_var->abort= 0; - } + DBUG_PRINT("info",("packet: '%*.s'; command: %d", packet_length, packet, command)); thd->command=command; /* From 69792afb144775874635d091204dccff724b5cc5 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Tue, 4 Dec 2007 18:51:03 +0300 Subject: [PATCH 25/29] Bug#32965 main.ctype_create fails. Disable failing test case. --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 0b0231e0ff0..7a3892a90a6 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -22,3 +22,4 @@ kill : Bug#29149: Test "kill" fails on Windows innodb_mysql : Bug#32724: innodb_mysql.test fails randomly wait_timeout : Bug#32801 wait_timeout.test fails randomly kill : Bug#29149 Test "kill" fails on Windows +ctype_create : Bug#32965 main.ctype_create fails From 1bfc9d692cbc0693d5570e0c156cd5607c128397 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@station." <> Date: Tue, 4 Dec 2007 18:52:43 +0300 Subject: [PATCH 26/29] Bug#32966 main.status fails. Disable failing test case. --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 7a3892a90a6..42fa242c7e1 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -23,3 +23,4 @@ innodb_mysql : Bug#32724: innodb_mysql.test fails randomly wait_timeout : Bug#32801 wait_timeout.test fails randomly kill : Bug#29149 Test "kill" fails on Windows ctype_create : Bug#32965 main.ctype_create fails +status : Bug#32966 main.status fails From b79b57c645048c197f9edfb09484eea631005751 Mon Sep 17 00:00:00 2001 From: "davi@mysql.com/endora.local" <> Date: Wed, 5 Dec 2007 09:48:13 -0200 Subject: [PATCH 27/29] Bug#32996 log_tables.test fails sporadically Only select entries from the general_log that were issued by the current connection. --- mysql-test/r/log_tables.result | 3 ++- mysql-test/t/log_tables.test | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result index a31f2047670..0a7634df85a 100644 --- a/mysql-test/r/log_tables.result +++ b/mysql-test/r/log_tables.result @@ -605,6 +605,7 @@ DROP PROCEDURE IF EXISTS `db_17876.archiveGeneralLog`; DROP DATABASE IF EXISTS `db_17876`; SET GLOBAL general_log = @old_general_log_state; SET GLOBAL slow_query_log = @old_slow_log_state; +select CONNECTION_ID() into @thread_id; truncate table mysql.general_log; set @old_general_log_state = @@global.general_log; set global general_log = on; @@ -711,7 +712,7 @@ set @lparam = "000 001 002 003 004 005 006 007 008 009" prepare long_query from "select ? as long_query"; execute long_query using @lparam; set global general_log = off; -select command_type, argument from mysql.general_log; +select command_type, argument from mysql.general_log where thread_id = @thread_id; command_type argument Query set @lparam = "000 001 002 003 004 005 006 007 008 009" "010 011 012 013 014 015 016 017 018 019" diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test index f02138fb30b..0c986c6d63a 100644 --- a/mysql-test/t/log_tables.test +++ b/mysql-test/t/log_tables.test @@ -811,6 +811,7 @@ SET GLOBAL slow_query_log = @old_slow_log_state; # Bug#21557 entries in the general query log truncated at 1000 characters. # +select CONNECTION_ID() into @thread_id; truncate table mysql.general_log; set @old_general_log_state = @@global.general_log; set global general_log = on; @@ -921,7 +922,7 @@ prepare long_query from "select ? as long_query"; execute long_query using @lparam; --enable_result_log set global general_log = off; -select command_type, argument from mysql.general_log; +select command_type, argument from mysql.general_log where thread_id = @thread_id; deallocate prepare long_query; set global general_log = @old_general_log_state; From 2cf168d6aac6af07a2daa8542fc3742701943f13 Mon Sep 17 00:00:00 2001 From: "joerg@trift2." <> Date: Fri, 7 Dec 2007 11:54:59 +0100 Subject: [PATCH 28/29] Makefile.am In the "test-bt" target, replace the call "$(MAKE) test-embedded" by the actions of that target. --- Makefile.am | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 0c9a0d85d26..73eeb425705 100644 --- a/Makefile.am +++ b/Makefile.am @@ -102,6 +102,7 @@ test-binlog-statement: @PERL@ ./mysql-test-run.pl $(force) --mysqld=--binlog-format=statement test-embedded: + # This code is duplicated in "test-bt", see the Changeset comment of 2007-Dec-07 if [ -e bin/mysqltest_embedded -o -e libmysqld/examples/mysqltest_embedded ] ; then \ cd mysql-test ; MTR_BUILD_THREAD=auto \ @PERL@ ./mysql-test-run.pl --comment=embedded --force --timer \ @@ -140,7 +141,13 @@ test-bt: -cd mysql-test ; MTR_BUILD_THREAD=auto \ @PERL@ ./mysql-test-run.pl --comment=NDB --force --timer \ --with-ndbcluster-only - -$(MAKE) test-embedded + -if [ -e bin/mysqltest_embedded -o -e libmysqld/examples/mysqltest_embedded ] ; then \ + cd mysql-test ; MTR_BUILD_THREAD=auto \ + @PERL@ ./mysql-test-run.pl --comment=embedded --force --timer \ + --embedded-server --skip-rpl --skip-ndbcluster ; \ + else \ + echo "no program found for 'embedded' tests - skipped testing" ; \ + fi -cd mysql-test ; MTR_BUILD_THREAD=auto \ @PERL@ ./mysql-test-run.pl --force --comment=funcs1_ps --ps-protocol --suite=funcs_1 -cd mysql-test ; MTR_BUILD_THREAD=auto \ From 151504a3d0e83fea92528116dd9855ce93683636 Mon Sep 17 00:00:00 2001 From: "joerg@trift2." <> Date: Fri, 7 Dec 2007 14:46:52 +0100 Subject: [PATCH 29/29] Makefile.am Makefile syntax error, comment should precede the whole target. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 73eeb425705..bc28fa3082b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -101,8 +101,8 @@ test-binlog-statement: cd mysql-test ; \ @PERL@ ./mysql-test-run.pl $(force) --mysqld=--binlog-format=statement +# This code is duplicated in "test-bt", see the Changeset comment of 2007-Dec-07 test-embedded: - # This code is duplicated in "test-bt", see the Changeset comment of 2007-Dec-07 if [ -e bin/mysqltest_embedded -o -e libmysqld/examples/mysqltest_embedded ] ; then \ cd mysql-test ; MTR_BUILD_THREAD=auto \ @PERL@ ./mysql-test-run.pl --comment=embedded --force --timer \