From d63d8cb1a3c3a3365e9d1705a98b2701e5d4a86c Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Thu, 2 Aug 2007 03:32:54 +0400 Subject: [PATCH 01/12] Add a test case for Bug#18287 create federated table always times out, error 1159 ' ' (fixed by the patch for Bug 25679) --- mysql-test/r/federated.result | 14 ++++++++++++++ mysql-test/t/federated.test | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result index f4750fed201..c6884216e56 100644 --- a/mysql-test/r/federated.result +++ b/mysql-test/r/federated.result @@ -1883,6 +1883,20 @@ a b 2 Curly drop table federated.t1; drop table federated.t1; + +Bug#18287 create federated table always times out, error 1159 ' ' + +Test that self-references work + +create table federated.t1 (a int primary key); +create table federated.t2 (a int primary key) +ENGINE=FEDERATED +connection='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +insert into federated.t1 (a) values (1); +select * from federated.t2; +a +1 +drop table federated.t1, federated.t2; DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test index a3750cb572d..59cd4f3e6a6 100644 --- a/mysql-test/t/federated.test +++ b/mysql-test/t/federated.test @@ -1631,5 +1631,19 @@ drop table federated.t1; connection slave; drop table federated.t1; +--echo +--echo Bug#18287 create federated table always times out, error 1159 ' ' +--echo +--echo Test that self-references work +--echo +connection slave; +create table federated.t1 (a int primary key); +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval create table federated.t2 (a int primary key) + ENGINE=FEDERATED + connection='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; +insert into federated.t1 (a) values (1); +select * from federated.t2; +drop table federated.t1, federated.t2; source include/federated_cleanup.inc; From ea3388f2b25c560b500046ad48faa41675af60a3 Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Thu, 2 Aug 2007 13:59:02 +0400 Subject: [PATCH 02/12] Add a test case for Bug#5719 "impossible to lock VIEW". It has been possible to lock a view in 5.1 for some time. --- mysql-test/r/lock.result | 70 ++++++++++++++++++++++++++++++++++++++++ mysql-test/t/lock.test | 65 +++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) diff --git a/mysql-test/r/lock.result b/mysql-test/r/lock.result index e2000a9ec91..6152e403637 100644 --- a/mysql-test/r/lock.result +++ b/mysql-test/r/lock.result @@ -96,4 +96,74 @@ ERROR HY000: You can't combine write-locking of system tables with other tables LOCK TABLES mysql.time_zone READ, mysql.proc WRITE; ERROR HY000: You can't combine write-locking of system tables with other tables or lock types DROP TABLE t1; + +Bug#5719 impossible to lock VIEW + +Just covering existing behaviour with tests. +Consistency has not been found here. + +drop view if exists v_bug5719; +drop table if exists t1, t2, t3; +create table t1 (a int); +create temporary table t2 (a int); +create table t3 (a int); +create view v_bug5719 as select 1; +lock table v_bug5719 write; +select * from t1; +ERROR HY000: Table 't1' was not locked with LOCK TABLES + +Allowed to select from a temporary talbe under LOCK TABLES + +select * from t2; +a +select * from t3; +ERROR HY000: Table 't3' was not locked with LOCK TABLES +select * from v_bug5719; +1 +1 +drop view v_bug5719; + +sic: did not left LOCK TABLES mode automatically + +select * from t1; +ERROR HY000: Table 't1' was not locked with LOCK TABLES +unlock tables; +create view v_bug5719 as select * from t1; +lock tables v_bug5719 write; +select * from v_bug5719; +a + +Allowed to use an underlying table under LOCK TABLES + +select * from t1; +a + +Allowed to select from a temporary table under LOCK TABLES + +select * from t2; +a +select * from t3; +ERROR HY000: Table 't3' was not locked with LOCK TABLES +drop table t1; + +sic: left LOCK TABLES mode + +select * from t3; +a +select * from v_bug5719; +ERROR HY000: View 'test.v_bug5719' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +unlock tables; +drop view v_bug5719; + +When limitation to use temporary tables in views is removed, please +add a test that shows what happens under LOCK TABLES when a view +references a temporary table, is locked, and the underlying table +is dropped. + +create view v_bug5719 as select * from t2; +ERROR HY000: View's SELECT refers to a temporary table 't2' + +Cleanup. + +drop table t2, t3; End of 5.1 tests. diff --git a/mysql-test/t/lock.test b/mysql-test/t/lock.test index 2b8b430f096..6069bbf7018 100644 --- a/mysql-test/t/lock.test +++ b/mysql-test/t/lock.test @@ -148,5 +148,70 @@ LOCK TABLES mysql.time_zone READ, mysql.proc WRITE; DROP TABLE t1; +--echo +--echo Bug#5719 impossible to lock VIEW +--echo +--echo Just covering existing behaviour with tests. +--echo Consistency has not been found here. +--echo +--disable_warnings +drop view if exists v_bug5719; +drop table if exists t1, t2, t3; +--enable_warnings +create table t1 (a int); +create temporary table t2 (a int); +create table t3 (a int); +create view v_bug5719 as select 1; +lock table v_bug5719 write; +--error ER_TABLE_NOT_LOCKED +select * from t1; +--echo +--echo Allowed to select from a temporary talbe under LOCK TABLES +--echo +select * from t2; +--error ER_TABLE_NOT_LOCKED +select * from t3; +select * from v_bug5719; +drop view v_bug5719; +--echo +--echo sic: did not left LOCK TABLES mode automatically +--echo +--error ER_TABLE_NOT_LOCKED +select * from t1; +unlock tables; +create view v_bug5719 as select * from t1; +lock tables v_bug5719 write; +select * from v_bug5719; +--echo +--echo Allowed to use an underlying table under LOCK TABLES +--echo +select * from t1; +--echo +--echo Allowed to select from a temporary table under LOCK TABLES +--echo +select * from t2; +--error ER_TABLE_NOT_LOCKED +select * from t3; +drop table t1; +--echo +--echo sic: left LOCK TABLES mode +--echo +select * from t3; +--error ER_VIEW_INVALID +select * from v_bug5719; +unlock tables; +drop view v_bug5719; +--echo +--echo When limitation to use temporary tables in views is removed, please +--echo add a test that shows what happens under LOCK TABLES when a view +--echo references a temporary table, is locked, and the underlying table +--echo is dropped. +--echo +--error ER_VIEW_SELECT_TMPTABLE +create view v_bug5719 as select * from t2; +--echo +--echo Cleanup. +--echo +drop table t2, t3; --echo End of 5.1 tests. From e76351df1ac157079727e63d673a432c5aedcee4 Mon Sep 17 00:00:00 2001 From: "anozdrin/alik@ibm." <> Date: Fri, 3 Aug 2007 11:50:17 +0400 Subject: [PATCH 03/12] Fix for BUG#30123: mysqldump is unable to work with old servers. New server (as of 5.1.21) provides new features: - SHOW CREATE TRIGGER; - character set information for SHOW TRIGGERS and SHOW CREATE EVENT | FUNCTION | PROCEDURE statements. Mysqldump uses these features to generate proper dump. The bug happened when new mysqldump was used to dump older servers. The problem was that 5.1.21 new features are not available, so mysqldump exited with error code or just crashed. The fix is to detect if mysqldump has ben run against older server and don't use new 5.1.21 functionality in this case. Certainly, the dump generated for the older server suffers from the character set problems fixed by BUG#16291 and the like. --- client/mysqldump.c | 556 ++++++++++++++++++++++++++++++--------------- 1 file changed, 373 insertions(+), 183 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index cfdde285040..9cb1c640d7b 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1227,6 +1227,125 @@ static int switch_character_set_results(MYSQL *mysql, const char *cs_name) return mysql_real_query(mysql, query_buffer, query_length); } +/** + Rewrite CREATE TRIGGER statement, enclosing DEFINER clause in + version-specific comment. + + This function parses the CREATE TRIGGER statement and encloses + DEFINER-clause in version-specific comment: + input query: CREATE DEFINER=a@b TRIGGER ... + rewritten query: CREATE * / / *!50017 DEFINER=a@b * / / *!50003 TRIGGER ... + + @note This function will go away when WL#3995 is implemented. + + @param[in] trigger_def_str CREATE TRIGGER statement string. + @param[in] trigger_def_length length of the trigger_def_str. + + @return pointer to the new allocated query string. +*/ + +static char *cover_definer_clause_in_trigger(const char *trigger_def_str, + uint trigger_def_length) +{ + char *query_str= NULL; + char *definer_begin= my_case_str(trigger_def_str, trigger_def_length, + C_STRING_WITH_LEN(" DEFINER")); + char *definer_end; + + if (!definer_begin) + return NULL; + + definer_end= my_case_str(definer_begin, strlen(definer_begin), + C_STRING_WITH_LEN(" TRIGGER")); + + if (definer_end) + { + char *query_str_tail; + + /* + Allocate memory for new query string: original string + from SHOW statement and version-specific comments. + */ + query_str= alloc_query_str(trigger_def_length + 23); + + query_str_tail= strnmov(query_str, + trigger_def_str, + definer_begin - trigger_def_str); + + query_str_tail= strmov(query_str_tail, + "*/ /*!50017"); + + query_str_tail= strnmov(query_str_tail, + definer_begin, + definer_end - definer_begin); + + query_str_tail= strxmov(query_str_tail, + "*/ /*!50003", + definer_end, + NullS); + } + + return query_str; +} + +/** + Rewrite CREATE FUNCTION or CREATE PROCEDURE statement, enclosing DEFINER + clause in version-specific comment. + + This function parses the CREATE FUNCTION | PROCEDURE statement and + encloses DEFINER-clause in version-specific comment: + input query: CREATE DEFINER=a@b FUNCTION ... + rewritten query: CREATE * / / *!50020 DEFINER=a@b * / / *!50003 FUNCTION ... + + @note This function will go away when WL#3995 is implemented. + + @param[in] def_str CREATE FUNCTION|PROCEDURE statement string. + @param[in] def_length length of the def_str. + + @return pointer to the new allocated query string. +*/ + +static char *cover_definer_clause_in_sp(const char *def_str, + uint def_str_length) +{ + char *query_str= NULL; + char *definer_begin= my_case_str(def_str, def_str_length, + C_STRING_WITH_LEN(" DEFINER")); + char *definer_end; + + if (!definer_begin) + return NULL; + + definer_end= my_case_str(definer_begin, strlen(definer_begin), + C_STRING_WITH_LEN(" PROCEDURE")); + + if (!definer_end) + { + definer_end= my_case_str(definer_begin, strlen(definer_begin), + C_STRING_WITH_LEN(" FUNCTION")); + } + + if (definer_end) + { + char *query_str_tail; + + /* + Allocate memory for new query string: original string + from SHOW statement and version-specific comments. + */ + query_str= alloc_query_str(def_str_length + 23); + + query_str_tail= strnmov(query_str, def_str, definer_begin - def_str); + query_str_tail= strmov(query_str_tail, "*/ /*!50020"); + query_str_tail= strnmov(query_str_tail, definer_begin, + definer_end - definer_begin); + query_str_tail= strxmov(query_str_tail, "*/ /*!50003", + definer_end, NullS); + } + + return query_str; +} + /* Open a new .sql file to dump the table or view into @@ -1766,16 +1885,36 @@ static uint dump_events_for_db(char *db) fprintf(sql_file, "DELIMITER %s\n", delimiter); - if (switch_db_collation(sql_file, db_name_buff, delimiter, db_cl_name, - row[6], &db_cl_altered)) + if (mysql_num_fields(event_res) >= 7) { - DBUG_RETURN(1); - } + if (switch_db_collation(sql_file, db_name_buff, delimiter, + db_cl_name, row[6], &db_cl_altered)) + { + DBUG_RETURN(1); + } - switch_cs_variables(sql_file, delimiter, - row[4], /* character_set_client */ - row[4], /* character_set_results */ - row[5]); /* collation_connection */ + switch_cs_variables(sql_file, delimiter, + row[4], /* character_set_client */ + row[4], /* character_set_results */ + row[5]); /* collation_connection */ + } + else + { + /* + mysqldump is being run against the server, that does not + provide character set information in SHOW CREATE + statements. + + NOTE: the dump may be incorrect, since character set + information is required in order to restore event properly. + */ + + fprintf(sql_file, + "--\n" + "-- WARNING: old server version. " + "The following dump may be incomplete.\n" + "--\n"); + } switch_sql_mode(sql_file, delimiter, row[1]); @@ -1788,13 +1927,17 @@ static uint dump_events_for_db(char *db) restore_time_zone(sql_file, delimiter); restore_sql_mode(sql_file, delimiter); - restore_cs_variables(sql_file, delimiter); - if (db_cl_altered) + if (mysql_num_fields(event_res) >= 7) { - if (restore_db_collation(sql_file, db_name_buff, delimiter, - db_cl_name)) - DBUG_RETURN(1); + restore_cs_variables(sql_file, delimiter); + + if (db_cl_altered) + { + if (restore_db_collation(sql_file, db_name_buff, delimiter, + db_cl_name)) + DBUG_RETURN(1); + } } } } /* end of event printing */ @@ -1929,74 +2072,44 @@ static uint dump_routines_for_db(char *db) } else if (strlen(row[2])) { - char *query_str= NULL; - char *definer_begin; - if (opt_drop) fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;\n", routine_type[i], routine_name); - /* - Cover DEFINER-clause in version-specific comments. + char *query_str= cover_definer_clause_in_sp(row[2], strlen(row[2])); - TODO: this is definitely a BAD IDEA to parse SHOW CREATE output. - However, we can not use INFORMATION_SCHEMA instead: - 1. INFORMATION_SCHEMA provides data in UTF8, but here we - need data in the original character set; - 2. INFORMATION_SCHEMA does not provide information about - routine parameters now. - */ - - definer_begin= my_case_str(row[2], strlen(row[2]), - C_STRING_WITH_LEN(" DEFINER")); - - if (definer_begin) + if (mysql_num_fields(routine_res) >= 6) { - char *definer_end= my_case_str(definer_begin, - strlen(definer_begin), - C_STRING_WITH_LEN(" PROCEDURE")); - - if (!definer_end) + if (switch_db_collation(sql_file, db_name_buff, ";", + db_cl_name, row[5], &db_cl_altered)) { - definer_end= my_case_str(definer_begin, strlen(definer_begin), - C_STRING_WITH_LEN(" FUNCTION")); + DBUG_RETURN(1); } - if (definer_end) - { - char *query_str_tail; - - /* - Allocate memory for new query string: original string - from SHOW statement and version-specific comments. - */ - query_str= alloc_query_str(strlen(row[2]) + 23); - - query_str_tail= strnmov(query_str, row[2], - definer_begin - row[2]); - query_str_tail= strmov(query_str_tail, "*/ /*!50020"); - query_str_tail= strnmov(query_str_tail, definer_begin, - definer_end - definer_begin); - query_str_tail= strxmov(query_str_tail, "*/ /*!50003", - definer_end, NullS); - } + switch_cs_variables(sql_file, ";", + row[3], /* character_set_client */ + row[3], /* character_set_results */ + row[4]); /* collation_connection */ } - - /* - we need to change sql_mode only for the CREATE - PROCEDURE/FUNCTION otherwise we may need to re-quote routine_name - */ - - if (switch_db_collation(sql_file, db_name_buff, ";", - db_cl_name, row[5], &db_cl_altered)) + else { - DBUG_RETURN(1); + /* + mysqldump is being run against the server, that does not + provide character set information in SHOW CREATE + statements. + + NOTE: the dump may be incorrect, since character set + information is required in order to restore stored + procedure/function properly. + */ + + fprintf(sql_file, + "--\n" + "-- WARNING: old server version. " + "The following dump may be incomplete.\n" + "--\n"); } - switch_cs_variables(sql_file, ";", - row[3], /* character_set_client */ - row[3], /* character_set_results */ - row[4]); /* collation_connection */ switch_sql_mode(sql_file, ";", row[1]); @@ -2007,12 +2120,16 @@ static uint dump_routines_for_db(char *db) (const char *) (query_str != NULL ? query_str : row[2])); restore_sql_mode(sql_file, ";"); - restore_cs_variables(sql_file, ";"); - if (db_cl_altered) + if (mysql_num_fields(routine_res) > 3) { - if (restore_db_collation(sql_file, db_name_buff, ";", db_cl_name)) - DBUG_RETURN(1); + restore_cs_variables(sql_file, ";"); + + if (db_cl_altered) + { + if (restore_db_collation(sql_file, db_name_buff, ";", db_cl_name)) + DBUG_RETURN(1); + } } my_free(query_str, MYF(MY_ALLOW_ZERO_PTR)); @@ -2551,153 +2668,212 @@ continue_xml: DBUG_RETURN((uint) num_fields); } /* get_table_structure */ +static void dump_trigger_old(MYSQL_RES *show_triggers_rs, + MYSQL_ROW *show_trigger_row, + const char *table_name) +{ + FILE *sql_file= md_result_file; -/* + char quoted_table_name_buf[NAME_LEN * 2 + 3]; + char *quoted_table_name= quote_name(table_name, quoted_table_name_buf, 1); - dump_triggers_for_table + char name_buff[NAME_LEN * 4 + 3]; - Dumps the triggers given a table/db name. This should be called after - the tables have been dumped in case a trigger depends on the existence - of a table + DBUG_ENTER("dump_trigger_old"); + fprintf(sql_file, + "--\n" + "-- WARNING: old server version. " + "The following dump may be incomplete.\n" + "--\n"); + + if (opt_compact) + fprintf(sql_file, "/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n"); + + fprintf(sql_file, + "DELIMITER ;;\n" + "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n" + "/*!50003 CREATE */ ", + (*show_trigger_row)[6]); + + if (mysql_num_fields(show_triggers_rs) > 7) + { + /* + mysqldump can be run against the server, that does not support + definer in triggers (there is no DEFINER column in SHOW TRIGGERS + output). So, we should check if we have this column before + accessing it. + */ + + uint user_name_len; + char user_name_str[USERNAME_LENGTH + 1]; + char quoted_user_name_str[USERNAME_LENGTH * 2 + 3]; + uint host_name_len; + char host_name_str[HOSTNAME_LENGTH + 1]; + char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; + + parse_user((*show_trigger_row)[7], + strlen((*show_trigger_row)[7]), + user_name_str, &user_name_len, + host_name_str, &host_name_len); + + fprintf(sql_file, + "/*!50017 DEFINER=%s@%s */ ", + quote_name(user_name_str, quoted_user_name_str, FALSE), + quote_name(host_name_str, quoted_host_name_str, FALSE)); + } + + fprintf(sql_file, + "/*!50003 TRIGGER %s %s %s ON %s FOR EACH ROW%s%s */;;\n" + "DELIMITER ;\n", + quote_name((*show_trigger_row)[0], name_buff, 0), /* Trigger */ + (*show_trigger_row)[4], /* Timing */ + (*show_trigger_row)[1], /* Event */ + quoted_table_name, + (strchr(" \t\n\r", *((*show_trigger_row)[3]))) ? "" : " ", + (*show_trigger_row)[3] /* Statement */); + + if (opt_compact) + fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n"); + + DBUG_VOID_RETURN; +} + +static int dump_trigger(MYSQL_RES *show_create_trigger_rs, + const char *db_name, + const char *db_cl_name) +{ + FILE *sql_file= md_result_file; + MYSQL_ROW row; + int db_cl_altered; + + DBUG_ENTER("dump_trigger"); + + while ((row= mysql_fetch_row(show_create_trigger_rs))) + { + char *query_str= cover_definer_clause_in_trigger(row[2], strlen(row[2])); + + + if (switch_db_collation(sql_file, db_name, ";", + db_cl_name, row[5], &db_cl_altered)) + DBUG_RETURN(TRUE); + + switch_cs_variables(sql_file, ";", + row[3], /* character_set_client */ + row[3], /* character_set_results */ + row[4]); /* collation_connection */ + + switch_sql_mode(sql_file, ";", row[1]); + + fprintf(sql_file, + "DELIMITER ;;\n" + "/*!50003 %s */;;\n" + "DELIMITER ;\n", + (const char *) (query_str != NULL ? query_str : row[2])); + + restore_sql_mode(sql_file, ";"); + restore_cs_variables(sql_file, ";"); + + if (db_cl_altered) + { + if (restore_db_collation(sql_file, db_name, ";", db_cl_name)) + DBUG_RETURN(TRUE); + } + + my_free(query_str, MYF(MY_ALLOW_ZERO_PTR)); + } + + DBUG_RETURN(FALSE); +} + +/** + Dump the triggers for a given table. + + This should be called after the tables have been dumped in case a trigger + depends on the existence of a table. + + @param[in] table_name + @param[in] db_name + + @return Error status. + @retval TRUE error has occurred. + @retval FALSE operation succeed. */ -static void dump_triggers_for_table(char *table, char *db_name) +static int dump_triggers_for_table(char *table_name, char *db_name) { - char *result_table; - char name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3]; - char query_buff[QUERY_LENGTH]; - uint old_opt_compatible_mode=opt_compatible_mode; FILE *sql_file= md_result_file; - MYSQL_RES *result; + char name_buff[NAME_LEN*4+3]; + char query_buff[QUERY_LENGTH]; + uint old_opt_compatible_mode= opt_compatible_mode; + MYSQL_RES *show_triggers_rs; MYSQL_ROW row; char db_cl_name[MY_CS_NAME_SIZE]; - int db_cl_altered; DBUG_ENTER("dump_triggers_for_table"); - DBUG_PRINT("enter", ("db: %s, table: %s", db_name, table)); + DBUG_PRINT("enter", ("db: %s, table_name: %s", db_name, table_name)); /* Do not use ANSI_QUOTES on triggers in dump */ opt_compatible_mode&= ~MASK_ANSI_QUOTES; - result_table= quote_name(table, table_buff, 1); - - my_snprintf(query_buff, sizeof(query_buff), - "SHOW TRIGGERS LIKE %s", - quote_for_like(table, name_buff)); - - if (mysql_query_with_error_report(mysql, &result, query_buff)) - { - if (path) - my_fclose(sql_file, MYF(MY_WME)); - DBUG_VOID_RETURN; - } /* Get database collation. */ if (fetch_db_collation(db_name, db_cl_name, sizeof (db_cl_name))) - DBUG_VOID_RETURN; + DBUG_RETURN(TRUE); - if (switch_character_set_results(mysql, "binary")) - DBUG_VOID_RETURN; + /* Get list of triggers. */ + + my_snprintf(query_buff, sizeof(query_buff), + "SHOW TRIGGERS LIKE %s", + quote_for_like(table_name, name_buff)); + + if (mysql_query_with_error_report(mysql, &show_triggers_rs, query_buff)) + DBUG_RETURN(TRUE); + + if (mysql_num_rows(show_triggers_rs)) + fprintf(sql_file, "\n"); /* Dump triggers. */ - while ((row= mysql_fetch_row(result))) + while ((row= mysql_fetch_row(show_triggers_rs))) { - MYSQL_RES *res2; my_snprintf(query_buff, sizeof (query_buff), "SHOW CREATE TRIGGER %s", quote_name(row[0], name_buff, TRUE)); - if (mysql_query_with_error_report(mysql, &res2, query_buff)) + if (mysql_query(mysql, query_buff)) { - if (path) - my_fclose(sql_file, MYF(MY_WME)); - maybe_exit(EX_MYSQLERR); - DBUG_VOID_RETURN; - } - - while ((row= mysql_fetch_row(res2))) - { - char *query_str= NULL; - char *definer_begin; - /* - Cover DEFINER-clause in version-specific comments. + mysqldump is being run against old server, that does not support + SHOW CREATE TRIGGER statement. We should use SHOW TRIGGERS output. - TODO: this is definitely a BAD IDEA to parse SHOW CREATE output. - However, we can not use INFORMATION_SCHEMA instead: - 1. INFORMATION_SCHEMA provides data in UTF8, but here we - need data in the original character set; - 2. INFORMATION_SCHEMA does not provide information about - routine parameters now. + NOTE: the dump may be incorrect, as old SHOW TRIGGERS does not + provide all the necessary information to restore trigger properly. */ - definer_begin= my_case_str(row[2], strlen(row[2]), - C_STRING_WITH_LEN(" DEFINER")); - - if (definer_begin) - { - char *definer_end= my_case_str(definer_begin, strlen(definer_begin), - C_STRING_WITH_LEN(" TRIGGER")); - - if (definer_end) - { - char *query_str_tail; - - /* - Allocate memory for new query string: original string - from SHOW statement and version-specific comments. - */ - query_str= alloc_query_str(strlen(row[2]) + 23); - - query_str_tail= strnmov(query_str, row[2], - definer_begin - row[2]); - query_str_tail= strmov(query_str_tail, "*/ /*!50017"); - query_str_tail= strnmov(query_str_tail, definer_begin, - definer_end - definer_begin); - query_str_tail= strxmov(query_str_tail, "*/ /*!50003", - definer_end, NullS); - } - } - - if (switch_db_collation(sql_file, db_name, ";", - db_cl_name, row[5], &db_cl_altered)) - DBUG_VOID_RETURN; - - switch_cs_variables(sql_file, ";", - row[3], /* character_set_client */ - row[3], /* character_set_results */ - row[4]); /* collation_connection */ - - switch_sql_mode(sql_file, ";", row[1]); - - fprintf(sql_file, - "DELIMITER ;;\n" - "/*!50003 %s */;;\n" - "DELIMITER ;\n", - (const char *) (query_str != NULL ? query_str : row[2])); - - restore_sql_mode(sql_file, ";"); - restore_cs_variables(sql_file, ";"); - - if (db_cl_altered) - { - if (restore_db_collation(sql_file, db_name, ";", db_cl_name)) - DBUG_VOID_RETURN; - } - - my_free(query_str, MYF(MY_ALLOW_ZERO_PTR)); + dump_trigger_old(show_triggers_rs, &row, table_name); } - mysql_free_result(res2); + else + { + MYSQL_RES *show_create_trigger_rs= mysql_store_result(mysql); + + if (!show_create_trigger_rs || + dump_trigger(show_create_trigger_rs, db_name, db_cl_name)) + { + DBUG_RETURN(TRUE); + } + + mysql_free_result(show_create_trigger_rs); + } + } - mysql_free_result(result); + if (mysql_num_rows(show_triggers_rs)) + fprintf(sql_file, "\n"); - if (switch_character_set_results(mysql, default_charset)) - DBUG_VOID_RETURN; + mysql_free_result(show_triggers_rs); /* make sure to set back opt_compatible mode to @@ -2705,7 +2881,7 @@ static void dump_triggers_for_table(char *table, char *db_name) */ opt_compatible_mode=old_opt_compatible_mode; - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } static void add_load_option(DYNAMIC_STRING *str, const char *option, @@ -3775,7 +3951,14 @@ static int dump_all_tables_in_db(char *database) order_by= 0; if (opt_dump_triggers && ! opt_xml && mysql_get_server_version(mysql) >= 50009) - dump_triggers_for_table(table, database); + { + if (dump_triggers_for_table(table, database)) + { + if (path) + my_fclose(md_result_file, MYF(MY_WME)); + maybe_exit(EX_MYSQLERR); + } + } } } if (opt_events && !opt_xml && @@ -3985,7 +4168,14 @@ static int dump_selected_tables(char *db, char **table_names, int tables) dump_table(*pos, db); if (opt_dump_triggers && mysql_get_server_version(mysql) >= 50009) - dump_triggers_for_table(*pos, db); + { + if (dump_triggers_for_table(*pos, db)) + { + if (path) + my_fclose(md_result_file, MYF(MY_WME)); + maybe_exit(EX_MYSQLERR); + } + } } /* Dump each selected view */ From a43431b3a1118154ec9b853d8909f3f2ddfecde9 Mon Sep 17 00:00:00 2001 From: "dlenev@mockturtle.local" <> Date: Sun, 5 Aug 2007 13:17:07 +0400 Subject: [PATCH 04/12] Fix for bug #21281 "Pending write lock is incorrectly removed when its statement being KILLed". When statement which was trying to obtain write lock on then table and which was blocked by existing read lock was killed, concurrent statements that were trying to obtain read locks on the same table and that were blocked by the presence of this pending write lock were not woken up and had to wait until this first read lock goes away. This problem was caused by the fact that we forgot to wake up threads which pending requests could have been satisfied after removing lock request for the killed thread. The patch solves the problem by waking up those threads in such situation. Test for this bug will be added to 5.1 only as it has much better facilities for its implementation. Particularly, by using I_S.PROCESSLIST and wait_condition.inc script we can wait until thread will be blocked on certain table lock without relying on unconditional sleep (which usage increases time needed for test runs and might cause spurious test failures on slower platforms). --- mysys/thr_lock.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 93884921687..02c9f08c946 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -383,6 +383,9 @@ static inline my_bool have_specific_lock(THR_LOCK_DATA *data, } +static void wake_up_waiters(THR_LOCK *lock); + + static enum enum_thr_lock_result wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, my_bool in_wait_list) @@ -444,8 +447,13 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, else wait->last=data->prev; data->type= TL_UNLOCK; /* No lock */ + check_locks(data->lock, "killed or timed out wait_for_lock", 1); + wake_up_waiters(data->lock); + } + else + { + check_locks(data->lock, "aborted wait_for_lock", 0); } - check_locks(data->lock,"failed wait_for_lock",0); } else { @@ -771,6 +779,26 @@ void thr_unlock(THR_LOCK_DATA *data) lock->read_no_write_count--; data->type=TL_UNLOCK; /* Mark unlocked */ check_locks(lock,"after releasing lock",1); + wake_up_waiters(lock); + pthread_mutex_unlock(&lock->mutex); + DBUG_VOID_RETURN; +} + + +/** + @brief Wake up all threads which pending requests for the lock + can be satisfied. + + @param lock Lock for which threads should be woken up + +*/ + +static void wake_up_waiters(THR_LOCK *lock) +{ + THR_LOCK_DATA *data; + enum thr_lock_type lock_type; + + DBUG_ENTER("wake_up_waiters"); if (!lock->write.data) /* If no active write locks */ { @@ -820,11 +848,7 @@ void thr_unlock(THR_LOCK_DATA *data) data=lock->write_wait.data; /* Free this too */ } if (data->type >= TL_WRITE_LOW_PRIORITY) - { - check_locks(lock,"giving write lock",0); - pthread_mutex_unlock(&lock->mutex); - DBUG_VOID_RETURN; - } + goto end; /* Release possible read locks together with the write lock */ } if (lock->read_wait.data) @@ -879,8 +903,7 @@ void thr_unlock(THR_LOCK_DATA *data) free_all_read_locks(lock,0); } end: - check_locks(lock,"thr_unlock",0); - pthread_mutex_unlock(&lock->mutex); + check_locks(lock, "after waking up waiters", 0); DBUG_VOID_RETURN; } @@ -1094,6 +1117,7 @@ my_bool thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread) lock->write_wait.last= data->prev; } } + wake_up_waiters(lock); pthread_mutex_unlock(&lock->mutex); DBUG_RETURN(found); } From c3e3a5e1889ed9f2ad7052daa173cbcb949eb01b Mon Sep 17 00:00:00 2001 From: "dlenev@mockturtle.local" <> Date: Sun, 5 Aug 2007 13:55:37 +0400 Subject: [PATCH 05/12] Added test for bug #21281 "Pending write lock is incorrectly removed when its statement being KILLed". The bug itself was fixed by separate patch in 5.0 tree. --- mysql-test/r/lock_multi.result | 10 ++++++++++ mysql-test/t/lock_multi.test | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index 2445b3e0c69..a3f7ab4505c 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -95,3 +95,13 @@ alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // unlock tables; drop table t1; +create table t1 (i int); +lock table t1 read; +update t1 set i= 10;; +select * from t1;; +kill query ID; +i +ERROR 70100: Query execution was interrupted +unlock tables; +drop table t1; +End of 5.1 tests diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index 4a6b4ff5e56..b7c406f9637 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -270,3 +270,38 @@ drop table t1; # End of 5.0 tests + +# +# Bug #21281 "Pending write lock is incorrectly removed when its +# statement being KILLed" +# +create table t1 (i int); +connection locker; +lock table t1 read; +connection writer; +--send update t1 set i= 10; +connection reader; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Locked" and info = "update t1 set i= 10"; +--source include/wait_condition.inc +--send select * from t1; +connection default; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Locked" and info = "select * from t1"; +--source include/wait_condition.inc +let $ID= `select id from information_schema.processlist where state = "Locked" and info = "update t1 set i= 10"`; +--replace_result $ID ID +eval kill query $ID; +connection reader; +--reap +connection writer; +--error ER_QUERY_INTERRUPTED +--reap +connection locker; +unlock tables; +connection default; +drop table t1; + +--echo End of 5.1 tests From ec5464d2e0e91557575d1d812bbc82bf17160cd0 Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Mon, 6 Aug 2007 14:22:24 +0400 Subject: [PATCH 06/12] A fix and a test case for Bug#29306 "Truncated data in MS Access with decimal (3,1) columns in a VIEW". mysql_list_fields() C API function would incorrectly set MYSQL_FIELD::decimals member for some view columns. The problem was in an incomplete implementation of Item_ident_for_show::make_field(), which is responsible for view columns metadata. --- sql/item.cc | 2 +- tests/mysql_client_test.c | 54 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 2fc58eebe75..e286c5e501c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1621,7 +1621,7 @@ void Item_ident_for_show::make_field(Send_field *tmp_field) tmp_field->type=field->type(); tmp_field->flags= field->table->maybe_null ? (field->flags & ~NOT_NULL_FLAG) : field->flags; - tmp_field->decimals= 0; + tmp_field->decimals= field->decimals(); } /**********************************************/ diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 75c86902972..cbeea064ffd 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -15570,7 +15570,7 @@ static void test_bug27876() int rc; MYSQL_RES *result; - char utf8_func[] = + unsigned char utf8_func[] = { 0xd1, 0x84, 0xd1, 0x83, 0xd0, 0xbd, 0xd0, 0xba, 0xd1, 0x86, 0xd0, 0xb8, 0xd0, 0xb9, 0xd0, 0xba, @@ -15578,7 +15578,7 @@ static void test_bug27876() 0x00 }; - char utf8_param[] = + unsigned char utf8_param[] = { 0xd0, 0xbf, 0xd0, 0xb0, 0xd1, 0x80, 0xd0, 0xb0, 0xd0, 0xbc, 0xd0, 0xb5, 0xd1, 0x82, 0xd1, 0x8a, @@ -15735,6 +15735,55 @@ static void test_bug27592() } +/** + Bug#29306 Truncated data in MS Access with decimal (3,1) columns in a VIEW +*/ + +static void test_bug29306() +{ + MYSQL_FIELD *field; + int rc; + MYSQL_RES *res; + + DBUG_ENTER("test_bug29306"); + myheader("test_bug29306"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS tab17557"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW IF EXISTS view17557"); + myquery(rc); + rc= mysql_query(mysql, "CREATE TABLE tab17557 (dd decimal (3,1))"); + myquery(rc); + rc= mysql_query(mysql, "CREATE VIEW view17557 as SELECT dd FROM tab17557"); + myquery(rc); + rc= mysql_query(mysql, "INSERT INTO tab17557 VALUES (7.6)"); + myquery(rc); + + /* Checking the view */ + res= mysql_list_fields(mysql, "view17557", NULL); + while ((field= mysql_fetch_field(res))) + { + if (! opt_silent) + { + printf("field name %s\n", field->name); + printf("field table %s\n", field->table); + printf("field decimals %d\n", field->decimals); + if (field->decimals < 1) + printf("Error! No decimals! \n"); + printf("\n\n"); + } + DIE_UNLESS(field->decimals == 1); + } + mysql_free_result(res); + + rc= mysql_query(mysql, "DROP TABLE tab17557"); + myquery(rc); + rc= mysql_query(mysql, "DROP VIEW view17557"); + myquery(rc); + + DBUG_VOID_RETURN; +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -16019,6 +16068,7 @@ static struct my_tests_st my_tests[]= { { "test_bug28505", test_bug28505 }, { "test_bug28934", test_bug28934 }, { "test_bug27592", test_bug27592 }, + { "test_bug29306", test_bug29306 }, { 0, 0 } }; From 0c4d8e0032eccef335449293e09742c015d11563 Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Mon, 6 Aug 2007 22:42:13 +0400 Subject: [PATCH 07/12] Fix failing ddl_i18n* tests in the team tree. --- client/mysqldump.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 9cb1c640d7b..b8933612db4 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2121,7 +2121,7 @@ static uint dump_routines_for_db(char *db) restore_sql_mode(sql_file, ";"); - if (mysql_num_fields(routine_res) > 3) + if (mysql_num_fields(routine_res) >= 6) { restore_cs_variables(sql_file, ";"); @@ -2819,6 +2819,9 @@ static int dump_triggers_for_table(char *table_name, char *db_name) /* Get database collation. */ + if (switch_character_set_results(mysql, "binary")) + DBUG_RETURN(TRUE); + if (fetch_db_collation(db_name, db_cl_name, sizeof (db_cl_name))) DBUG_RETURN(TRUE); @@ -2831,9 +2834,6 @@ static int dump_triggers_for_table(char *table_name, char *db_name) if (mysql_query_with_error_report(mysql, &show_triggers_rs, query_buff)) DBUG_RETURN(TRUE); - if (mysql_num_rows(show_triggers_rs)) - fprintf(sql_file, "\n"); - /* Dump triggers. */ while ((row= mysql_fetch_row(show_triggers_rs))) @@ -2870,11 +2870,11 @@ static int dump_triggers_for_table(char *table_name, char *db_name) } - if (mysql_num_rows(show_triggers_rs)) - fprintf(sql_file, "\n"); - mysql_free_result(show_triggers_rs); + if (switch_character_set_results(mysql, default_charset)) + DBUG_RETURN(TRUE); + /* make sure to set back opt_compatible mode to original value From 057ab256ccc00e5e5816a6299110f4d16062909b Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Mon, 6 Aug 2007 22:49:47 +0400 Subject: [PATCH 08/12] Fix warnings. --- client/mysqldump.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index b8933612db4..da24cedc7d7 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2072,11 +2072,12 @@ static uint dump_routines_for_db(char *db) } else if (strlen(row[2])) { + char *query_str; if (opt_drop) fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;\n", routine_type[i], routine_name); - char *query_str= cover_definer_clause_in_sp(row[2], strlen(row[2])); + query_str= cover_definer_clause_in_sp(row[2], strlen(row[2])); if (mysql_num_fields(routine_res) >= 6) { @@ -2705,10 +2706,10 @@ static void dump_trigger_old(MYSQL_RES *show_triggers_rs, accessing it. */ - uint user_name_len; + size_t user_name_len; char user_name_str[USERNAME_LENGTH + 1]; char quoted_user_name_str[USERNAME_LENGTH * 2 + 3]; - uint host_name_len; + size_t host_name_len; char host_name_str[HOSTNAME_LENGTH + 1]; char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; @@ -3893,7 +3894,7 @@ static int init_dumping(char *database, int init_func(char*)) /* Return 1 if we should copy the table */ -my_bool include_table(uchar* hash_key, uint len) +my_bool include_table(const char* hash_key, uint len) { return !hash_search(&ignore_table, (uchar*) hash_key, len); } From 4cc808b7cf89056250095d9a2f998eb5aa3fd60e Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Mon, 6 Aug 2007 22:52:50 +0400 Subject: [PATCH 09/12] Fix "db_cl_altered might be used uninitialized" warning. --- client/mysqldump.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index da24cedc7d7..5afab7c7828 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1820,7 +1820,7 @@ static uint dump_events_for_db(char *db) MYSQL_ROW row, event_list_row; char db_cl_name[MY_CS_NAME_SIZE]; - int db_cl_altered; + int db_cl_altered= FALSE; DBUG_ENTER("dump_events_for_db"); DBUG_PRINT("enter", ("db: '%s'", db)); @@ -2005,7 +2005,7 @@ static uint dump_routines_for_db(char *db) MYSQL_ROW row, routine_list_row; char db_cl_name[MY_CS_NAME_SIZE]; - int db_cl_altered; + int db_cl_altered= FALSE; DBUG_ENTER("dump_routines_for_db"); DBUG_PRINT("enter", ("db: '%s'", db)); @@ -2746,7 +2746,7 @@ static int dump_trigger(MYSQL_RES *show_create_trigger_rs, { FILE *sql_file= md_result_file; MYSQL_ROW row; - int db_cl_altered; + int db_cl_altered= FALSE; DBUG_ENTER("dump_trigger"); From 256450d88147aec11f8aae9afdf7c4f87c57d431 Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Mon, 6 Aug 2007 23:43:53 +0400 Subject: [PATCH 10/12] Fix one more warning. --- client/mysqldump.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 5afab7c7828..b11beef647e 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2803,7 +2803,6 @@ static int dump_trigger(MYSQL_RES *show_create_trigger_rs, static int dump_triggers_for_table(char *table_name, char *db_name) { - FILE *sql_file= md_result_file; char name_buff[NAME_LEN*4+3]; char query_buff[QUERY_LENGTH]; uint old_opt_compatible_mode= opt_compatible_mode; From a3b210d408978b8932719a56753f8d42c1bfbac0 Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Wed, 8 Aug 2007 14:02:07 +0400 Subject: [PATCH 11/12] Apply patch for Bug#27806 table comments not passed in to storage engine during "CREATE ... LIKE ..." Only affects engine writers. No change in server behaviour. --- sql/table.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/table.cc b/sql/table.cc index 12fffe1dde7..27f9ccc418e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2484,6 +2484,7 @@ void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table) create_info->row_type= share->row_type; create_info->default_table_charset= share->table_charset; create_info->table_charset= 0; + create_info->comment= share->comment; DBUG_VOID_RETURN; } From 3ecef8c0b902b7ed213ba89ec3e8e5637033435e Mon Sep 17 00:00:00 2001 From: "kostja@bodhi.(none)" <> Date: Wed, 8 Aug 2007 15:49:19 +0400 Subject: [PATCH 12/12] A fix for Bug#28830 Test case log_state fails on VMWare Windows clone due to loaded system --- mysql-test/r/log_state.result | 4 ++-- mysql-test/t/log_state.test | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/log_state.result b/mysql-test/r/log_state.result index 0c6be16b9b7..3a3ef584ce3 100644 --- a/mysql-test/r/log_state.result +++ b/mysql-test/r/log_state.result @@ -37,14 +37,14 @@ set session long_query_time=1; select sleep(2); sleep(2) 0 -select * from mysql.slow_log; +select * from mysql.slow_log where sql_text NOT LIKE '%slow_log%'; start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text set global slow_query_log= ON; set session long_query_time=1; select sleep(2); sleep(2) 0 -select * from mysql.slow_log; +select * from mysql.slow_log where sql_text NOT LIKE '%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) show global variables diff --git a/mysql-test/t/log_state.test b/mysql-test/t/log_state.test index b0bb818b783..c67da261ef1 100644 --- a/mysql-test/t/log_state.test +++ b/mysql-test/t/log_state.test @@ -28,7 +28,7 @@ connection con1; set session long_query_time=1; select sleep(2); --replace_column 1 TIMESTAMP 2 USER_HOST 3 QUERY_TIME -select * from mysql.slow_log; +select * from mysql.slow_log where sql_text NOT LIKE '%slow_log%'; connection default; set global slow_query_log= ON; @@ -36,7 +36,7 @@ connection con1; set session long_query_time=1; select sleep(2); --replace_column 1 TIMESTAMP 2 USER_HOST 3 QUERY_TIME -select * from mysql.slow_log; +select * from mysql.slow_log where sql_text NOT LIKE '%slow_log%'; connection default; show global variables where Variable_name = 'log' or Variable_name = 'log_slow_queries' or