From c7ae355d89b5d0d85175403a26addea338736f50 Mon Sep 17 00:00:00 2001 From: "tnurnberg@mysql.com" <> Date: Tue, 30 May 2006 14:49:05 +0200 Subject: [PATCH 1/3] Bug#17371: Unable to dump a schema with invalid views 'show create' works even on views that are short of a base-table (this throw a warning though, like you would expect). Unfortunately, this is not what mysqldump uses; it creates stand-in tables and hence requests 'show fields' on the view which fails with missing base-tables. The --force option prevents the dump from stopping at this point; furthermore this patch dumps a comment showing create for the offending view for better diagnostics. This solution was confirmed by submitter as solving their/clients' problem. Problem might become non-issue once mysqldump no longer creates stand-in tables. --- client/mysqldump.c | 21 ++++++++++++++++++++- mysql-test/r/mysqldump.result | 9 +++++++++ mysql-test/t/mysqldump.test | 13 +++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index ee6d7b9d12b..31882515a34 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1494,9 +1494,15 @@ static uint get_table_structure(char *table, char *db, char *table_type, field= mysql_fetch_field_direct(result, 0); if (strcmp(field->name, "View") == 0) { + char *scv_buff = NULL; + if (verbose) fprintf(stderr, "-- It's a view, create dummy table for view\n"); + /* save "show create" statement for later */ + if ((row= mysql_fetch_row(result)) && (scv_buff=row[1])) + scv_buff= my_strdup(scv_buff, MYF(0)); + mysql_free_result(result); /* @@ -1514,9 +1520,22 @@ static uint get_table_structure(char *table, char *db, char *table_type, "SHOW FIELDS FROM %s", result_table); if (mysql_query_with_error_report(sock, 0, query_buff)) { + /* + View references invalid or privileged table/col/fun (err 1356), + so we cannot create a stand-in table. Be defensive and dump + a comment with the view's 'show create' statement. (Bug #17371) + */ + + if (mysql_errno(sock) == ER_VIEW_INVALID) + fprintf(sql_file, "\n-- failed on view %s: %s\n\n", result_table, scv_buff ? scv_buff : ""); + + my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR)); + safe_exit(EX_MYSQLERR); - DBUG_RETURN(0); + DBUG_RETURN(0); } + else + my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR)); if ((result= mysql_store_result(sock))) { diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 467e0818646..94c9c4f9007 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -2731,3 +2731,12 @@ p CREATE DEFINER=`root`@`localhost` PROCEDURE `p`() select 42 drop function f; drop procedure p; +create table t1 ( id serial ); +create view v1 as select * from t1; +drop table t1; +mysqldump { + +-- failed on view `v1`: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`id` AS `id` from `t1` + +} mysqldump +drop view v1; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 4076fd258e9..9cd8671bb99 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1143,3 +1143,16 @@ show create procedure p; drop function f; drop procedure p; +# +# Bug #17371 Unable to dump a schema with invalid views +# +# +create table t1 ( id serial ); +create view v1 as select * from t1; +drop table t1; +# mysqldump gets 1356 from server, but gives us 2 +--echo mysqldump { +--error 2 +--exec $MYSQL_DUMP --force -N --compact --skip-comments test +--echo } mysqldump +drop view v1; From 7b63337d312480c020a5b54a36b76a5cb8059659 Mon Sep 17 00:00:00 2001 From: "cmiller@zippy.(none)" <> Date: Mon, 12 Jun 2006 08:54:45 -0400 Subject: [PATCH 2/3] Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode This is a modification of serg's and guilhem's suggestion in the bug report, in that it also causes the transaction log to be written to disc. --- mysql-test/r/bdb.result | 34 ++++++++++++++++++++++++++++++++++ mysql-test/t/bdb.test | 35 +++++++++++++++++++++++++++++++++++ sql/log.cc | 22 +++++++++++++++++----- sql/log_event.cc | 27 +++++++++++++++++++++++++++ sql/log_event.h | 21 +++++++++++++++++++++ 5 files changed, 134 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result index af6319afe99..588644a6c66 100644 --- a/mysql-test/r/bdb.result +++ b/mysql-test/r/bdb.result @@ -1928,4 +1928,38 @@ create table t1 (a int) engine=bdb; commit; alter table t1 add primary key(a); drop table t1; +set autocommit=1; +reset master; +create table bug16206 (a int) engine= blackhole; +insert into bug16206 values(1); +start transaction; +insert into bug16206 values(2); +commit; +show binlog events; +Log_name Pos Event_type Server_id End_log_pos Info +f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 +f n Query 1 n use `test`; create table bug16206 (a int) engine= blackhole +f n Query 1 n use `test`; insert into bug16206 values(1) +f n Query 1 n use `test`; insert into bug16206 values(2) +drop table bug16206; +reset master; +create table bug16206 (a int) engine= bdb; +insert into bug16206 values(0); +insert into bug16206 values(1); +start transaction; +insert into bug16206 values(2); +commit; +insert into bug16206 values(3); +show binlog events; +Log_name Pos Event_type Server_id End_log_pos Info +f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 +f n Query 1 n use `test`; create table bug16206 (a int) engine= bdb +f n Query 1 n use `test`; insert into bug16206 values(0) +f n Query 1 n use `test`; insert into bug16206 values(1) +f n Query 1 n use `test`; BEGIN +f n Query 1 n use `test`; insert into bug16206 values(2) +f n Query 1 n use `test`; COMMIT +f n Query 1 n use `test`; insert into bug16206 values(3) +drop table bug16206; +set autocommit=0; End of 5.0 tests diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test index d017d91bfb1..d2e3ca5f36e 100644 --- a/mysql-test/t/bdb.test +++ b/mysql-test/t/bdb.test @@ -1019,4 +1019,39 @@ commit; alter table t1 add primary key(a); drop table t1; + +# +# Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode +# +set autocommit=1; + +let $VERSION=`select version()`; + +reset master; +create table bug16206 (a int) engine= blackhole; +insert into bug16206 values(1); +start transaction; +insert into bug16206 values(2); +commit; +--replace_result $VERSION VERSION +--replace_column 1 f 2 n 5 n +show binlog events; +drop table bug16206; + +reset master; +create table bug16206 (a int) engine= bdb; +insert into bug16206 values(0); +insert into bug16206 values(1); +start transaction; +insert into bug16206 values(2); +commit; +insert into bug16206 values(3); +--replace_result $VERSION VERSION +--replace_column 1 f 2 n 5 n +show binlog events; +drop table bug16206; + +set autocommit=0; + + --echo End of 5.0 tests diff --git a/sql/log.cc b/sql/log.cc index ba02c9ba082..cfb90d398e6 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -36,6 +36,8 @@ MYSQL_LOG mysql_log, mysql_slow_log, mysql_bin_log; ulong sync_binlog_counter= 0; +static Muted_query_log_event invisible_commit; + static bool test_if_number(const char *str, long *res, bool allow_wildcards); static bool binlog_init(); @@ -94,7 +96,9 @@ static int binlog_end_trans(THD *thd, IO_CACHE *trans_log, Log_event *end_ev) { int error=0; DBUG_ENTER("binlog_end_trans"); - if (end_ev) + + /* NULL denotes ROLLBACK with nothing to replicate */ + if (end_ev != NULL) error= mysql_bin_log.write(thd, trans_log, end_ev); statistic_increment(binlog_cache_use, &LOCK_status); @@ -126,14 +130,19 @@ static int binlog_commit(THD *thd, bool all) DBUG_ASSERT(mysql_bin_log.is_open() && (all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))); - if (!my_b_tell(trans_log)) + if (my_b_tell(trans_log) == 0) { // we're here because trans_log was flushed in MYSQL_LOG::log() DBUG_RETURN(0); } - Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE); - qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE) - DBUG_RETURN(binlog_end_trans(thd, trans_log, &qev)); + if (all) + { + Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE); + qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE) + DBUG_RETURN(binlog_end_trans(thd, trans_log, &qev)); + } + else + DBUG_RETURN(binlog_end_trans(thd, trans_log, &invisible_commit)); } static int binlog_rollback(THD *thd, bool all) @@ -1813,6 +1822,9 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) DBUG_ENTER("MYSQL_LOG::write(THD *, IO_CACHE *, Log_event *)"); VOID(pthread_mutex_lock(&LOCK_log)); + /* NULL would represent nothing to replicate after ROLLBACK */ + DBUG_ASSERT(commit_event != NULL); + if (likely(is_open())) // Should always be true { uint length; diff --git a/sql/log_event.cc b/sql/log_event.cc index 266d6b064bd..cabf4631284 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1229,6 +1229,18 @@ bool Query_log_event::write(IO_CACHE* file) my_b_safe_write(file, (byte*) query, q_len)) ? 1 : 0; } +/* + Query_log_event::Query_log_event() + + The simplest constructor that could possibly work. This is used for + creating static objects that have a special meaning and are invisible + to the log. +*/ +Query_log_event::Query_log_event() + :Log_event(), data_buf(0) +{ +} + /* Query_log_event::Query_log_event() @@ -1875,6 +1887,21 @@ end: #endif +/************************************************************************** + Muted_query_log_event methods +**************************************************************************/ + +#ifndef MYSQL_CLIENT +/* + Muted_query_log_event::Muted_query_log_event() +*/ +Muted_query_log_event::Muted_query_log_event() + :Query_log_event() +{ +} +#endif + + /************************************************************************** Start_log_event_v3 methods **************************************************************************/ diff --git a/sql/log_event.h b/sql/log_event.h index 0e1eb7cd13c..f1b441dedb1 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -783,6 +783,7 @@ public: void print(FILE* file, PRINT_EVENT_INFO* print_event_info= 0); #endif + Query_log_event(); Query_log_event(const char* buf, uint event_len, const Format_description_log_event *description_event, Log_event_type event_type); @@ -806,6 +807,26 @@ public: /* Writes derived event-specific part of post header. */ }; + +/***************************************************************************** + + Muted Query Log Event class + + Pretends to Log SQL queries, but doesn't actually do so. + + ****************************************************************************/ +class Muted_query_log_event: public Query_log_event +{ +public: +#ifndef MYSQL_CLIENT + Muted_query_log_event(); + + bool write(IO_CACHE* file) { return(false); }; + virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; } +#endif +}; + + #ifdef HAVE_REPLICATION /***************************************************************************** From 178bb4bc6f5fe7b71893fc0e0749fd56c48389aa Mon Sep 17 00:00:00 2001 From: "cmiller@zippy.(none)" <> Date: Wed, 14 Jun 2006 14:18:42 -0400 Subject: [PATCH 3/3] Bug#19262: internal function create_typelib() uses DBUG_ENTER() but not DBUG_RETURN Trivial replacement of return with DBUG_RETURN. --- sql/sp_head.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 3b29a841966..14295072fff 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -565,7 +565,7 @@ create_typelib(MEM_ROOT *mem_root, create_field *field_def, List *src) result->name= ""; if (!(result->type_names=(const char **) alloc_root(mem_root,(sizeof(char *)+sizeof(int))*(result->count+1)))) - return 0; + DBUG_RETURN(0); result->type_lengths= (unsigned int *)(result->type_names + result->count+1); List_iterator it(*src); String conv; @@ -599,7 +599,7 @@ create_typelib(MEM_ROOT *mem_root, create_field *field_def, List *src) result->type_names[result->count]= 0; result->type_lengths[result->count]= 0; } - return result; + DBUG_RETURN(result); }