From 4ffd997a8e3548c186078111d23e9a6a708f4f23 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 23 Jul 2007 15:05:50 +0200 Subject: [PATCH 01/26] Bug#28012 Patch : IM crashes instead of reporting an error when mysqldpath is bad On the windows platform, if an instance object failed to initialize during program start, the instance manager would crash. This could happen if an incorrect mysqld path was supplied in the defaults configuration file. The patch prevents the program from crashing and makes it show an error message instead. mysql-test/r/im_options.result: - Options have changed names. server-tools/instance-manager/instance.cc: - Added code to verify that the instance object was initialized before any attempt is made to start the associated process. - Instance::complete_initialization method will now return TRUE on an error during instance initialization. server-tools/instance-manager/instance_options.cc: - Parsed result byte sequence from executed process doesn't contain a new line character anymore. server-tools/instance-manager/parse_output.cc: - 'popen' didn't behave as intended on the windows platform. - The function parse_output_and_get_value was completly rewritten to correct the error in the windows built and to be more easily maintained across platforms. server-tools/instance-manager/parse_output.h: - 'popen' didn't behave as intended on the windows platform. - The function parse_output_and_get_value was completly rewritten to correct the error in the windows built and to be more easily maintained across platforms. server-tools/instance-manager/portability.h: - Add more portability constants for convenience. --- mysql-test/r/im_options.result | 10 +- server-tools/instance-manager/instance.cc | 36 +- .../instance-manager/instance_options.cc | 13 +- server-tools/instance-manager/parse_output.cc | 421 +++++++++++++++--- server-tools/instance-manager/parse_output.h | 16 +- server-tools/instance-manager/portability.h | 5 + 6 files changed, 393 insertions(+), 108 deletions(-) diff --git a/mysql-test/r/im_options.result b/mysql-test/r/im_options.result index 3225db0c8c5..22bd5d5bdf6 100644 --- a/mysql-test/r/im_options.result +++ b/mysql-test/r/im_options.result @@ -37,9 +37,10 @@ log-slow-queries option_value language option_value character-sets-dir option_value basedir option_value +shutdown-delay option_value skip-stack-trace option_value -skip-innodb option_value -skip-ndbcluster option_value +loose-skip-innodb option_value +loose-skip-ndbcluster option_value nonguarded option_value log-output option_value SET mysqld2.server_id = 2; @@ -57,9 +58,10 @@ log-slow-queries option_value language option_value character-sets-dir option_value basedir option_value +shutdown-delay option_value skip-stack-trace option_value -skip-innodb option_value -skip-ndbcluster option_value +loose-skip-innodb option_value +loose-skip-ndbcluster option_value nonguarded option_value log-output option_value server_id option_value diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc index edc9c88fe9f..80e7e99214b 100644 --- a/server-tools/instance-manager/instance.cc +++ b/server-tools/instance-manager/instance.cc @@ -524,24 +524,17 @@ bool Instance::init(const LEX_STRING *name_arg) /** - Complete instance options initialization. + @brief Complete instance options initialization. - SYNOPSIS - complete_initialization() - - RETURN - FALSE - ok - TRUE - error + @return Error status. + @retval FALSE ok + @retval TRUE error */ bool Instance::complete_initialization() { configured= ! options.complete_initialization(); - return FALSE; - /* - TODO: return actual status (from - Instance_options::complete_initialization()) here. - */ + return !configured; } /************************************************************************** @@ -644,25 +637,24 @@ bool Instance::is_mysqld_running() /** - Start mysqld. + @brief Start mysqld. - SYNOPSIS - start_mysqld() + Reset flags and start Instance Monitor thread, which will start mysqld. - DESCRIPTION - Reset flags and start Instance Monitor thread, which will start mysqld. + @note Instance must be locked before calling the operation. - MT-NOTE: instance must be locked before calling the operation. - - RETURN - FALSE - ok - TRUE - could not start instance + @return Error status code + @retval FALSE Ok + @retval TRUE Could not start instance */ bool Instance::start_mysqld() { Instance_monitor *instance_monitor; + if (!configured) + return TRUE; + /* Prepare instance to start Instance Monitor thread. diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc index 5665c6f8670..8b96d6f0f96 100644 --- a/server-tools/instance-manager/instance_options.cc +++ b/server-tools/instance-manager/instance_options.cc @@ -156,7 +156,8 @@ int Instance_options::get_default_option(char *result, size_t result_len, goto err; /* +2 eats first "--" from the option string (E.g. "--datadir") */ - rc= parse_output_and_get_value((char*) cmd.buffer, option_name + 2, + rc= parse_output_and_get_value((char*) cmd.buffer, + option_name + 2, strlen(option_name + 2), result, result_len, GET_VALUE); err: return rc; @@ -194,8 +195,8 @@ bool Instance_options::fill_instance_version() bzero(result, MAX_VERSION_LENGTH); - if (parse_output_and_get_value((char*) cmd.buffer, "Ver", result, - MAX_VERSION_LENGTH, GET_LINE)) + if (parse_output_and_get_value((char*) cmd.buffer, STRING_WITH_LEN("Ver"), + result, MAX_VERSION_LENGTH, GET_LINE)) { log_error("Failed to get version of '%s': unexpected output.", (const char *) mysqld_path.str); @@ -206,8 +207,7 @@ bool Instance_options::fill_instance_version() { char *start; - /* chop the newline from the end of the version string */ - result[strlen(result) - NEWLINE_LEN]= '\0'; + /* trim leading whitespaces */ start= result; while (my_isspace(default_charset_info, *start)) @@ -255,7 +255,8 @@ bool Instance_options::fill_mysqld_real_path() bzero(result, FN_REFLEN); - if (parse_output_and_get_value((char*) cmd.buffer, "Usage: ", + if (parse_output_and_get_value((char*) cmd.buffer, + STRING_WITH_LEN("Usage: "), result, FN_REFLEN, GET_LINE)) { diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc index 36eb5185f6b..4dc67657512 100644 --- a/server-tools/instance-manager/parse_output.cc +++ b/server-tools/instance-manager/parse_output.cc @@ -24,6 +24,13 @@ #include "parse.h" #include "portability.h" +/************************************************************************** + Private module implementation. +**************************************************************************/ + +namespace { /* no-indent */ + +/*************************************************************************/ void trim_space(const char **text, uint *word_len) { @@ -39,90 +46,362 @@ void trim_space(const char **text, uint *word_len) *word_len= (end - start)+1; } -/* - Parse output of the given command +/*************************************************************************/ - SYNOPSIS - parse_output_and_get_value() - - command the command to execue with popen. - word the word to look for (usually an option name) - result the buffer to store the next word (option value) - input_buffer_len self-explanatory - flag this equals to GET_LINE if we want to get all the line after - the matched word and GET_VALUE otherwise. - - DESCRIPTION - - Parse output of the "command". Find the "word" and return the next one - if flag is GET_VALUE. Return the rest of the parsed string otherwise. - - RETURN - 0 - ok, the word has been found - 1 - error occured or the word is not found +/** + @brief A facade to the internal workings of optaining the output from an + executed system process. */ -int parse_output_and_get_value(const char *command, const char *word, - char *result, size_t input_buffer_len, - uint flag) +class Mysqld_output_parser +{ +public: + Mysqld_output_parser() + { } + + virtual ~Mysqld_output_parser() + { } + +public: + bool parse(const char *command, + const char *option_name_str, + uint option_name_length, + char *option_value_buf, + size_t option_value_buf_size, + enum_option_type option_type); + +protected: + /** + @brief Run a process and attach stdout- and stdin-pipes to it. + + @param command The path to the process to be executed + + @return Error status. + @retval TRUE An error occurred + @retval FALSE Operation was a success + */ + + virtual bool run_command(const char *command)= 0; + + + /** + @brief Read a sequence of bytes from the executed process' stdout pipe. + + The sequence is terminated by either '\0', LF or CRLF tokens. The + terminating token is excluded from the result. + + @param line_buffer A pointer to a character buffer + @param line_buffer_size The size of the buffer in bytes + + @return Error status. + @retval TRUE An error occured + @retval FALSE Operation was a success + */ + + virtual bool read_line(char *line_buffer, + uint line_buffer_size)= 0; + + + /** + @brief Release any resources needed after a execution and parsing. + */ + + virtual bool cleanup()= 0; +}; + +/*************************************************************************/ + +bool Mysqld_output_parser::parse(const char *command, + const char *option_name_str, + uint option_name_length, + char *option_value_buf, + size_t option_value_buf_size, + enum_option_type option_type) { - FILE *output; - uint wordlen; /* should be enough to store the string from the output */ - enum { MAX_LINE_LEN= 512 }; - char linebuf[MAX_LINE_LEN]; - int rc= 1; + const int LINE_BUFFER_SIZE= 512; + char line_buffer[LINE_BUFFER_SIZE]; - wordlen= strlen(word); + if (run_command(command)) + return TRUE; - /* - Successful return of popen does not tell us whether the command has been - executed successfully: if the command was not found, we'll get EOF - when reading the output buffer below. - */ - if (!(output= popen(command, "r"))) - goto err; - - /* - We want fully buffered stream. We also want system to - allocate appropriate buffer. - */ - setvbuf(output, NULL, _IOFBF, 0); - - while (fgets(linebuf, sizeof(linebuf) - 1, output)) + while (true) { - uint found_word_len= 0; - char *linep= linebuf; - - linebuf[sizeof(linebuf) - 1]= '\0'; /* safety */ - - /* - Find the word(s) we are looking for in the line - */ - if ((linep= strstr(linep, word))) + if (read_line(line_buffer, LINE_BUFFER_SIZE)) { - /* - If we have found our word(s), then move linep past the word(s) - */ - linep+= wordlen; - if (flag & GET_VALUE) + cleanup(); + return TRUE; + } + + uint found_word_len= 0; + char *linep= line_buffer; + + line_buffer[sizeof(line_buffer) - 1]= '\0'; /* safety */ + + /* Find the word(s) we are looking for in the line. */ + + linep= strstr(linep, option_name_str); + + if (!linep) + continue; + + linep+= option_name_length; + + switch (option_type) + { + case GET_VALUE: + trim_space((const char**) &linep, &found_word_len); + + if (option_value_buf_size <= found_word_len) { - trim_space((const char**) &linep, &found_word_len); - if (input_buffer_len <= found_word_len) - goto err; - strmake(result, linep, found_word_len); + cleanup(); + return TRUE; } - else /* currently there are only two options */ - strmake(result, linep, input_buffer_len - 1); - rc= 0; + + strmake(option_value_buf, linep, found_word_len); + + break; + + case GET_LINE: + strmake(option_value_buf, linep, option_value_buf_size - 1); + break; } + + cleanup(); + + return FALSE; } - - /* we are not interested in the termination status */ - pclose(output); - -err: - return rc; } +/************************************************************************** + Platform-specific implementation: UNIX. +**************************************************************************/ + +#ifndef __WIN__ + +class Mysqld_output_parser_unix : public Mysqld_output_parser +{ +public: + Mysqld_output_parser_unix() : + m_stdout(NULL) + { } + +protected: + virtual bool run_command(const char *command); + + virtual bool read_line(char *line_buffer, + uint line_buffer_size); + + virtual bool cleanup(); + +private: + FILE *m_stdout; +}; + +bool Mysqld_output_parser_unix::run_command(const char *command) +{ + if (!(m_stdout= popen(command, "r"))) + return TRUE; + + /* + We want fully buffered stream. We also want system to allocate + appropriate buffer. + */ + + setvbuf(m_stdout, NULL, _IOFBF, 0); + + return FALSE; +} + +bool Mysqld_output_parser_unix::read_line(char *line_buffer, + uint line_buffer_size) +{ + char *retbuff = fgets(line_buffer, line_buffer_size, m_stdout); + /* Remove any tailing new line charaters */ + if (line_buffer[line_buffer_size-1] == LF) + line_buffer[line_buffer_size-1]= '\0'; + return (retbuff == NULL); +} + +bool Mysqld_output_parser_unix::cleanup() +{ + if (m_stdout) + pclose(m_stdout); + + return FALSE; +} + +#else /* Windows */ + +/************************************************************************** + Platform-specific implementation: Windows. +**************************************************************************/ + +class Mysqld_output_parser_win : public Mysqld_output_parser +{ +public: + Mysqld_output_parser_win() : + m_internal_buffer(NULL), + m_internal_buffer_offset(0), + m_internal_buffer_size(0) + { } + +protected: + virtual bool run_command(const char *command); + virtual bool read_line(char *line_buffer, + uint line_buffer_size); + virtual bool cleanup(); + +private: + HANDLE m_h_child_stdout_wr; + HANDLE m_h_child_stdout_rd; + uint m_internal_buffer_offset; + uint m_internal_buffer_size; + char *m_internal_buffer; +}; + +bool Mysqld_output_parser_win::run_command(const char *command) +{ + BOOL op_status; + + SECURITY_ATTRIBUTES sa_attr; + sa_attr.nLength= sizeof(SECURITY_ATTRIBUTES); + sa_attr.bInheritHandle= TRUE; + sa_attr.lpSecurityDescriptor= NULL; + + op_status= CreatePipe(&m_h_child_stdout_rd, + &m_h_child_stdout_wr, + &sa_attr, + 0 /* Use system-default buffer size. */); + + if (!op_status) + return TRUE; + + SetHandleInformation(m_h_child_stdout_rd, HANDLE_FLAG_INHERIT, 0); + + STARTUPINFO si_start_info; + ZeroMemory(&si_start_info, sizeof(STARTUPINFO)); + si_start_info.cb= sizeof(STARTUPINFO); + si_start_info.hStdError= m_h_child_stdout_wr; + si_start_info.hStdOutput= m_h_child_stdout_wr; + si_start_info.dwFlags|= STARTF_USESTDHANDLES; + + PROCESS_INFORMATION pi_proc_info; + + op_status= CreateProcess(NULL, /* Application name. */ + (char*)command, /* Command line. */ + NULL, /* Process security attributes. */ + NULL, /* Primary thread security attr.*/ + TRUE, /* Handles are inherited. */ + 0, /* Creation flags. */ + NULL, /* Use parent's environment. */ + NULL, /* Use parent's curr. directory. */ + &si_start_info, /* STARTUPINFO pointer. */ + &pi_proc_info); /* Rec. PROCESS_INFORMATION. */ + + if (!retval) + { + CloseHandle(m_h_child_stdout_rd); + CloseHandle(m_h_child_stdout_wr); + + return TRUE; + } + + /* Close unnessary handles. */ + + CloseHandle(pi_proc_info.hProcess); + CloseHandle(pi_proc_info.hThread); + + return FALSE; +} + +bool Mysqld_output_parser_win::read_line(char *line_buffer, + uint line_buffer_size) +{ + DWORD dw_read_count= m_internal_buffer_size; + bzero(line_buffer,line_buffer_size); + char *buff_ptr= line_buffer; + char ch; + + while (buff_ptr - line_buffer < line_buffer_size) + { + do + { + ReadFile(m_h_child_stdout_rd, &ch, + 1, &dw_read_count, NULL); + } while ((ch == CR || ch == LF) && buff_ptr == line_buffer); + + if (dw_read_count == 0) + return TRUE; + + if (ch == CR || ch == LF) + break; + + *buff_ptr++ = ch; + } + + return FALSE; +} + +bool Mysqld_output_parser_win::cleanup() +{ + /* Close all handles. */ + + CloseHandle(m_h_child_stdout_wr); + CloseHandle(m_h_child_stdout_rd); + + return FALSE; +} +#endif + +/*************************************************************************/ + +} /* End of private module implementation. */ + +/*************************************************************************/ + +/** + @brief Parse output of the given command + + @param command The command to execute. + @param option_name_str Option name. + @param option_name_length Length of the option name. + @param[out] option_value_buf The buffer to store option value. + @param option_value_buf_size Size of the option value buffer. + @param option_type Type of the option: + - GET_LINE if we want to get all the + line after the option name; + - GET_VALUE otherwise. + + Execute the process by running "command". Find the "option name" and + return the next word if "option_type" is GET_VALUE. Return the rest of + the parsed string otherwise. + + @note This function has a separate windows implementation. + + @return The error status. + @retval FALSE Ok, the option name has been found. + @retval TRUE Error occured or the option name is not found. +*/ + +bool parse_output_and_get_value(const char *command, + const char *option_name_str, + uint option_name_length, + char *option_value_buf, + size_t option_value_buf_size, + enum_option_type option_type) +{ +#ifndef __WIN__ + Mysqld_output_parser_unix parser; +#else /* __WIN__ */ + Mysqld_output_parser_win parser; +#endif + + return parser.parse(command, + option_name_str, + option_name_length, + option_value_buf, + option_value_buf_size, + option_type); +} diff --git a/server-tools/instance-manager/parse_output.h b/server-tools/instance-manager/parse_output.h index 8851934f230..41618f643a3 100644 --- a/server-tools/instance-manager/parse_output.h +++ b/server-tools/instance-manager/parse_output.h @@ -17,11 +17,17 @@ #include -#define GET_VALUE 1 -#define GET_LINE 2 +enum enum_option_type +{ + GET_VALUE = 1, + GET_LINE +}; -int parse_output_and_get_value(const char *command, const char *word, - char *result, size_t input_buffer_len, - uint flag); +bool parse_output_and_get_value(const char *command, + const char *option_name_str, + uint option_name_length, + char *option_value_buf, + size_t option_value_buf_size, + enum_option_type option_type); #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H */ diff --git a/server-tools/instance-manager/portability.h b/server-tools/instance-manager/portability.h index eb677a0135c..990e6140a9e 100644 --- a/server-tools/instance-manager/portability.h +++ b/server-tools/instance-manager/portability.h @@ -48,11 +48,16 @@ typedef int pid_t; #define NEWLINE "\r\n" #define NEWLINE_LEN 2 +const char CR = '\r'; +const char LF = '\n'; + #else /* ! __WIN__ */ #define NEWLINE "\n" #define NEWLINE_LEN 1 +const char LF = '\n'; + #endif /* __WIN__ */ #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H */ From 04fc8b71d66810df6784876d58fe3a5e534b2ac4 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 23 Jul 2007 16:23:35 -0600 Subject: [PATCH 02/26] Bug#29959 (Non-standard bison syntax in sql_yacc.yy) In sql/sql_yacc.yy, use the %prec construct at the end of rule join_table sql/sql_yacc.yy: In sql/sql_yacc.yy, use the %prec construct at the end of rule join_table --- sql/sql_yacc.yy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6fbd521e302..d71e756e91c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5567,7 +5567,7 @@ join_table: so that [INNER | CROSS] JOIN is properly nested as other left-associative joins. */ - table_ref %prec TABLE_REF_PRIORITY normal_join table_ref + table_ref normal_join table_ref %prec TABLE_REF_PRIORITY { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); } | table_ref STRAIGHT_JOIN table_factor { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=1; } From cfdd203549bf8676d4aefb527bb43f8429a39c4d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jul 2007 09:43:49 +0200 Subject: [PATCH 03/26] Bug#28641 CREATE EVENT with '2038.01.18 03:00:00' let server crash. Creating an EVENT to be executed at a time close to the end of the allowed range (2038.01.19 03:14:07 UTC) would cause the server to crash. The expected behavior is to accept all calendar times within the interval and reject all other values without crashing. This patch replaces the function 'sec_to_epoch_TIME' with a Time_zone API call. This function was broken because it invoked the internal function 'sec_to_epoch' without respecting the restrictions on the function parameters (and this caused assertion failure). It also was used as a reverse function to Time_zone_utc::gmt_sec_to_TIME which it isn't. mysql-test/r/events_bugs.result: Added test case mysql-test/t/events_bugs.test: Added test case sql/event_data_objects.cc: Replaced function 'sec_since_epoch_TIME' since it was implemented as a wrapper around 'sec_since_epoch' without taking parameter restrictions into account. The function was used to load information about event execution time from mysql.events table. Further more, the function wasn't the inverse function of Time_zone_utc::gmt_sec_to_TIME() which was used by events code to store information about event execution time. sql/event_db_repository.cc: Replaced my_tz_UTC object with my_tz_OFFSET0 object because the first one doesn't supply us with a bijective MYSQL_TIME<->my_time_t translation. Instead the function sec_since_epoch_TIME was used as a reverse function to the method my_tz_UTC::gmt_sec_to_TIME. sql/event_queue.cc: Replaced my_tz_UTC object with my_tz_OFFSET0 object because the first one doesn't supply us with a bijective MYSQL_TIME<->my_time_t translation. Instead the function sec_since_epoch_TIME was used as a reverse function to the method my_tz_UTC::gmt_sec_to_TIME. sql/tztime.cc: * Remove function 'sec_since_epoch_TIME' since it was implemented as a wrapper around 'sec_since_epoch' without taking parameter restrictions into account. The function was used to load information about event execution time from mysql.events table. Further more, the function wasn't the inverse function of Time_zone_utc::gmt_sec_to_TIME() which was used by events code to store information about event execution time. * Added static Time_zone object for UTC+0 time zone. sql/tztime.h: Include extern pointer to static Time_zone object. --- mysql-test/r/events_bugs.result | 7 +++++++ mysql-test/t/events_bugs.test | 15 +++++++++++++++ sql/event_data_objects.cc | 9 +++++---- sql/event_db_repository.cc | 8 ++++---- sql/event_queue.cc | 2 +- sql/tztime.cc | 15 ++------------- sql/tztime.h | 1 + 7 files changed, 35 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/events_bugs.result b/mysql-test/r/events_bugs.result index 557c8e0b477..1bfa0e84f72 100644 --- a/mysql-test/r/events_bugs.result +++ b/mysql-test/r/events_bugs.result @@ -611,3 +611,10 @@ id ev_nm ev_cnt DROP TABLE event_log; SET GLOBAL event_scheduler = OFF; DROP DATABASE events_test; +SET GLOBAL event_scheduler= ON; +CREATE EVENT bug28641 ON SCHEDULE AT '2038.01.18 03:00:00' + DO BEGIN +SELECT 1; +END;| +SET GLOBAL event_scheduler= OFF; +DROP EVENT bug28641; diff --git a/mysql-test/t/events_bugs.test b/mysql-test/t/events_bugs.test index 4186b4701fa..36052fdb9af 100644 --- a/mysql-test/t/events_bugs.test +++ b/mysql-test/t/events_bugs.test @@ -722,3 +722,18 @@ let $wait_condition= --source include/wait_condition.inc DROP DATABASE events_test; + + +# +# Bug#28641 CREATE EVENT with '2038.01.18 03:00:00' let server crash. +# +SET GLOBAL event_scheduler= ON; +DELIMITER |; +CREATE EVENT bug28641 ON SCHEDULE AT '2038.01.18 03:00:00' + DO BEGIN + SELECT 1; + END;| + +DELIMITER ;| +SET GLOBAL event_scheduler= OFF; +DROP EVENT bug28641; diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 7b58c10079a..144a87e13f6 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -979,17 +979,18 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table) DBUG_RETURN(TRUE); starts_null= table->field[ET_FIELD_STARTS]->is_null(); + my_bool not_used= FALSE; if (!starts_null) { table->field[ET_FIELD_STARTS]->get_date(&time, TIME_NO_ZERO_DATE); - starts= sec_since_epoch_TIME(&time); + starts= my_tz_OFFSET0->TIME_to_gmt_sec(&time,¬_used); } ends_null= table->field[ET_FIELD_ENDS]->is_null(); if (!ends_null) { table->field[ET_FIELD_ENDS]->get_date(&time, TIME_NO_ZERO_DATE); - ends= sec_since_epoch_TIME(&time); + ends= my_tz_OFFSET0->TIME_to_gmt_sec(&time,¬_used); } if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null()) @@ -1007,7 +1008,7 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table) if (table->field[ET_FIELD_EXECUTE_AT]->get_date(&time, TIME_NO_ZERO_DATE)) DBUG_RETURN(TRUE); - execute_at= sec_since_epoch_TIME(&time); + execute_at= my_tz_OFFSET0->TIME_to_gmt_sec(&time,¬_used); } /* @@ -1039,7 +1040,7 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table) { table->field[ET_FIELD_LAST_EXECUTED]->get_date(&time, TIME_NO_ZERO_DATE); - last_executed= sec_since_epoch_TIME(&time); + last_executed= my_tz_OFFSET0->TIME_to_gmt_sec(&time,¬_used); } last_executed_changed= FALSE; diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index a16a04739e2..b7bcb6344fd 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -250,7 +250,7 @@ mysql_event_fill_row(THD *thd, if (!et->starts_null) { MYSQL_TIME time; - my_tz_UTC->gmt_sec_to_TIME(&time, et->starts); + my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->starts); fields[ET_FIELD_STARTS]->set_notnull(); fields[ET_FIELD_STARTS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); @@ -259,7 +259,7 @@ mysql_event_fill_row(THD *thd, if (!et->ends_null) { MYSQL_TIME time; - my_tz_UTC->gmt_sec_to_TIME(&time, et->ends); + my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->ends); fields[ET_FIELD_ENDS]->set_notnull(); fields[ET_FIELD_ENDS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); @@ -278,7 +278,7 @@ mysql_event_fill_row(THD *thd, fields[ET_FIELD_ENDS]->set_null(); MYSQL_TIME time; - my_tz_UTC->gmt_sec_to_TIME(&time, et->execute_at); + my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->execute_at); fields[ET_FIELD_EXECUTE_AT]->set_notnull(); fields[ET_FIELD_EXECUTE_AT]-> @@ -1004,7 +1004,7 @@ update_timing_fields_for_event(THD *thd, if (update_last_executed) { MYSQL_TIME time; - my_tz_UTC->gmt_sec_to_TIME(&time, last_executed); + my_tz_OFFSET0->gmt_sec_to_TIME(&time, last_executed); fields[ET_FIELD_LAST_EXECUTED]->set_notnull(); fields[ET_FIELD_LAST_EXECUTED]->store_time(&time, diff --git a/sql/event_queue.cc b/sql/event_queue.cc index 634cc764d74..04449dd48a1 100644 --- a/sql/event_queue.cc +++ b/sql/event_queue.cc @@ -740,7 +740,7 @@ Event_queue::dump_internal_status() printf("WOC : %s\n", waiting_on_cond? "YES":"NO"); MYSQL_TIME time; - my_tz_UTC->gmt_sec_to_TIME(&time, next_activation_at); + my_tz_OFFSET0->gmt_sec_to_TIME(&time, next_activation_at); if (time.year != 1970) printf("Next activation : %04d-%02d-%02d %02d:%02d:%02d\n", time.year, time.month, time.day, time.hour, time.minute, time.second); diff --git a/sql/tztime.cc b/sql/tztime.cc index 0c717dd2ece..14192d06978 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -807,19 +807,6 @@ sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec) SECS_PER_MIN + sec; } - - /* - Works like sec_since_epoch but expects MYSQL_TIME structure as parameter. -*/ - -my_time_t -sec_since_epoch_TIME(MYSQL_TIME *t) -{ - return sec_since_epoch(t->year, t->month, t->day, - t->hour, t->minute, t->second); -} - - /* Converts local time in broken down MYSQL_TIME representation to my_time_t representation. @@ -1425,7 +1412,9 @@ Time_zone_offset::get_name() const static Time_zone_utc tz_UTC; static Time_zone_system tz_SYSTEM; +static Time_zone_offset tz_OFFSET0(0); +Time_zone *my_tz_OFFSET0= &tz_OFFSET0; Time_zone *my_tz_UTC= &tz_UTC; Time_zone *my_tz_SYSTEM= &tz_SYSTEM; diff --git a/sql/tztime.h b/sql/tztime.h index f7cc7042d79..ddd80b88bf2 100644 --- a/sql/tztime.h +++ b/sql/tztime.h @@ -59,6 +59,7 @@ public: extern Time_zone * my_tz_UTC; extern Time_zone * my_tz_SYSTEM; +extern Time_zone * my_tz_OFFSET0; extern Time_zone * my_tz_find(THD *thd, const String *name); extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap); extern void my_tz_free(); From 5e0e5e5e3b6e63018e4e355c6c046357df19c546 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jul 2007 13:31:46 +0400 Subject: [PATCH 04/26] Temporary enable IM tests in 5.1-runtime tree. Enable assert in Thread_registry. mysql-test/t/disabled.def: Temporary enable IM tests in the team tree. server-tools/instance-manager/thread_registry.cc: Uncomment assert. --- mysql-test/t/disabled.def | 20 +++++++++++-------- .../instance-manager/thread_registry.cc | 3 +-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 07c5b4d56a3..b41875fe740 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -11,14 +11,18 @@ ############################################################################## user_limits : Bug#23921 random failure of user_limits.test -im_options : Bug#20294 2006-07-24 stewart Instance manager test im_options fails randomly -im_daemon_life_cycle : Bug#20294 2007-05-14 alik Instance manager tests fail randomly -im_cmd_line : Bug#20294 2007-05-14 alik Instance manager tests fail randomly -im_utils : Bug#20294 2007-05-30 alik Instance manager tests fail randomly -im_instance_conf : Bug#20294 2007-05-30 alik Instance manager tests fail randomly -im_life_cycle : BUG#27851 Instance manager dies on ASSERT in ~Thread_registry() or from not being able to close a mysqld instance. -im_instance_conf : BUG#28743 Instance manager generates warnings in test suite -im_utils : BUG#28743 Instance manager generates warnings in test suite +# +# Temporary enable IM tests to catch the assert. +# +# im_options : Bug#20294 2006-07-24 stewart Instance manager test im_options fails randomly +# im_daemon_life_cycle : Bug#20294 2007-05-14 alik Instance manager tests fail randomly +# im_cmd_line : Bug#20294 2007-05-14 alik Instance manager tests fail randomly +# im_utils : Bug#20294 2007-05-30 alik Instance manager tests fail randomly +# im_instance_conf : Bug#20294 2007-05-30 alik Instance manager tests fail randomly +# im_life_cycle : BUG#27851 Instance manager dies on ASSERT in ~Thread_registry() or from not being able to close a mysqld instance. +# im_instance_conf : BUG#28743 Instance manager generates warnings in test suite +# im_utils : BUG#28743 Instance manager generates warnings in test suite + concurrent_innodb : BUG#21579 2006-08-11 mleich innodb_concurrent random failures with varying differences ctype_big5 : BUG#26711 2007-06-21 Lars Test has never worked on Double Whopper diff --git a/server-tools/instance-manager/thread_registry.cc b/server-tools/instance-manager/thread_registry.cc index b06c1240d92..700ed22afe7 100644 --- a/server-tools/instance-manager/thread_registry.cc +++ b/server-tools/instance-manager/thread_registry.cc @@ -67,8 +67,7 @@ Thread_registry::~Thread_registry() if (head.next != &head) log_error("Not all threads died properly\n"); /* All threads must unregister */ - // Disabled assert temporarily - BUG#28030 - // DBUG_ASSERT(head.next == &head); + DBUG_ASSERT(head.next == &head); pthread_mutex_unlock(&LOCK_thread_registry); pthread_cond_destroy(&COND_thread_registry_is_empty); From 696b001ab719f3ecc50da7b72580dddb0e216d8a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jul 2007 12:15:29 +0200 Subject: [PATCH 05/26] Fix of build errors for windows. server-tools/instance-manager/parse_output.cc: * Fixed merge error: retval -> op_status * Fixed warning: unsigned compared with signed. --- server-tools/instance-manager/parse_output.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc index 4dc67657512..3511589acd6 100644 --- a/server-tools/instance-manager/parse_output.cc +++ b/server-tools/instance-manager/parse_output.cc @@ -300,7 +300,7 @@ bool Mysqld_output_parser_win::run_command(const char *command) &si_start_info, /* STARTUPINFO pointer. */ &pi_proc_info); /* Rec. PROCESS_INFORMATION. */ - if (!retval) + if (!op_status) { CloseHandle(m_h_child_stdout_rd); CloseHandle(m_h_child_stdout_wr); @@ -324,7 +324,7 @@ bool Mysqld_output_parser_win::read_line(char *line_buffer, char *buff_ptr= line_buffer; char ch; - while (buff_ptr - line_buffer < line_buffer_size) + while ((unsigned)(buff_ptr - line_buffer) < line_buffer_size) { do { From 48e879f9ac3d57b6c931c36a7d590e16229ae1a4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jul 2007 18:38:52 +0400 Subject: [PATCH 06/26] Allow mysql.proc to have extra (unknown) fields. This allows 5.0 to work with 5.1 databases. --- sql/sp.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sp.cc b/sql/sp.cc index c0e7d5e2271..75d6fa4618f 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -273,7 +273,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK) goto done; - if (table->s->fields != MYSQL_PROC_FIELD_COUNT) + if (table->s->fields < MYSQL_PROC_FIELD_COUNT) { ret= SP_GET_FIELD_FAILED; goto done; @@ -523,7 +523,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) strxmov(definer, thd->lex->definer->user.str, "@", thd->lex->definer->host.str, NullS); - if (table->s->fields != MYSQL_PROC_FIELD_COUNT) + if (table->s->fields < MYSQL_PROC_FIELD_COUNT) { ret= SP_GET_FIELD_FAILED; goto done; From 2612fc43b53a69320ba41011aa632ec35b734211 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Jul 2007 19:46:50 +0400 Subject: [PATCH 07/26] Patch inspired by BUG#10491: Server returns data as charset binary SHOW CREATE TABLE or SELECT FROM I_S. The problem is that mysqldump generates incorrect dump for a table with non-ASCII column name if the mysqldump's character set is ASCII. The fix is to: 1. Switch character_set_client for the mysqldump's connection to binary before issuing SHOW CREATE TABLE statement in order to avoid conversion. 2. Dump switch character_set_client statements to UTF8 and back for CREATE TABLE statement. client/mysqldump.c: 1. Switch character_set_client for the mysqldump's connection to binary before issuing SHOW CREATE TABLE statement in order to avoid conversion. 2. Dump switch character_set_client statements to UTF8 and back for CREATE TABLE statement. mysql-test/r/mysqldump-max.result: Update result file. mysql-test/r/mysqldump.result: Update result file. mysql-test/r/openssl_1.result: Update result file. mysql-test/r/show_check.result: Update result file. mysql-test/t/show_check.test: Test case: - create a table with non-ASCII column name; - dump the database by mysqldump using ASCII character set; - drop the database; - load the dump; - check that the table has been re-created properly. --- client/mysqldump.c | 30 ++++- mysql-test/r/mysqldump-max.result | 36 ++++++ mysql-test/r/mysqldump.result | 180 ++++++++++++++++++++++++++++++ mysql-test/r/openssl_1.result | 9 ++ mysql-test/r/show_check.result | 20 ++++ mysql-test/t/show_check.test | 57 ++++++++++ 6 files changed, 329 insertions(+), 3 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index f72cb0171e1..c745ca10272 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -992,6 +992,21 @@ static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res, return 0; } + +static int switch_character_set_results(MYSQL *mysql, const char *cs_name) +{ + char query_buffer[QUERY_LENGTH]; + size_t query_length; + + query_length= my_snprintf(query_buffer, + sizeof (query_buffer), + "SET SESSION character_set_results = '%s'", + (const char *) cs_name); + + return mysql_real_query(mysql, query_buffer, query_length); +} + + /* Open a new .sql file to dump the table or view into @@ -1671,7 +1686,10 @@ static uint get_table_structure(char *table, char *db, char *table_type, MYSQL_FIELD *field; my_snprintf(buff, sizeof(buff), "show create table %s", result_table); - if (mysql_query_with_error_report(mysql, 0, buff)) + + if (switch_character_set_results(mysql, "binary") || + mysql_query_with_error_report(mysql, &result, buff) || + switch_character_set_results(mysql, default_charset)) DBUG_RETURN(0); if (path) @@ -1702,7 +1720,6 @@ static uint get_table_structure(char *table, char *db, char *table_type, check_io(sql_file); } - result= mysql_store_result(mysql); field= mysql_fetch_field_direct(result, 0); if (strcmp(field->name, "View") == 0) { @@ -1794,7 +1811,14 @@ static uint get_table_structure(char *table, char *db, char *table_type, } row= mysql_fetch_row(result); - fprintf(sql_file, "%s;\n", row[1]); + + fprintf(sql_file, + "SET @saved_cs_client = @@character_set_client;\n" + "SET character_set_client = utf8;\n" + "%s;\n" + "SET character_set_client = @saved_cs_client;\n", + row[1]); + check_io(sql_file); mysql_free_result(result); } diff --git a/mysql-test/r/mysqldump-max.result b/mysql-test/r/mysqldump-max.result index 9ae3e368e28..261c7a7f197 100644 --- a/mysql-test/r/mysqldump-max.result +++ b/mysql-test/r/mysqldump-max.result @@ -93,55 +93,73 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; INSERT DELAYED IGNORE INTO `t1` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t2` DISABLE KEYS */; INSERT DELAYED IGNORE INTO `t2` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); /*!40000 ALTER TABLE `t2` ENABLE KEYS */; DROP TABLE IF EXISTS `t3`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t3` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=MEMORY DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t3` DISABLE KEYS */; INSERT DELAYED IGNORE INTO `t3` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); /*!40000 ALTER TABLE `t3` ENABLE KEYS */; DROP TABLE IF EXISTS `t4`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t4` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=MEMORY DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t4` DISABLE KEYS */; INSERT DELAYED IGNORE INTO `t4` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); /*!40000 ALTER TABLE `t4` ENABLE KEYS */; DROP TABLE IF EXISTS `t5`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t5` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=ARCHIVE DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t5` DISABLE KEYS */; INSERT DELAYED IGNORE INTO `t5` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); /*!40000 ALTER TABLE `t5` ENABLE KEYS */; DROP TABLE IF EXISTS `t6`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t6` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t6` DISABLE KEYS */; INSERT IGNORE INTO `t6` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); @@ -172,55 +190,73 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; INSERT DELAYED INTO `t1` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t2` DISABLE KEYS */; INSERT DELAYED INTO `t2` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); /*!40000 ALTER TABLE `t2` ENABLE KEYS */; DROP TABLE IF EXISTS `t3`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t3` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=MEMORY DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t3` DISABLE KEYS */; INSERT DELAYED INTO `t3` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); /*!40000 ALTER TABLE `t3` ENABLE KEYS */; DROP TABLE IF EXISTS `t4`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t4` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=MEMORY DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t4` DISABLE KEYS */; INSERT DELAYED INTO `t4` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); /*!40000 ALTER TABLE `t4` ENABLE KEYS */; DROP TABLE IF EXISTS `t5`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t5` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=ARCHIVE DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t5` DISABLE KEYS */; INSERT DELAYED INTO `t5` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); /*!40000 ALTER TABLE `t5` ENABLE KEYS */; DROP TABLE IF EXISTS `t6`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t6` ( `id` int(8) default NULL, `name` varchar(32) default NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t6` DISABLE KEYS */; INSERT INTO `t6` VALUES (1,'first value'),(2,'first value'),(3,'first value'),(4,'first value'),(5,'first value'); diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index da05fe7bc5b..73841a2150f 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -28,9 +28,12 @@ DROP TABLE t1; CREATE TABLE t1 (a decimal(64, 20)); INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"), ("0987654321098765432109876543210987654321"); +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` decimal(64,20) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; INSERT INTO `t1` VALUES ('1234567890123456789012345678901234567890.00000000000000000000'),('987654321098765432109876543210987654321.00000000000000000000'); DROP TABLE t1; # @@ -40,9 +43,12 @@ CREATE TABLE t1 (a double); INSERT INTO t1 VALUES ('-9e999999'); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` double default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; INSERT INTO `t1` VALUES (RES); DROP TABLE t1; # @@ -58,15 +64,21 @@ INSERT INTO t1 VALUES ('1.2345', 2.3456); INSERT INTO t1 VALUES ("1.2345", 2.3456); ERROR 42S22: Unknown column '1.2345' in 'field list' SET SQL_MODE=@OLD_SQL_MODE; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` decimal(10,5) default NULL, `b` float default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` decimal(10,5) default NULL, `b` float default NULL ); +SET character_set_client = @saved_cs_client; INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; @@ -80,10 +92,13 @@ INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456) /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` decimal(10,5) default NULL, `b` float default NULL ); +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -106,10 +121,13 @@ UNLOCK TABLES; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` decimal(10,5) default NULL, `b` float default NULL ); +SET character_set_client = @saved_cs_client; INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; @@ -185,9 +203,12 @@ INSERT INTO t1 VALUES (_koi8r x'C1C2C3C4C5'), (NULL); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` varchar(255) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=koi8r; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -218,9 +239,12 @@ INSERT INTO t1 VALUES (1), (2); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL40' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) TYPE=MyISAM; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -241,9 +265,12 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) TYPE=MyISAM; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -262,9 +289,12 @@ DROP TABLE t1; # Bug #2592 'mysqldump doesn't quote "tricky" names correctly' # create table ```a` (i int); +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE ```a` ( `i` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; drop table ```a`; # # Bug #2591 "mysqldump quotes names inconsistently" @@ -282,9 +312,12 @@ create table t1(a int); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -307,9 +340,12 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS "t1"; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE "t1" ( "a" int(11) default NULL ); +SET character_set_client = @saved_cs_client; LOCK TABLES "t1" WRITE; /*!40000 ALTER TABLE "t1" DISABLE KEYS */; @@ -335,9 +371,12 @@ set global sql_mode='ANSI_QUOTES'; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -360,9 +399,12 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS "t1"; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE "t1" ( "a" int(11) default NULL ); +SET character_set_client = @saved_cs_client; LOCK TABLES "t1" WRITE; /*!40000 ALTER TABLE "t1" DISABLE KEYS */; @@ -392,9 +434,12 @@ insert into t1 values (1),(2),(3); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; @@ -483,9 +528,12 @@ INSERT INTO t1 VALUES (_latin1 ' /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` char(10) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -516,9 +564,12 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` char(10) default NULL ) TYPE=MyISAM; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -539,9 +590,12 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` char(10) default NULL ) TYPE=MyISAM; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -562,9 +616,12 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` char(10) default NULL ) TYPE=MyISAM; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -598,9 +655,12 @@ INSERT INTO t2 VALUES (4),(5),(6); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t2` WRITE; /*!40000 ALTER TABLE `t2` DISABLE KEYS */; @@ -636,9 +696,12 @@ INSERT INTO `t1` VALUES (0x602010000280100005E71A); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `b` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -674,9 +737,12 @@ INSERT INTO t1 VALUES (4),(5),(6); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -705,9 +771,12 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; INSERT DELAYED IGNORE INTO `t1` VALUES (1),(2),(3),(4),(5),(6); @@ -1071,6 +1140,8 @@ insert into t1 (F_8d3bba7425e7c98c50f52ca1b52d3735) values (1); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `F_c4ca4238a0b923820dcc509a6f75849b` int(11) default NULL, `F_c81e728d9d4c2f636f067f89cc14862c` int(11) default NULL, @@ -1403,6 +1474,7 @@ CREATE TABLE `t1` ( `F_6faa8040da20ef399b63a72d0e4ab575` int(11) default NULL, `F_fe73f687e5bc5280214e0486b273a5f9` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -1443,9 +1515,12 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -1484,13 +1559,19 @@ INSERT INTO t2 VALUES (1), (2); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -1513,13 +1594,19 @@ CREATE TABLE `t2` ( /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -1719,17 +1806,26 @@ create table t3(a int); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t3`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t3` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -1759,9 +1855,12 @@ mysqldump: Got error: 1064: You have an error in your SQL syntax; check the manu /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; @@ -1792,12 +1891,15 @@ insert into t1 values (0815, 4711, 2006); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS "t1"; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE "t1" ( "a b" int(11) NOT NULL default '0', "c""d" int(11) NOT NULL default '0', "e`f" int(11) NOT NULL default '0', PRIMARY KEY ("a b","c""d","e`f") ); +SET character_set_client = @saved_cs_client; LOCK TABLES "t1" WRITE; /*!40000 ALTER TABLE "t1" DISABLE KEYS */; @@ -1823,12 +1925,15 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a b` int(11) NOT NULL default '0', `c"d` int(11) NOT NULL default '0', `e``f` int(11) NOT NULL default '0', PRIMARY KEY (`a b`,`c"d`,`e``f`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -1874,10 +1979,13 @@ create view v2 as select * from t2 where a like 'a%' with check option; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` varchar(30) default NULL, KEY `a` (`a`(5)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t2` WRITE; /*!40000 ALTER TABLE `t2` DISABLE KEYS */; @@ -1955,9 +2063,12 @@ create view v1 as select * from t1; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -2012,10 +2123,13 @@ create view v2 as select * from t2 where a like 'a%' with check option; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` varchar(30) default NULL, KEY `a` (`a`(5)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t2` WRITE; /*!40000 ALTER TABLE `t2` DISABLE KEYS */; @@ -2064,9 +2178,12 @@ INSERT INTO t1 VALUES ('\''); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` char(10) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -2107,11 +2224,14 @@ select v3.a from v3, v1 where v1.a=v3.a and v3.b=3 limit 1; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL, `b` int(11) default NULL, `c` varchar(30) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -2227,10 +2347,13 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL, `b` bigint(20) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -2262,9 +2385,12 @@ end */;; DELIMITER ; /*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t2` WRITE; /*!40000 ALTER TABLE `t2` DISABLE KEYS */; @@ -2307,10 +2433,13 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL, `b` bigint(20) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -2318,9 +2447,12 @@ INSERT INTO `t1` VALUES (1,NULL),(2,NULL),(4,NULL),(11,NULL); /*!40000 ALTER TABLE `t1` ENABLE KEYS */; UNLOCK TABLES; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t2` WRITE; /*!40000 ALTER TABLE `t2` DISABLE KEYS */; @@ -2444,9 +2576,12 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `id` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -2534,10 +2669,13 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `d` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, UNIQUE KEY `d` (`d`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -2568,10 +2706,13 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `d` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, UNIQUE KEY `d` (`d`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -2618,9 +2759,12 @@ a2 /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS "t1 test"; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE "t1 test" ( "a1" int(11) default NULL ); +SET character_set_client = @saved_cs_client; LOCK TABLES "t1 test" WRITE; /*!40000 ALTER TABLE "t1 test" DISABLE KEYS */; @@ -2636,9 +2780,12 @@ INSERT INTO `t2 test` SET a2 = NEW.a1; END */;; DELIMITER ; /*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */; DROP TABLE IF EXISTS "t2 test"; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE "t2 test" ( "a2" int(11) default NULL ); +SET character_set_client = @saved_cs_client; LOCK TABLES "t2 test" WRITE; /*!40000 ALTER TABLE "t2 test" DISABLE KEYS */; @@ -2687,11 +2834,14 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL, `b` varchar(32) default NULL, `c` varchar(32) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -2779,9 +2929,12 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -2825,10 +2978,13 @@ insert into t1 values ('',''); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` binary(1) default NULL, `b` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -2857,10 +3013,13 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` binary(1) default NULL, `b` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -3015,9 +3174,12 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_test_db` /*!40100 DEFAULT CH USE `mysqldump_test_db`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `id` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -3062,11 +3224,14 @@ create view nasishnasifu as select mysqldump_tables.basetable.id from mysqldump_ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_tables` /*!40100 DEFAULT CHARACTER SET latin1 */; USE `mysqldump_tables`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `basetable` ( `id` bigint(20) unsigned NOT NULL auto_increment, `tag` varchar(64) default NULL, UNIQUE KEY `id` (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_views` /*!40100 DEFAULT CHARACTER SET latin1 */; @@ -3134,10 +3299,13 @@ mysqldump: Couldn't execute 'SHOW MASTER STATUS': Access denied; you need the SU mysqldump: Couldn't execute 'SHOW MASTER STATUS': Access denied; you need the SUPER,REPLICATION CLIENT privilege for this operation (1227) grant REPLICATION CLIENT on *.* to mysqltest_1@localhost; CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=537; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL, `b` varchar(34) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; drop table t1; drop user mysqltest_1@localhost; # @@ -3226,22 +3394,31 @@ CREATE TABLE t1 (a int) ENGINE=merge UNION=(t2, t3); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t2`,`t3`); +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t2` WRITE; /*!40000 ALTER TABLE `t2` DISABLE KEYS */; /*!40000 ALTER TABLE `t2` ENABLE KEYS */; UNLOCK TABLES; DROP TABLE IF EXISTS `t3`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t3` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t3` WRITE; /*!40000 ALTER TABLE `t3` DISABLE KEYS */; @@ -3317,10 +3494,13 @@ drop database mysqldump_test_db; # CREATE TABLE t1 (c1 INT, c2 LONGBLOB); INSERT INTO t1 SET c1=11, c2=REPEAT('q',509); +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `c1` int(11) default NULL, `c2` longblob ); +SET character_set_client = @saved_cs_client; INSERT INTO `t1` VALUES (11,0x7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171); DROP TABLE t1; # diff --git a/mysql-test/r/openssl_1.result b/mysql-test/r/openssl_1.result index 3f10eed7ad7..9c6c29eea47 100644 --- a/mysql-test/r/openssl_1.result +++ b/mysql-test/r/openssl_1.result @@ -77,9 +77,12 @@ INSERT INTO t1 VALUES (1), (2); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ); +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -108,9 +111,12 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ); +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -139,9 +145,12 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) default NULL ); +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index e4cdd4f183b..7e5dc7e61c1 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -1088,6 +1088,26 @@ DROP TABLE t1; DROP VIEW v1; DROP PROCEDURE p1; DROP FUNCTION f1; +set names koi8r; +DROP DATABASE IF EXISTS mysqltest1; +CREATE DATABASE mysqltest1; +use mysqltest1; +CREATE TABLE t1(ËÏÌÏÎËÁ1 INT); + +---> Dumping mysqltest1 to show_check.mysqltest1.sql + + +DROP DATABASE mysqltest1; + + +---> Restoring mysqltest1... +SHOW CREATE TABLE mysqltest1.t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ËÏÌÏÎËÁ1` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP DATABASE mysqltest1; +use test; flush status; show variables like "log_queries_not_using_indexes"; Variable_name Value diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index a58d81a414b..4d470ee4233 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -559,6 +559,10 @@ show status like 'slow_queries'; # FROM I_S. # +# +# Part 1: check that meta-data specifies not-binary character set. +# + # Ensure that all needed objects are dropped. --disable_warnings @@ -766,6 +770,59 @@ DROP VIEW v1; DROP PROCEDURE p1; DROP FUNCTION f1; +# +# Part 2: check that table with non-latin1 characters are dumped/restored +# correctly. +# + +# Ensure that all needed objects are dropped. + +set names koi8r; + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest1; +--enable_warnings + +# Create objects. + +CREATE DATABASE mysqltest1; + +use mysqltest1; + +CREATE TABLE t1(ËÏÌÏÎËÁ1 INT); + +# Check: +# - Dump mysqltest1; + +--echo +--echo ---> Dumping mysqltest1 to show_check.mysqltest1.sql + +--exec $MYSQL_DUMP --default-character-set=latin1 --character-sets-dir=$CHARSETSDIR --databases mysqltest1 > $MYSQLTEST_VARDIR/tmp/show_check.mysqltest1.sql + +# - Clean mysqltest1; + +--echo +--echo + +DROP DATABASE mysqltest1; + +# - Restore mysqltest1; + +--echo +--echo + +--echo ---> Restoring mysqltest1... +--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/show_check.mysqltest1.sql + +# - Check definition of the table. + +SHOW CREATE TABLE mysqltest1.t1; + +# Cleanup. + +DROP DATABASE mysqltest1; +use test; + # # Bug #28808: log_queries_not_using_indexes variable dynamic change is ignored # From 1336b0eb1371868c3e6596565cbe35978dfa6140 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 26 Jul 2007 20:05:01 +0400 Subject: [PATCH 08/26] Fix for BUG#30029: mysql_upgrade fails for 5.0 -> 5.1.21, 5.1.20 -> 5.1.21 upgrades. We generate mysql_fix_privilege.sql file, which contains SQL statements required to upgrade the system database. This script is generated by concatenation of mysql_system_tables.sql and mysql_system_tables_fix.sql. The problem was that - in order to create general_log and slow_log tables we use stored programs in mysql_system_tables.sql; - we upgrade mysql.proc table in mysql_system_tables_fix.sql; So, if mysql.proc table needs to be upgraded, stored procedures can not be used in mysql_system_tables.sql. In other words, in mysql_system_tables.sql stored programs must not be used because they may be unavailable at this point. The fix is to use dynamic SQL instead of stored programs. There is no test case for this bug because our test suite is not suitable for such test cases. system_mysql_db_fix* test cases play with the database "test". Here we need to modify the system database and we can not do that in the test suite. scripts/mysql_system_tables.sql: Use dynamic SQL instead of stored programs. --- scripts/mysql_system_tables.sql | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql index f46c7c7027a..cd0882e3af4 100644 --- a/scripts/mysql_system_tables.sql +++ b/scripts/mysql_system_tables.sql @@ -63,16 +63,21 @@ CREATE TABLE IF NOT EXISTS proc (db char(64) collate utf8_bin DEFAULT '' NOT NUL CREATE TABLE IF NOT EXISTS procs_priv ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Routine_name char(64) binary DEFAULT '' NOT NULL, Routine_type enum('FUNCTION','PROCEDURE') NOT NULL, Grantor char(77) DEFAULT '' NOT NULL, Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Timestamp timestamp(14), PRIMARY KEY (Host,Db,User,Routine_name,Routine_type), KEY Grantor (Grantor) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges'; +-- Create general_log if CSV is enabled. -delimiter ;; -CREATE PROCEDURE create_general_log_table() BEGIN DECLARE is_csv_enabled int DEFAULT 0; SELECT @@have_csv = 'YES' INTO is_csv_enabled; IF (is_csv_enabled) THEN CREATE TABLE IF NOT EXISTS general_log (event_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT, thread_id INTEGER, server_id INTEGER, command_type VARCHAR(64), argument MEDIUMTEXT) engine=CSV CHARACTER SET utf8 comment='General log'; END IF; END;; -CALL create_general_log_table();; -DROP PROCEDURE create_general_log_table;; +SET @str = IF (@@have_csv = 'YES', 'CREATE TABLE IF NOT EXISTS general_log (event_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT, thread_id INTEGER, server_id INTEGER, command_type VARCHAR(64), argument MEDIUMTEXT) engine=CSV CHARACTER SET utf8 comment="General log"', 'SET @dummy = 0'); -CREATE PROCEDURE create_slow_log_table() BEGIN DECLARE is_csv_enabled int DEFAULT 0; SELECT @@have_csv = 'YES' INTO is_csv_enabled; IF (is_csv_enabled) THEN CREATE TABLE IF NOT EXISTS slow_log (start_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT NOT NULL, query_time TIME NOT NULL, lock_time TIME NOT NULL, rows_sent INTEGER NOT NULL, rows_examined INTEGER NOT NULL, db VARCHAR(512), last_insert_id INTEGER, insert_id INTEGER, server_id INTEGER, sql_text MEDIUMTEXT NOT NULL) engine=CSV CHARACTER SET utf8 comment='Slow log'; END IF; END;; -CALL create_slow_log_table();; -DROP PROCEDURE create_slow_log_table;; -delimiter ; +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + +-- Create slow_log if CSV is enabled. + +SET @str = IF (@@have_csv = 'YES', 'CREATE TABLE IF NOT EXISTS slow_log (start_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT NOT NULL, query_time TIME NOT NULL, lock_time TIME NOT NULL, rows_sent INTEGER NOT NULL, rows_examined INTEGER NOT NULL, db VARCHAR(512), last_insert_id INTEGER, insert_id INTEGER, server_id INTEGER, sql_text MEDIUMTEXT NOT NULL) engine=CSV CHARACTER SET utf8 comment="Slow log"', 'SET @dummy = 0'); + +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; CREATE TABLE IF NOT EXISTS event ( db char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', name char(64) CHARACTER SET utf8 NOT NULL default '', body longblob NOT NULL, definer char(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', execute_at DATETIME default NULL, interval_value int(11) default NULL, interval_field ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR','DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND','DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND','SECOND_MICROSECOND') default NULL, created TIMESTAMP NOT NULL, modified TIMESTAMP NOT NULL, last_executed DATETIME default NULL, starts DATETIME default NULL, ends DATETIME default NULL, status ENUM('ENABLED','DISABLED','SLAVESIDE_DISABLED') NOT NULL default 'ENABLED', on_completion ENUM('DROP','PRESERVE') NOT NULL default 'DROP', sql_mode set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE') DEFAULT '' NOT NULL, comment char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', originator int(10) NOT NULL, time_zone char(64) CHARACTER SET latin1 NOT NULL DEFAULT 'SYSTEM', character_set_client char(32) collate utf8_bin, collation_connection char(32) collate utf8_bin, db_collation char(32) collate utf8_bin, body_utf8 longblob, PRIMARY KEY (db, name) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events'; From 4462578a1cde5b772a253a532cad3b9113eaf7f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Jul 2007 00:31:06 -0600 Subject: [PATCH 09/26] WL#3984 (Revise locking of mysql.general_log and mysql.slow_log) Bug#25422 (Hang with log tables) Bug 17876 (Truncating mysql.slow_log in a SP after using cursor locks the thread) Bug 23044 (Warnings on flush of a log table) Bug 29129 (Resetting general_log while the GLOBAL READ LOCK is set causes a deadlock) Prior to this fix, the server would hang when performing concurrent ALTER TABLE or TRUNCATE TABLE statements against the LOG TABLES, which are mysql.general_log and mysql.slow_log. The root cause traces to the following code: in sql_base.cc, open_table() if (table->in_use != thd) { /* wait_for_condition will unlock LOCK_open for us */ wait_for_condition(thd, &LOCK_open, &COND_refresh); } The problem with this code is that the current implementation of the LOGGER creates 'fake' THD objects, like - Log_to_csv_event_handler::general_log_thd - Log_to_csv_event_handler::slow_log_thd which are not associated to a real thread running in the server, so that waiting for these non-existing threads to release table locks cause the dead lock. In general, the design of Log_to_csv_event_handler does not fit into the general architecture of the server, so that the concept of general_log_thd and slow_log_thd has to be abandoned: - this implementation does not work with table locking - it will not work with commands like SHOW PROCESSLIST - having the log tables always opened does not integrate well with DDL operations / FLUSH TABLES / SET GLOBAL READ_ONLY With this patch, the fundamental design of the LOGGER has been changed to: - always open and close a log table when writing a log - remove totally the usage of fake THD objects - clarify how locking of log tables is implemented in general. See WL#3984 for details related to the new locking design. Additional changes (misc bugs exposed and fixed): 1) mysqldump which would ignore some tables in dump_all_tables_in_db(), but forget to ignore the same in dump_all_views_in_db(). 2) mysqldump would also issue an empty "LOCK TABLE" command when all the tables to lock are to be ignored (numrows == 0), instead of not issuing the query. 3) Internal errors handlers could intercept errors but not warnings (see sql_error.cc). 4) Implementing a nested call to open tables, for the performance schema tables, exposed an existing bug in remove_table_from_cache(), which would perform: in_use->some_tables_deleted=1; against another thread, without any consideration about thread locking. This call inside remove_table_from_cache() was not required anyway, since calling mysql_lock_abort() takes care of aborting -- cleanly -- threads that might hold a lock on a table. This line (in_use->some_tables_deleted=1) has been removed. sql/handler.cc: Moved logic for system / log tables in the SQL layer. sql/handler.h: Moved logic for system / log tables in the SQL layer. sql/lock.cc: Revised locking of log tables sql/log.cc: Major cleanup: changed how log tables are locked / written to. sql/log.h: Major cleanup: changed how log tables are locked / written to. sql/mysql_priv.h: performance schema helpers sql/slave.cc: open_ltable() lock flags sql/sp.cc: open_ltable() lock flags sql/sql_acl.cc: open_ltable() lock flags sql/sql_class.h: performance schema helpers sql/sql_delete.cc: log tables cleanup in TRUNCATE sql/sql_error.cc: Internal handlers can also intercept warnings sql/sql_insert.cc: open_ltable() lock flags sql/sql_parse.cc: performance schema helpers sql/sql_plugin.cc: open_ltable() lock flags sql/sql_rename.cc: log tables cleanup in RENAME sql/sql_servers.cc: open_ltable() lock flags sql/sql_show.cc: Move INFORMATION_SCHEMA_NAME to table.cc sql/sql_table.cc: log tables cleanup (admin operations, ALTER TABLE) sql/sql_udf.cc: open_ltable() lock flags sql/table.cc: Implemented TABLE_CATEGORY. sql/share/errmsg.txt: Changed the wording and name of ER_CANT_READ_LOCK_LOG_TABLE sql/table.h: Implemented TABLE_CATEGORY. storage/csv/ha_tina.cc: Moved logic for system / log tables in the SQL layer. storage/csv/ha_tina.h: Moved logic for system / log tables in the SQL layer. storage/myisam/ha_myisam.cc: Moved logic for system / log tables in the SQL layer. storage/myisam/ha_myisam.h: Moved logic for system / log tables in the SQL layer. client/mysqldump.c: Don't lock tables in the ignore list. Don't issue empty LOCK TABLES queries. sql/sql_base.cc: log tables cleanup performance schema helpers mysql-test/r/ps.result: Adjust test results mysql-test/r/show_check.result: Adjust test results mysql-test/r/status.result: Adjust test results mysql-test/t/log_state.test: Added tests for Bug#29129 mysql-test/t/ps.test: Make the test output deterministic mysql-test/t/show_check.test: Make the test output deterministic mysql-test/r/log_state.result: Changed the default location of the log output to LOG_FILE, for backward compatibility with MySQL 5.0 --- Adjust test results mysql-test/r/log_tables.result: cleanup for -ps-protocol mysql-test/t/log_tables.test: cleanup for -ps-protocol sql/set_var.cc: Changed the default location of the log output to LOG_FILE, for backward compatibility with MySQL 5.0 --- log tables cleanup --- client/mysqldump.c | 25 +- mysql-test/r/log_state.result | 24 +- mysql-test/r/log_tables.result | 297 +++++++++++-- mysql-test/r/ps.result | 54 ++- mysql-test/r/show_check.result | 31 +- mysql-test/r/status.result | 12 +- mysql-test/t/log_state.test | 53 +++ mysql-test/t/log_tables.test | 410 ++++++++++++++---- mysql-test/t/ps.test | 7 + mysql-test/t/show_check.test | 7 + sql/handler.cc | 40 +- sql/handler.h | 39 +- sql/lock.cc | 76 +++- sql/log.cc | 732 +++++++++++++-------------------- sql/log.h | 93 +---- sql/mysql_priv.h | 14 +- sql/set_var.cc | 28 +- sql/share/errmsg.txt | 4 +- sql/slave.cc | 2 +- sql/sp.cc | 2 +- sql/sql_acl.cc | 2 +- sql/sql_base.cc | 130 ++++-- sql/sql_class.h | 1 + sql/sql_delete.cc | 22 - sql/sql_error.cc | 3 + sql/sql_insert.cc | 2 +- sql/sql_parse.cc | 29 +- sql/sql_plugin.cc | 4 +- sql/sql_rename.cc | 20 - sql/sql_servers.cc | 6 +- sql/sql_show.cc | 3 - sql/sql_table.cc | 49 +-- sql/sql_udf.cc | 4 +- sql/table.cc | 80 +++- sql/table.h | 120 +++++- storage/csv/ha_tina.cc | 12 - storage/csv/ha_tina.h | 5 - storage/myisam/ha_myisam.cc | 36 +- storage/myisam/ha_myisam.h | 5 - 39 files changed, 1490 insertions(+), 993 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 0f30ebddacc..b77549df781 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -3726,11 +3726,12 @@ static int dump_all_tables_in_db(char *database) { DYNAMIC_STRING query; init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024); - for (numrows= 0 ; (table= getTableName(1)) ; numrows++) + for (numrows= 0 ; (table= getTableName(1)) ; ) { char *end= strmov(afterdot, table); if (include_table(hash_key,end - hash_key)) { + numrows++; dynstr_append_checked(&query, quote_name(table, table_buff, 1)); dynstr_append_checked(&query, " READ /*!32311 LOCAL */,"); } @@ -3804,6 +3805,11 @@ static my_bool dump_all_views_in_db(char *database) char *table; uint numrows; char table_buff[NAME_LEN*2+3]; + char hash_key[2*NAME_LEN+2]; /* "db.tablename" */ + char *afterdot; + + afterdot= strmov(hash_key, database); + *afterdot++= '.'; if (init_dumping(database, init_dumping_views)) return 1; @@ -3813,10 +3819,15 @@ static my_bool dump_all_views_in_db(char *database) { DYNAMIC_STRING query; init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024); - for (numrows= 0 ; (table= getTableName(1)); numrows++) + for (numrows= 0 ; (table= getTableName(1)); ) { - dynstr_append_checked(&query, quote_name(table, table_buff, 1)); - dynstr_append_checked(&query, " READ /*!32311 LOCAL */,"); + char *end= strmov(afterdot, table); + if (include_table(hash_key,end - hash_key)) + { + numrows++; + dynstr_append_checked(&query, quote_name(table, table_buff, 1)); + dynstr_append_checked(&query, " READ /*!32311 LOCAL */,"); + } } if (numrows && mysql_real_query(mysql, query.str, query.length-1)) DB_error(mysql, "when using LOCK TABLES"); @@ -3830,7 +3841,11 @@ static my_bool dump_all_views_in_db(char *database) /* We shall continue here, if --force was given */ } while ((table= getTableName(0))) - get_view_structure(table, database); + { + char *end= strmov(afterdot, table); + if (include_table(hash_key, end - hash_key)) + get_view_structure(table, database); + } if (opt_xml) { fputs("\n", md_result_file); diff --git a/mysql-test/r/log_state.result b/mysql-test/r/log_state.result index 946797aeec7..0c6be16b9b7 100644 --- a/mysql-test/r/log_state.result +++ b/mysql-test/r/log_state.result @@ -131,7 +131,7 @@ set global general_log=ON; set global log_output=default; show variables like 'log_output'; Variable_name Value -log_output TABLE +log_output FILE set global general_log=OFF; set global log_output=FILE; truncate table mysql.general_log; @@ -153,3 +153,25 @@ select * from mysql.general_log; event_time user_host thread_id server_id command_type argument TIMESTAMP USER_HOST # 1 Query drop table t1 TIMESTAMP USER_HOST # 1 Query select * from mysql.general_log +SET @old_general_log_state = @@global.general_log; +SET @old_slow_log_state = @@global.slow_query_log; +SET GLOBAL general_log = ON; +SET GLOBAL slow_query_log = ON; +FLUSH TABLES WITH READ LOCK; +SET GLOBAL general_log = OFF; +SET GLOBAL slow_query_log = OFF; +UNLOCK TABLES; +FLUSH TABLES WITH READ LOCK; +SET GLOBAL general_log = ON; +SET GLOBAL slow_query_log = ON; +UNLOCK TABLES; +SET GLOBAL READ_ONLY = ON; +SET GLOBAL general_log = OFF; +SET GLOBAL slow_query_log = OFF; +SET GLOBAL READ_ONLY = OFF; +SET GLOBAL READ_ONLY = ON; +SET GLOBAL general_log = ON; +SET GLOBAL slow_query_log = ON; +SET GLOBAL READ_ONLY = OFF; +SET GLOBAL general_log = @old_general_log_state; +SET GLOBAL slow_query_log = @old_slow_log_state; diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result index ce3dabe3a56..39349183276 100644 --- a/mysql-test/r/log_tables.result +++ b/mysql-test/r/log_tables.result @@ -29,30 +29,83 @@ on (mysql.general_log.command_type = join_test.command_type) drop table join_test; flush logs; lock tables mysql.general_log WRITE; -ERROR HY000: You can't write-lock a log table. Only read access is possible +ERROR HY000: You can't use locks with log tables. lock tables mysql.slow_log WRITE; -ERROR HY000: You can't write-lock a log table. Only read access is possible +ERROR HY000: You can't use locks with log tables. lock tables mysql.general_log READ; -ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead +ERROR HY000: You can't use locks with log tables. lock tables mysql.slow_log READ; -ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead +ERROR HY000: You can't use locks with log tables. lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL; -unlock tables; -lock tables mysql.general_log READ LOCAL; +ERROR HY000: You can't use locks with log tables. +show create table mysql.general_log; +Table Create Table +general_log CREATE TABLE `general_log` ( + `event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext, + `thread_id` int(11) DEFAULT NULL, + `server_id` int(11) DEFAULT NULL, + `command_type` varchar(64) DEFAULT NULL, + `argument` mediumtext +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='General log' +show fields from mysql.general_log; +Field Type Null Key Default Extra +event_time timestamp NO CURRENT_TIMESTAMP +user_host mediumtext YES NULL +thread_id int(11) YES NULL +server_id int(11) YES NULL +command_type varchar(64) YES NULL +argument mediumtext YES NULL +show create table mysql.slow_log; +Table Create Table +slow_log CREATE TABLE `slow_log` ( + `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext NOT NULL, + `query_time` time NOT NULL, + `lock_time` time NOT NULL, + `rows_sent` int(11) NOT NULL, + `rows_examined` int(11) NOT NULL, + `db` varchar(512) DEFAULT NULL, + `last_insert_id` int(11) DEFAULT NULL, + `insert_id` int(11) DEFAULT NULL, + `server_id` int(11) DEFAULT NULL, + `sql_text` mediumtext NOT NULL +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log' +show fields from mysql.slow_log; +Field Type Null Key Default Extra +start_time timestamp NO CURRENT_TIMESTAMP +user_host mediumtext NO +query_time time NO +lock_time time NO +rows_sent int(11) NO +rows_examined int(11) NO +db varchar(512) YES NULL +last_insert_id int(11) YES NULL +insert_id int(11) YES NULL +server_id int(11) YES NULL +sql_text mediumtext NO flush logs; -unlock tables; -select "Mark that we woke up from flush logs in the test" - as "test passed"; -test passed -Mark that we woke up from flush logs in the test -lock tables mysql.general_log READ LOCAL; -truncate mysql.general_log; -unlock tables; -select "Mark that we woke up from TRUNCATE in the test" - as "test passed"; -test passed -Mark that we woke up from TRUNCATE in the test -use test; +flush tables; +SET GLOBAL GENERAL_LOG=ON; +SET GLOBAL SLOW_QUERY_LOG=ON; +show open tables; +Database Table In_use Name_locked +mysql general_log 0 0 +flush logs; +show open tables; +Database Table In_use Name_locked +mysql general_log 0 0 +flush tables; +show open tables; +Database Table In_use Name_locked +mysql general_log 0 0 +SET GLOBAL GENERAL_LOG=OFF; +SET GLOBAL SLOW_QUERY_LOG=OFF; +flush tables; +show open tables; +Database Table In_use Name_locked +SET GLOBAL GENERAL_LOG=ON; +SET GLOBAL SLOW_QUERY_LOG=ON; truncate table mysql.general_log; set names utf8; create table bug16905 (s char(15) character set utf8 default 'пуÑто'); @@ -71,7 +124,7 @@ sleep(2) 0 select * from mysql.slow_log; start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text -TIMESTAMP USER_HOST QUERY_TIME 00:00:00 1 0 test 0 0 1 select sleep(2) +TIMESTAMP USER_HOST QUERY_TIME 00:00:00 1 0 mysql 0 0 1 select sleep(2) alter table mysql.general_log engine=myisam; ERROR HY000: You cannot 'ALTER' a log table if logging is enabled alter table mysql.slow_log engine=myisam; @@ -158,15 +211,13 @@ TIMESTAMP USER_HOST THREAD_ID 1 Query set global slow_query_log='ON' TIMESTAMP USER_HOST THREAD_ID 1 Query select * from mysql.general_log flush logs; lock tables mysql.general_log WRITE; -ERROR HY000: You can't write-lock a log table. Only read access is possible +ERROR HY000: You can't use locks with log tables. lock tables mysql.slow_log WRITE; -ERROR HY000: You can't write-lock a log table. Only read access is possible +ERROR HY000: You can't use locks with log tables. lock tables mysql.general_log READ; -ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead +ERROR HY000: You can't use locks with log tables. lock tables mysql.slow_log READ; -ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead -lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL; -unlock tables; +ERROR HY000: You can't use locks with log tables. set global general_log='OFF'; set global slow_query_log='OFF'; set @save_storage_engine= @@session.storage_engine; @@ -217,6 +268,7 @@ flush tables with read lock; unlock tables; use mysql; lock tables general_log read local, help_category read local; +ERROR HY000: You can't use locks with log tables. unlock tables; use mysql; RENAME TABLE general_log TO renamed_general_log; @@ -258,9 +310,9 @@ RENAME TABLE general_log TO general_log2; set global slow_query_log='OFF'; RENAME TABLE slow_log TO slow_log2; set global general_log='ON'; -ERROR HY000: Cannot activate 'general' log +ERROR 42S02: Table 'mysql.general_log' doesn't exist set global slow_query_log='ON'; -ERROR HY000: Cannot activate 'slow query' log +ERROR 42S02: Table 'mysql.slow_log' doesn't exist RENAME TABLE general_log2 TO general_log; RENAME TABLE slow_log2 TO slow_log; set global general_log='ON'; @@ -355,3 +407,192 @@ SET SESSION long_query_time =@old_long_query_time; FLUSH LOGS; ALTER TABLE mysql.slow_log DROP COLUMN seq; ALTER TABLE mysql.slow_log ENGINE = CSV; +drop procedure if exists proc25422_truncate_slow; +drop procedure if exists proc25422_truncate_general; +drop procedure if exists proc25422_alter_slow; +drop procedure if exists proc25422_alter_general; +use test// +create procedure proc25422_truncate_slow (loops int) +begin +declare v1 int default 0; +while v1 < loops do +truncate mysql.slow_log; +set v1 = v1 + 1; +end while; +end// +create procedure proc25422_truncate_general (loops int) +begin +declare v1 int default 0; +while v1 < loops do +truncate mysql.general_log; +set v1 = v1 + 1; +end while; +end// +create procedure proc25422_alter_slow (loops int) +begin +declare v1 int default 0; +declare ER_BAD_LOG_STATEMENT condition for 1575; +declare continue handler for ER_BAD_LOG_STATEMENT begin end; +while v1 < loops do +set @old_log_state = @@global.slow_query_log; +set global slow_query_log = 'OFF'; +alter table mysql.slow_log engine = CSV; +set global slow_query_log = @old_log_state; +set v1 = v1 + 1; +end while; +end// +create procedure proc25422_alter_general (loops int) +begin +declare v1 int default 0; +declare ER_BAD_LOG_STATEMENT condition for 1575; +declare continue handler for ER_BAD_LOG_STATEMENT begin end; +while v1 < loops do +set @old_log_state = @@global.general_log; +set global general_log = 'OFF'; +alter table mysql.general_log engine = CSV; +set global general_log = @old_log_state; +set v1 = v1 + 1; +end while; +end// +"Serial test (proc25422_truncate_slow)" +call proc25422_truncate_slow(100); +"Serial test (proc25422_truncate_general)" +call proc25422_truncate_general(100); +"Serial test (proc25422_alter_slow)" +call proc25422_alter_slow(100); +"Serial test (proc25422_alter_general)" +call proc25422_alter_general(100); +"Parallel test" +call proc25422_truncate_slow(100); +call proc25422_truncate_slow(100); +call proc25422_truncate_general(100); +call proc25422_truncate_general(100); +call proc25422_alter_slow(100); +call proc25422_alter_slow(100); +call proc25422_alter_general(100); +call proc25422_alter_general(100); +drop procedure proc25422_truncate_slow; +drop procedure proc25422_truncate_general; +drop procedure proc25422_alter_slow; +drop procedure proc25422_alter_general; +FLUSH TABLE mysql.general_log; +show warnings; +Level Code Message +FLUSH TABLE mysql.slow_log; +show warnings; +Level Code Message +DROP TABLE IF EXISTS `db_17876.slow_log_data`; +DROP TABLE IF EXISTS `db_17876.general_log_data`; +DROP PROCEDURE IF EXISTS `db_17876.archiveSlowLog`; +DROP PROCEDURE IF EXISTS `db_17876.archiveGeneralLog`; +DROP DATABASE IF EXISTS `db_17876`; +CREATE DATABASE db_17876; +CREATE TABLE `db_17876.slow_log_data` ( +`start_time` timestamp default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, +`user_host` mediumtext , +`query_time` time , +`lock_time` time , +`rows_sent` int(11) , +`rows_examined` int(11) , +`db` varchar(512) default NULL, +`last_insert_id` int(11) default NULL, +`insert_id` int(11) default NULL, +`server_id` int(11) default NULL, +`sql_text` mediumtext +); +CREATE TABLE `db_17876.general_log_data` ( +`event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, +`user_host` mediumtext, +`thread_id` int(11) DEFAULT NULL, +`server_id` int(11) DEFAULT NULL, +`command_type` varchar(64) DEFAULT NULL, +`argument` mediumtext +); +CREATE procedure `db_17876.archiveSlowLog`() +BEGIN +DECLARE start_time, query_time, lock_time CHAR(20); +DECLARE user_host MEDIUMTEXT; +DECLARE rows_set, rows_examined, last_insert_id, insert_id, server_id INT; +DECLARE dbname MEDIUMTEXT; +DECLARE sql_text BLOB; +DECLARE done INT DEFAULT 0; +DECLARE ER_SP_FETCH_NO_DATA CONDITION for 1329; +DECLARE cur1 CURSOR FOR SELECT * FROM mysql.slow_log; +OPEN cur1; +REPEAT +BEGIN +BEGIN +DECLARE CONTINUE HANDLER FOR ER_SP_FETCH_NO_DATA SET done = 1; +FETCH cur1 INTO +start_time, user_host, query_time, lock_time, +rows_set, rows_examined, dbname, last_insert_id, +insert_id, server_id, sql_text; +END; +IF NOT done THEN +BEGIN +INSERT INTO +`db_17876.slow_log_data` + VALUES(start_time, user_host, query_time, lock_time, rows_set, rows_examined, +dbname, last_insert_id, insert_id, server_id, sql_text); +END; +END IF; +END; +UNTIL done END REPEAT; +CLOSE cur1; +TRUNCATE mysql.slow_log; +END // +CREATE procedure `db_17876.archiveGeneralLog`() +BEGIN +DECLARE event_time CHAR(20); +DECLARE user_host, argument MEDIUMTEXT; +DECLARE thread_id, server_id INT; +DECLARE sql_text BLOB; +DECLARE done INT DEFAULT 0; +DECLARE command_type VARCHAR(64); +DECLARE ER_SP_FETCH_NO_DATA CONDITION for 1329; +DECLARE cur1 CURSOR FOR SELECT * FROM mysql.general_log; +OPEN cur1; +REPEAT +BEGIN +BEGIN +DECLARE CONTINUE HANDLER FOR ER_SP_FETCH_NO_DATA SET done = 1; +FETCH cur1 INTO +event_time, user_host, thread_id, server_id, +command_type, argument; +END; +IF NOT done THEN +BEGIN +INSERT INTO +`db_17876.general_log_data` + VALUES(event_time, user_host, thread_id, server_id, +command_type, argument); +END; +END IF; +END; +UNTIL done END REPEAT; +CLOSE cur1; +TRUNCATE mysql.general_log; +END // +SET @old_general_log_state = @@global.general_log; +SET @old_slow_log_state = @@global.slow_query_log; +SET GLOBAL general_log = ON; +SET GLOBAL slow_query_log = ON; +select "put something into general_log"; +put something into general_log +put something into general_log +select "... and something more ..."; +... and something more ... +... and something more ... +call `db_17876.archiveSlowLog`(); +call `db_17876.archiveGeneralLog`(); +SET GLOBAL general_log = OFF; +SET GLOBAL slow_query_log = OFF; +call `db_17876.archiveSlowLog`(); +call `db_17876.archiveGeneralLog`(); +DROP TABLE `db_17876.slow_log_data`; +DROP TABLE `db_17876.general_log_data`; +DROP PROCEDURE IF EXISTS `db_17876.archiveSlowLog`; +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; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 9214d470b37..341a6b7cd43 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1850,61 +1850,57 @@ create procedure proc_1() flush tables; flush tables; show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 select Host, User from mysql.user limit 0; Host User select Host, Db from mysql.host limit 0; Host Db show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 +mysql slow_log 0 0 mysql host 0 0 mysql user 0 0 call proc_1(); show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 select Host, User from mysql.user limit 0; Host User select Host, Db from mysql.host limit 0; Host Db show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 +mysql slow_log 0 0 mysql host 0 0 mysql user 0 0 call proc_1(); show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 select Host, User from mysql.user limit 0; Host User select Host, Db from mysql.host limit 0; Host Db show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 +mysql slow_log 0 0 mysql host 0 0 mysql user 0 0 call proc_1(); show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 select Host, User from mysql.user limit 0; Host User select Host, Db from mysql.host limit 0; Host Db show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 +mysql slow_log 0 0 mysql host 0 0 mysql user 0 0 flush tables; @@ -1922,54 +1918,50 @@ select Host, Db from mysql.host limit 0; Host Db show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 -mysql host 0 0 mysql user 0 0 +mysql general_log 0 0 +mysql host 0 0 prepare abc from "flush tables"; execute abc; show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 select Host, User from mysql.user limit 0; Host User select Host, Db from mysql.host limit 0; Host Db show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 +mysql slow_log 0 0 mysql host 0 0 mysql user 0 0 execute abc; show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 select Host, User from mysql.user limit 0; Host User select Host, Db from mysql.host limit 0; Host Db show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 +mysql slow_log 0 0 mysql host 0 0 mysql user 0 0 execute abc; show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 select Host, User from mysql.user limit 0; Host User select Host, Db from mysql.host limit 0; Host Db show open tables from mysql; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 +mysql slow_log 0 0 mysql host 0 0 mysql user 0 0 flush tables; diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 2bdd29602fb..9f79c34cd2c 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -251,14 +251,13 @@ drop table t1; flush tables; show open tables; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 create table t1(n int); insert into t1 values (1); show open tables; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 +mysql slow_log 0 0 test t1 0 0 drop table t1; create table t1 (a int not null, b VARCHAR(10), INDEX (b) ) AVG_ROW_LENGTH=10 CHECKSUM=1 COMMENT="test" ENGINE=MYISAM MIN_ROWS=10 MAX_ROWS=100 PACK_KEYS=1 DELAY_KEY_WRITE=1 ROW_FORMAT=fixed; @@ -672,24 +671,23 @@ SELECT 1 FROM mysql.db, mysql.proc, mysql.user, mysql.time_zone, mysql.time_zone 1 SHOW OPEN TABLES; Database Table In_use Name_locked -mysql proc 0 0 +mysql db 0 0 test urkunde 0 0 mysql time_zone 0 0 -mysql db 0 0 +mysql general_log 0 0 test txt1 0 0 -mysql slow_log 1 0 +mysql proc 0 0 test tyt2 0 0 -mysql general_log 1 0 mysql user 0 0 mysql time_zone_name 0 0 SHOW OPEN TABLES FROM mysql; Database Table In_use Name_locked -mysql proc 0 0 -mysql time_zone 0 0 mysql db 0 0 -mysql slow_log 1 0 -mysql general_log 1 0 +mysql time_zone 0 0 +mysql general_log 0 0 +mysql slow_log 0 0 mysql user 0 0 +mysql proc 0 0 mysql time_zone_name 0 0 SHOW OPEN TABLES FROM mysql LIKE 'u%'; Database Table In_use Name_locked @@ -702,16 +700,15 @@ test tyt2 0 0 mysql time_zone_name 0 0 SHOW OPEN TABLES LIKE '%o%'; Database Table In_use Name_locked -mysql proc 0 0 mysql time_zone 0 0 -mysql slow_log 1 0 -mysql general_log 1 0 +mysql general_log 0 0 +mysql slow_log 0 0 +mysql proc 0 0 mysql time_zone_name 0 0 FLUSH TABLES; SHOW OPEN TABLES; Database Table In_use Name_locked -mysql general_log 1 0 -mysql slow_log 1 0 +mysql general_log 0 0 DROP TABLE txt1; DROP TABLE tyt2; DROP TABLE urkunde; diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index b6dcbc251d7..8f10625744b 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -1,11 +1,11 @@ flush status; show status like 'Table_lock%'; Variable_name Value -Table_locks_immediate 0 +Table_locks_immediate 1 Table_locks_waited 0 select * from information_schema.session_status where variable_name like 'Table_lock%'; VARIABLE_NAME VARIABLE_VALUE -TABLE_LOCKS_IMMEDIATE 0 +TABLE_LOCKS_IMMEDIATE 2 TABLE_LOCKS_WAITED 0 SET SQL_LOG_BIN=0; drop table if exists t1; @@ -18,11 +18,11 @@ update t1 set n = 3; unlock tables; show status like 'Table_lock%'; Variable_name Value -Table_locks_immediate 3 +Table_locks_immediate 17 Table_locks_waited 1 select * from information_schema.session_status where variable_name like 'Table_lock%'; VARIABLE_NAME VARIABLE_VALUE -TABLE_LOCKS_IMMEDIATE 3 +TABLE_LOCKS_IMMEDIATE 18 TABLE_LOCKS_WAITED 1 drop table t1; select 1; @@ -97,7 +97,7 @@ Variable_name Value Com_show_status 3 show status like 'hand%write%'; Variable_name Value -Handler_write 0 +Handler_write 5 show status like '%tmp%'; Variable_name Value Created_tmp_disk_tables 0 @@ -105,7 +105,7 @@ Created_tmp_files 0 Created_tmp_tables 0 show status like 'hand%write%'; Variable_name Value -Handler_write 0 +Handler_write 7 show status like '%tmp%'; Variable_name Value Created_tmp_disk_tables 0 diff --git a/mysql-test/t/log_state.test b/mysql-test/t/log_state.test index 16f466e9b54..b0bb818b783 100644 --- a/mysql-test/t/log_state.test +++ b/mysql-test/t/log_state.test @@ -126,6 +126,59 @@ drop table t1; --replace_column 1 TIMESTAMP 2 USER_HOST 3 # select * from mysql.general_log; +# +# Bug#29129 (Resetting general_log while the GLOBAL READ LOCK is set causes +# a deadlock) + +# save state + +SET @old_general_log_state = @@global.general_log; +SET @old_slow_log_state = @@global.slow_query_log; + +# Test ON->OFF transition under a GLOBAL READ LOCK + +SET GLOBAL general_log = ON; +SET GLOBAL slow_query_log = ON; + +FLUSH TABLES WITH READ LOCK; + +SET GLOBAL general_log = OFF; +SET GLOBAL slow_query_log = OFF; + +UNLOCK TABLES; + +# Test OFF->ON transition under a GLOBAL READ LOCK + +FLUSH TABLES WITH READ LOCK; + +SET GLOBAL general_log = ON; +SET GLOBAL slow_query_log = ON; + +UNLOCK TABLES; + +# Test ON->OFF transition under a GLOBAL READ_ONLY + +SET GLOBAL READ_ONLY = ON; + +SET GLOBAL general_log = OFF; +SET GLOBAL slow_query_log = OFF; + +SET GLOBAL READ_ONLY = OFF; + +# Test OFF->ON transition under a GLOBAL READ_ONLY + +SET GLOBAL READ_ONLY = ON; + +SET GLOBAL general_log = ON; +SET GLOBAL slow_query_log = ON; + +SET GLOBAL READ_ONLY = OFF; + +# Restore state + +SET GLOBAL general_log = @old_general_log_state; +SET GLOBAL slow_query_log = @old_slow_log_state; + --enable_ps_protocol # diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test index e8eff7cba0a..8baa4e5a373 100644 --- a/mysql-test/t/log_tables.test +++ b/mysql-test/t/log_tables.test @@ -64,10 +64,10 @@ flush logs; # check locking of the log tables # ---error ER_CANT_WRITE_LOCK_LOG_TABLE +--error ER_CANT_LOCK_LOG_TABLE lock tables mysql.general_log WRITE; ---error ER_CANT_WRITE_LOCK_LOG_TABLE +--error ER_CANT_LOCK_LOG_TABLE lock tables mysql.slow_log WRITE; # @@ -76,78 +76,59 @@ lock tables mysql.slow_log WRITE; # tables are always opened and locked by the logger. # ---error ER_CANT_READ_LOCK_LOG_TABLE +--error ER_CANT_LOCK_LOG_TABLE lock tables mysql.general_log READ; ---error ER_CANT_READ_LOCK_LOG_TABLE +--error ER_CANT_LOCK_LOG_TABLE lock tables mysql.slow_log READ; # -# This call should result in TL_READ lock on the log table. This is ok and -# should pass. +# This call should result in TL_READ lock on the log table. +# This is not ok and should fail. # +--error ER_CANT_LOCK_LOG_TABLE lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL; -unlock tables; +# Misc locking tests + +show create table mysql.general_log; +show fields from mysql.general_log; + +show create table mysql.slow_log; +show fields from mysql.slow_log; # -# check that FLUSH LOGS waits for all readers of the log table to vanish +# check that FLUSH LOGS does not flush the log tables # -connect (con1,localhost,root,,); -connect (con2,localhost,root,,); +flush logs; +flush tables; -connection con1; +SET GLOBAL GENERAL_LOG=ON; +SET GLOBAL SLOW_QUERY_LOG=ON; -lock tables mysql.general_log READ LOCAL; - -connection con2; - -# this should wait for log tables to unlock -send flush logs; - -connection con1; - -unlock tables; - -# this connection should be alive by the time -connection con2; - -reap; - -select "Mark that we woke up from flush logs in the test" - as "test passed"; +show open tables; +flush logs; +show open tables; # -# perform the same check for TRUNCATE: it should also wait for readers -# to disappear +# check that FLUSH TABLES does flush the log tables # -connection con1; +flush tables; +# Since the flush is logged, mysql.general_log will be in the cache +show open tables; -lock tables mysql.general_log READ LOCAL; +SET GLOBAL GENERAL_LOG=OFF; +SET GLOBAL SLOW_QUERY_LOG=OFF; -connection con2; +flush tables; +# Here the table cache is empty +show open tables; -# this should wait for log tables to unlock -send truncate mysql.general_log; - -connection con1; - -unlock tables; - -# this connection should be alive by the time -connection con2; - -reap; - -select "Mark that we woke up from TRUNCATE in the test" - as "test passed"; - -connection con1; - -use test; +SET GLOBAL GENERAL_LOG=ON; +SET GLOBAL SLOW_QUERY_LOG=ON; # # Bug #16905 Log tables: unicode statements are logged incorrectly @@ -220,10 +201,10 @@ flush logs; # check locking of myisam-based log tables ---error ER_CANT_WRITE_LOCK_LOG_TABLE +--error ER_CANT_LOCK_LOG_TABLE lock tables mysql.general_log WRITE; ---error ER_CANT_WRITE_LOCK_LOG_TABLE +--error ER_CANT_LOCK_LOG_TABLE lock tables mysql.slow_log WRITE; # @@ -232,21 +213,12 @@ lock tables mysql.slow_log WRITE; # tables are always opened and locked by the logger. # ---error ER_CANT_READ_LOCK_LOG_TABLE +--error ER_CANT_LOCK_LOG_TABLE lock tables mysql.general_log READ; ---error ER_CANT_READ_LOCK_LOG_TABLE +--error ER_CANT_LOCK_LOG_TABLE lock tables mysql.slow_log READ; -# -# This call should result in TL_READ lock on the log table. This is ok and -# should pass. -# - -lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL; - -unlock tables; - # check that we can drop them set global general_log='OFF'; set global slow_query_log='OFF'; @@ -314,6 +286,7 @@ use test; flush tables with read lock; unlock tables; use mysql; +--error ER_CANT_LOCK_LOG_TABLE lock tables general_log read local, help_category read local; unlock tables; @@ -368,9 +341,9 @@ set global slow_query_log='OFF'; RENAME TABLE slow_log TO slow_log2; # this should fail ---error ER_CANT_ACTIVATE_LOG +--error ER_NO_SUCH_TABLE set global general_log='ON'; ---error ER_CANT_ACTIVATE_LOG +--error ER_NO_SUCH_TABLE set global slow_query_log='ON'; RENAME TABLE general_log2 TO general_log; @@ -470,8 +443,305 @@ FLUSH LOGS; ALTER TABLE mysql.slow_log DROP COLUMN seq; ALTER TABLE mysql.slow_log ENGINE = CSV; -# kill all connections -disconnect con1; -disconnect con2; +# +# Bug#25422 (Hang with log tables) +# + +--disable_warnings +drop procedure if exists proc25422_truncate_slow; +drop procedure if exists proc25422_truncate_general; +drop procedure if exists proc25422_alter_slow; +drop procedure if exists proc25422_alter_general; +--enable_warnings + +delimiter //; + +use test// +create procedure proc25422_truncate_slow (loops int) +begin + declare v1 int default 0; + while v1 < loops do + truncate mysql.slow_log; + set v1 = v1 + 1; + end while; +end// + +create procedure proc25422_truncate_general (loops int) +begin + declare v1 int default 0; + while v1 < loops do + truncate mysql.general_log; + set v1 = v1 + 1; + end while; +end// + +create procedure proc25422_alter_slow (loops int) +begin + declare v1 int default 0; + declare ER_BAD_LOG_STATEMENT condition for 1575; + declare continue handler for ER_BAD_LOG_STATEMENT begin end; + + while v1 < loops do + set @old_log_state = @@global.slow_query_log; + set global slow_query_log = 'OFF'; + alter table mysql.slow_log engine = CSV; + set global slow_query_log = @old_log_state; + set v1 = v1 + 1; + end while; +end// + +create procedure proc25422_alter_general (loops int) +begin + declare v1 int default 0; + declare ER_BAD_LOG_STATEMENT condition for 1575; + declare continue handler for ER_BAD_LOG_STATEMENT begin end; + + while v1 < loops do + set @old_log_state = @@global.general_log; + set global general_log = 'OFF'; + alter table mysql.general_log engine = CSV; + set global general_log = @old_log_state; + set v1 = v1 + 1; + end while; +end// + +delimiter ;// + +--echo "Serial test (proc25422_truncate_slow)" +call proc25422_truncate_slow(100); +--echo "Serial test (proc25422_truncate_general)" +call proc25422_truncate_general(100); +--echo "Serial test (proc25422_alter_slow)" +call proc25422_alter_slow(100); +--echo "Serial test (proc25422_alter_general)" +call proc25422_alter_general(100); + +--echo "Parallel test" + +# ER_BAD_LOG_STATEMENT errors will occur, +# since concurrent threads do SET GLOBAL general_log= ... +# This is silenced by handlers and will not affect the test + +connect (addconroot1, localhost, root,,); +connect (addconroot2, localhost, root,,); +connect (addconroot3, localhost, root,,); +connect (addconroot4, localhost, root,,); +connect (addconroot5, localhost, root,,); +connect (addconroot6, localhost, root,,); +connect (addconroot7, localhost, root,,); +connect (addconroot8, localhost, root,,); + +connection addconroot1; +send call proc25422_truncate_slow(100); +connection addconroot2; +send call proc25422_truncate_slow(100); + +connection addconroot3; +send call proc25422_truncate_general(100); +connection addconroot4; +send call proc25422_truncate_general(100); + +connection addconroot5; +send call proc25422_alter_slow(100); +connection addconroot6; +send call proc25422_alter_slow(100); + +connection addconroot7; +send call proc25422_alter_general(100); +connection addconroot8; +send call proc25422_alter_general(100); + +connection addconroot1; +reap; +connection addconroot2; +reap; +connection addconroot3; +reap; +connection addconroot4; +reap; +connection addconroot5; +reap; +connection addconroot6; +reap; +connection addconroot7; +reap; +connection addconroot8; +reap; + +connection default; + +disconnect addconroot1; +disconnect addconroot2; +disconnect addconroot3; +disconnect addconroot4; +disconnect addconroot5; +disconnect addconroot6; +disconnect addconroot7; +disconnect addconroot8; + +drop procedure proc25422_truncate_slow; +drop procedure proc25422_truncate_general; +drop procedure proc25422_alter_slow; +drop procedure proc25422_alter_general; + --enable_ps_protocol + +# +# Bug#23044 (Warnings on flush of a log table) +# + +FLUSH TABLE mysql.general_log; +show warnings; + +FLUSH TABLE mysql.slow_log; +show warnings; + +# +# Bug#17876 (Truncating mysql.slow_log in a SP after using cursor locks the +# thread) +# + +--disable_warnings +DROP TABLE IF EXISTS `db_17876.slow_log_data`; +DROP TABLE IF EXISTS `db_17876.general_log_data`; +DROP PROCEDURE IF EXISTS `db_17876.archiveSlowLog`; +DROP PROCEDURE IF EXISTS `db_17876.archiveGeneralLog`; +DROP DATABASE IF EXISTS `db_17876`; +--enable_warnings + +CREATE DATABASE db_17876; + +CREATE TABLE `db_17876.slow_log_data` ( + `start_time` timestamp default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + `user_host` mediumtext , + `query_time` time , + `lock_time` time , + `rows_sent` int(11) , + `rows_examined` int(11) , + `db` varchar(512) default NULL, + `last_insert_id` int(11) default NULL, + `insert_id` int(11) default NULL, + `server_id` int(11) default NULL, + `sql_text` mediumtext +); + +CREATE TABLE `db_17876.general_log_data` ( + `event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext, + `thread_id` int(11) DEFAULT NULL, + `server_id` int(11) DEFAULT NULL, + `command_type` varchar(64) DEFAULT NULL, + `argument` mediumtext +); + +DELIMITER //; + +CREATE procedure `db_17876.archiveSlowLog`() +BEGIN + DECLARE start_time, query_time, lock_time CHAR(20); + DECLARE user_host MEDIUMTEXT; + DECLARE rows_set, rows_examined, last_insert_id, insert_id, server_id INT; + DECLARE dbname MEDIUMTEXT; + DECLARE sql_text BLOB; + DECLARE done INT DEFAULT 0; + DECLARE ER_SP_FETCH_NO_DATA CONDITION for 1329; + + DECLARE cur1 CURSOR FOR SELECT * FROM mysql.slow_log; + + OPEN cur1; + + REPEAT + BEGIN + BEGIN + DECLARE CONTINUE HANDLER FOR ER_SP_FETCH_NO_DATA SET done = 1; + + FETCH cur1 INTO + start_time, user_host, query_time, lock_time, + rows_set, rows_examined, dbname, last_insert_id, + insert_id, server_id, sql_text; + END; + + IF NOT done THEN + BEGIN + INSERT INTO + `db_17876.slow_log_data` + VALUES(start_time, user_host, query_time, lock_time, rows_set, rows_examined, + dbname, last_insert_id, insert_id, server_id, sql_text); + END; + END IF; + END; + UNTIL done END REPEAT; + + CLOSE cur1; + TRUNCATE mysql.slow_log; +END // + +CREATE procedure `db_17876.archiveGeneralLog`() +BEGIN + DECLARE event_time CHAR(20); + DECLARE user_host, argument MEDIUMTEXT; + DECLARE thread_id, server_id INT; + DECLARE sql_text BLOB; + DECLARE done INT DEFAULT 0; + DECLARE command_type VARCHAR(64); + DECLARE ER_SP_FETCH_NO_DATA CONDITION for 1329; + + DECLARE cur1 CURSOR FOR SELECT * FROM mysql.general_log; + + OPEN cur1; + + REPEAT + BEGIN + BEGIN + DECLARE CONTINUE HANDLER FOR ER_SP_FETCH_NO_DATA SET done = 1; + + FETCH cur1 INTO + event_time, user_host, thread_id, server_id, + command_type, argument; + END; + + IF NOT done THEN + BEGIN + INSERT INTO + `db_17876.general_log_data` + VALUES(event_time, user_host, thread_id, server_id, + command_type, argument); + END; + END IF; + END; + UNTIL done END REPEAT; + + CLOSE cur1; + TRUNCATE mysql.general_log; +END // + +DELIMITER ;// + +SET @old_general_log_state = @@global.general_log; +SET @old_slow_log_state = @@global.slow_query_log; + +SET GLOBAL general_log = ON; +SET GLOBAL slow_query_log = ON; + +select "put something into general_log"; +select "... and something more ..."; + +call `db_17876.archiveSlowLog`(); +call `db_17876.archiveGeneralLog`(); + +SET GLOBAL general_log = OFF; +SET GLOBAL slow_query_log = OFF; + +call `db_17876.archiveSlowLog`(); +call `db_17876.archiveGeneralLog`(); + +DROP TABLE `db_17876.slow_log_data`; +DROP TABLE `db_17876.general_log_data`; +DROP PROCEDURE IF EXISTS `db_17876.archiveSlowLog`; +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; + diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 394f44bbc83..5a4d30fdd50 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -2018,10 +2018,17 @@ delimiter ;| select func_1(), func_1(), func_1() from dual; drop function func_1; drop procedure proc_1; + +# make the output deterministic: +# the order used in SHOW OPEN TABLES +# is too much implementation dependent +--disable_ps_protocol flush tables; select Host, User from mysql.user limit 0; select Host, Db from mysql.host limit 0; show open tables from mysql; +--enable_ps_protocol + prepare abc from "flush tables"; execute abc; show open tables from mysql; diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index 09c0b08a3cd..5d7d8d3130d 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -438,6 +438,11 @@ drop table if exists t1; CREATE TABLE txt1(a int); CREATE TABLE tyt2(a int); CREATE TABLE urkunde(a int); + +# make the output deterministic: +# the order used in SHOW OPEN TABLES +# is too much implementation dependent +--disable_ps_protocol FLUSH TABLES; SELECT 1 FROM mysql.db, mysql.proc, mysql.user, mysql.time_zone, mysql.time_zone_name, txt1, tyt2, urkunde LIMIT 0; SHOW OPEN TABLES; @@ -447,6 +452,8 @@ SHOW OPEN TABLES LIKE 't%'; SHOW OPEN TABLES LIKE '%o%'; FLUSH TABLES; SHOW OPEN TABLES; +--enable_ps_protocol + DROP TABLE txt1; DROP TABLE tyt2; DROP TABLE urkunde; diff --git a/sql/handler.cc b/sql/handler.cc index 2d836b30862..e0ec2962d17 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1516,34 +1516,6 @@ THD *handler::ha_thd(void) const } -bool handler::check_if_log_table_locking_is_allowed(uint sql_command, - ulong type, TABLE *table) -{ - /* - Deny locking of the log tables, which is incompatible with - concurrent insert. The routine is not called if the table is - being locked from a logger THD (general_log_thd or slow_log_thd) - or from a privileged thread (see log.cc for details) - */ - if (table->s->log_table && - sql_command != SQLCOM_TRUNCATE && - sql_command != SQLCOM_ALTER_TABLE && - !(sql_command == SQLCOM_FLUSH && - type & REFRESH_LOG) && - (table->reginfo.lock_type >= TL_READ_NO_INSERT)) - { - /* - The check >= TL_READ_NO_INSERT denies all write locks - plus the only read lock (TL_READ_NO_INSERT itself) - */ - table->reginfo.lock_type == TL_READ_NO_INSERT ? - my_error(ER_CANT_READ_LOCK_LOG_TABLE, MYF(0)) : - my_error(ER_CANT_WRITE_LOCK_LOG_TABLE, MYF(0)); - return FALSE; - } - return TRUE; -} - /** @brief Open database-handler. @@ -3681,6 +3653,18 @@ int handler::ha_write_row(uchar *buf) return 0; } + +/** + Write a record to the engine bypassing row-level binary logging. + This method is used internally by the server for writing to + performance schema tables, which are never replicated. +*/ +int handler::ha_write_row_no_binlog(uchar *buf) +{ + return write_row(buf); +} + + int handler::ha_update_row(const uchar *old_data, uchar *new_data) { int error; diff --git a/sql/handler.h b/sql/handler.h index f45b28c55f5..06f0a2cf035 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1035,44 +1035,6 @@ public: { cached_table_flags= table_flags(); } - /* - Check whether a handler allows to lock the table. - - SYNOPSIS - check_if_locking_is_allowed() - thd Handler of the thread, trying to lock the table - table Table handler to check - count Total number of tables to be locked - current Index of the current table in the list of the tables - to be locked. - system_count Pointer to the counter of system tables seen thus - far. - called_by_privileged_thread TRUE if called from a logger THD - (general_log_thd or slow_log_thd) - or by a privileged thread, which - has the right to lock log tables. - - DESCRIPTION - Check whether a handler allows to lock the table. For instance, - MyISAM does not allow to lock mysql.proc along with other tables. - This limitation stems from the fact that MyISAM does not support - row-level locking and we have to add this limitation to avoid - deadlocks. - - RETURN - TRUE Locking is allowed - FALSE Locking is not allowed. The error was thrown. - */ - virtual bool check_if_locking_is_allowed(uint sql_command, - ulong type, TABLE *table, - uint count, uint current, - uint *system_count, - bool called_by_privileged_thread) - { - return TRUE; - } - bool check_if_log_table_locking_is_allowed(uint sql_command, - ulong type, TABLE *table); int ha_open(TABLE *table, const char *name, int mode, int test_if_locked); void adjust_next_insert_id_after_explicit_value(ulonglong nr); int update_auto_increment(); @@ -1196,6 +1158,7 @@ public: */ int ha_external_lock(THD *thd, int lock_type); int ha_write_row(uchar * buf); + int ha_write_row_no_binlog(uchar * buf); int ha_update_row(const uchar * old_data, uchar * new_data); int ha_delete_row(const uchar * buf); diff --git a/sql/lock.cc b/sql/lock.cc index 4260a031def..34a2e202f8f 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -117,9 +117,64 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, MYSQL_LOCK *sql_lock; TABLE *write_lock_used; int rc; + uint i; + bool log_table_write_query; + uint system_count; + DBUG_ENTER("mysql_lock_tables"); *need_reopen= FALSE; + system_count= 0; + + log_table_write_query= (is_log_table_write_query(thd->lex->sql_command) + || ((flags & MYSQL_LOCK_PERF_SCHEMA) != 0)); + + for (i=0 ; is->table_category != TABLE_UNKNOWN_CATEGORY); + + /* + Table I/O to performance schema tables is performed + only internally by the server implementation. + When a user is requesting a lock, the following + constraints are enforced: + */ + if (t->s->require_write_privileges() && + ! log_table_write_query) + { + /* + A user should not be able to prevent writes, + or hold any type of lock in a session, + since this would be a DOS attack. + */ + if ((t->reginfo.lock_type >= TL_READ_NO_INSERT) + || (thd->lex->sql_command == SQLCOM_LOCK_TABLES)) + { + my_error(ER_CANT_LOCK_LOG_TABLE, MYF(0)); + DBUG_RETURN(0); + } + } + + if ((t->s->table_category == TABLE_CATEGORY_SYSTEM) && + (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE)) + { + system_count++; + } + } + + /* + Locking of system tables is restricted: + locking a mix of system and non-system tables in the same lock + is prohibited, to prevent contention. + */ + if ((system_count > 0) && (system_count < count)) + { + my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0)); + DBUG_RETURN(0); + } for (;;) { @@ -439,7 +494,8 @@ void mysql_lock_downgrade_write(THD *thd, TABLE *table, { MYSQL_LOCK *locked; TABLE *write_lock_used; - if ((locked = get_lock_data(thd,&table,1,1,&write_lock_used))) + if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK, + &write_lock_used))) { for (uint i=0; i < locked->lock_count; i++) thr_downgrade_write_lock(locked->locks[i], new_lock_type); @@ -698,25 +754,19 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, TABLE **to, **table_buf; DBUG_ENTER("get_lock_data"); + DBUG_ASSERT((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS)); + DBUG_PRINT("info", ("count %d", count)); *write_lock_used=0; - uint system_count= 0; for (i=tables=lock_count=0 ; i < count ; i++) { - if (table_ptr[i]->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE) + TABLE *t= table_ptr[i]; + + if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE) { - tables+=table_ptr[i]->file->lock_count(); + tables+= t->file->lock_count(); lock_count++; } - /* - Check if we can lock the table. For some tables we cannot do that - beacause of handler-specific locking issues. - */ - if (!table_ptr[i]-> file-> - check_if_locking_is_allowed(thd->lex->sql_command, thd->lex->type, - table_ptr[i], count, i, &system_count, - logger.is_privileged_thread(thd))) - DBUG_RETURN(0); } /* diff --git a/sql/log.cc b/sql/log.cc index 0bf77d68410..af039c15ffc 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -57,6 +57,35 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all); static int binlog_rollback(handlerton *hton, THD *thd, bool all); static int binlog_prepare(handlerton *hton, THD *thd, bool all); +/** + Silence all errors and warnings reported when performing a write + to a log table. + Errors and warnings are not reported to the client or SQL exception + handlers, so that the presence of logging does not interfere and affect + the logic of an application. +*/ +class Silence_log_table_errors : public Internal_error_handler +{ +public: + Silence_log_table_errors() + {} + + virtual ~Silence_log_table_errors() {} + + virtual bool handle_error(uint sql_errno, + MYSQL_ERROR::enum_warning_level level, + THD *thd); +}; + +bool +Silence_log_table_errors::handle_error(uint /* sql_errno */, + MYSQL_ERROR::enum_warning_level /* level */, + THD * /* thd */) +{ + return TRUE; +} + + sql_print_message_func sql_print_message_handlers[3] = { sql_print_information, @@ -187,6 +216,19 @@ public: handlerton *binlog_hton; +bool LOGGER::is_log_table_enabled(uint log_table_type) +{ + switch (log_table_type) { + case QUERY_LOG_SLOW: + return (table_log_handler != NULL) && opt_slow_log; + case QUERY_LOG_GENERAL: + return (table_log_handler != NULL) && opt_log ; + default: + DBUG_ASSERT(0); + return FALSE; /* make compiler happy */ + } +} + /* Check if a given table is opened log table */ int check_if_log_table(uint db_len, const char *db, uint table_name_len, @@ -200,211 +242,38 @@ int check_if_log_table(uint db_len, const char *db, uint table_name_len, if (table_name_len == 11 && !(lower_case_table_names ? my_strcasecmp(system_charset_info, table_name, "general_log") : - strcmp(table_name, "general_log")) && - (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_GENERAL))) - return QUERY_LOG_GENERAL; - else - if (table_name_len == 8 && !(lower_case_table_names ? - my_strcasecmp(system_charset_info, table_name, "slow_log") : - strcmp(table_name, "slow_log")) && - (!check_if_opened ||logger.is_log_table_enabled(QUERY_LOG_SLOW))) + strcmp(table_name, "general_log"))) + { + if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_GENERAL)) + return QUERY_LOG_GENERAL; + return 0; + } + + if (table_name_len == 8 && !(lower_case_table_names ? + my_strcasecmp(system_charset_info, table_name, "slow_log") : + strcmp(table_name, "slow_log"))) + { + if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_SLOW)) return QUERY_LOG_SLOW; + return 0; + } } return 0; } -/* - Open log table of a given type (general or slow log) - - SYNOPSIS - open_log_table() - - log_table_type type of the log table to open: QUERY_LOG_GENERAL - or QUERY_LOG_SLOW - - DESCRIPTION - - The function opens a log table and marks it as such. Log tables are open - during the whole time, while server is running. Except for the moments - when they have to be reopened: during FLUSH LOGS and TRUNCATE. This - function is invoked directly only once during startup. All subsequent - calls happen through reopen_log_table(), which performs additional check. - - RETURN - FALSE - OK - TRUE - error occured -*/ - -bool Log_to_csv_event_handler::open_log_table(uint log_table_type) -{ - THD *log_thd, *curr= current_thd; - TABLE_LIST *table; - bool error= FALSE; - DBUG_ENTER("open_log_table"); - - switch (log_table_type) { - case QUERY_LOG_GENERAL: - log_thd= general_log_thd; - table= &general_log; - /* clean up table before reuse/initial usage */ - bzero((char*) table, sizeof(TABLE_LIST)); - table->alias= table->table_name= (char*) "general_log"; - table->table_name_length= 11; - break; - case QUERY_LOG_SLOW: - log_thd= slow_log_thd; - table= &slow_log; - bzero((char*) table, sizeof(TABLE_LIST)); - table->alias= table->table_name= (char*) "slow_log"; - table->table_name_length= 8; - break; - default: - assert(0); // Impossible - } - - /* - This way we check that appropriate log thd was created ok during - initialization. We cannot check "is_log_tables_initialized" var, as - the very initialization is not finished until this function is - completed in the very first time. - */ - if (!log_thd) - { - DBUG_PRINT("error",("Cannot initialize log tables")); - DBUG_RETURN(TRUE); - } - - /* - Set THD's thread_stack. This is needed to perform stack overrun - check, which is done by some routines (e.g. open_table()). - In the case we are called by thread, which already has this parameter - set, we use this value. Otherwise we do a wild guess. This won't help - to correctly track the stack overrun in these exceptional cases (which - could probably happen only during startup and shutdown) but at least - lets us to pass asserts. - The problem stems from the fact that logger THDs are not real threads. - */ - if (curr) - log_thd->thread_stack= curr->thread_stack; - else - log_thd->thread_stack= (char*) &log_thd; - - log_thd->store_globals(); - - table->lock_type= TL_WRITE_CONCURRENT_INSERT; - table->db= log_thd->db; - table->db_length= log_thd->db_length; - - lex_start(log_thd); - log_thd->clear_error(); - if (simple_open_n_lock_tables(log_thd, table) || - table->table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) || - table->table->file->ha_rnd_init(0)) - error= TRUE; - else - { - table->table->use_all_columns(); - table->table->locked_by_logger= TRUE; - table->table->no_replicate= TRUE; - - /* Honor next number columns if present */ - table->table->next_number_field= table->table->found_next_number_field; - } - /* restore thread settings */ - if (curr) - curr->store_globals(); - else - { - my_pthread_setspecific_ptr(THR_THD, 0); - my_pthread_setspecific_ptr(THR_MALLOC, 0); - } - - /* - After a log table was opened, we should clear privileged thread - flag (which allows locking of a log table by a special thread, usually - the one who closed log tables temporarily). - */ - privileged_thread= 0; - DBUG_RETURN(error); -} - - Log_to_csv_event_handler::Log_to_csv_event_handler() { - /* init artificial THD's */ - general_log_thd= new THD; - /* logger thread always works with mysql database */ - general_log_thd->db= my_strdup("mysql", MYF(0)); - general_log_thd->db_length= 5; - general_log.table= 0; - - slow_log_thd= new THD; - /* logger thread always works with mysql database */ - slow_log_thd->db= my_strdup("mysql", MYF(0));; - slow_log_thd->db_length= 5; - slow_log.table= 0; - /* no privileged thread exists at the moment */ - privileged_thread= 0; } Log_to_csv_event_handler::~Log_to_csv_event_handler() { - /* now cleanup the tables */ - if (general_log_thd) - { - delete general_log_thd; - general_log_thd= NULL; - } - - if (slow_log_thd) - { - delete slow_log_thd; - slow_log_thd= NULL; - } -} - - -/* - Reopen log table of a given type - - SYNOPSIS - reopen_log_table() - - log_table_type type of the log table to open: QUERY_LOG_GENERAL - or QUERY_LOG_SLOW - - DESCRIPTION - - The function is a wrapper around open_log_table(). It is used during - FLUSH LOGS and TRUNCATE of the log tables (i.e. when we need to close - and reopen them). The difference is in the check of the - logger.is_log_tables_initialized var, which can't be done in - open_log_table(), as it makes no sense during startup. - - NOTE: this code assumes that we have logger mutex locked - - RETURN - FALSE - ok - TRUE - open_log_table() returned an error -*/ - -bool Log_to_csv_event_handler::reopen_log_table(uint log_table_type) -{ - /* don't open the log table, if it wasn't enabled during startup */ - if (!logger.is_log_tables_initialized) - return FALSE; - return open_log_table(log_table_type); } void Log_to_csv_event_handler::cleanup() { - if (opt_log) - close_log_table(QUERY_LOG_GENERAL, FALSE); - if (opt_slow_log) - close_log_table(QUERY_LOG_SLOW, FALSE); logger.is_log_tables_initialized= FALSE; } @@ -436,49 +305,88 @@ void Log_to_csv_event_handler::cleanup() */ bool Log_to_csv_event_handler:: - log_general(time_t event_time, const char *user_host, + log_general(THD *thd, time_t event_time, const char *user_host, uint user_host_len, int thread_id, const char *command_type, uint command_type_len, const char *sql_text, uint sql_text_len, CHARSET_INFO *client_cs) { - TABLE *table= general_log.table; + TABLE_LIST table_list; + TABLE *table; + bool result= TRUE; + bool need_close= FALSE; + bool need_pop= FALSE; + bool need_rnd_end= FALSE; uint field_index; + Silence_log_table_errors error_handler; + Open_tables_state open_tables_backup; + Field_timestamp *field0; + ulonglong save_thd_options; + bool save_query_start_used; + time_t save_start_time; + time_t save_time_after_lock; + time_t save_user_time; + bool save_time_zone_used; + + save_thd_options= thd->options; + thd->options&= ~OPTION_BIN_LOG; + + save_query_start_used= thd->query_start_used; + save_start_time= thd->start_time; + save_time_after_lock= thd->time_after_lock; + save_user_time= thd->user_time; + save_time_zone_used= thd->time_zone_used; + + bzero(& table_list, sizeof(TABLE_LIST)); + table_list.alias= table_list.table_name= GENERAL_LOG_NAME.str; + table_list.table_name_length= GENERAL_LOG_NAME.length; + + table_list.lock_type= TL_WRITE_CONCURRENT_INSERT; + + table_list.db= MYSQL_SCHEMA_NAME.str; + table_list.db_length= MYSQL_SCHEMA_NAME.length; + + table= open_performance_schema_table(thd, & table_list, + & open_tables_backup); + need_close= TRUE; + + if (!table || + table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) || + table->file->ha_rnd_init(0)) + goto err; + + need_rnd_end= TRUE; + + /* Honor next number columns if present */ + table->next_number_field= table->found_next_number_field; /* "INSERT INTO general_log" can generate warning sometimes. - Let's reset warnings from previous queries, - otherwise warning list can grow too much, - so thd->query gets spoiled as some point in time, - and mysql_parse() receives a broken query. QQ: this problem needs to be studied in more details. - Probably it's better to suppress warnings in logging INSERTs at all. - Comment this line and run "cast.test" to see what's happening: + Comment this 2 lines and run "cast.test" to see what's happening: */ - mysql_reset_errors(table->in_use, 1); - - /* below should never happen */ - if (unlikely(!logger.is_log_tables_initialized)) - return FALSE; + thd->push_internal_handler(& error_handler); + need_pop= TRUE; /* NOTE: we do not call restore_record() here, as all fields are filled by the Logger (=> no need to load default ones). */ - /* Set current time. Required for CURRENT_TIMESTAMP to work */ - general_log_thd->start_time= event_time; - /* We do not set a value for table->field[0], as it will use default value (which is CURRENT_TIMESTAMP). */ /* check that all columns exist */ - if (!table->field[1] || !table->field[2] || !table->field[3] || - !table->field[4] || !table->field[5]) + if (table->s->fields < 6) goto err; + DBUG_ASSERT(table->field[0]->type() == MYSQL_TYPE_TIMESTAMP); + + field0= (Field_timestamp*) (table->field[0]); + field0->set_time(); + /* do a write */ if (table->field[1]->store(user_host, user_host_len, client_cs) || table->field[2]->store((longlong) thread_id, TRUE) || @@ -500,16 +408,39 @@ bool Log_to_csv_event_handler:: table->field[field_index]->set_default(); } - /* log table entries are not replicated at the moment */ - tmp_disable_binlog(current_thd); + /* log table entries are not replicated */ + if (table->file->ha_write_row_no_binlog(table->record[0])) + { + struct tm start; + localtime_r(&event_time, &start); - table->file->ha_write_row(table->record[0]); + sql_print_error("%02d%02d%02d %2d:%02d:%02d - Failed to write to mysql.general_log", + start.tm_year % 100, start.tm_mon + 1, + start.tm_mday, start.tm_hour, + start.tm_min, start.tm_sec); + } - reenable_binlog(current_thd); + result= FALSE; - return FALSE; err: - return TRUE; + if (need_rnd_end) + { + table->file->ha_rnd_end(); + table->file->ha_release_auto_increment(); + } + if (need_pop) + thd->pop_internal_handler(); + if (need_close) + close_performance_schema_table(thd, & open_tables_backup); + + thd->options= save_thd_options; + + thd->query_start_used= save_query_start_used; + thd->start_time= save_start_time; + thd->time_after_lock= save_time_after_lock; + thd->user_time= save_user_time; + thd->time_zone_used= save_time_zone_used; + return result; } @@ -548,34 +479,61 @@ bool Log_to_csv_event_handler:: longlong query_time, longlong lock_time, bool is_command, const char *sql_text, uint sql_text_len) { - /* table variables */ - TABLE *table= slow_log.table; + TABLE_LIST table_list; + TABLE *table; + bool result= TRUE; + bool need_close= FALSE; + bool need_rnd_end= FALSE; + Open_tables_state open_tables_backup; + bool save_query_start_used; + time_t save_start_time; + time_t save_time_after_lock; + time_t save_user_time; + bool save_time_zone_used; CHARSET_INFO *client_cs= thd->variables.character_set_client; - DBUG_ENTER("log_slow"); + DBUG_ENTER("Log_to_csv_event_handler::log_slow"); - /* below should never happen */ - if (unlikely(!logger.is_log_tables_initialized)) - return FALSE; + bzero(& table_list, sizeof(TABLE_LIST)); + table_list.alias= table_list.table_name= SLOW_LOG_NAME.str; + table_list.table_name_length= SLOW_LOG_NAME.length; + + table_list.lock_type= TL_WRITE_CONCURRENT_INSERT; + + table_list.db= MYSQL_SCHEMA_NAME.str; + table_list.db_length= MYSQL_SCHEMA_NAME.length; + + save_query_start_used= thd->query_start_used; + save_start_time= thd->start_time; + save_time_after_lock= thd->time_after_lock; + save_user_time= thd->user_time; + save_time_zone_used= thd->time_zone_used; + + table= open_performance_schema_table(thd, & table_list, + & open_tables_backup); + need_close= TRUE; + + if (!table || + table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) || + table->file->ha_rnd_init(0)) + goto err; + + need_rnd_end= TRUE; + + /* Honor next number columns if present */ + table->next_number_field= table->found_next_number_field; - /* - Set start time for CURRENT_TIMESTAMP to the start of the query. - This will be default value for the field[0] - */ - slow_log_thd->start_time= query_start_arg; restore_record(table, s->default_values); // Get empty record + /* check that all columns exist */ + if (table->s->fields < 11) + goto err; + /* We do not set a value for table->field[0], as it will use default value. */ - if (!table->field[1] || !table->field[2] || !table->field[3] || - !table->field[4] || !table->field[5] || !table->field[6] || - !table->field[7] || !table->field[8] || !table->field[9] || - !table->field[10]) - goto err; - /* store the value */ if (table->field[1]->store(user_host, user_host_len, client_cs)) goto err; @@ -612,7 +570,6 @@ bool Log_to_csv_event_handler:: table->field[4]->set_null(); table->field[5]->set_null(); } - /* fill database field */ if (thd->db) { @@ -654,17 +611,71 @@ bool Log_to_csv_event_handler:: if (table->field[10]->store(sql_text,sql_text_len, client_cs)) goto err; - /* log table entries are not replicated at the moment */ - tmp_disable_binlog(current_thd); + /* log table entries are not replicated */ + if (table->file->ha_write_row_no_binlog(table->record[0])) + { + struct tm start; + localtime_r(¤t_time, &start); - /* write the row */ - table->file->ha_write_row(table->record[0]); + sql_print_error("%02d%02d%02d %2d:%02d:%02d - Failed to write to mysql.slow_log", + start.tm_year % 100, start.tm_mon + 1, + start.tm_mday, start.tm_hour, + start.tm_min, start.tm_sec); + } - reenable_binlog(current_thd); + result= FALSE; - DBUG_RETURN(0); err: - DBUG_RETURN(1); + if (need_rnd_end) + { + table->file->ha_rnd_end(); + table->file->ha_release_auto_increment(); + } + if (need_close) + close_performance_schema_table(thd, & open_tables_backup); + + thd->query_start_used= save_query_start_used; + thd->start_time= save_start_time; + thd->time_after_lock= save_time_after_lock; + thd->user_time= save_user_time; + thd->time_zone_used= save_time_zone_used; + DBUG_RETURN(result); +} + +int Log_to_csv_event_handler:: + activate_log(THD *thd, uint log_table_type) +{ + TABLE_LIST table_list; + TABLE *table; + int result; + Open_tables_state open_tables_backup; + + DBUG_ENTER("Log_to_csv_event_handler::activate_log"); + + bzero(& table_list, sizeof(TABLE_LIST)); + + if (log_table_type == QUERY_LOG_GENERAL) + { + table_list.alias= table_list.table_name= GENERAL_LOG_NAME.str; + table_list.table_name_length= GENERAL_LOG_NAME.length; + } + else + { + DBUG_ASSERT(log_table_type == QUERY_LOG_SLOW); + table_list.alias= table_list.table_name= SLOW_LOG_NAME.str; + table_list.table_name_length= SLOW_LOG_NAME.length; + } + + table_list.lock_type= TL_WRITE_CONCURRENT_INSERT; + + table_list.db= MYSQL_SCHEMA_NAME.str; + table_list.db_length= MYSQL_SCHEMA_NAME.length; + + table= open_performance_schema_table(thd, & table_list, + & open_tables_backup); + result= (table ? 0 : 1); + close_performance_schema_table(thd, & open_tables_backup); + DBUG_RETURN(result); } bool Log_to_csv_event_handler:: @@ -697,10 +708,19 @@ bool Log_to_file_event_handler:: longlong query_time, longlong lock_time, bool is_command, const char *sql_text, uint sql_text_len) { - return mysql_slow_log.write(thd, current_time, query_start_arg, - user_host, user_host_len, - query_time, lock_time, is_command, - sql_text, sql_text_len); + bool res; + + (void) pthread_mutex_lock(mysql_slow_log.get_log_lock()); + + /* TODO: MYSQL_QUERY_LOG::write is not thread-safe */ + res= mysql_slow_log.write(thd, current_time, query_start_arg, + user_host, user_host_len, + query_time, lock_time, is_command, + sql_text, sql_text_len); + + (void) pthread_mutex_unlock(mysql_slow_log.get_log_lock()); + + return res; } @@ -710,15 +730,24 @@ bool Log_to_file_event_handler:: */ bool Log_to_file_event_handler:: - log_general(time_t event_time, const char *user_host, + log_general(THD *thd, time_t event_time, const char *user_host, uint user_host_len, int thread_id, const char *command_type, uint command_type_len, const char *sql_text, uint sql_text_len, CHARSET_INFO *client_cs) { - return mysql_log.write(event_time, user_host, user_host_len, - thread_id, command_type, command_type_len, - sql_text, sql_text_len); + bool res; + + (void) pthread_mutex_lock (mysql_log.get_log_lock()); + + /* TODO: MYSQL_QUERY_LOG::write is not thread-safe */ + res= mysql_log.write(event_time, user_host, user_host_len, + thread_id, command_type, command_type_len, + sql_text, sql_text_len); + + (void) pthread_mutex_unlock (mysql_log.get_log_lock()); + + return res; } @@ -787,7 +816,7 @@ bool LOGGER::error_log_print(enum loglevel level, const char *format, void LOGGER::cleanup_base() { DBUG_ASSERT(inited == 1); - (void) pthread_mutex_destroy(&LOCK_logger); + rwlock_destroy(&LOCK_logger); if (table_log_handler) { table_log_handler->cleanup(); @@ -806,12 +835,6 @@ void LOGGER::cleanup_end() } -void LOGGER::close_log_table(uint log_table_type, bool lock_in_use) -{ - table_log_handler->close_log_table(log_table_type, lock_in_use); -} - - /* Perform basic log initialization: create file-based log handler and init error log. @@ -833,7 +856,7 @@ void LOGGER::init_base() init_error_log(LOG_FILE); file_log_handler->init_pthread_objects(); - (void) pthread_mutex_init(&LOCK_logger, MY_MUTEX_INIT_SLOW); + my_rwlock_init(&LOCK_logger, NULL); } @@ -848,29 +871,6 @@ void LOGGER::init_log_tables() } -bool LOGGER::reopen_log_table(uint log_table_type) -{ - return table_log_handler->reopen_log_table(log_table_type); -} - -bool LOGGER::reopen_log_tables() -{ - /* - we use | and not || here, to ensure that both reopen_log_table - are called, even if the first one fails - */ - if ((opt_slow_log && logger.reopen_log_table(QUERY_LOG_SLOW)) | - (opt_log && logger.reopen_log_table(QUERY_LOG_GENERAL))) - return TRUE; - return FALSE; -} - - -void LOGGER::tmp_close_log_tables(THD *thd) -{ - table_log_handler->tmp_close_log_tables(thd); -} - bool LOGGER::flush_logs(THD *thd) { int rc= 0; @@ -879,19 +879,11 @@ bool LOGGER::flush_logs(THD *thd) Now we lock logger, as nobody should be able to use logging routines while log tables are closed */ - logger.lock(); - if (logger.is_log_tables_initialized) - table_log_handler->tmp_close_log_tables(thd); // the locking happens here + logger.lock_exclusive(); /* reopen log files */ file_log_handler->flush(); - /* reopen tables in the case they were enabled */ - if (logger.is_log_tables_initialized) - { - if (reopen_log_tables()) - rc= TRUE; - } /* end of log flush */ logger.unlock(); return rc; @@ -939,7 +931,7 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, if (thd->slave_thread) return 0; - lock(); + lock_shared(); if (!opt_slow_log) { unlock(); @@ -1011,7 +1003,7 @@ bool LOGGER::general_log_print(THD *thd, enum enum_server_command command, else id=0; /* Log from connect handler */ - lock(); + lock_shared(); if (!opt_log) { unlock(); @@ -1035,7 +1027,7 @@ bool LOGGER::general_log_print(THD *thd, enum enum_server_command command, while (*current_handler) error+= (*current_handler++)-> - log_general(current_time, user_host_buff, + log_general(thd, current_time, user_host_buff, user_host_len, id, command_name[(uint) command].str, command_name[(uint) command].length, @@ -1122,35 +1114,42 @@ void LOGGER::init_general_log(uint general_log_printer) bool LOGGER::activate_log_handler(THD* thd, uint log_type) { - bool res= 0; - lock(); + bool res= FALSE; + lock_exclusive(); switch (log_type) { case QUERY_LOG_SLOW: if (!opt_slow_log) { - if ((res= reopen_log_table(log_type))) - goto err; file_log_handler->get_mysql_slow_log()-> open_slow_log(sys_var_slow_log_path.value); init_slow_log(log_output_options); - opt_slow_log= TRUE; + if (table_log_handler->activate_log(thd, QUERY_LOG_SLOW)) + { + /* Error printed by open table in activate_log() */ + res= TRUE; + } + else + opt_slow_log= TRUE; } break; case QUERY_LOG_GENERAL: if (!opt_log) { - if ((res= reopen_log_table(log_type))) - goto err; file_log_handler->get_mysql_log()-> open_query_log(sys_var_general_log_path.value); init_general_log(log_output_options); - opt_log= TRUE; + if (table_log_handler->activate_log(thd, QUERY_LOG_GENERAL)) + { + /* Error printed by open table in activate_log() */ + res= TRUE; + } + else + opt_log= TRUE; } break; default: DBUG_ASSERT(0); } -err: unlock(); return res; } @@ -1158,23 +1157,17 @@ err: void LOGGER::deactivate_log_handler(THD *thd, uint log_type) { - TABLE_LIST *table_list; my_bool *tmp_opt= 0; MYSQL_LOG *file_log; - THD *log_thd; switch (log_type) { case QUERY_LOG_SLOW: - table_list= &table_log_handler->slow_log; tmp_opt= &opt_slow_log; file_log= file_log_handler->get_mysql_slow_log(); - log_thd= table_log_handler->slow_log_thd; break; case QUERY_LOG_GENERAL: - table_list= &table_log_handler->general_log; tmp_opt= &opt_log; file_log= file_log_handler->get_mysql_log(); - log_thd= table_log_handler->general_log_thd; break; default: assert(0); // Impossible @@ -1183,81 +1176,16 @@ void LOGGER::deactivate_log_handler(THD *thd, uint log_type) if (!(*tmp_opt)) return; - if (is_log_tables_initialized) - lock_and_wait_for_table_name(log_thd, table_list); - lock(); - - if (is_log_tables_initialized) - { - VOID(pthread_mutex_lock(&LOCK_open)); - close_log_table(log_type, TRUE); - table_list->table= 0; - query_cache_invalidate3(log_thd, table_list, 0); - unlock_table_name(log_thd, table_list); - VOID(pthread_mutex_unlock(&LOCK_open)); - } + lock_exclusive(); file_log->close(0); *tmp_opt= FALSE; unlock(); } -/* - Close log tables temporarily. The thread which closed - them this way can lock them in any mode it needs. - NOTE: one should call logger.lock() before entering this - function. -*/ -void Log_to_csv_event_handler::tmp_close_log_tables(THD *thd) -{ - TABLE_LIST close_slow_log, close_general_log; - - /* fill lists, we will need to perform operations on tables */ - bzero((char*) &close_slow_log, sizeof(TABLE_LIST)); - close_slow_log.alias= close_slow_log.table_name=(char*) "slow_log"; - close_slow_log.table_name_length= 8; - close_slow_log.db= (char*) "mysql"; - close_slow_log.db_length= 5; - - bzero((char*) &close_general_log, sizeof(TABLE_LIST)); - close_general_log.alias= close_general_log.table_name=(char*) "general_log"; - close_general_log.table_name_length= 11; - close_general_log.db= (char*) "mysql"; - close_general_log.db_length= 5; - - privileged_thread= thd; - - VOID(pthread_mutex_lock(&LOCK_open)); - /* - NOTE: in fact, the first parameter used in query_cache_invalidate3() - could be any non-NULL THD, as the underlying code makes certain - assumptions about this. - Here we use one of the logger handler THD's. Simply because it - seems appropriate. - */ - if (opt_log) - { - close_log_table(QUERY_LOG_GENERAL, TRUE); - query_cache_invalidate3(general_log_thd, &close_general_log, 0); - } - if (opt_slow_log) - { - close_log_table(QUERY_LOG_SLOW, TRUE); - query_cache_invalidate3(general_log_thd, &close_slow_log, 0); - } - VOID(pthread_mutex_unlock(&LOCK_open)); -} - /* the parameters are unused for the log tables */ bool Log_to_csv_event_handler::init() { - /* - we use | and not || here, to ensure that both open_log_table - are called, even if the first one fails - */ - if ((opt_log && open_log_table(QUERY_LOG_GENERAL)) | - (opt_slow_log && open_log_table(QUERY_LOG_SLOW))) - return 1; return 0; } @@ -1268,7 +1196,7 @@ int LOGGER::set_handlers(uint error_log_printer, /* error log table is not supported yet */ DBUG_ASSERT(error_log_printer < LOG_TABLE); - lock(); + lock_exclusive(); if ((slow_log_printer & LOG_TABLE || general_log_printer & LOG_TABLE) && !is_log_tables_initialized) @@ -1290,72 +1218,6 @@ int LOGGER::set_handlers(uint error_log_printer, } -/* - Close log table of a given type (general or slow log) - - SYNOPSIS - close_log_table() - - log_table_type type of the log table to close: QUERY_LOG_GENERAL - or QUERY_LOG_SLOW - lock_in_use Set to TRUE if the caller owns LOCK_open. FALSE otherwise. - - DESCRIPTION - - The function closes a log table. It is invoked (1) when we need to reopen - log tables (e.g. FLUSH LOGS or TRUNCATE on the log table is being - executed) or (2) during shutdown. -*/ - -void Log_to_csv_event_handler:: - close_log_table(uint log_table_type, bool lock_in_use) -{ - THD *log_thd, *curr= current_thd; - TABLE_LIST *table; - - if (!logger.is_log_table_enabled(log_table_type)) - return; /* do nothing */ - - switch (log_table_type) { - case QUERY_LOG_GENERAL: - log_thd= general_log_thd; - table= &general_log; - break; - case QUERY_LOG_SLOW: - log_thd= slow_log_thd; - table= &slow_log; - break; - default: - assert(0); // Impossible - } - - /* - Set thread stack start for the logger thread. See comment in - open_log_table() for details. - */ - if (curr) - log_thd->thread_stack= curr->thread_stack; - else - log_thd->thread_stack= (char*) &log_thd; - - /* close the table */ - log_thd->store_globals(); - table->table->file->ha_rnd_end(); - table->table->file->ha_release_auto_increment(); - /* discard logger mark before unlock*/ - table->table->locked_by_logger= FALSE; - close_thread_tables(log_thd, lock_in_use); - - if (curr) - curr->store_globals(); - else - { - my_pthread_setspecific_ptr(THR_THD, 0); - my_pthread_setspecific_ptr(THR_MALLOC, 0); - } -} - - /* Save position of binary log transaction cache. diff --git a/sql/log.h b/sql/log.h index d92e0117bcc..faf6ead450c 100644 --- a/sql/log.h +++ b/sql/log.h @@ -212,6 +212,10 @@ public: return open(generate_name(log_name, ".log", 0, buf), LOG_NORMAL, 0, WRITE_CACHE); } + + /* TODO: fix MYSQL_LOG::write to be thread safe instead. */ + inline pthread_mutex_t* get_log_lock() { return &LOCK_log; } + private: time_t last_time; }; @@ -398,7 +402,7 @@ public: const char *sql_text, uint sql_text_len)= 0; virtual bool log_error(enum loglevel level, const char *format, va_list args)= 0; - virtual bool log_general(time_t event_time, const char *user_host, + virtual bool log_general(THD *thd, time_t event_time, const char *user_host, uint user_host_len, int thread_id, const char *command_type, uint command_type_len, const char *sql_text, uint sql_text_len, @@ -412,27 +416,7 @@ int check_if_log_table(uint db_len, const char *db, uint table_name_len, class Log_to_csv_event_handler: public Log_event_handler { - /* - We create artificial THD for each of the logs. This is to avoid - locking issues: we don't want locks on the log tables reside in the - THD's of the query. The reason is the locking order and duration. - */ - THD *general_log_thd, *slow_log_thd; - /* - This is for the thread, which called tmp_close_log_tables. The thread - will be allowed to write-lock the log tables (as it explicitly disabled - logging). This is used for such operations as REPAIR, which require - exclusive lock on the log tables. - NOTE: there can be only one priviliged thread, as one should - lock logger with logger.lock() before calling tmp_close_log_tables(). - So no other thread could get privileged status at the same time. - */ - THD *privileged_thread; friend class LOGGER; - TABLE_LIST general_log, slow_log; - -private: - bool open_log_table(uint log_type); public: Log_to_csv_event_handler(); @@ -447,18 +431,13 @@ public: const char *sql_text, uint sql_text_len); virtual bool log_error(enum loglevel level, const char *format, va_list args); - virtual bool log_general(time_t event_time, const char *user_host, + virtual bool log_general(THD *thd, time_t event_time, const char *user_host, uint user_host_len, int thread_id, const char *command_type, uint command_type_len, const char *sql_text, uint sql_text_len, - CHARSET_INFO *client_cs); - void tmp_close_log_tables(THD *thd); - void close_log_table(uint log_type, bool lock_in_use); - bool reopen_log_table(uint log_type); - THD* get_privileged_thread() - { - return privileged_thread; - } + CHARSET_INFO *client_cs); + + int activate_log(THD *thd, uint log_type); }; @@ -484,7 +463,7 @@ public: const char *sql_text, uint sql_text_len); virtual bool log_error(enum loglevel level, const char *format, va_list args); - virtual bool log_general(time_t event_time, const char *user_host, + virtual bool log_general(THD *thd, time_t event_time, const char *user_host, uint user_host_len, int thread_id, const char *command_type, uint command_type_len, const char *sql_text, uint sql_text_len, @@ -499,7 +478,7 @@ public: /* Class which manages slow, general and error log event handlers */ class LOGGER { - pthread_mutex_t LOCK_logger; + rw_lock_t LOCK_logger; /* flag to check whether logger mutex is initialized */ uint inited; @@ -519,21 +498,10 @@ public: LOGGER() : inited(0), table_log_handler(NULL), file_log_handler(NULL), is_log_tables_initialized(FALSE) {} - void lock() { (void) pthread_mutex_lock(&LOCK_logger); } - void unlock() { (void) pthread_mutex_unlock(&LOCK_logger); } - void tmp_close_log_tables(THD *thd); - bool is_log_table_enabled(uint log_table_type) - { - switch (log_table_type) { - case QUERY_LOG_SLOW: - return table_log_handler && table_log_handler->slow_log.table != 0; - case QUERY_LOG_GENERAL: - return table_log_handler && table_log_handler->general_log.table != 0; - default: - DBUG_ASSERT(0); - return FALSE; /* make compiler happy */ - } - } + void lock_shared() { rw_rdlock(&LOCK_logger); } + void lock_exclusive() { rw_wrlock(&LOCK_logger); } + void unlock() { rw_unlock(&LOCK_logger); } + bool is_log_table_enabled(uint log_table_type); /* We want to initialize all log mutexes as soon as possible, but we cannot do it in constructor, as safe_mutex relies on @@ -543,20 +511,6 @@ public: void init_base(); void init_log_tables(); bool flush_logs(THD *thd); - THD *get_general_log_thd() - { - if (table_log_handler) - return (THD *) table_log_handler->general_log_thd; - else - return NULL; - } - THD *get_slow_log_thd() - { - if (table_log_handler) - return (THD *) table_log_handler->slow_log_thd; - else - return NULL; - } /* Perform basic logger cleanup. this will leave e.g. error log open. */ void cleanup_base(); /* Free memory. Nothing could be logged after this function is called */ @@ -568,10 +522,6 @@ public: bool general_log_print(THD *thd,enum enum_server_command command, const char *format, va_list args); - void close_log_table(uint log_type, bool lock_in_use); - bool reopen_log_table(uint log_type); - bool reopen_log_tables(); - /* we use this function to setup all enabled log event handlers */ int set_handlers(uint error_log_printer, uint slow_log_printer, @@ -593,19 +543,6 @@ public: return file_log_handler->get_mysql_log(); return NULL; } - THD* get_privileged_thread() - { - if (table_log_handler) - return table_log_handler->get_privileged_thread(); - else - return NULL; - } - bool is_privileged_thread(THD *thd) - { - return thd == get_general_log_thd() || - thd == get_slow_log_thd() || - thd == get_privileged_thread(); - } }; enum enum_binlog_format { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7b7bc81957e..1b36d97ad3f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -944,6 +944,7 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length); bool is_update_query(enum enum_sql_command command); +bool is_log_table_write_query(enum enum_sql_command command); bool alloc_query(THD *thd, const char *packet, uint packet_length); void mysql_init_select(LEX *lex); void mysql_reset_thd_for_next_command(THD *thd); @@ -1123,7 +1124,8 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key, uint key_length, uint db_flags, int *error); void release_table_share(TABLE_SHARE *share, enum release_type type); TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name); -TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update); +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 reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in); @@ -1231,6 +1233,11 @@ void reset_status_vars(); /* information schema */ extern LEX_STRING INFORMATION_SCHEMA_NAME; +/* log tables */ +extern LEX_STRING MYSQL_SCHEMA_NAME; +extern LEX_STRING GENERAL_LOG_NAME; +extern LEX_STRING SLOW_LOG_NAME; + extern const LEX_STRING partition_keywords[]; ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name); ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx); @@ -1557,6 +1564,10 @@ bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, void close_system_tables(THD *thd, Open_tables_state *backup); TABLE *open_system_table_for_update(THD *thd, TABLE_LIST *one_table); +TABLE *open_performance_schema_table(THD *thd, TABLE_LIST *one_table, + Open_tables_state *backup); +void close_performance_schema_table(THD *thd, Open_tables_state *backup); + bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables, bool have_lock = FALSE); bool close_cached_connection_tables(THD *thd, bool wait_for_refresh, LEX_STRING *connect_string, @@ -1891,6 +1902,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, #define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN 0x0004 #define MYSQL_OPEN_TEMPORARY_ONLY 0x0008 #define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0010 +#define MYSQL_LOCK_PERF_SCHEMA 0x0020 void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); diff --git a/sql/set_var.cc b/sql/set_var.cc index bd5234b42be..d21a4c18716 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2053,21 +2053,15 @@ end: bool sys_var_log_state::update(THD *thd, set_var *var) { - bool res= 0; + bool res; pthread_mutex_lock(&LOCK_global_system_variables); if (!var->save_result.ulong_value) - logger.deactivate_log_handler(thd, log_type); - else { - if ((res= logger.activate_log_handler(thd, log_type))) - { - my_error(ER_CANT_ACTIVATE_LOG, MYF(0), - log_type == QUERY_LOG_GENERAL ? "general" : - "slow query"); - goto err; - } + logger.deactivate_log_handler(thd, log_type); + res= false; } -err: + else + res= logger.activate_log_handler(thd, log_type); pthread_mutex_unlock(&LOCK_global_system_variables); return res; } @@ -2143,7 +2137,7 @@ bool update_sys_var_str_path(THD *thd, sys_var_str *var_str, } pthread_mutex_lock(&LOCK_global_system_variables); - logger.lock(); + logger.lock_exclusive(); if (file_log && log_state) file_log->close(0); @@ -2206,7 +2200,7 @@ static void sys_default_slow_log_path(THD *thd, enum_var_type type) bool sys_var_log_output::update(THD *thd, set_var *var) { pthread_mutex_lock(&LOCK_global_system_variables); - logger.lock(); + logger.lock_exclusive(); logger.init_slow_log(var->save_result.ulong_value); logger.init_general_log(var->save_result.ulong_value); *value= var->save_result.ulong_value; @@ -2219,10 +2213,10 @@ bool sys_var_log_output::update(THD *thd, set_var *var) void sys_var_log_output::set_default(THD *thd, enum_var_type type) { pthread_mutex_lock(&LOCK_global_system_variables); - logger.lock(); - logger.init_slow_log(LOG_TABLE); - logger.init_general_log(LOG_TABLE); - *value= LOG_TABLE; + logger.lock_exclusive(); + logger.init_slow_log(LOG_FILE); + logger.init_general_log(LOG_FILE); + *value= LOG_FILE; logger.unlock(); pthread_mutex_unlock(&LOCK_global_system_variables); } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 682eee06e02..966e841ccbf 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5936,8 +5936,8 @@ ER_WARN_DEPRECATED_SYNTAX_WITH_VER ER_CANT_WRITE_LOCK_LOG_TABLE eng "You can't write-lock a log table. Only read access is possible" ger "Eine Log-Tabelle kann nicht schreibgesperrt werden. Es ist ohnehin nur Lesezugriff möglich" -ER_CANT_READ_LOCK_LOG_TABLE - eng "You can't use usual read lock with log tables. Try READ LOCAL instead" +ER_CANT_LOCK_LOG_TABLE + eng "You can't use locks with log tables." ger "Log-Tabellen können nicht mit normalen Lesesperren gesperrt werden. Verwenden Sie statt dessen READ LOCAL" ER_FOREIGN_DUPLICATE_KEY 23000 S1009 eng "Upholding foreign key constraints for table '%.192s', entry '%-.192s', key %d would lead to a duplicate entry" diff --git a/sql/slave.cc b/sql/slave.cc index 2e8e3f582de..96a105b06e4 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -977,7 +977,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, thd->proc_info = "Opening master dump table"; tables.lock_type = TL_WRITE; - if (!open_ltable(thd, &tables, TL_WRITE)) + if (!open_ltable(thd, &tables, TL_WRITE, 0)) { sql_print_error("create_table_from_dump: could not open created table"); goto err; diff --git a/sql/sp.cc b/sql/sp.cc index aed4976f839..2111ae8b154 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1067,7 +1067,7 @@ sp_show_status_routine(THD *thd, int type, const char *name_pattern) tables.db= (char*)"mysql"; tables.table_name= tables.alias= (char*)"proc"; - if (! (table= open_ltable(thd, &tables, TL_READ))) + if (! (table= open_ltable(thd, &tables, TL_READ, 0))) { res= SP_OPEN_TABLE_FAILED; goto done; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 67fa380d313..91f1570f653 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1602,7 +1602,7 @@ bool change_password(THD *thd, const char *host, const char *user, } #endif - if (!(table= open_ltable(thd, &tables, TL_WRITE))) + if (!(table= open_ltable(thd, &tables, TL_WRITE, 0))) DBUG_RETURN(1); VOID(pthread_mutex_lock(&acl_cache->lock)); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0cd46a7c6fb..5b63eac35dd 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -902,8 +902,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, bool found=0; for (TABLE_LIST *table= tables; table; table= table->next_local) { - if ((!table->table || !table->table->s->log_table) && - remove_table_from_cache(thd, table->db, table->table_name, + if (remove_table_from_cache(thd, table->db, table->table_name, RTFC_OWNED_BY_THD_FLAG)) found=1; } @@ -951,8 +950,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, are employed by CREATE TABLE as in this case table simply does not exist yet. */ - if (!table->s->log_table && - (table->needs_reopen_or_name_lock() && table->db_stat)) + if (table->needs_reopen_or_name_lock() && table->db_stat) { found=1; DBUG_PRINT("signal", ("Waiting for COND_refresh")); @@ -2468,8 +2466,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, &state)) { /* - Here we flush tables marked for flush. However we never flush log - tables here. They are flushed only on FLUSH LOGS. + Here we flush tables marked for flush. Normally, table->s->version contains the value of refresh_version from the moment when this table was (re-)opened and added to the cache. @@ -2486,7 +2483,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, c1: name lock t2; -- blocks c2: open t1; -- blocks */ - if (table->needs_reopen_or_name_lock() && !table->s->log_table) + if (table->needs_reopen_or_name_lock()) { DBUG_PRINT("note", ("Found table '%s.%s' with different refresh version", @@ -2962,10 +2959,9 @@ void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, for (; table ; table=table->next) { /* - Reopen marked for flush. But close log tables. They are flushed only - explicitly on FLUSH LOGS + Reopen marked for flush. */ - if (table->needs_reopen_or_name_lock() && !table->s->log_table) + if (table->needs_reopen_or_name_lock()) { found=1; if (table->db_stat) @@ -3012,10 +3008,6 @@ void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, Wait until all threads has closed the tables in the list We have also to wait if there is thread that has a lock on this table even if the table is closed - NOTE: log tables are handled differently by the logging routines. - E.g. general_log is always opened and locked by the logger - and the table handler used by the logger, will be skipped by - this check. */ bool table_is_used(TABLE *table, bool wait_for_name_lock) @@ -3034,10 +3026,10 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock) search= (TABLE*) hash_next(&open_cache, (uchar*) key, key_length, &state)) { - DBUG_PRINT("info", ("share: 0x%lx locked_by_logger: %d " + DBUG_PRINT("info", ("share: 0x%lx " "open_placeholder: %d locked_by_name: %d " "db_stat: %u version: %lu", - (ulong) search->s, search->locked_by_logger, + (ulong) search->s, search->open_placeholder, search->locked_by_name, search->db_stat, search->s->version)); @@ -3049,12 +3041,9 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock) - If we are in flush table and we didn't execute the flush - If the table engine is open and it's an old version (We must wait until all engines are shut down to use the table) - However we fo not wait if we encountered a table, locked by the logger. - Log tables are managed separately by logging routines. */ - if (!search->locked_by_logger && - (search->locked_by_name && wait_for_name_lock || - (search->is_name_opened() && search->needs_reopen_or_name_lock()))) + if ( (search->locked_by_name && wait_for_name_lock) || + (search->is_name_opened() && search->needs_reopen_or_name_lock())) DBUG_RETURN(1); } } while ((table=table->next)); @@ -3766,6 +3755,7 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table, thd Thread handler table_list Table to open is first table in this list lock_type Lock to use for open + lock_flags Flags passed to mysql_lock_table NOTE This function don't do anything like SP/SF/views/triggers analysis done @@ -3781,7 +3771,8 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table, table_list->table table */ -TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) +TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type, + uint lock_flags) { TABLE *table; bool refresh; @@ -3816,8 +3807,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) { DBUG_ASSERT(thd->lock == 0); // You must lock everything at once if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK) - if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1, 0, - &refresh))) + if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1, + lock_flags, &refresh))) table= 0; } } @@ -4156,11 +4147,6 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) DBUG_ASSERT(thd->lock == 0); // You must lock everything at once TABLE **start,**ptr; uint lock_flag= MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN; - - /* Ignore GLOBAL READ LOCK and GLOBAL READ_ONLY if called from a logger */ - if (logger.is_privileged_thread(thd)) - lock_flag|= (MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK | - MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY); if (!(ptr=start=(TABLE**) thd->alloc(sizeof(TABLE*)*count))) DBUG_RETURN(-1); @@ -7189,7 +7175,6 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, else if (in_use != thd) { DBUG_PRINT("info", ("Table was in use by other thread")); - in_use->some_tables_deleted=1; if (table->is_name_opened()) { DBUG_PRINT("info", ("Found another active instance of the table")); @@ -7625,7 +7610,7 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, if (!table) goto error; - DBUG_ASSERT(table->s->system_table); + DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM); table->use_all_columns(); table->reginfo.lock_type= tables->lock_type; @@ -7692,12 +7677,91 @@ open_system_table_for_update(THD *thd, TABLE_LIST *one_table) { DBUG_ENTER("open_system_table_for_update"); - TABLE *table= open_ltable(thd, one_table, one_table->lock_type); + TABLE *table= open_ltable(thd, one_table, one_table->lock_type, 0); if (table) { - DBUG_ASSERT(table->s->system_table); + DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM); table->use_all_columns(); } DBUG_RETURN(table); } + +/** + Open a performance schema table. + Opening such tables is performed internally in the server + implementation, and is a 'nested' open, since some tables + might be already opened by the current thread. + The thread context before this call is saved, and is restored + when calling close_performance_schema_table(). + @param thd The current thread + @param one_table Performance schema table to open + @param backup [out] Temporary storage used to save the thread context +*/ +TABLE * +open_performance_schema_table(THD *thd, TABLE_LIST *one_table, + Open_tables_state *backup) +{ + uint flags= ( MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK + | MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY + | MYSQL_LOCK_PERF_SCHEMA ); + + DBUG_ENTER("open_performance_schema_table"); + + thd->reset_n_backup_open_tables_state(backup); + + TABLE *table= open_ltable(thd, one_table, one_table->lock_type, flags); + if (table) + { + DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_PERFORMANCE); + /* Make sure all columns get assigned to a default value */ + table->use_all_columns(); + } + + DBUG_RETURN(table); +} + +/** + Close a performance schema table. + The last table opened by open_performance_schema_table() + is closed, then the thread context is restored. + @param thd The current thread + @param backup [in] the context to restore. +*/ +void close_performance_schema_table(THD *thd, Open_tables_state *backup) +{ + bool found_old_table; + + if (thd->lock) + { + /* + Note: + We do not create explicitly a separate transaction for the + performance table I/O, but borrow the current transaction. + lock + unlock will autocommit the change done in the + performance schema table: this is the expected result. + The current transaction should not be affected by this code. + TODO: Note that if a transactional engine is used for log tables, + this code will need to be revised, as a separate transaction + might be needed. + */ + mysql_unlock_tables(thd, thd->lock); + thd->lock= 0; + } + + safe_mutex_assert_not_owner(&LOCK_open); + + pthread_mutex_lock(&LOCK_open); + + found_old_table= false; + while (thd->open_tables) + found_old_table|= close_thread_table(thd, &thd->open_tables); + + if (found_old_table) + broadcast_refresh(); + + pthread_mutex_unlock(&LOCK_open); + + thd->restore_backup_open_tables_state(backup); +} + diff --git a/sql/sql_class.h b/sql/sql_class.h index 71c13e001ee..d8005c40522 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2438,6 +2438,7 @@ public: #define CF_HAS_ROW_COUNT 2 #define CF_STATUS_COMMAND 4 #define CF_SHOW_TABLE_COMMAND 8 +#define CF_WRITE_LOGS_COMMAND 16 /* Functions in sql_class.cc */ diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7c868092921..7d8fc119cf9 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -906,9 +906,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) char path[FN_REFLEN]; TABLE *table; bool error; - uint closed_log_tables= 0, lock_logger= 0; uint path_length; - uint log_type; DBUG_ENTER("mysql_truncate"); bzero((char*) &create_info,sizeof(create_info)); @@ -960,18 +958,6 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) DBUG_RETURN(TRUE); } - log_type= check_if_log_table(table_list->db_length, table_list->db, - table_list->table_name_length, - table_list->table_name, 1); - /* close log tables in use */ - if (log_type) - { - lock_logger= 1; - logger.lock(); - logger.close_log_table(log_type, FALSE); - closed_log_tables= closed_log_tables | log_type; - } - // Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this // crashes, replacement works. *(path + path_length - reg_ext_length)= // '\0'; @@ -997,14 +983,6 @@ end: VOID(pthread_mutex_lock(&LOCK_open)); unlock_table_name(thd, table_list); VOID(pthread_mutex_unlock(&LOCK_open)); - - if (opt_slow_log && (closed_log_tables & QUERY_LOG_SLOW)) - logger.reopen_log_table(QUERY_LOG_SLOW); - - if (opt_log && (closed_log_tables & QUERY_LOG_GENERAL)) - logger.reopen_log_table(QUERY_LOG_GENERAL); - if (lock_logger) - logger.unlock(); } else if (error) { diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 5ebeba6109a..8bdb2e59ed5 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -137,6 +137,9 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, level= MYSQL_ERROR::WARN_LEVEL_ERROR; } + if (thd->handle_error(code, level)) + DBUG_RETURN(NULL); + if (thd->spcont && thd->spcont->handle_error(code, level, thd)) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b747c706f75..dc5db54e128 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2254,7 +2254,7 @@ pthread_handler_t handle_delayed_insert(void *arg) } /* open table */ - if (!(di->table=open_ltable(thd,&di->table_list,TL_WRITE_DELAYED))) + if (!(di->table=open_ltable(thd, &di->table_list, TL_WRITE_DELAYED, 0))) { thd->fatal_error(); // Abort waiting inserts goto err; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f2a61b7f7c5..c2820581d71 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -197,8 +197,8 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA; + sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND; + sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND; sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA; @@ -210,8 +210,8 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA; + sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND; + sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; @@ -250,6 +250,14 @@ void init_update_queries(void) */ sql_command_flags[SQLCOM_CALL]= CF_HAS_ROW_COUNT; sql_command_flags[SQLCOM_EXECUTE]= CF_HAS_ROW_COUNT; + + /* + The following admin table operations are allowed + on log tables. + */ + sql_command_flags[SQLCOM_REPAIR]= CF_WRITE_LOGS_COMMAND; + sql_command_flags[SQLCOM_OPTIMIZE]= CF_WRITE_LOGS_COMMAND; + sql_command_flags[SQLCOM_ANALYZE]= CF_WRITE_LOGS_COMMAND; } @@ -259,6 +267,17 @@ bool is_update_query(enum enum_sql_command command) return (sql_command_flags[command] & CF_CHANGES_DATA) != 0; } +/** + Check if a sql command is allowed to write to log tables. + @param command The SQL command + @return true if writing is allowed +*/ +bool is_log_table_write_query(enum enum_sql_command command) +{ + DBUG_ASSERT(command >= 0 && command <= SQLCOM_END); + return (sql_command_flags[command] & CF_WRITE_LOGS_COMMAND) != 0; +} + void execute_init_command(THD *thd, sys_var_str *init_command_var, rw_lock_t *var_mutex) { @@ -493,7 +512,7 @@ int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name) if (lower_case_table_names) my_casedn_str(files_charset_info, tbl_name); - if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT))) + if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT, 0))) DBUG_RETURN(1); if (check_one_table_access(thd, SELECT_ACL, table_list)) diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index a44e20b8daf..0d088063462 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1617,7 +1617,7 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl DBUG_RETURN(TRUE); /* need to open before acquiring LOCK_plugin or it will deadlock */ - if (! (table = open_ltable(thd, &tables, TL_WRITE))) + if (! (table = open_ltable(thd, &tables, TL_WRITE, 0))) DBUG_RETURN(TRUE); pthread_mutex_lock(&LOCK_plugin); @@ -1674,7 +1674,7 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) tables.table_name= tables.alias= (char *)"plugin"; /* need to open before acquiring LOCK_plugin or it will deadlock */ - if (! (table= open_ltable(thd, &tables, TL_WRITE))) + if (! (table= open_ltable(thd, &tables, TL_WRITE, 0))) DBUG_RETURN(TRUE); pthread_mutex_lock(&LOCK_plugin); diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index f5e1b8988f3..750bcd50479 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -37,7 +37,6 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) TABLE_LIST *ren_table= 0; int to_table; char *rename_log_table[2]= {NULL, NULL}; - int disable_logs= 0; DBUG_ENTER("mysql_rename_tables"); /* @@ -79,12 +78,6 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) ren_table->table_name_length, ren_table->table_name, 1))) { - /* - Log table encoutered we will need to disable and lock logs - for duration of rename. - */ - disable_logs= TRUE; - /* as we use log_table_rename as an array index, we need it to start with 0, while QUERY_LOG_SLOW == 1 and QUERY_LOG_GENERAL == 2. @@ -136,12 +129,6 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) rename_log_table[1]); DBUG_RETURN(1); } - - if (disable_logs) - { - logger.lock(); - logger.tmp_close_log_tables(thd); - } } pthread_mutex_lock(&LOCK_open); @@ -200,13 +187,6 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) pthread_mutex_unlock(&LOCK_open); err: - /* enable logging back if needed */ - if (disable_logs) - { - if (logger.reopen_log_tables()) - error= TRUE; - logger.unlock(); - } start_waiting_global_read_lock(thd); DBUG_RETURN(error); } diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index ac5ea6f4ac4..911372d5f4e 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -366,7 +366,7 @@ insert_server(THD *thd, FOREIGN_SERVER *server) tables.alias= tables.table_name= (char*) "servers"; /* need to open before acquiring THR_LOCK_plugin or it will deadlock */ - if (! (table= open_ltable(thd, &tables, TL_WRITE))) + if (! (table= open_ltable(thd, &tables, TL_WRITE, 0))) goto end; /* insert the server into the table */ @@ -588,7 +588,7 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) if ((error= delete_server_record_in_cache(server_options))) goto end; - if (! (table= open_ltable(thd, &tables, TL_WRITE))) + if (! (table= open_ltable(thd, &tables, TL_WRITE, 0))) { error= my_errno; goto end; @@ -705,7 +705,7 @@ int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered) tables.db= (char*)"mysql"; tables.alias= tables.table_name= (char*)"servers"; - if (!(table= open_ltable(thd, &tables, TL_WRITE))) + if (!(table= open_ltable(thd, &tables, TL_WRITE, 0))) { error= my_errno; goto end; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5b8cb93baab..fdd75fbe844 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2176,9 +2176,6 @@ void calc_sum_of_all_status(STATUS_VAR *to) } -/* INFORMATION_SCHEMA name */ -LEX_STRING INFORMATION_SCHEMA_NAME= { C_STRING_WITH_LEN("information_schema")}; - /* This is only used internally, but we need it here as a forward reference */ extern ST_SCHEMA_TABLE schema_tables[]; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index dc3e72554fa..502600a673f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1513,7 +1513,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, table->db_type= share->db_type(); /* Disable drop of enabled log tables */ - if (share && share->log_table && + if (share && (share->table_category == TABLE_CATEGORY_PERFORMANCE) && check_if_log_table(table->db_length, table->db, table->table_name_length, table->table_name, 1)) { @@ -3966,7 +3966,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, Item *item; Protocol *protocol= thd->protocol; LEX *lex= thd->lex; - int result_code, disable_logs= 0; + int result_code; DBUG_ENTER("mysql_admin_table"); if (end_active_trans(thd)) @@ -4014,22 +4014,6 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (view_operator_func == NULL) table->required_type=FRMTYPE_TABLE; - /* - If we want to perform an admin operation on the log table - (E.g. rename) and lock_type >= TL_READ_NO_INSERT disable - log tables - */ - - if (check_if_log_table(table->db_length, table->db, - table->table_name_length, - table->table_name, 1) && - lock_type >= TL_READ_NO_INSERT) - { - disable_logs= 1; - logger.lock(); - logger.tmp_close_log_tables(thd); - } - open_and_lock_tables(thd, table); thd->no_warnings_for_error= 0; table->next_global= save_next_global; @@ -4099,8 +4083,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, } /* Close all instances of the table to allow repair to rename files */ - if (lock_type == TL_WRITE && table->table->s->version && - !table->table->s->log_table) + if (lock_type == TL_WRITE && table->table->s->version) { pthread_mutex_lock(&LOCK_open); const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open, @@ -4258,7 +4241,7 @@ send_result_message: close_thread_tables(thd); if (!result_code) // recreation went ok { - if ((table->table= open_ltable(thd, table, lock_type)) && + if ((table->table= open_ltable(thd, table, lock_type, 0)) && ((result_code= table->table->file->analyze(thd, check_opt)) > 0)) result_code= 0; // analyze went ok } @@ -4324,10 +4307,9 @@ send_result_message: } if (table->table) { - /* in the below check we do not refresh the log tables */ if (fatal_error) table->table->s->version=0; // Force close of table - else if (open_for_modify && !table->table->s->log_table) + else if (open_for_modify) { if (table->table->s->tmp_table) table->table->file->info(HA_STATUS_CONST); @@ -4350,24 +4332,11 @@ send_result_message: } send_eof(thd); - if (disable_logs) - { - if (logger.reopen_log_tables()) - my_error(ER_CANT_ACTIVATE_LOG, MYF(0)); - logger.unlock(); - } DBUG_RETURN(FALSE); err: ha_autocommit_or_rollback(thd, 1); close_thread_tables(thd); // Shouldn't be needed - /* enable logging back if needed */ - if (disable_logs) - { - if (logger.reopen_log_tables()) - my_error(ER_CANT_ACTIVATE_LOG, MYF(0)); - logger.unlock(); - } if (table) table->table=0; DBUG_RETURN(TRUE); @@ -4812,7 +4781,7 @@ mysql_discard_or_import_tablespace(THD *thd, not complain when we lock the table */ thd->tablespace_op= TRUE; - if (!(table=open_ltable(thd,table_list,TL_WRITE))) + if (!(table=open_ltable(thd, table_list, TL_WRITE, 0))) { thd->tablespace_op=FALSE; DBUG_RETURN(-1); @@ -5728,7 +5697,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, #ifdef WITH_PARTITION_STORAGE_ENGINE if (alter_info->flags & ALTER_PARTITION) { - my_error(ER_WRONG_USAGE, MYF(0), "PARTITION", "log table"); + my_error(ER_WRONG_USAGE, MYF(0), "PARTITION", "log table"); DBUG_RETURN(TRUE); } #endif @@ -5817,7 +5786,7 @@ view_err: start_waiting_global_read_lock(thd); DBUG_RETURN(error); } - if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ))) + if (!(table=open_ltable(thd, table_list, TL_WRITE_ALLOW_READ, 0))) DBUG_RETURN(TRUE); table->use_all_columns(); @@ -6986,7 +6955,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, strxmov(table_name, table->db ,".", table->table_name, NullS); - t= table->table= open_ltable(thd, table, TL_READ); + t= table->table= open_ltable(thd, table, TL_READ, 0); thd->clear_error(); // these errors shouldn't get client protocol->prepare_for_resend(); diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 8361fc64f33..10bb7844d88 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -472,7 +472,7 @@ int mysql_create_function(THD *thd,udf_func *udf) tables.db= (char*) "mysql"; tables.table_name= tables.alias= (char*) "func"; /* Allow creation of functions even if we can't open func table */ - if (!(table = open_ltable(thd,&tables,TL_WRITE))) + if (!(table = open_ltable(thd, &tables, TL_WRITE, 0))) goto err; table->use_all_columns(); restore_record(table, s->default_values); // Default values for fields @@ -547,7 +547,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) bzero((char*) &tables,sizeof(tables)); tables.db=(char*) "mysql"; tables.table_name= tables.alias= (char*) "func"; - if (!(table = open_ltable(thd,&tables,TL_WRITE))) + if (!(table = open_ltable(thd, &tables, TL_WRITE, 0))) goto err; table->use_all_columns(); table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin); diff --git a/sql/table.cc b/sql/table.cc index 5ac43343934..fef63170ea6 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -21,6 +21,18 @@ #include #include "md5.h" +/* INFORMATION_SCHEMA name */ +LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")}; + +/* MYSQL_SCHEMA name */ +LEX_STRING MYSQL_SCHEMA_NAME= {C_STRING_WITH_LEN("mysql")}; + +/* GENERAL_LOG name */ +LEX_STRING GENERAL_LOG_NAME= {C_STRING_WITH_LEN("general_log")}; + +/* SLOW_LOG name */ +LEX_STRING SLOW_LOG_NAME= {C_STRING_WITH_LEN("slow_log")}; + /* Functions defined in this file */ void open_table_error(TABLE_SHARE *share, int error, int db_errno, @@ -31,6 +43,7 @@ static void fix_type_pointers(const char ***array, TYPELIB *point_to_type, uint types, char **names); static uint find_field(Field **fields, uchar *record, uint start, uint length); +inline bool is_system_table_name(const char *name, uint length); /************************************************************************** Object_creation_ctx implementation. @@ -192,6 +205,49 @@ char *fn_rext(char *name) return name + strlen(name); } +TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name) +{ + DBUG_ASSERT(db != NULL); + DBUG_ASSERT(name != NULL); + + if ((db->length == INFORMATION_SCHEMA_NAME.length) && + (my_strcasecmp(system_charset_info, + INFORMATION_SCHEMA_NAME.str, + db->str) == 0)) + { + return TABLE_CATEGORY_INFORMATION; + } + + if ((db->length == MYSQL_SCHEMA_NAME.length) && + (my_strcasecmp(system_charset_info, + MYSQL_SCHEMA_NAME.str, + db->str) == 0)) + { + if (is_system_table_name(name->str, name->length)) + { + return TABLE_CATEGORY_SYSTEM; + } + + if ((name->length == GENERAL_LOG_NAME.length) && + (my_strcasecmp(system_charset_info, + GENERAL_LOG_NAME.str, + name->str) == 0)) + { + return TABLE_CATEGORY_PERFORMANCE; + } + + if ((name->length == SLOW_LOG_NAME.length) && + (my_strcasecmp(system_charset_info, + SLOW_LOG_NAME.str, + name->str) == 0)) + { + return TABLE_CATEGORY_PERFORMANCE; + } + } + + return TABLE_CATEGORY_USER; +} + /* Allocate a setup TABLE_SHARE structure @@ -297,7 +353,8 @@ void init_tmp_table_share(TABLE_SHARE *share, const char *key, bzero((char*) share, sizeof(*share)); init_sql_alloc(&share->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); - share->tmp_table= INTERNAL_TMP_TABLE; + share->table_category= TABLE_CATEGORY_TEMPORARY; + share->tmp_table= INTERNAL_TMP_TABLE; share->db.str= (char*) key; share->db.length= strlen(key); share->table_cache_key.str= (char*) key; @@ -544,28 +601,11 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags) *root_ptr= &share->mem_root; error= open_binary_frm(thd, share, head, file); *root_ptr= old_root; - - if (share->db.length == 5 && !(lower_case_table_names ? - my_strcasecmp(system_charset_info, share->db.str, "mysql") : - strcmp(share->db.str, "mysql"))) - { - /* - We can't mark all tables in 'mysql' database as system since we don't - allow to lock such tables for writing with any other tables (even with - other system tables) and some privilege tables need this. - */ - share->system_table= is_system_table_name(share->table_name.str, - share->table_name.length); - if (!share->system_table) - { - share->log_table= check_if_log_table(share->db.length, share->db.str, - share->table_name.length, - share->table_name.str, 0); - } - } error_given= 1; } + share->table_category= get_table_category(& share->db, & share->table_name); + if (!error) thd->status_var.opened_shares++; diff --git a/sql/table.h b/sql/table.h index 494b74d564c..77d8e819d3e 100644 --- a/sql/table.h +++ b/sql/table.h @@ -140,6 +140,100 @@ class Field_timestamp; class Field_blob; class Table_triggers_list; +/** + Category of table found in the table share. +*/ +enum enum_table_category +{ + /** + Unknown value. + */ + TABLE_UNKNOWN_CATEGORY=0, + + /** + Temporary table. + The table is visible only in the session. + Therefore, + - FLUSH TABLES WITH READ LOCK + - SET GLOBAL READ_ONLY = ON + do not apply to this table. + Note that LOCK TABLE FOR READ/WRITE + can be used on temporary tables. + Temporary tables are not part of the table cache. + */ + TABLE_CATEGORY_TEMPORARY=1, + + /** + User table. + These tables do honor: + - LOCK TABLE FOR READ/WRITE + - FLUSH TABLES WITH READ LOCK + - SET GLOBAL READ_ONLY = ON + User tables are cached in the table cache. + */ + TABLE_CATEGORY_USER=2, + + /** + System table, maintained by the server. + These tables do honor: + - LOCK TABLE FOR READ/WRITE + - FLUSH TABLES WITH READ LOCK + - SET GLOBAL READ_ONLY = ON + Typically, writes to system tables are performed by + the server implementation, not explicitly be a user. + System tables are cached in the table cache. + */ + TABLE_CATEGORY_SYSTEM=3, + + /** + Information schema tables. + These tables are an interface provided by the system + to inspect the system metadata. + These tables do *not* honor: + - LOCK TABLE FOR READ/WRITE + - FLUSH TABLES WITH READ LOCK + - SET GLOBAL READ_ONLY = ON + as there is no point in locking explicitely + an INFORMATION_SCHEMA table. + Nothing is directly written to information schema tables. + Note that this value is not used currently, + since information schema tables are not shared, + but implemented as session specific temporary tables. + */ + /* + TODO: Fixing the performance issues of I_S will lead + to I_S tables in the table cache, which should use + this table type. + */ + TABLE_CATEGORY_INFORMATION=4, + + /** + Performance schema tables. + These tables are an interface provided by the system + to inspect the system performance data. + These tables do *not* honor: + - LOCK TABLE FOR READ/WRITE + - FLUSH TABLES WITH READ LOCK + - SET GLOBAL READ_ONLY = ON + as there is no point in locking explicitely + a PERFORMANCE_SCHEMA table. + An example of PERFORMANCE_SCHEMA tables are: + - mysql.slow_log + - mysql.general_log, + which *are* updated even when there is either + a GLOBAL READ LOCK or a GLOBAL READ_ONLY in effect. + User queries do not write directly to these tables + (there are exceptions for log tables). + The server implementation perform writes. + Performance tables are cached in the table cache. + */ + TABLE_CATEGORY_PERFORMANCE=5 +}; +typedef enum enum_table_category TABLE_CATEGORY; + +TABLE_CATEGORY get_table_category(const LEX_STRING *db, + const LEX_STRING *name); + /* This structure is shared between different table objects. There is one instance of table share per one table in the database. @@ -148,6 +242,10 @@ class Table_triggers_list; typedef struct st_table_share { st_table_share() {} /* Remove gcc warning */ + + /** Category of this table. */ + TABLE_CATEGORY table_category; + /* hash of field names (contains pointers to elements of field array) */ HASH name_hash; /* hash of field names */ MEM_ROOT mem_root; @@ -259,18 +357,6 @@ typedef struct st_table_share */ int cached_row_logging_check; - /* - TRUE if this is a system table like 'mysql.proc', which we want to be - able to open and lock even when we already have some tables open and - locked. To avoid deadlocks we have to put certain restrictions on - locking of this table for writing. FALSE - otherwise. - */ - bool system_table; - /* - This flag is set for the log tables. Used during FLUSH instances to skip - log tables, while closing tables (since logs must be always available) - */ - bool log_table; #ifdef WITH_PARTITION_STORAGE_ENGINE bool auto_partitioned; const char *partition_info; @@ -334,6 +420,16 @@ typedef struct st_table_share set_table_cache_key(key_buff, key_length); } + inline bool honor_global_locks() + { + return ((table_category == TABLE_CATEGORY_USER) + || (table_category == TABLE_CATEGORY_SYSTEM)); + } + + inline bool require_write_privileges() + { + return (table_category == TABLE_CATEGORY_PERFORMANCE); + } } TABLE_SHARE; diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index 34c1fcde58d..00ca2a6c07f 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -786,18 +786,6 @@ void ha_tina::update_status() } -bool ha_tina::check_if_locking_is_allowed(uint sql_command, - ulong type, TABLE *table, - uint count, uint current, - uint *system_count, - bool called_by_privileged_thread) -{ - if (!called_by_privileged_thread) - return check_if_log_table_locking_is_allowed(sql_command, type, table); - - return TRUE; -} - /* Open a database file. Keep in mind that tables are caches, so this will not be called for every request. Any sort of positions diff --git a/storage/csv/ha_tina.h b/storage/csv/ha_tina.h index 5bb3e9a79a0..5ce09783b9b 100644 --- a/storage/csv/ha_tina.h +++ b/storage/csv/ha_tina.h @@ -131,11 +131,6 @@ public: */ ha_rows estimate_rows_upper_bound() { return HA_POS_ERROR; } - virtual bool check_if_locking_is_allowed(uint sql_command, - ulong type, TABLE *table, - uint count, uint current, - uint *system_count, - bool called_by_logger_thread); int open(const char *name, int mode, uint open_options); int close(void); int write_row(uchar * buf); diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index c86459ae0a7..77334b2cfba 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -607,41 +607,7 @@ err: #endif /* HAVE_REPLICATION */ -bool ha_myisam::check_if_locking_is_allowed(uint sql_command, - ulong type, TABLE *table, - uint count, uint current, - uint *system_count, - bool called_by_privileged_thread) -{ - /* - To be able to open and lock for reading system tables like 'mysql.proc', - when we already have some tables opened and locked, and avoid deadlocks - we have to disallow write-locking of these tables with any other tables. - */ - if (table->s->system_table && - table->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE) - (*system_count)++; - - /* 'current' is an index, that's why '<=' below. */ - if (*system_count > 0 && *system_count <= current) - { - my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0)); - return FALSE; - } - - /* - Deny locking of the log tables, which is incompatible with - concurrent insert. Unless called from a logger THD (general_log_thd - or slow_log_thd) or by a privileged thread. - */ - if (!called_by_privileged_thread) - return check_if_log_table_locking_is_allowed(sql_command, type, table); - - return TRUE; -} - - /* Name is here without an extension */ - +/* Name is here without an extension */ int ha_myisam::open(const char *name, int mode, uint test_if_locked) { MI_KEYDEF *keyinfo; diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h index 024675075c2..635f314b3da 100644 --- a/storage/myisam/ha_myisam.h +++ b/storage/myisam/ha_myisam.h @@ -60,11 +60,6 @@ class ha_myisam: public handler uint max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; } uint checksum() const; - virtual bool check_if_locking_is_allowed(uint sql_command, - ulong type, TABLE *table, - uint count, uint current, - uint *system_count, - bool called_by_logger_thread); int open(const char *name, int mode, uint test_if_locked); int close(void); int write_row(uchar * buf); From 0936976e8d21a4980145d31657b862652af29f22 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Jul 2007 16:37:29 +0400 Subject: [PATCH 10/26] A fix and a test case for Bug#24918 drop table and lock / inconsistent between perm and temp tables. Review fixes. The original bug report complains that if we locked a temporary table with LOCK TABLES statement, we would not leave LOCK TABLES mode when this temporary table is dropped. Additionally, the bug was escalated when it was discovered than when a temporary transactional table that was previously locked with LOCK TABLES statement was dropped, futher actions with this table, such as UNLOCK TABLES, would lead to a crash. The problem originates from incomplete support of transactional temporary tables. When we added calls to handler::store_lock()/handler::external_lock() to operations that work with such tables, we only covered the normal server code flow and did not cover LOCK TABLES mode. In LOCK TABLES mode, ::external_lock(LOCK) would sometimes be called without matching ::external_lock(UNLOCK), e.g. when a transactional temporary table was dropped. Additionally, this table would be left in the list of LOCKed TABLES. The patch aims to address this inadequacy. Now, whenever an instance of 'handler' is destroyed, we assert that it was priorly external_lock(UNLOCK)-ed. All the places that violate this assert were fixed. This patch introduces no changes in behavior -- the discrepancy in behavior will be fixed when we start calling ::store_lock()/::external_lock() for all tables, regardless whether they are transactional or not, temporary or not. mysql-test/r/innodb_mysql.result: Update test results (Bug#24918) mysql-test/t/innodb_mysql.test: Add a test case for Bug#24918 sql/handler.h: Make handler::external_lock() a protected method. Backport from 5.1 its public wrapper handler::ha_external_lock(). Assert that the handler is not closed if it is still locked. sql/lock.cc: In mysql_lock_tables only call lock_external() for the list of tables that we called store_lock() for. E.g. get_lock_data() does not add non-transactional temporary tables to the lock list, so lock_external() should not be called for them. Use handler::ha_external_lock() instead of handler::external_lock(). Add comments for mysql_lock_remove(), parameterize one strange side effect that it has. At least in one place where mysql_lock_remove is used, this side effect is not desired (DROP TABLE). The parameter will be dropped in 5.1, along with the side effect. sql/mysql_priv.h: Update declaration of mysql_lock_remove(). sql/opt_range.cc: Deploy handler::ha_external_lock() instead of handler::external_lock() sql/sql_base.cc: When closing a temporary table, remove the table from the list of LOCKed TABLES of this thread, in case it's there. It's there if it is a transactional temporary table. Use a new declaration of mysql_lock_remove(). sql/sql_class.h: Extend the comment for THD::temporary_tables. sql/sql_table.cc: Deploy handler::ha_external_lock() instead of handler::external_lock() --- mysql-test/r/innodb_mysql.result | 28 ++++++++++++++++++++++ mysql-test/t/innodb_mysql.test | 34 +++++++++++++++++++++++++++ sql/handler.h | 40 +++++++++++++++++++++++++++++--- sql/lock.cc | 35 +++++++++++++++++++++++----- sql/mysql_priv.h | 3 ++- sql/opt_range.cc | 6 ++--- sql/sql_base.cc | 40 ++++++++++++++++++++++++++++---- sql/sql_class.h | 24 ++++++++++++++----- sql/sql_table.cc | 10 ++++---- 9 files changed, 192 insertions(+), 28 deletions(-) diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index f32878309b8..6fb98f509ef 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -739,4 +739,32 @@ drop table if exists t1; create table t1 (a int) engine=innodb; alter table t1 alter a set default 1; drop table t1; + +Bug#24918 drop table and lock / inconsistent between +perm and temp tables + +Check transactional tables under LOCK TABLES + +drop table if exists t24918, t24918_tmp, t24918_trans, t24918_trans_tmp, +t24918_access; +create table t24918_access (id int); +create table t24918 (id int) engine=myisam; +create temporary table t24918_tmp (id int) engine=myisam; +create table t24918_trans (id int) engine=innodb; +create temporary table t24918_trans_tmp (id int) engine=innodb; +lock table t24918 write, t24918_tmp write, t24918_trans write, t24918_trans_tmp write; +drop table t24918; +select * from t24918_access; +ERROR HY000: Table 't24918_access' was not locked with LOCK TABLES +drop table t24918_trans; +select * from t24918_access; +ERROR HY000: Table 't24918_access' was not locked with LOCK TABLES +drop table t24918_trans_tmp; +select * from t24918_access; +ERROR HY000: Table 't24918_access' was not locked with LOCK TABLES +drop table t24918_tmp; +select * from t24918_access; +ERROR HY000: Table 't24918_access' was not locked with LOCK TABLES +unlock tables; +drop table t24918_access; End of 5.0 tests diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index 0d43d13ec3a..60d46863bfd 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -754,4 +754,38 @@ create table t1 (a int) engine=innodb; alter table t1 alter a set default 1; drop table t1; + +--echo +--echo Bug#24918 drop table and lock / inconsistent between +--echo perm and temp tables +--echo +--echo Check transactional tables under LOCK TABLES +--echo +--disable_warnings +drop table if exists t24918, t24918_tmp, t24918_trans, t24918_trans_tmp, +t24918_access; +--enable_warnings +create table t24918_access (id int); +create table t24918 (id int) engine=myisam; +create temporary table t24918_tmp (id int) engine=myisam; +create table t24918_trans (id int) engine=innodb; +create temporary table t24918_trans_tmp (id int) engine=innodb; + +lock table t24918 write, t24918_tmp write, t24918_trans write, t24918_trans_tmp write; +drop table t24918; +--error ER_TABLE_NOT_LOCKED +select * from t24918_access; +drop table t24918_trans; +--error ER_TABLE_NOT_LOCKED +select * from t24918_access; +drop table t24918_trans_tmp; +--error ER_TABLE_NOT_LOCKED +select * from t24918_access; +drop table t24918_tmp; +--error ER_TABLE_NOT_LOCKED +select * from t24918_access; +unlock tables; + +drop table t24918_access; + --echo End of 5.0 tests diff --git a/sql/handler.h b/sql/handler.h index a3767573178..cd9f9a91008 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -508,6 +508,29 @@ class handler :public Sql_alloc */ virtual int rnd_init(bool scan) =0; virtual int rnd_end() { return 0; } + /** + Is not invoked for non-transactional temporary tables. + + Tells the storage engine that we intend to read or write data + from the table. This call is prefixed with a call to handler::store_lock() + and is invoked only for those handler instances that stored the lock. + + Calls to rnd_init/index_init are prefixed with this call. When table + IO is complete, we call external_lock(F_UNLCK). + A storage engine writer should expect that each call to + ::external_lock(F_[RD|WR]LOCK is followed by a call to + ::external_lock(F_UNLCK). If it is not, it is a bug in MySQL. + + The name and signature originate from the first implementation + in MyISAM, which would call fcntl to set/clear an advisory + lock on the data file in this method. + + @param lock_type F_RDLCK, F_WRLCK, F_UNLCK + + @return non-0 in case of failure, 0 in case of success. + When lock_type is F_UNLCK, the return value is ignored. + */ + virtual int external_lock(THD *thd, int lock_type) { return 0; } public: const handlerton *ht; /* storage engine of this handler */ @@ -548,6 +571,7 @@ public: uint raid_type,raid_chunks; FT_INFO *ft_handler; enum {NONE=0, INDEX, RND} inited; + bool locked; bool auto_increment_column_changed; bool implicit_emptied; /* Can be !=0 only if HEAP */ const COND *pushed_cond; @@ -560,10 +584,11 @@ public: create_time(0), check_time(0), update_time(0), key_used_on_scan(MAX_KEY), active_index(MAX_KEY), ref_length(sizeof(my_off_t)), block_size(0), - raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0), + raid_type(0), ft_handler(0), inited(NONE), + locked(FALSE), implicit_emptied(0), pushed_cond(NULL) {} - virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ } + virtual ~handler(void) { DBUG_ASSERT(locked == FALSE); /* TODO: DBUG_ASSERT(inited == NONE); */ } virtual handler *clone(MEM_ROOT *mem_root); int ha_open(const char *name, int mode, int test_if_locked); void adjust_next_insert_id_after_explicit_value(ulonglong nr); @@ -597,6 +622,13 @@ public: virtual const char *index_type(uint key_number) { DBUG_ASSERT(0); return "";} + int ha_external_lock(THD *thd, int lock_type) + { + int rc; + DBUG_ENTER("ha_external_lock"); + locked= lock_type != F_UNLCK; + DBUG_RETURN(external_lock(thd, lock_type)); + } int ha_index_init(uint idx) { DBUG_ENTER("ha_index_init"); @@ -689,7 +721,6 @@ public: virtual int extra_opt(enum ha_extra_function operation, ulong cache_size) { return extra(operation); } virtual int reset() { return extra(HA_EXTRA_RESET); } - virtual int external_lock(THD *thd, int lock_type) { return 0; } virtual void unlock_row() {} virtual int start_stmt(THD *thd, thr_lock_type lock_type) {return 0;} /* @@ -837,6 +868,9 @@ public: /* lock_count() can be more than one if the table is a MERGE */ virtual uint lock_count(void) const { return 1; } + /** + Is not invoked for non-transactional temporary tables. + */ virtual THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type)=0; diff --git a/sql/lock.cc b/sql/lock.cc index 93358e56701..f730ac56d35 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -151,7 +151,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, } thd->proc_info="System lock"; - if (lock_external(thd, tables, count)) + if (sql_lock->table_count && lock_external(thd, sql_lock->table, + sql_lock->table_count)) { /* Clear the lock type of all lock data to avoid reusage. */ reset_lock_data(sql_lock); @@ -246,12 +247,12 @@ static int lock_external(THD *thd, TABLE **tables, uint count) (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT)) lock_type=F_RDLCK; - if ((error=(*tables)->file->external_lock(thd,lock_type))) + if ((error= (*tables)->file->ha_external_lock(thd,lock_type))) { print_lock_error(error, (*tables)->file->table_type()); for (; i-- ; tables--) { - (*tables)->file->external_lock(thd, F_UNLCK); + (*tables)->file->ha_external_lock(thd, F_UNLCK); (*tables)->current_lock=F_UNLCK; } DBUG_RETURN(error); @@ -353,10 +354,28 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) } +/** + Try to find the table in the list of locked tables. + In case of success, unlock the table and remove it from this list. -void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table) + @note This function has a legacy side effect: the table is + unlocked even if it is not found in the locked list. + It's not clear if this side effect is intentional or still + desirable. It might lead to unmatched calls to + unlock_external(). Moreover, a discrepancy can be left + unnoticed by the storage engine, because in + unlock_external() we call handler::external_lock(F_UNLCK) only + if table->current_lock is not F_UNLCK. + + @param always_unlock specify explicitly if the legacy side + effect is desired. +*/ + +void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table, + bool always_unlock) { - mysql_unlock_some_tables(thd, &table,1); + if (always_unlock == TRUE) + mysql_unlock_some_tables(thd, &table, /* table count */ 1); if (locked) { reg1 uint i; @@ -370,6 +389,10 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table) DBUG_ASSERT(table->lock_position == i); + /* Unlock if not yet unlocked */ + if (always_unlock == FALSE) + mysql_unlock_some_tables(thd, &table, /* table count */ 1); + /* Decrement table_count in advance, making below expressions easier */ old_tables= --locked->table_count; @@ -623,7 +646,7 @@ static int unlock_external(THD *thd, TABLE **table,uint count) if ((*table)->current_lock != F_UNLCK) { (*table)->current_lock = F_UNLCK; - if ((error=(*table)->file->external_lock(thd, F_UNLCK))) + if ((error= (*table)->file->ha_external_lock(thd, F_UNLCK))) { error_code=error; print_lock_error(error_code, (*table)->file->table_type()); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d14aab57489..ca6aa8ecab0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1452,7 +1452,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count); -void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); +void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table, + bool always_unlock); void mysql_lock_abort(THD *thd, TABLE *table); bool mysql_lock_abort_for_thread(THD *thd, TABLE *table); MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 247f0eada49..d978c8882ac 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -972,7 +972,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() DBUG_PRINT("info", ("Freeing separate handler 0x%lx (free: %d)", (long) file, free_file)); file->reset(); - file->external_lock(current_thd, F_UNLCK); + file->ha_external_lock(current_thd, F_UNLCK); file->close(); } } @@ -1142,7 +1142,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) /* Caller will free the memory */ goto failure; /* purecov: inspected */ } - if (file->external_lock(thd, F_RDLCK)) + if (file->ha_external_lock(thd, F_RDLCK)) goto failure; if (!head->no_keyread) { @@ -1152,7 +1152,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) if (file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) || init() || reset()) { - file->external_lock(thd, F_UNLCK); + file->ha_external_lock(thd, F_UNLCK); file->close(); goto failure; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3860dfa1ded..61847a6b168 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1037,6 +1037,31 @@ TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name) return 0; // Not a temporary table } + +/** + Drop a temporary table. + + Try to locate the table in the list of thd->temporary_tables. + If the table is found: + - if the table is in thd->locked_tables, unlock it and + remove it from the list of locked tables. Currently only transactional + temporary tables are present in the locked_tables list. + - Close the temporary table, remove its .FRM + - remove the table from the list of temporary tables + + This function is used to drop user temporary tables, as well as + internal tables created in CREATE TEMPORARY TABLE ... SELECT + or ALTER TABLE. Even though part of the work done by this function + is redundant when the table is internal, as long as we + link both internal and user temporary tables into the same + thd->temporary_tables list, it's impossible to tell here whether + we're dealing with an internal or a user temporary table. + + @retval TRUE the table was not found in the list of temporary tables + of this thread + @retval FALSE the table was found and dropped successfully. +*/ + bool close_temporary_table(THD *thd, const char *db, const char *table_name) { TABLE *table,**prev; @@ -1045,6 +1070,11 @@ bool close_temporary_table(THD *thd, const char *db, const char *table_name) return 1; table= *prev; *prev= table->next; + /* + If LOCK TABLES list is not empty and contains this table, + unlock the table and remove the table from this list. + */ + mysql_lock_remove(thd, thd->locked_tables, table, FALSE); close_temporary(table, 1); if (thd->slave_thread) --slave_open_temp_tables; @@ -1120,7 +1150,7 @@ TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find) !memcmp(list->s->table_cache_key, key, key_length)) { if (thd->locked_tables) - mysql_lock_remove(thd, thd->locked_tables,list); + mysql_lock_remove(thd, thd->locked_tables, list, TRUE); VOID(hash_delete(&open_cache,(byte*) list)); // Close table } else @@ -1151,6 +1181,8 @@ TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find) dropped is already unlocked. In the former case it will also remove lock on the table. But one should not rely on this behaviour as it may change in future. + Currently, however, this function is never called for a + table that was locked with LOCK TABLES. */ void drop_open_table(THD *thd, TABLE *table, const char *db_name, @@ -2099,7 +2131,7 @@ bool close_data_tables(THD *thd,const char *db, const char *table_name) if (!strcmp(table->s->table_name, table_name) && !strcmp(table->s->db, db)) { - mysql_lock_remove(thd, thd->locked_tables,table); + mysql_lock_remove(thd, thd->locked_tables, table, TRUE); table->file->close(); table->db_stat=0; } @@ -2239,7 +2271,7 @@ void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, instances of this table. */ mysql_lock_abort(thd, table); - mysql_lock_remove(thd, thd->locked_tables, table); + mysql_lock_remove(thd, thd->locked_tables, table, TRUE); /* We want to protect the table from concurrent DDL operations (like RENAME TABLE) until we will re-open and re-lock it. @@ -2343,7 +2375,7 @@ bool drop_locked_tables(THD *thd,const char *db, const char *table_name) if (!strcmp(table->s->table_name, table_name) && !strcmp(table->s->db, db)) { - mysql_lock_remove(thd, thd->locked_tables,table); + mysql_lock_remove(thd, thd->locked_tables, table, TRUE); VOID(hash_delete(&open_cache,(byte*) table)); found=1; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 058f130d4e7..6ffbd9b4ac7 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -995,13 +995,25 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1, class Open_tables_state { public: - /* - open_tables - list of regular tables in use by this thread - temporary_tables - list of temp tables in use by this thread - handler_tables - list of tables that were opened with HANDLER OPEN - and are still in use by this thread + /** + List of regular tables in use by this thread. Contains temporary and + base tables that were opened with @see open_tables(). */ - TABLE *open_tables, *temporary_tables, *handler_tables, *derived_tables; + TABLE *open_tables; + /** + List of temporary tables used by this thread. Contains user-level + temporary tables, created with CREATE TEMPORARY TABLE, and + internal temporary tables, created, e.g., to resolve a SELECT, + or for an intermediate table used in ALTER. + XXX Why are internal temporary tables added to this list? + */ + TABLE *temporary_tables; + /** + List of tables that were opened with HANDLER OPEN and are + still in use by this thread. + */ + TABLE *handler_tables; + TABLE *derived_tables; /* During a MySQL session, one can lock tables in two modes: automatic or manual. In automatic mode all necessary tables are locked just before diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e02595836ca..f11082a712c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3791,10 +3791,10 @@ view_err: { VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); - table->file->external_lock(thd, F_WRLCK); + table->file->ha_external_lock(thd, F_WRLCK); alter_table_manage_keys(table, table->file->indexes_are_disabled(), alter_info->keys_onoff); - table->file->external_lock(thd, F_UNLCK); + table->file->ha_external_lock(thd, F_UNLCK); VOID(pthread_mutex_unlock(&LOCK_open)); error= ha_commit_stmt(thd); if (ha_commit(thd)) @@ -3813,7 +3813,7 @@ view_err: The following function call will free the new_table pointer, in close_temporary_table(), so we can safely directly jump to err */ - close_temporary_table(thd,new_db,tmp_name); + close_temporary_table(thd, new_db, tmp_name); goto err; } /* Close lock if this is a transactional table */ @@ -4086,7 +4086,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (!(copy= new Copy_field[to->s->fields])) DBUG_RETURN(-1); /* purecov: inspected */ - if (to->file->external_lock(thd, F_WRLCK)) + if (to->file->ha_external_lock(thd, F_WRLCK)) DBUG_RETURN(-1); /* We need external lock before we can disable/enable keys */ @@ -4238,7 +4238,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, free_io_cache(from); *copied= found_count; *deleted=delete_count; - if (to->file->external_lock(thd,F_UNLCK)) + if (to->file->ha_external_lock(thd,F_UNLCK)) error=1; DBUG_RETURN(error > 0 ? -1 : 0); } From a09787e8dd5e8d2ce193326b4dfb1cf672057930 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Jul 2007 15:37:37 +0200 Subject: [PATCH 11/26] Bug #30094 mi_test_all: assertion failure updated to keypart_map api storage/myisam/mi_test2.c: Bug #30094 mi_test_all: assertion failure updated to keypart_map api prefix char keys are not supported anymore --- storage/myisam/mi_test1.c | 5 +++-- storage/myisam/mi_test2.c | 23 +++++++++++++---------- storage/myisam/mi_test3.c | 8 ++++---- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/storage/myisam/mi_test1.c b/storage/myisam/mi_test1.c index 1165ea4bb32..08627ba7e92 100644 --- a/storage/myisam/mi_test1.c +++ b/storage/myisam/mi_test1.c @@ -258,7 +258,8 @@ static int run_test(const char *filename) continue; create_key(key,j); my_errno=0; - if ((error = mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))) + if ((error = mi_rkey(file,read_record,0,key,HA_WHOLE_KEY, + HA_READ_KEY_EXACT))) { if (verbose || (flags[j] >= 1 || (error && my_errno != HA_ERR_KEY_NOT_FOUND))) @@ -285,7 +286,7 @@ static int run_test(const char *filename) { create_key(key,i); my_errno=0; - error=mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT); + error=mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT); if (verbose || (error == 0 && flags[i] == 0 && unique_key) || (error && (flags[i] != 0 || my_errno != HA_ERR_KEY_NOT_FOUND))) diff --git a/storage/myisam/mi_test2.c b/storage/myisam/mi_test2.c index 96ee82e023c..99d0c23d2a4 100644 --- a/storage/myisam/mi_test2.c +++ b/storage/myisam/mi_test2.c @@ -263,7 +263,7 @@ int main(int argc, char *argv[]) if (!j) for (j=999 ; j>0 && key1[j] == 0 ; j--) ; sprintf(key,"%6d",j); - if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) + if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) { printf("Test in loop: Can't find key: \"%s\"\n",key); goto err; @@ -291,7 +291,7 @@ int main(int argc, char *argv[]) if (j != 0) { sprintf(key,"%6d",j); - if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) + if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) { printf("can't find key1: \"%s\"\n",key); goto err; @@ -325,7 +325,7 @@ int main(int argc, char *argv[]) if (j != 0) { sprintf(key,"%6d",j); - if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) + if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) { printf("can't find key1: \"%s\"\n",key); goto err; @@ -377,7 +377,7 @@ int main(int argc, char *argv[]) DBUG_PRINT("progpos",("first - next -> last - prev -> first")); if (verbose) printf(" Using key: \"%s\" Keys: %d\n",key,dupp_keys); - if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) + if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) goto err; if (mi_rsame(file,read_record2,-1)) goto err; @@ -422,7 +422,7 @@ int main(int argc, char *argv[]) } /* Check of mi_rnext_same */ - if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) + if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) goto err; ant=1; while (!mi_rnext_same(file,read_record3) && ant < dupp_keys+10) @@ -496,7 +496,7 @@ int main(int argc, char *argv[]) goto err; if (bcmp(read_record2,read_record3,reclength)) printf("Can't find last record\n"); - +#ifdef NOT_ANYMORE if (!silent) puts("- Test read key-part"); strmov(key2,key); @@ -514,12 +514,14 @@ int main(int argc, char *argv[]) goto end; } } +#endif if (dupp_keys > 2) { if (!silent) printf("- Read key (first) - next - delete - next -> last\n"); DBUG_PRINT("progpos",("first - next - delete - next -> last")); - if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) goto err; + if (mi_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) + goto err; if (mi_rnext(file,read_record3,0)) goto err; if (mi_delete(file,read_record3)) goto err; opt_delete++; @@ -555,7 +557,8 @@ int main(int argc, char *argv[]) if (!silent) printf("- Read first - delete - next -> last\n"); DBUG_PRINT("progpos",("first - delete - next -> last")); - if (mi_rkey(file,read_record3,0,key,0,HA_READ_KEY_EXACT)) goto err; + if (mi_rkey(file,read_record3,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT)) + goto err; if (mi_delete(file,read_record3)) goto err; opt_delete++; ant=1; @@ -618,10 +621,10 @@ int main(int argc, char *argv[]) copy_key(file,(uint) i,(uchar*) read_record,(uchar*) key); copy_key(file,(uint) i,(uchar*) read_record2,(uchar*) key2); min_key.key= key; - min_key.length= USE_WHOLE_KEY; + min_key.keypart_map= HA_WHOLE_KEY; min_key.flag= HA_READ_KEY_EXACT; max_key.key= key2; - max_key.length= USE_WHOLE_KEY; + max_key.keypart_map= HA_WHOLE_KEY; max_key.flag= HA_READ_AFTER_KEY; range_records= mi_records_in_range(file,(int) i, &min_key, &max_key); diff --git a/storage/myisam/mi_test3.c b/storage/myisam/mi_test3.c index 982b999c3a5..ed9cd8e7b8c 100644 --- a/storage/myisam/mi_test3.c +++ b/storage/myisam/mi_test3.c @@ -243,8 +243,8 @@ int test_read(MI_INFO *file,int id) for (i=0 ; i < 100 ; i++) { find=rnd(100000); - if (!mi_rkey(file,record.id,1,(uchar*) &find, - sizeof(find),HA_READ_KEY_EXACT)) + if (!mi_rkey(file,record.id,1,(uchar*) &find, HA_WHOLE_KEY, + HA_READ_KEY_EXACT)) found++; else { @@ -426,8 +426,8 @@ int test_update(MI_INFO *file,int id,int lock_type) { tmp=rnd(100000); int4store(find,tmp); - if (!mi_rkey(file,record.id,1,(uchar*) find, - sizeof(find),HA_READ_KEY_EXACT)) + if (!mi_rkey(file,record.id,1,(uchar*) find, HA_WHOLE_KEY, + HA_READ_KEY_EXACT)) found++; else { From 339ea316b938b9b1c2a166c6580bf84333d80a5f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Jul 2007 17:39:01 +0400 Subject: [PATCH 12/26] Fix for BUG#28030: test im_instance_conf fails with an assert. The problem was a race condition on shutdown -- when IM got shutdown request while a guarded mysqld is starting. In this case the Guardian thread tried to stop the mysqld, but might fail if the mysqld hadn't created pid-file so far. When this happened, the mysqld-monitor thread didn't stop, so the assert in Thread_registry happened. The fix is to make several attempts to stop mysqld if it is active. server-tools/instance-manager/guardian.cc: Try to stop mysqld several times if it is still active. server-tools/instance-manager/instance.cc: Make Instance::kill_mysqld() to return operation status. server-tools/instance-manager/instance.h: Make Instance::kill_mysqld() to return operation status. server-tools/instance-manager/thread_registry.cc: Log unregistered thread ids. --- server-tools/instance-manager/guardian.cc | 31 ++++++++++++++++++- server-tools/instance-manager/instance.cc | 8 +++-- server-tools/instance-manager/instance.h | 2 +- .../instance-manager/thread_registry.cc | 8 +++-- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc index e114496248e..b49b0ec0a00 100644 --- a/server-tools/instance-manager/guardian.cc +++ b/server-tools/instance-manager/guardian.cc @@ -403,6 +403,8 @@ void Guardian::init() void Guardian::stop_instances() { + static const int NUM_STOP_ATTEMPTS = 100; + Instance_map::Iterator instances_it(instance_map); Instance *instance; @@ -438,7 +440,34 @@ void Guardian::stop_instances() /* Request mysqld to stop. */ - instance->kill_mysqld(SIGTERM); + bool instance_stopped= FALSE; + + for (int cur_attempt= 0; cur_attempt < NUM_STOP_ATTEMPTS; ++cur_attempt) + { + if (!instance->kill_mysqld(SIGTERM)) + { + instance_stopped= TRUE; + break; + } + + if (!instance->is_active()) + { + instance_stopped= TRUE; + break; + } + + /* Sleep for 0.3 sec and check again. */ + + my_sleep(300000); + } + + /* + Abort if we failed to stop mysqld instance. That should not happen, + but if it happened, we don't know what to do and prefer to have clear + failure with coredump. + */ + + DBUG_ASSERT(instance_stopped); instance->unlock(); } diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc index 80e7e99214b..4a1b658737e 100644 --- a/server-tools/instance-manager/instance.cc +++ b/server-tools/instance-manager/instance.cc @@ -771,7 +771,7 @@ bool Instance::stop_mysqld() These operations should also be used in Guardian to manage instances. */ -void Instance::kill_mysqld(int signum) +bool Instance::kill_mysqld(int signum) { pid_t mysqld_pid= options.load_pid(); @@ -780,7 +780,7 @@ void Instance::kill_mysqld(int signum) log_info("Instance '%s': no pid file to send a signal (%d).", (const char *) get_name()->str, (int) signum); - return; + return TRUE; } log_info("Instance '%s': sending %d to %d...", @@ -792,7 +792,7 @@ void Instance::kill_mysqld(int signum) { log_info("Instance '%s': kill() failed.", (const char *) get_name()->str); - return; + return TRUE; } /* Kill suceeded */ @@ -804,6 +804,8 @@ void Instance::kill_mysqld(int signum) /* After sucessful hard kill the pidfile need to be removed */ options.unlink_pidfile(); } + + return FALSE; } diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h index e87bb49b49c..aa9c923cba1 100644 --- a/server-tools/instance-manager/instance.h +++ b/server-tools/instance-manager/instance.h @@ -104,7 +104,7 @@ public: bool start_mysqld(); bool stop_mysqld(); - void kill_mysqld(int signo); + bool kill_mysqld(int signo); void lock(); void unlock(); diff --git a/server-tools/instance-manager/thread_registry.cc b/server-tools/instance-manager/thread_registry.cc index 700ed22afe7..72d81523022 100644 --- a/server-tools/instance-manager/thread_registry.cc +++ b/server-tools/instance-manager/thread_registry.cc @@ -64,8 +64,12 @@ Thread_registry::~Thread_registry() /* Check that no one uses the repository. */ pthread_mutex_lock(&LOCK_thread_registry); - if (head.next != &head) - log_error("Not all threads died properly\n"); + for (Thread_info *ti= head.next; ti != &head; ti= ti->next) + { + log_error("Thread_registry: unregistered thread: %lu.", + (unsigned long) ti->thread_id); + } + /* All threads must unregister */ DBUG_ASSERT(head.next == &head); From e030b5dcc030e5777ed6260e4a9bb1c135b32aed Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Jul 2007 18:20:17 +0400 Subject: [PATCH 13/26] Fix for BUG#30027: mysqldump does not dump views properly. mysqldump generates view defitions in two stages: - dump CREATE TABLE statements for the temporary tables. For each view a temporary table, that has the same structure as the view is created. - dump DROP TABLE statements for the temporary tables and CREATE VIEW statements for the view. This approach is required because views can have dependencies on each other (a view can use other views). So, they should be created in the particular order. mysqldump however is not smart enough, so in order to resolve dependencies it creates temporary tables first of all. The problem was that mysqldump might have generated incorrect dump for the temporary table when a view has non-ASCII column name. That happened when default-character-set is not utf8. The fix is to: 1. Switch character_set_client for the mysqldump's connection to binary before issuing SHOW FIELDS statement in order to avoid conversion. 2. Dump switch character_set_client statements to UTF8 and back for CREATE TABLE statement that is issued to create temporary table. client/mysqldump.c: 1. Switch character_set_results for mysqldump's connection to binary before SHOW FIELDS in order to avoid conversion to client character set. 2. Dump switch character_set_client statements to UTF8 and back for CREATE TABLE statement. mysql-test/r/mysqldump.result: Update result file. mysql-test/t/mysqldump.test: Test case for BUG#30027. --- client/mysqldump.c | 69 ++++++++++++++++++++--------------- mysql-test/r/mysqldump.result | 69 +++++++++++++++++++++++++++++++++++ mysql-test/t/mysqldump.test | 58 +++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 30 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 0f30ebddacc..6f0e30b8f35 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2174,7 +2174,9 @@ static uint get_table_structure(char *table, char *db, char *table_type, */ my_snprintf(query_buff, sizeof(query_buff), "SHOW FIELDS FROM %s", result_table); - if (mysql_query_with_error_report(mysql, 0, query_buff)) + if (switch_character_set_results(mysql, "binary") || + mysql_query_with_error_report(mysql, &result, query_buff) || + switch_character_set_results(mysql, default_charset)) { /* View references invalid or privileged table/col/fun (err 1356), @@ -2192,43 +2194,50 @@ static uint get_table_structure(char *table, char *db, char *table_type, else my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR)); - if ((result= mysql_store_result(mysql))) + if (mysql_num_rows(result)) { - if (mysql_num_rows(result)) + if (opt_drop) { - if (opt_drop) - { /* - We have already dropped any table of the same name - above, so here we just drop the view. - */ - - fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n", - opt_quoted_table); - check_io(sql_file); - } - - fprintf(sql_file, "/*!50001 CREATE TABLE %s (\n", result_table); - /* - Get first row, following loop will prepend comma - keeps - from having to know if the row being printed is last to - determine if there should be a _trailing_ comma. + We have already dropped any table of the same name above, so + here we just drop the view. */ - row= mysql_fetch_row(result); - fprintf(sql_file, " %s %s", quote_name(row[0], name_buff, 0), - row[1]); - - while((row= mysql_fetch_row(result))) - { - /* col name, col type */ - fprintf(sql_file, ",\n %s %s", - quote_name(row[0], name_buff, 0), row[1]); - } - fprintf(sql_file, "\n) */;\n"); + fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n", + opt_quoted_table); check_io(sql_file); } + + fprintf(sql_file, + "SET @saved_cs_client = @@character_set_client;\n" + "SET character_set_client = utf8;\n" + "/*!50001 CREATE TABLE %s (\n", + result_table); + + /* + Get first row, following loop will prepend comma - keeps from + having to know if the row being printed is last to determine if + there should be a _trailing_ comma. + */ + + row= mysql_fetch_row(result); + + fprintf(sql_file, " %s %s", quote_name(row[0], name_buff, 0), + row[1]); + + while((row= mysql_fetch_row(result))) + { + /* col name, col type */ + fprintf(sql_file, ",\n %s %s", + quote_name(row[0], name_buff, 0), row[1]); + } + fprintf(sql_file, + "\n) */;\n" + "SET character_set_client = @saved_cs_client;\n"); + + check_io(sql_file); } + mysql_free_result(result); if (path) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index e8c971a41bc..88ec05bc788 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1887,9 +1887,12 @@ INSERT INTO `t2` VALUES ('alfred'),('angie'),('bingo'),('waffle'),('lemon'); UNLOCK TABLES; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( `a` varchar(30) ) */; +SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE `v2`*/; /*!50001 DROP VIEW IF EXISTS `v2`*/; /*!50001 SET @saved_cs_client = @@character_set_client */; @@ -1978,9 +1981,12 @@ LOCK TABLES `t1` WRITE; UNLOCK TABLES; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( `a` int(11) ) */; +SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE `v1`*/; /*!50001 DROP VIEW IF EXISTS `v1`*/; /*!50001 SET @saved_cs_client = @@character_set_client */; @@ -2046,9 +2052,12 @@ INSERT INTO `t2` VALUES ('alfred'),('angie'),('bingo'),('waffle'),('lemon'); UNLOCK TABLES; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( `a` varchar(30) ) */; +SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE `v2`*/; /*!50001 DROP VIEW IF EXISTS `v2`*/; /*!50001 SET @saved_cs_client = @@character_set_client */; @@ -2151,23 +2160,32 @@ INSERT INTO `t1` VALUES (1,2,'one'),(2,4,'two'),(3,6,'three'); UNLOCK TABLES; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( `a` int(11), `b` int(11), `c` varchar(30) ) */; +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( `a` int(11) ) */; +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v3`; /*!50001 DROP VIEW IF EXISTS `v3`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `v3` ( `a` int(11), `b` int(11), `c` varchar(30) ) */; +SET character_set_client = @saved_cs_client; /*!50001 DROP TABLE `v1`*/; /*!50001 DROP VIEW IF EXISTS `v1`*/; /*!50001 SET @saved_cs_client = @@character_set_client */; @@ -2867,25 +2885,34 @@ INSERT INTO `t1` VALUES (1,'first value','xxxx'),(2,'second value','tttt'),(3,'t UNLOCK TABLES; DROP TABLE IF EXISTS `v0`; /*!50001 DROP VIEW IF EXISTS `v0`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `v0` ( `a` int(11), `b` varchar(32), `c` varchar(32) ) */; +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( `a` int(11), `b` varchar(32), `c` varchar(32) ) */; +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `v2` ( `a` int(11), `b` varchar(32), `c` varchar(32) ) */; +SET character_set_client = @saved_cs_client; USE `test`; /*!50001 DROP TABLE `v0`*/; @@ -3248,9 +3275,12 @@ INSERT INTO `t1` VALUES (1232131),(4711),(3231),(815); UNLOCK TABLES; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( `id` int(11) ) */; +SET character_set_client = @saved_cs_client; USE `mysqldump_test_db`; /*!50001 DROP TABLE `v1`*/; @@ -3302,9 +3332,12 @@ CREATE TABLE `basetable` ( CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_views` /*!40100 DEFAULT CHARACTER SET latin1 */; USE `mysqldump_views`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `nasishnasifu` ( `id` bigint(20) unsigned ) */; +SET character_set_client = @saved_cs_client; USE `mysqldump_tables`; @@ -3870,9 +3903,12 @@ INSERT INTO `t1` VALUES (1232131),(4711),(3231),(815); UNLOCK TABLES; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; /*!50001 CREATE TABLE `v1` ( `id` int(11) ) */; +SET character_set_client = @saved_cs_client; USE `mysqldump_test_db`; /*!50001 DROP TABLE `v1`*/; @@ -3903,5 +3939,38 @@ drop view v1; drop table t1; drop database mysqldump_test_db; # +# Bug #30027: mysqldump does not dump views properly. +# + +# Cleanup. +DROP DATABASE IF EXISTS mysqldump_test_db; + +# Create objects. +CREATE DATABASE mysqldump_test_db; +set names koi8r; +CREATE VIEW mysqldump_test_db.v2 AS SELECT 1 AS ËÏÌÏÎËÁ1; +CREATE VIEW mysqldump_test_db.v1 AS SELECT ËÏÌÏÎËÁ1 FROM mysqldump_test_db.v2; +set names latin1; + +# Dump mysqldump_test_db to /dev/shm/t1/var/tmp/bug30027.sql. + +# Drop mysqldump_test_db. +DROP DATABASE mysqldump_test_db; + +# Restore mysqldump_test_db from /dev/shm/t1/var/tmp/bug30027.sql. + +# Check the view. +set names utf8; +SHOW CREATE VIEW mysqldump_test_db.v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqldump_test_db`.`v1` AS select `v2`.`колонка1` AS `колонка1` from `mysqldump_test_db`.`v2` koi8r koi8r_general_ci +SHOW CREATE VIEW mysqldump_test_db.v2; +View Create View character_set_client collation_connection +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqldump_test_db`.`v2` AS select 1 AS `колонка1` koi8r koi8r_general_ci +set names latin1; + +# Cleanup. +DROP DATABASE mysqldump_test_db; +# # End of 5.1 tests # diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 38d8a07fe48..a0d1195addc 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1676,6 +1676,64 @@ drop database mysqldump_test_db; --exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug26121.sql --remove_file $MYSQLTEST_VARDIR/tmp/bug26121.sql +########################################################################### + +--echo # +--echo # Bug #30027: mysqldump does not dump views properly. +--echo # + +--echo +--echo # Cleanup. + +--disable_warnings +DROP DATABASE IF EXISTS mysqldump_test_db; +--enable_warnings + +--echo +--echo # Create objects. + +CREATE DATABASE mysqldump_test_db; + +set names koi8r; + +CREATE VIEW mysqldump_test_db.v2 AS SELECT 1 AS ËÏÌÏÎËÁ1; +CREATE VIEW mysqldump_test_db.v1 AS SELECT ËÏÌÏÎËÁ1 FROM mysqldump_test_db.v2; + +set names latin1; + +--echo +--echo # Dump mysqldump_test_db to $MYSQLTEST_VARDIR/tmp/bug30027.sql. + +--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --default-character-set=latin1 --databases mysqldump_test_db > $MYSQLTEST_VARDIR/tmp/bug30027.sql +# --exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --databases mysqldump_test_db > $MYSQLTEST_VARDIR/tmp/bug30027.sql + +--echo +--echo # Drop mysqldump_test_db. + +DROP DATABASE mysqldump_test_db; + +--echo +--echo # Restore mysqldump_test_db from $MYSQLTEST_VARDIR/tmp/bug30027.sql. + +--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/bug30027.sql + +--echo +--echo # Check the view. + +set names utf8; + +SHOW CREATE VIEW mysqldump_test_db.v1; +SHOW CREATE VIEW mysqldump_test_db.v2; + +set names latin1; + +--echo +--echo # Cleanup. + +DROP DATABASE mysqldump_test_db; + +########################################################################### + --echo # --echo # End of 5.1 tests --echo # From 07955aea2dc369be7637f28331bd1072a995d572 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Jul 2007 16:56:29 +0200 Subject: [PATCH 14/26] Bug #29929 LOCK TABLES does not pre-lock tables used in triggers of the locked tables When a table was explicitly locked with LOCK TABLES no associated tables from any related trigger on the subject table were locked. As a result of this the user could experience unexpected locking behavior and statement failures similar to "failed: 1100: Table'xx' was not locked with LOCK TABLES". This patch fixes this problem by making sure triggers are pre-loaded on any statement if the subject table was explicitly locked with LOCK TABLES. mysql-test/r/sp-prelocking.result: Added test case mysql-test/t/sp-prelocking.test: Added test case sql/sql_lex.cc: - Moved some conditional logic out of the table iteration. - Added event map values for LOCK TABLE command. sql/table.cc: - Refactored set_trg_event_tpye into the two simpler functions set_trg_event_map and set_trg_event_map as methods for manipulating the table event map. The original function was only called from st_lex::set_trg_event_type_for_tables so it was possible to move the event map creation logic to this function as a loop optimization. sql/table.h: - Refactored set_trg_event_tpye into the two simpler functions set_trg_event_map and set_trg_event_map as methods for manipulating the table event map. The original function was only called from st_lex::set_trg_event_type_for_tables so it was possible to move the event map creation logic to this function as a loop optimization. --- mysql-test/r/sp-prelocking.result | 30 +++++++ mysql-test/t/sp-prelocking.test | 31 +++++++ sql/sql_lex.cc | 135 +++++++++++++++++++++++++++++- sql/table.cc | 129 ---------------------------- sql/table.h | 1 - 5 files changed, 193 insertions(+), 133 deletions(-) diff --git a/mysql-test/r/sp-prelocking.result b/mysql-test/r/sp-prelocking.result index c19bd1abd26..186b2c05d34 100644 --- a/mysql-test/r/sp-prelocking.result +++ b/mysql-test/r/sp-prelocking.result @@ -289,4 +289,34 @@ create table t1 select f_bug22427() as i; ERROR 42S01: Table 't1' already exists drop table t1; drop function f_bug22427; +# +# Bug #29929 LOCK TABLES does not pre-lock tables used in triggers of the locked tables +# +DROP table IF EXISTS t1,t2; +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c2 INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW +BEGIN +UPDATE t2 SET c2= c2 + 1; +END// +# Take a table lock on t1. +# This should pre-lock t2 through the trigger. +LOCK TABLE t1 WRITE; +INSERT INTO t1 VALUES (3); +UNLOCK TABLES; +LOCK TABLE t1 READ; +INSERT INTO t2 values(4); +ERROR HY000: Table 't2' was not locked with LOCK TABLES +UNLOCK TABLES; +SELECT * FROM t1; +c1 +1 +3 +SELECT * FROM t2; +c2 +3 +DROP TRIGGER t1_ai; +DROP TABLE t1, t2; End of 5.0 tests diff --git a/mysql-test/t/sp-prelocking.test b/mysql-test/t/sp-prelocking.test index 60e97260839..966c59a5789 100644 --- a/mysql-test/t/sp-prelocking.test +++ b/mysql-test/t/sp-prelocking.test @@ -356,4 +356,35 @@ create table t1 select f_bug22427() as i; drop table t1; drop function f_bug22427; +--echo # +--echo # Bug #29929 LOCK TABLES does not pre-lock tables used in triggers of the locked tables +--echo # +--disable_warnings +DROP table IF EXISTS t1,t2; +--enable_warnings +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c2 INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +DELIMITER //; +CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW +BEGIN +UPDATE t2 SET c2= c2 + 1; +END// +DELIMITER ;// +--echo # Take a table lock on t1. +--echo # This should pre-lock t2 through the trigger. +LOCK TABLE t1 WRITE; +INSERT INTO t1 VALUES (3); +UNLOCK TABLES; +LOCK TABLE t1 READ; +--error ER_TABLE_NOT_LOCKED +INSERT INTO t2 values(4); +UNLOCK TABLES; +SELECT * FROM t1; +SELECT * FROM t2; +DROP TRIGGER t1_ai; +DROP TABLE t1, t2; + --echo End of 5.0 tests + diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index c37d77345b6..106dcf88a84 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2035,12 +2035,131 @@ void st_select_lex_unit::set_limit(SELECT_LEX *sl) /** - Update the parsed tree with information about triggers that - may be fired when executing this statement. + @brief Set the initial purpose of this TABLE_LIST object in the list of used + tables. + + We need to track this information on table-by-table basis, since when this + table becomes an element of the pre-locked list, it's impossible to identify + which SQL sub-statement it has been originally used in. + + E.g.: + + User request: SELECT * FROM t1 WHERE f1(); + FUNCTION f1(): DELETE FROM t2; RETURN 1; + BEFORE DELETE trigger on t2: INSERT INTO t3 VALUES (old.a); + + For this user request, the pre-locked list will contain t1, t2, t3 + table elements, each needed for different DML. + + The trigger event map is updated to reflect INSERT, UPDATE, DELETE, + REPLACE, LOAD DATA, CREATE TABLE .. SELECT, CREATE TABLE .. + REPLACE SELECT statements, and additionally ON DUPLICATE KEY UPDATE + clause. */ void st_lex::set_trg_event_type_for_tables() { + enum trg_event_type trg_event; + + uint8 new_trg_event_map= 0; + + /* + Some auxiliary operations + (e.g. GRANT processing) create TABLE_LIST instances outside + the parser. Additionally, some commands (e.g. OPTIMIZE) change + the lock type for a table only after parsing is done. Luckily, + these do not fire triggers and do not need to pre-load them. + For these TABLE_LISTs set_trg_event_type is never called, and + trg_event_map is always empty. That means that the pre-locking + algorithm will ignore triggers defined on these tables, if + any, and the execution will either fail with an assert in + sql_trigger.cc or with an error that a used table was not + pre-locked, in case of a production build. + + TODO: this usage pattern creates unnecessary module dependencies + and should be rewritten to go through the parser. + Table list instances created outside the parser in most cases + refer to mysql.* system tables. It is not allowed to have + a trigger on a system table, but keeping track of + initialization provides extra safety in case this limitation + is circumvented. + */ + + switch (sql_command) { + case SQLCOM_LOCK_TABLES: + /* + On a LOCK TABLE, all triggers must be pre-loaded for this TABLE_LIST + when opening an associated TABLE. + */ + new_trg_event_map= static_cast + (1 << static_cast(TRG_EVENT_INSERT)) | + static_cast + (1 << static_cast(TRG_EVENT_UPDATE)) | + static_cast + (1 << static_cast(TRG_EVENT_DELETE)); + break; + /* + Basic INSERT. If there is an additional ON DUPLIATE KEY UPDATE + clause, it will be handled later in this method. + */ + case SQLCOM_INSERT: /* fall through */ + case SQLCOM_INSERT_SELECT: + /* + LOAD DATA ... INFILE is expected to fire BEFORE/AFTER INSERT + triggers. + If the statement also has REPLACE clause, it will be + handled later in this method. + */ + case SQLCOM_LOAD: /* fall through */ + /* + REPLACE is semantically equivalent to INSERT. In case + of a primary or unique key conflict, it deletes the old + record and inserts a new one. So we also may need to + fire ON DELETE triggers. This functionality is handled + later in this method. + */ + case SQLCOM_REPLACE: /* fall through */ + case SQLCOM_REPLACE_SELECT: + /* + CREATE TABLE ... SELECT defaults to INSERT if the table or + view already exists. REPLACE option of CREATE TABLE ... + REPLACE SELECT is handled later in this method. + */ + case SQLCOM_CREATE_TABLE: + new_trg_event_map|= static_cast + (1 << static_cast(TRG_EVENT_INSERT)); + break; + /* Basic update and multi-update */ + case SQLCOM_UPDATE: /* fall through */ + case SQLCOM_UPDATE_MULTI: + new_trg_event_map|= static_cast + (1 << static_cast(TRG_EVENT_UPDATE)); + break; + /* Basic delete and multi-delete */ + case SQLCOM_DELETE: /* fall through */ + case SQLCOM_DELETE_MULTI: + new_trg_event_map|= static_cast + (1 << static_cast(TRG_EVENT_DELETE)); + break; + default: + break; + } + + switch (duplicates) { + case DUP_UPDATE: + new_trg_event_map|= static_cast + (1 << static_cast(TRG_EVENT_UPDATE)); + break; + case DUP_REPLACE: + new_trg_event_map|= static_cast + (1 << static_cast(TRG_EVENT_DELETE)); + break; + case DUP_ERROR: + default: + break; + } + + /* Do not iterate over sub-selects, only the tables in the outermost SELECT_LEX can be modified, if any. @@ -2049,7 +2168,17 @@ void st_lex::set_trg_event_type_for_tables() while (tables) { - tables->set_trg_event_type(this); + /* + This is a fast check to filter out statements that do + not change data, or tables on the right side, in case of + INSERT .. SELECT, CREATE TABLE .. SELECT and so on. + Here we also filter out OPTIMIZE statement and non-updateable + views, for which lock_type is TL_UNLOCK or TL_READ after + parsing. + */ + if (static_cast(tables->lock_type) >= + static_cast(TL_WRITE_ALLOW_WRITE)) + tables->trg_event_map= new_trg_event_map; tables= tables->next_local; } } diff --git a/sql/table.cc b/sql/table.cc index f24f5c6fbcc..f27076076bf 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1776,135 +1776,6 @@ void st_table::reset_item_list(List *item_list) const } } - -/** - Set the initial purpose of this TABLE_LIST object in the list of - used tables. We need to track this information on table-by- - table basis, since when this table becomes an element of the - pre-locked list, it's impossible to identify which SQL - sub-statement it has been originally used in. - - E.g.: - - User request: SELECT * FROM t1 WHERE f1(); - FUNCTION f1(): DELETE FROM t2; RETURN 1; - BEFORE DELETE trigger on t2: INSERT INTO t3 VALUES (old.a); - - For this user request, the pre-locked list will contain t1, t2, t3 - table elements, each needed for different DML. - - This method is called immediately after parsing for tables - of the table list of the top-level select lex. - - The trigger event map is updated to reflect INSERT, UPDATE, DELETE, - REPLACE, LOAD DATA, CREATE TABLE .. SELECT, CREATE TABLE .. - REPLACE SELECT statements, and additionally ON DUPLICATE KEY UPDATE - clause. -*/ - -void -TABLE_LIST::set_trg_event_type(const st_lex *lex) -{ - enum trg_event_type trg_event; - - /* - Some auxiliary operations - (e.g. GRANT processing) create TABLE_LIST instances outside - the parser. Additionally, some commands (e.g. OPTIMIZE) change - the lock type for a table only after parsing is done. Luckily, - these do not fire triggers and do not need to pre-load them. - For these TABLE_LISTs set_trg_event_type is never called, and - trg_event_map is always empty. That means that the pre-locking - algorithm will ignore triggers defined on these tables, if - any, and the execution will either fail with an assert in - sql_trigger.cc or with an error that a used table was not - pre-locked, in case of a production build. - - TODO: this usage pattern creates unnecessary module dependencies - and should be rewritten to go through the parser. - Table list instances created outside the parser in most cases - refer to mysql.* system tables. It is not allowed to have - a trigger on a system table, but keeping track of - initialization provides extra safety in case this limitation - is circumvented. - */ - - /* - This is a fast check to filter out statements that do - not change data, or tables on the right side, in case of - INSERT .. SELECT, CREATE TABLE .. SELECT and so on. - Here we also filter out OPTIMIZE statement and non-updateable - views, for which lock_type is TL_UNLOCK or TL_READ after - parsing. - */ - if (static_cast(lock_type) < static_cast(TL_WRITE_ALLOW_WRITE)) - return; - - switch (lex->sql_command) { - /* - Basic INSERT. If there is an additional ON DUPLIATE KEY UPDATE - clause, it will be handled later in this method. - */ - case SQLCOM_INSERT: /* fall through */ - case SQLCOM_INSERT_SELECT: - /* - LOAD DATA ... INFILE is expected to fire BEFORE/AFTER INSERT - triggers. - If the statement also has REPLACE clause, it will be - handled later in this method. - */ - case SQLCOM_LOAD: /* fall through */ - /* - REPLACE is semantically equivalent to INSERT. In case - of a primary or unique key conflict, it deletes the old - record and inserts a new one. So we also may need to - fire ON DELETE triggers. This functionality is handled - later in this method. - */ - case SQLCOM_REPLACE: /* fall through */ - case SQLCOM_REPLACE_SELECT: - /* - CREATE TABLE ... SELECT defaults to INSERT if the table or - view already exists. REPLACE option of CREATE TABLE ... - REPLACE SELECT is handled later in this method. - */ - case SQLCOM_CREATE_TABLE: - trg_event= TRG_EVENT_INSERT; - break; - /* Basic update and multi-update */ - case SQLCOM_UPDATE: /* fall through */ - case SQLCOM_UPDATE_MULTI: - trg_event= TRG_EVENT_UPDATE; - break; - /* Basic delete and multi-delete */ - case SQLCOM_DELETE: /* fall through */ - case SQLCOM_DELETE_MULTI: - trg_event= TRG_EVENT_DELETE; - break; - default: - /* - OK to return, since value of 'duplicates' is irrelevant - for non-updating commands. - */ - return; - } - trg_event_map|= static_cast(1 << static_cast(trg_event)); - - switch (lex->duplicates) { - case DUP_UPDATE: - trg_event= TRG_EVENT_UPDATE; - break; - case DUP_REPLACE: - trg_event= TRG_EVENT_DELETE; - break; - case DUP_ERROR: - default: - return; - } - trg_event_map|= static_cast(1 << static_cast(trg_event)); -} - - /* calculate md5 of query diff --git a/sql/table.h b/sql/table.h index f8f7d7f06b7..f411ce489c4 100644 --- a/sql/table.h +++ b/sql/table.h @@ -770,7 +770,6 @@ struct TABLE_LIST void reinit_before_use(THD *thd); Item_subselect *containing_subselect(); - void set_trg_event_type(const st_lex *lex); private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); From 818b0b84e0268e38a563dcf2c6ce0c3c2cf2f7f7 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Jul 2007 21:06:50 +0400 Subject: [PATCH 15/26] Fix test so that it will be environment-independent. mysql-test/r/mysqldump.result: Update result file. --- mysql-test/r/mysqldump.result | 4 ++-- mysql-test/t/mysqldump.test | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 88ec05bc788..05f795f4e68 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -3952,12 +3952,12 @@ CREATE VIEW mysqldump_test_db.v2 AS SELECT 1 AS CREATE VIEW mysqldump_test_db.v1 AS SELECT ËÏÌÏÎËÁ1 FROM mysqldump_test_db.v2; set names latin1; -# Dump mysqldump_test_db to /dev/shm/t1/var/tmp/bug30027.sql. +# Dump mysqldump_test_db to bug30027.sql. # Drop mysqldump_test_db. DROP DATABASE mysqldump_test_db; -# Restore mysqldump_test_db from /dev/shm/t1/var/tmp/bug30027.sql. +# Restore mysqldump_test_db from bug30027.sql. # Check the view. set names utf8; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index a0d1195addc..3d3420b46b4 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1702,10 +1702,9 @@ CREATE VIEW mysqldump_test_db.v1 AS SELECT set names latin1; --echo ---echo # Dump mysqldump_test_db to $MYSQLTEST_VARDIR/tmp/bug30027.sql. +--echo # Dump mysqldump_test_db to bug30027.sql. --exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --default-character-set=latin1 --databases mysqldump_test_db > $MYSQLTEST_VARDIR/tmp/bug30027.sql -# --exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --databases mysqldump_test_db > $MYSQLTEST_VARDIR/tmp/bug30027.sql --echo --echo # Drop mysqldump_test_db. @@ -1713,7 +1712,7 @@ set names latin1; DROP DATABASE mysqldump_test_db; --echo ---echo # Restore mysqldump_test_db from $MYSQLTEST_VARDIR/tmp/bug30027.sql. +--echo # Restore mysqldump_test_db from bug30027.sql. --exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/bug30027.sql From 5a03bfbbce3f8bb9b7a3e9655d167ea6625e654e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Jul 2007 21:50:37 +0400 Subject: [PATCH 16/26] Fix merge. --- mysql-test/r/mysqldump.result | 54 +++++++++++++++++++++++++++++----- mysql-test/r/show_check.result | 20 +++++++++++++ 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index c42272d612b..9b3f4efe119 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1812,14 +1812,21 @@ SET character_set_client = utf8; CREATE TABLE `t3` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -1849,9 +1856,12 @@ mysqldump: Got error: 1064: You have an error in your SQL syntax; check the manu /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; @@ -1882,12 +1892,15 @@ insert into t1 values (0815, 4711, 2006); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ANSI' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS "t1"; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE "t1" ( "a b" int(11) NOT NULL DEFAULT '0', "c""d" int(11) NOT NULL DEFAULT '0', "e`f" int(11) NOT NULL DEFAULT '0', PRIMARY KEY ("a b","c""d","e`f") ); +SET character_set_client = @saved_cs_client; LOCK TABLES "t1" WRITE; /*!40000 ALTER TABLE "t1" DISABLE KEYS */; @@ -1913,12 +1926,15 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a b` int(11) NOT NULL DEFAULT '0', `c"d` int(11) NOT NULL DEFAULT '0', `e``f` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`a b`,`c"d`,`e``f`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -1964,10 +1980,13 @@ create view v2 as select * from t2 where a like 'a%' with check option; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` varchar(30) DEFAULT NULL, KEY `a` (`a`(5)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t2` WRITE; /*!40000 ALTER TABLE `t2` DISABLE KEYS */; @@ -3131,9 +3150,12 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -3187,10 +3209,13 @@ insert into t1 values ('',''); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` binary(1) DEFAULT NULL, `b` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -3219,10 +3244,13 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` binary(1) DEFAULT NULL, `b` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -3543,14 +3571,6 @@ grant RELOAD on *.* to mysqltest_1@localhost; mysqldump: Couldn't execute 'SHOW MASTER STATUS': Access denied; you need the SUPER,REPLICATION CLIENT privilege for this operation (1227) mysqldump: Couldn't execute 'SHOW MASTER STATUS': Access denied; you need the SUPER,REPLICATION CLIENT privilege for this operation (1227) grant REPLICATION CLIENT on *.* to mysqltest_1@localhost; -SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; -CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=537; -CREATE TABLE `t1` ( - `a` int(11) default NULL, - `b` varchar(34) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; -SET character_set_client = @saved_cs_client; drop table t1; drop user mysqltest_1@localhost; # @@ -3639,22 +3659,31 @@ CREATE TABLE t1 (a int) ENGINE=merge UNION=(t2, t3); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t2`,`t3`); +SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `t2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t2` WRITE; /*!40000 ALTER TABLE `t2` DISABLE KEYS */; /*!40000 ALTER TABLE `t2` ENABLE KEYS */; UNLOCK TABLES; DROP TABLE IF EXISTS `t3`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t3` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t3` WRITE; /*!40000 ALTER TABLE `t3` DISABLE KEYS */; @@ -3734,10 +3763,13 @@ drop database mysqldump_test_db; # CREATE TABLE t1 (c1 INT, c2 LONGBLOB); INSERT INTO t1 SET c1=11, c2=REPEAT('q',509); +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `c1` int(11) DEFAULT NULL, `c2` longblob ); +SET character_set_client = @saved_cs_client; INSERT INTO `t1` VALUES (11,0x7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171); DROP TABLE t1; # @@ -3770,10 +3802,13 @@ INSERT INTO t1 VALUES (3,4), (4,5); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; @@ -4037,9 +4072,12 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_test_db` /*!40100 DEFAULT CH USE `mysqldump_test_db`; DROP TABLE IF EXISTS `t1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `id` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; +SET character_set_client = @saved_cs_client; LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 2bdd29602fb..2914384aa29 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -1148,6 +1148,26 @@ DROP TABLE t1; DROP VIEW v1; DROP PROCEDURE p1; DROP FUNCTION f1; +set names koi8r; +DROP DATABASE IF EXISTS mysqltest1; +CREATE DATABASE mysqltest1; +use mysqltest1; +CREATE TABLE t1(ËÏÌÏÎËÁ1 INT); + +---> Dumping mysqltest1 to show_check.mysqltest1.sql + + +DROP DATABASE mysqltest1; + + +---> Restoring mysqltest1... +SHOW CREATE TABLE mysqltest1.t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ËÏÌÏÎËÁ1` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP DATABASE mysqltest1; +use test; flush status; show variables like "log_queries_not_using_indexes"; Variable_name Value From cc5b3745661bdf5328c87e7045abe8ec7d9b1522 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Jul 2007 12:19:36 -0600 Subject: [PATCH 17/26] Code review changes --- sql/handler.cc | 2 ++ sql/lock.cc | 41 ++++++++++++++++++++++++++++++----------- sql/log.cc | 42 +++++++++++++++++------------------------- sql/log.h | 3 --- sql/sql_parse.cc | 2 +- 5 files changed, 50 insertions(+), 40 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index e0ec2962d17..c4abfeea0a8 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3658,6 +3658,8 @@ int handler::ha_write_row(uchar *buf) Write a record to the engine bypassing row-level binary logging. This method is used internally by the server for writing to performance schema tables, which are never replicated. + TODO: Merge this function with ha_write_row(), and provide a way + to disable the binlog there. */ int handler::ha_write_row_no_binlog(uchar *buf) { diff --git a/sql/lock.cc b/sql/lock.cc index 34a2e202f8f..acb34c0d66a 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -111,21 +111,23 @@ static void print_lock_error(int error, const char *); static int thr_lock_errno_to_mysql[]= { 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK }; -MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, - uint flags, bool *need_reopen) +/** + Perform semantic checks for mysql_lock_tables. + @param thd The current thread + @param tables The tables to lock + @param count The number of tables to lock + @param flags Lock flags + @return 0 if all the check passed, non zero if a check failed. +*/ +int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags) { - MYSQL_LOCK *sql_lock; - TABLE *write_lock_used; - int rc; - uint i; bool log_table_write_query; uint system_count; + uint i; - DBUG_ENTER("mysql_lock_tables"); + DBUG_ENTER("mysql_lock_tables_check"); - *need_reopen= FALSE; system_count= 0; - log_table_write_query= (is_log_table_write_query(thd->lex->sql_command) || ((flags & MYSQL_LOCK_PERF_SCHEMA) != 0)); @@ -154,7 +156,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, || (thd->lex->sql_command == SQLCOM_LOCK_TABLES)) { my_error(ER_CANT_LOCK_LOG_TABLE, MYF(0)); - DBUG_RETURN(0); + DBUG_RETURN(1); } } @@ -173,9 +175,26 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, if ((system_count > 0) && (system_count < count)) { my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0)); - DBUG_RETURN(0); + DBUG_RETURN(1); } + DBUG_RETURN(0); +} + +MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, + uint flags, bool *need_reopen) +{ + MYSQL_LOCK *sql_lock; + TABLE *write_lock_used; + int rc; + + DBUG_ENTER("mysql_lock_tables"); + + *need_reopen= FALSE; + + if (mysql_lock_tables_check(thd, tables, count, flags)) + DBUG_RETURN (NULL); + for (;;) { if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS, diff --git a/sql/log.cc b/sql/log.cc index af039c15ffc..c7a8037d4b5 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -708,19 +708,10 @@ bool Log_to_file_event_handler:: longlong query_time, longlong lock_time, bool is_command, const char *sql_text, uint sql_text_len) { - bool res; - - (void) pthread_mutex_lock(mysql_slow_log.get_log_lock()); - - /* TODO: MYSQL_QUERY_LOG::write is not thread-safe */ - res= mysql_slow_log.write(thd, current_time, query_start_arg, - user_host, user_host_len, - query_time, lock_time, is_command, - sql_text, sql_text_len); - - (void) pthread_mutex_unlock(mysql_slow_log.get_log_lock()); - - return res; + return mysql_slow_log.write(thd, current_time, query_start_arg, + user_host, user_host_len, + query_time, lock_time, is_command, + sql_text, sql_text_len); } @@ -736,18 +727,9 @@ bool Log_to_file_event_handler:: const char *sql_text, uint sql_text_len, CHARSET_INFO *client_cs) { - bool res; - - (void) pthread_mutex_lock (mysql_log.get_log_lock()); - - /* TODO: MYSQL_QUERY_LOG::write is not thread-safe */ - res= mysql_log.write(event_time, user_host, user_host_len, - thread_id, command_type, command_type_len, - sql_text, sql_text_len); - - (void) pthread_mutex_unlock (mysql_log.get_log_lock()); - - return res; + return mysql_log.write(event_time, user_host, user_host_len, + thread_id, command_type, command_type_len, + sql_text, sql_text_len); } @@ -1959,6 +1941,8 @@ bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host, struct tm start; uint time_buff_len= 0; + (void) pthread_mutex_lock(&LOCK_log); + /* Test if someone closed between the is_open test and lock */ if (is_open()) { @@ -2003,6 +1987,7 @@ bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host, goto err; } + (void) pthread_mutex_unlock(&LOCK_log); return FALSE; err: @@ -2011,6 +1996,7 @@ err: write_error= 1; sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); } + (void) pthread_mutex_unlock(&LOCK_log); return TRUE; } @@ -2053,8 +2039,13 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, bool error= 0; DBUG_ENTER("MYSQL_QUERY_LOG::write"); + (void) pthread_mutex_lock(&LOCK_log); + if (!is_open()) + { + (void) pthread_mutex_unlock(&LOCK_log); DBUG_RETURN(0); + } if (is_open()) { // Safety agains reopen @@ -2158,6 +2149,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, } } } + (void) pthread_mutex_unlock(&LOCK_log); DBUG_RETURN(error); } diff --git a/sql/log.h b/sql/log.h index faf6ead450c..3b1a0950daa 100644 --- a/sql/log.h +++ b/sql/log.h @@ -213,9 +213,6 @@ public: WRITE_CACHE); } - /* TODO: fix MYSQL_LOG::write to be thread safe instead. */ - inline pthread_mutex_t* get_log_lock() { return &LOCK_log; } - private: time_t last_time; }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c2820581d71..848d9e2c066 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -210,7 +210,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND; + sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; From 2e23c6f09051ba86fe46d471cc37628097b8c367 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Jul 2007 12:30:02 -0600 Subject: [PATCH 18/26] manual merge --- sql/table.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/table.cc b/sql/table.cc index fef63170ea6..b3d49830149 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -19,7 +19,7 @@ #include "mysql_priv.h" #include "sql_trigger.h" #include -#include "md5.h" +#include "my_md5.h" /* INFORMATION_SCHEMA name */ LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")}; From eac42d5ac0bb9b9f082c3008da9f55213c581845 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 29 Jul 2007 14:01:16 +0200 Subject: [PATCH 19/26] Cleanup patch - Removed unused variable. sql/sql_lex.cc: - Removed unused variable --- sql/sql_lex.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 9194b133df4..e7fa3317cd2 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2391,8 +2391,6 @@ void st_select_lex_unit::set_limit(SELECT_LEX *sl) void st_lex::set_trg_event_type_for_tables() { - enum trg_event_type trg_event; - uint8 new_trg_event_map= 0; /* From 151e6aba09c20314c13a410b3c90cb79c1701fce Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 29 Jul 2007 14:05:03 +0200 Subject: [PATCH 20/26] Clean up patch - Removed unused variable. sql/sql_lex.cc: - Removed unused variable --- sql/sql_lex.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 106dcf88a84..a62d8b383a5 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2059,8 +2059,6 @@ void st_select_lex_unit::set_limit(SELECT_LEX *sl) void st_lex::set_trg_event_type_for_tables() { - enum trg_event_type trg_event; - uint8 new_trg_event_map= 0; /* From d803c8663be28432c50fca8940fcd2fee6925a14 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Jul 2007 14:03:47 +0400 Subject: [PATCH 21/26] Fix merge: update result files. mysql-test/r/ddl_i18n_koi8r.result: Update result file. mysql-test/r/ddl_i18n_utf8.result: Update result file. --- mysql-test/r/ddl_i18n_koi8r.result | 12 ++++++++++++ mysql-test/r/ddl_i18n_utf8.result | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/mysql-test/r/ddl_i18n_koi8r.result b/mysql-test/r/ddl_i18n_koi8r.result index 9e5931330e2..3d38319df21 100644 --- a/mysql-test/r/ddl_i18n_koi8r.result +++ b/mysql-test/r/ddl_i18n_koi8r.result @@ -1689,12 +1689,18 @@ DELETE FROM mysqltest2.log| CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest1` /*!40100 DEFAULT CHARACTER SET cp866 */; USE `mysqltest1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `log` ( `msg` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +SET character_set_client = @saved_cs_client; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `c` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +SET character_set_client = @saved_cs_client; INSERT INTO `t1` VALUES (1),(0),(1); ALTER DATABASE mysqltest1 CHARACTER SET utf8 COLLATE utf8_unicode_ci ; /*!50003 SET @saved_cs_client = @@character_set_client */ ; @@ -1762,12 +1768,18 @@ ALTER DATABASE mysqltest1 CHARACTER SET cp866 COLLATE cp866_general_ci ; CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest2` /*!40100 DEFAULT CHARACTER SET cp866 */; USE `mysqltest2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `log` ( `msg` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +SET character_set_client = @saved_cs_client; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `c` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +SET character_set_client = @saved_cs_client; INSERT INTO `t1` VALUES (1),(0),(1); ALTER DATABASE mysqltest2 CHARACTER SET utf8 COLLATE utf8_unicode_ci ; /*!50003 SET @saved_cs_client = @@character_set_client */ ; diff --git a/mysql-test/r/ddl_i18n_utf8.result b/mysql-test/r/ddl_i18n_utf8.result index d74d014d755..b8e690bfeb7 100644 --- a/mysql-test/r/ddl_i18n_utf8.result +++ b/mysql-test/r/ddl_i18n_utf8.result @@ -1689,12 +1689,18 @@ DELETE FROM mysqltest2.log| CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest1` /*!40100 DEFAULT CHARACTER SET cp866 */; USE `mysqltest1`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `log` ( `msg` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +SET character_set_client = @saved_cs_client; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `c` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +SET character_set_client = @saved_cs_client; INSERT INTO `t1` VALUES (1),(0),(1); ALTER DATABASE mysqltest1 CHARACTER SET utf8 COLLATE utf8_unicode_ci ; /*!50003 SET @saved_cs_client = @@character_set_client */ ; @@ -1762,12 +1768,18 @@ ALTER DATABASE mysqltest1 CHARACTER SET cp866 COLLATE cp866_general_ci ; CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest2` /*!40100 DEFAULT CHARACTER SET cp866 */; USE `mysqltest2`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `log` ( `msg` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +SET character_set_client = @saved_cs_client; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; CREATE TABLE `t1` ( `c` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +SET character_set_client = @saved_cs_client; INSERT INTO `t1` VALUES (1),(0),(1); ALTER DATABASE mysqltest2 CHARACTER SET utf8 COLLATE utf8_unicode_ci ; /*!50003 SET @saved_cs_client = @@character_set_client */ ; From eb6c85e7552dcf63f2b2ed065051f571425d8426 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Jul 2007 14:22:29 +0400 Subject: [PATCH 22/26] Fix a compilation warning. sql/handler.h: Fix a warning. --- sql/handler.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/handler.h b/sql/handler.h index cd9f9a91008..2caf9b20945 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -624,7 +624,6 @@ public: int ha_external_lock(THD *thd, int lock_type) { - int rc; DBUG_ENTER("ha_external_lock"); locked= lock_type != F_UNLCK; DBUG_RETURN(external_lock(thd, lock_type)); From e0644f180ef6ba4699aebaf5f81f676082568b8c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Jul 2007 19:23:53 +0400 Subject: [PATCH 23/26] Disable IM tests. --- mysql-test/t/disabled.def | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index b41875fe740..b536d35c01e 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -11,17 +11,14 @@ ############################################################################## user_limits : Bug#23921 random failure of user_limits.test -# -# Temporary enable IM tests to catch the assert. -# -# im_options : Bug#20294 2006-07-24 stewart Instance manager test im_options fails randomly -# im_daemon_life_cycle : Bug#20294 2007-05-14 alik Instance manager tests fail randomly -# im_cmd_line : Bug#20294 2007-05-14 alik Instance manager tests fail randomly -# im_utils : Bug#20294 2007-05-30 alik Instance manager tests fail randomly -# im_instance_conf : Bug#20294 2007-05-30 alik Instance manager tests fail randomly -# im_life_cycle : BUG#27851 Instance manager dies on ASSERT in ~Thread_registry() or from not being able to close a mysqld instance. -# im_instance_conf : BUG#28743 Instance manager generates warnings in test suite -# im_utils : BUG#28743 Instance manager generates warnings in test suite +im_options : Bug#20294 2006-07-24 stewart Instance manager test im_options fails randomly +im_daemon_life_cycle : Bug#20294 2007-05-14 alik Instance manager tests fail randomly +im_cmd_line : Bug#20294 2007-05-14 alik Instance manager tests fail randomly +im_utils : Bug#20294 2007-05-30 alik Instance manager tests fail randomly +im_instance_conf : Bug#20294 2007-05-30 alik Instance manager tests fail randomly +im_life_cycle : BUG#27851 Instance manager dies on ASSERT in ~Thread_registry() or from not being able to close a mysqld instance. +im_instance_conf : BUG#28743 Instance manager generates warnings in test suite +im_utils : BUG#28743 Instance manager generates warnings in test suite concurrent_innodb : BUG#21579 2006-08-11 mleich innodb_concurrent random failures with varying differences ctype_big5 : BUG#26711 2007-06-21 Lars Test has never worked on Double Whopper From d9037b26e492a1bf56fcacb2358caa5850d0cc32 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Jul 2007 19:56:02 +0200 Subject: [PATCH 24/26] handler::ha_write_row_no_binlog() hack removed, existing table->no_replicate code is used instead --- sql/handler.cc | 13 ------------- sql/handler.h | 1 - sql/log.cc | 4 ++-- sql/sql_base.cc | 1 + 4 files changed, 3 insertions(+), 16 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index c4abfeea0a8..0da56350de5 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3654,19 +3654,6 @@ int handler::ha_write_row(uchar *buf) } -/** - Write a record to the engine bypassing row-level binary logging. - This method is used internally by the server for writing to - performance schema tables, which are never replicated. - TODO: Merge this function with ha_write_row(), and provide a way - to disable the binlog there. -*/ -int handler::ha_write_row_no_binlog(uchar *buf) -{ - return write_row(buf); -} - - int handler::ha_update_row(const uchar *old_data, uchar *new_data) { int error; diff --git a/sql/handler.h b/sql/handler.h index 06f0a2cf035..1992af5b1ad 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1158,7 +1158,6 @@ public: */ int ha_external_lock(THD *thd, int lock_type); int ha_write_row(uchar * buf); - int ha_write_row_no_binlog(uchar * buf); int ha_update_row(const uchar * old_data, uchar * new_data); int ha_delete_row(const uchar * buf); diff --git a/sql/log.cc b/sql/log.cc index c7a8037d4b5..4ca7e9d31fd 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -409,7 +409,7 @@ bool Log_to_csv_event_handler:: } /* log table entries are not replicated */ - if (table->file->ha_write_row_no_binlog(table->record[0])) + if (table->file->ha_write_row(table->record[0])) { struct tm start; localtime_r(&event_time, &start); @@ -612,7 +612,7 @@ bool Log_to_csv_event_handler:: goto err; /* log table entries are not replicated */ - if (table->file->ha_write_row_no_binlog(table->record[0])) + if (table->file->ha_write_row(table->record[0])) { struct tm start; localtime_r(¤t_time, &start); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5b63eac35dd..b471ff8a108 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7716,6 +7716,7 @@ open_performance_schema_table(THD *thd, TABLE_LIST *one_table, DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_PERFORMANCE); /* Make sure all columns get assigned to a default value */ table->use_all_columns(); + table->no_replicate= 1; } DBUG_RETURN(table); From 7a47324e11dc96fe127025c9b49149d693e96c5c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Jul 2007 23:01:44 -0600 Subject: [PATCH 25/26] Fixed ressource leak when activation of LOGGER failed. --- sql/log.cc | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index c7a8037d4b5..44804e09b38 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1096,37 +1096,46 @@ void LOGGER::init_general_log(uint general_log_printer) bool LOGGER::activate_log_handler(THD* thd, uint log_type) { + MYSQL_QUERY_LOG *file_log; bool res= FALSE; lock_exclusive(); switch (log_type) { case QUERY_LOG_SLOW: if (!opt_slow_log) { - file_log_handler->get_mysql_slow_log()-> - open_slow_log(sys_var_slow_log_path.value); - init_slow_log(log_output_options); + file_log= file_log_handler->get_mysql_slow_log(); + + file_log->open_slow_log(sys_var_slow_log_path.value); if (table_log_handler->activate_log(thd, QUERY_LOG_SLOW)) { /* Error printed by open table in activate_log() */ res= TRUE; + file_log->close(0); } else + { + init_slow_log(log_output_options); opt_slow_log= TRUE; + } } break; case QUERY_LOG_GENERAL: if (!opt_log) { - file_log_handler->get_mysql_log()-> - open_query_log(sys_var_general_log_path.value); - init_general_log(log_output_options); + file_log= file_log_handler->get_mysql_log(); + + file_log->open_query_log(sys_var_general_log_path.value); if (table_log_handler->activate_log(thd, QUERY_LOG_GENERAL)) { /* Error printed by open table in activate_log() */ res= TRUE; + file_log->close(0); } else + { + init_general_log(log_output_options); opt_log= TRUE; + } } break; default: From 5404ba422e35d75054d3941b6e52f237fbb46e91 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 31 Jul 2007 20:52:43 +0400 Subject: [PATCH 26/26] Post-merge fixes. sql/sql_base.cc: Fix an incorrect manual merge. --- sql/sql_base.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f85f3a2884a..05c65d63d19 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1701,18 +1701,18 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list) @retval FALSE the table was found and dropped successfully. */ -bool close_temporary_table(THD *thd, const char *db, const char *table_name) +bool close_temporary_table(THD *thd, TABLE_LIST *table_list) { TABLE *table; if (!(table= find_temporary_table(thd, table_list))) return 1; - close_temporary_table(thd, table, 1, 1); /* If LOCK TABLES list is not empty and contains this table, unlock the table and remove the table from this list. */ mysql_lock_remove(thd, thd->locked_tables, table, FALSE); + close_temporary_table(thd, table, 1, 1); return 0; }