List:Commits« Previous MessageNext Message »
From:Luis Soares Date:July 27 2009 2:13am
Subject:bzr commit into mysql-5.1-bugteam branch (luis.soares:3043) Bug#46265
View as plain text  
#At file:///home/lsoares/Workspace/mysql-server/bugfix/b46265/mysql-5.1-bugteam/ based on revid:davi.arnaut@stripped

 3043 Luis Soares	2009-07-27
      BUG#46265: Can not disable warning about unsafe statements for 
      binary logging
      
      Several warnings are printed when using statement based logging
      and unsafe operations are logged to the binlog. For example, this
      is the case for statements using LIMIT + ORDER BY PK. As a
      consequence, this would rapidly increase mysqld error log size,
      in some cases to several gigabytes, causing a maintenance
      nightmare.
            
      This patch proposes a mechanism to selectively and voluntarily
      suppress warnings from mysqld error log. It adds a dynamic server
      variable "suppress_log_warnings", which can be used to set/reset
      warning filtering from mysqld error log. Its details are the
      following:
            
        - Default: empty => no suppressions from error log.
            
        - Accepted values: list of tuples separated by commas, eg:
            
          <LEVEL>:<CODE>,<LEVEL>:<CODE>
            
          where LEVEL is one of: 'warning' or 'note, and code is the
          numerical representation of the warning code to suppress. In
          the case of unsafe statement warnings the code is 1592. As
          such, to suppress such warnings one could use:
               
          --suppress_log_warnings=warning:1592
            
          or
              
          mysql>SET @@global.suppress_log_warnings=warning:1592
            
        - Multiple suppressions can be done by adding other tuples
          <LEVEL>:<CODE> and separating each with a comma.
            
      Every time the suppress_log_warnings variable is set, the
      internal structure (instance of class Suppress_Log_Warnings) is
      updated and new rules are computed based on the
      suppress_log_warnings variable content. 
            
      Finally, in this patch we only address the suppressing of unsafe
      warnings from error log, however, for this mechanism to work with
      other warnings, one needs to refactor part of the source code so
      that calls to sql_print_warnings get replaced with
      sql_print_or_suppress_warnings referencing the warning code
      whenever possible.
     @ mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result
        Result file update. Notice the extra warning for unsafe statements that are 
        not suppressed. These are intended and guarded by DBUG_EXECUTE_IF.
     @ mysql-test/suite/binlog/t/binlog_stm_unsafe_warning-master.opt
        Added option to suppress unsafe warning.
     @ mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test
        Added test case for explicit suppressions through new server variable:
        suppress_log_warning.
     @ sql/log.cc
        Added function that conditionally prints to the error log, based on
        the rules established by the contents of suppress_log_warnings filtering
        rules.
     @ sql/mysql_priv.h
        Added references to sql_print_or_suppress_warning and 
        opt_suppress_log_warnings.
     @ sql/mysqld.cc
        Added handling of command line arguments for option: suppress_log_warnings.
        If options are given, then it initializes the Suppress_Log_Warnings instance
        with the given argument.
     @ sql/set_var.cc
        Added new servr system variable suppress_log_warnings. Everytime, the
        variable is reset, the suppress_log_warnings filter gets updated.
     @ sql/set_var.h
        Exported system variable suppress_log_warnings.
     @ sql/sql_class.cc
        Replaced the sql_print_warning, for unsafe statements, with 
        sql_print_or_suppress_warning.
     @ sql/sql_error.cc
        Created a class named Suppress_Log_Warnings. It holds warning filters for
        mysqld's error log. At its core is a Hash that maps error code into information
        on which levels the error code is to be suppressed. The class interface provides
        methods to set list of suppressions and check if a code is to be suppressed for 
        a specific level. Apart from these, it also contains private utility methods.
     @ sql/sql_error.h
        Added interface for class Suppress_Log_Warnings.

    modified:
      mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result
      mysql-test/suite/binlog/t/binlog_stm_unsafe_warning-master.opt
      mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test
      sql/log.cc
      sql/mysql_priv.h
      sql/mysqld.cc
      sql/set_var.cc
      sql/set_var.h
      sql/sql_class.cc
      sql/sql_error.cc
      sql/sql_error.h
=== modified file 'mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result'
--- a/mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result	2009-06-27 13:18:47 +0000
+++ b/mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result	2009-07-27 02:13:28 +0000
@@ -1,3 +1,90 @@
+SET @old_debug= @@global.debug;
+SET @old_suppress_log_warnings= @@global.suppress_log_warnings;
+echo ###### PART I: basic variable testing
+### assertion: show that the variable exists and has CLI value
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+Variable_name	Value
+suppress_log_warnings	warning:1592,note:1592
+### assertion: show that variable is dynamic: set to different value
+SET @@global.suppress_log_warnings= 'warning:1953';
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+Variable_name	Value
+suppress_log_warnings	warning:1953
+### assertion: show that variable is dynamic: set to default value
+SET @@global.suppress_log_warnings= DEFAULT;
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+Variable_name	Value
+suppress_log_warnings	
+### assertion: this variable should be able to cope with long values set on session
+SET @@global.suppress_log_warnings='warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312';
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+Variable_name	Value
+suppress_log_warnings	warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312
+### assertion: show that variable is dynamic: set to original value
+SET @@global.suppress_log_warnings= @old_suppress_log_warnings;
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+Variable_name	Value
+suppress_log_warnings	warning:1592,note:1592
+###### PART II: check that warnings are/aren't printed when option to suppress is used
+SET @@global.debug= "+d,b46265_extra_warning_when_not_supressing";
+### assertion: no warnings because CLI option to suppress warnings was set
+CREATE TABLE t1 (a int, b int, pattern varchar(256), primary key (a));
+INSERT INTO t1 VALUES (1,2,null), (2,3,null);
+UPDATE t1 SET b='4', pattern='b46265-suppressed_log_warning-1592' WHERE a=1 LIMIT 1;
+Warnings:
+Note	1592	Statement may not be safe to log in statement format.
+UPDATE t1 SET b='5', pattern='b46265-suppressed_log_warning-1592' WHERE a=2 ORDER BY a LIMIT 1;
+Warnings:
+Note	1592	Statement may not be safe to log in statement format.
+DROP TABLE t1;
+### assertion: we get warnings again by reverting CLI option dynamically
+SET @@global.suppress_log_warnings= "";
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+Variable_name	Value
+suppress_log_warnings	
+CREATE TABLE t1 (a int, b int, pattern varchar(256), primary key (a));
+INSERT INTO t1 VALUES (1,2,null), (2,3,null);
+UPDATE t1 SET b='4', pattern='b46265-not-suppressed_log_warning-1592' WHERE a=1 LIMIT 1;
+Warnings:
+Note	1592	Statement may not be safe to log in statement format.
+Note	1592	BUG#46265: FOR TESTING PURPOSES ONLY THIS WARNING IS PUSHED WHEN NOT SUPPRESSING THE WARNING FROM ERROR LOG!
+UPDATE t1 SET b='5', pattern='b46265-not-suppressed_log_warning-1592' WHERE a=2 ORDER BY a LIMIT 1;
+Warnings:
+Note	1592	Statement may not be safe to log in statement format.
+Note	1592	BUG#46265: FOR TESTING PURPOSES ONLY THIS WARNING IS PUSHED WHEN NOT SUPPRESSING THE WARNING FROM ERROR LOG!
+DROP TABLE t1;
+### assertion: warnings are turned off again by setting option dynamically
+SET @@global.suppress_log_warnings= 'warning:1592';
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+Variable_name	Value
+suppress_log_warnings	warning:1592
+CREATE TABLE t1 (a int, b int, pattern varchar(256), primary key (a));
+INSERT INTO t1 VALUES (1,2,null), (2,3,null);
+UPDATE t1 SET b='4', pattern='b46265-suppressed_log_warning-1592' WHERE a=1 LIMIT 1;
+Warnings:
+Note	1592	Statement may not be safe to log in statement format.
+UPDATE t1 SET b='5', pattern='b46265-suppressed_log_warning-1592' WHERE a=2 ORDER BY a LIMIT 1;
+Warnings:
+Note	1592	Statement may not be safe to log in statement format.
+DROP TABLE t1;
+### assertion: we get warnings again by setting the variable to default (no suppressions)
+SET @@global.suppress_log_warnings= DEFAULT;
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+Variable_name	Value
+suppress_log_warnings	
+CREATE TABLE t1 (a int, b int, pattern varchar(256), primary key (a));
+INSERT INTO t1 VALUES (1,2,null), (2,3,null);
+UPDATE t1 SET b='4', pattern='b46265-not-suppressed_log_warning-1592' WHERE a=1 LIMIT 1;
+Warnings:
+Note	1592	Statement may not be safe to log in statement format.
+Note	1592	BUG#46265: FOR TESTING PURPOSES ONLY THIS WARNING IS PUSHED WHEN NOT SUPPRESSING THE WARNING FROM ERROR LOG!
+UPDATE t1 SET b='5', pattern='b46265-not-suppressed_log_warning-1592' WHERE a=2 ORDER BY a LIMIT 1;
+Warnings:
+Note	1592	Statement may not be safe to log in statement format.
+Note	1592	BUG#46265: FOR TESTING PURPOSES ONLY THIS WARNING IS PUSHED WHEN NOT SUPPRESSING THE WARNING FROM ERROR LOG!
+DROP TABLE t1;
+SET @@global.suppress_log_warnings= @old_suppress_log_warnings;
+SET @@global.debug= @old_debug;
 ### NOT filtered database => assertion: warnings ARE shown
 DROP TABLE IF EXISTS t1;
 CREATE TABLE t1 (a int, b int, primary key (a));

=== modified file 'mysql-test/suite/binlog/t/binlog_stm_unsafe_warning-master.opt'
--- a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning-master.opt	2009-06-27 13:18:47 +0000
+++ b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning-master.opt	2009-07-27 02:13:28 +0000
@@ -1 +1 @@
---binlog-ignore-db=b42851
+--binlog-ignore-db=b42851 --suppress-log-warnings=warning:1592,note:1592

=== modified file 'mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test'
--- a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test	2009-06-27 13:18:47 +0000
+++ b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test	2009-07-27 02:13:28 +0000
@@ -1,18 +1,52 @@
 # BUG#42851: Spurious "Statement is not safe to log in statement
 #            format." warnings
 #
+# BUG#46265: Can not disable warning about unsafe statements for
+#            binary logging
+#
 # WHY
 # ===
-#   
+#
 #   This test aims at checking that the fix that removes spurious
-#   entries in the error log when the statement is filtered out from
-#   binlog, is working.
+#   entries in the error log when: (i) option to suppresss warnings 
+#   is used; or (ii) the statement is filtered out from binlog; is 
+#   indeed working.
+#
 #
 # HOW
 # ===
 #
-#   The test case is split into three assertions when issuing statements
-#   containing LIMIT and ORDER BY:
+#  - PART I: basic variable testing
+#
+#     i) Check that dynamic variable is working properly
+#
+#
+#  - PART II: is split into four assertions. These rely on conditional
+#             code in the server, which will push an extra warning to
+#             the warning pool, when the warning is not suppressed
+#             from mysqld error log. This way MTR can find out what is
+#             and what is not suppressed from error log (check result
+#             file for details on the extra warning). Details on each
+#             sub-test are provided below:
+#
+#     i) assert that warnings are suppressed when CLI option was used
+#
+#    ii) assert that warnings are *not* suppressed when variable is
+#        changed dynamically to not suppress warnings (setting it to
+#        "").
+#
+#   iii) assert that warnings are suppressed when variable is changed
+#        dynamically to suppress warnings (set to 'warning:1592')
+#
+#    iv) assert that warnings are *not* suppressed when variable is
+#        changed dynamically to the default value (set to
+#        'warning:1592')
+#
+#  - Part III: of the test is split into three assertions when issuing
+#              statements containing LIMIT and ORDER BY:
+#
+#    The test case is split into three assertions when issuing
+#    statements containing LIMIT and ORDER BY:
 #
 #     i) issue statements in database that is not filtered => check
 #        that warnings ARE shown;
@@ -25,6 +59,73 @@
 
 -- source include/have_log_bin.inc
 -- source include/have_binlog_format_statement.inc
+-- source include/have_debug.inc
+
+SET @old_debug= @@global.debug;
+SET @old_suppress_log_warnings= @@global.suppress_log_warnings;
+
+-- echo echo ###### PART I: basic variable testing
+
+-- echo ### assertion: show that the variable exists and has CLI value
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+
+-- echo ### assertion: show that variable is dynamic: set to different value
+SET @@global.suppress_log_warnings= 'warning:1953';
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+-- echo ### assertion: show that variable is dynamic: set to default value
+SET @@global.suppress_log_warnings= DEFAULT;
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+-- echo ### assertion: this variable should be able to cope with long values set on session
+SET @@global.suppress_log_warnings='warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312,warning:1592,warning:23423,warning:1235,note:20312';
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+-- echo ### assertion: show that variable is dynamic: set to original value
+SET @@global.suppress_log_warnings= @old_suppress_log_warnings;
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+
+-- echo ###### PART II: check that warnings are/aren't printed when option to suppress is used
+
+SET @@global.debug= "+d,b46265_extra_warning_when_not_supressing";
+
+-- echo ### assertion: no warnings because CLI option to suppress warnings was set
+CREATE TABLE t1 (a int, b int, pattern varchar(256), primary key (a));
+INSERT INTO t1 VALUES (1,2,null), (2,3,null);
+UPDATE t1 SET b='4', pattern='b46265-suppressed_log_warning-1592' WHERE a=1 LIMIT 1;
+UPDATE t1 SET b='5', pattern='b46265-suppressed_log_warning-1592' WHERE a=2 ORDER BY a LIMIT 1;
+DROP TABLE t1; 
+
+-- echo ### assertion: we get warnings again by reverting CLI option dynamically
+SET @@global.suppress_log_warnings= "";
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+
+CREATE TABLE t1 (a int, b int, pattern varchar(256), primary key (a));
+INSERT INTO t1 VALUES (1,2,null), (2,3,null);
+UPDATE t1 SET b='4', pattern='b46265-not-suppressed_log_warning-1592' WHERE a=1 LIMIT 1;
+UPDATE t1 SET b='5', pattern='b46265-not-suppressed_log_warning-1592' WHERE a=2 ORDER BY a LIMIT 1;
+DROP TABLE t1; 
+
+-- echo ### assertion: warnings are turned off again by setting option dynamically
+SET @@global.suppress_log_warnings= 'warning:1592';
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+
+CREATE TABLE t1 (a int, b int, pattern varchar(256), primary key (a));
+INSERT INTO t1 VALUES (1,2,null), (2,3,null);
+UPDATE t1 SET b='4', pattern='b46265-suppressed_log_warning-1592' WHERE a=1 LIMIT 1;
+UPDATE t1 SET b='5', pattern='b46265-suppressed_log_warning-1592' WHERE a=2 ORDER BY a LIMIT 1;
+DROP TABLE t1; 
+
+-- echo ### assertion: we get warnings again by setting the variable to default (no suppressions)
+SET @@global.suppress_log_warnings= DEFAULT;
+SHOW VARIABLES LIKE 'suppress_log_warnings';
+
+CREATE TABLE t1 (a int, b int, pattern varchar(256), primary key (a));
+INSERT INTO t1 VALUES (1,2,null), (2,3,null);
+UPDATE t1 SET b='4', pattern='b46265-not-suppressed_log_warning-1592' WHERE a=1 LIMIT 1;
+UPDATE t1 SET b='5', pattern='b46265-not-suppressed_log_warning-1592' WHERE a=2 ORDER BY a LIMIT 1;
+DROP TABLE t1; 
+
+# clean up 
+SET @@global.suppress_log_warnings= @old_suppress_log_warnings;
+SET @@global.debug= @old_debug;
 
 -- echo ### NOT filtered database => assertion: warnings ARE shown
 
@@ -71,3 +172,4 @@ DROP TABLE t1;
 
 # clean up
 DROP DATABASE b42851;
+

=== modified file 'sql/log.cc'
--- a/sql/log.cc	2009-07-18 20:07:56 +0000
+++ b/sql/log.cc	2009-07-27 02:13:28 +0000
@@ -4946,6 +4946,26 @@ void sql_print_error(const char *format,
 }
 
 
+void sql_print_or_suppress_warning(uint code, const char *format, ...) 
+{
+  if (!suppress_log_warnings->is_suppress_warning(code))
+  {
+    DBUG_EXECUTE_IF("b46265_extra_warning_when_not_supressing",
+                    push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                                 ER_BINLOG_UNSAFE_STATEMENT, "BUG#46265: FOR TESTING"
+                                 " PURPOSES ONLY THIS WARNING IS PUSHED WHEN NOT"
+                                 " SUPPRESSING THE WARNING FROM ERROR LOG!"););
+
+    va_list args;
+    DBUG_ENTER("sql_print_or_suppress_warning");
+
+    va_start(args, format);
+    error_log_print(WARNING_LEVEL, format, args);
+    va_end(args);
+
+    DBUG_VOID_RETURN;
+  }
+}
 void sql_print_warning(const char *format, ...) 
 {
   va_list args;

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2009-07-24 16:20:46 +0000
+++ b/sql/mysql_priv.h	2009-07-27 02:13:28 +0000
@@ -845,6 +845,8 @@ Item *negate_expression(THD *thd, Item *
 int vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
 void sql_print_error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
 void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+void sql_print_or_suppress_warning(uint code, const char *format, ...) 
+  ATTRIBUTE_FORMAT(printf, 2, 3);
 void sql_print_information(const char *format, ...)
   ATTRIBUTE_FORMAT(printf, 1, 2);
 typedef void (*sql_print_message_func)(const char *format, ...)
@@ -2002,6 +2004,7 @@ extern uint opt_large_page_size;
 #ifdef MYSQL_SERVER
 extern char *opt_logname, *opt_slow_logname;
 extern const char *log_output_str;
+extern char *opt_suppress_log_warnings;
 
 extern MYSQL_BIN_LOG mysql_bin_log;
 extern LOGGER logger;

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2009-07-24 16:20:46 +0000
+++ b/sql/mysqld.cc	2009-07-27 02:13:28 +0000
@@ -403,6 +403,7 @@ static pthread_cond_t COND_thread_cache,
 
 /* Global variables */
 
+char *opt_suppress_log_warnings;
 bool opt_update_log, opt_bin_log, opt_ignore_builtin_innodb= 0;
 my_bool opt_log, opt_slow_log;
 ulong log_output_options;
@@ -605,6 +606,7 @@ I_List<THD> threads;
 I_List<NAMED_LIST> key_caches;
 Rpl_filter* rpl_filter;
 Rpl_filter* binlog_filter;
+Suppress_Log_Warnings *suppress_log_warnings;
 
 struct system_variables global_system_variables;
 struct system_variables max_system_variables;
@@ -670,7 +672,6 @@ my_bool master_ssl;
 char *master_ssl_key, *master_ssl_cert;
 char *master_ssl_ca, *master_ssl_capath, *master_ssl_cipher;
 char *opt_logname, *opt_slow_logname;
-
 /* Static variables */
 
 static bool kill_in_progress, segfaulted;
@@ -1316,6 +1317,7 @@ void clean_up(bool print_message)
 #endif
   delete binlog_filter;
   delete rpl_filter;
+  delete suppress_log_warnings;
 #ifndef EMBEDDED_LIBRARY
   end_ssl();
 #endif
@@ -3185,6 +3187,12 @@ static int init_common_variables(const c
     sql_perror("Could not allocate replication and binlog filters");
     return 1;
   }
+  suppress_log_warnings= new Suppress_Log_Warnings;
+  if (!suppress_log_warnings)
+  {
+    sql_perror("Could not allocate suppress log warnings filter");
+    return 1;
+  }
 
   if (init_thread_environment() ||
       mysql_init_variables())
@@ -3510,6 +3518,11 @@ You should consider changing lower_case_
 			files_charset_info :
 			&my_charset_bin);
 
+  if (opt_suppress_log_warnings)
+  {
+    sys_var_suppress_log_warnings.value= my_strdup(opt_suppress_log_warnings, MYF(0));
+    sys_var_slow_log_path.value_length= strlen(opt_suppress_log_warnings);
+  }
   return 0;
 }
 
@@ -5649,7 +5662,8 @@ enum options_mysqld
   OPT_SLAVE_EXEC_MODE,
   OPT_GENERAL_LOG_FILE,
   OPT_SLOW_QUERY_LOG_FILE,
-  OPT_IGNORE_BUILTIN_INNODB
+  OPT_IGNORE_BUILTIN_INNODB,
+  OPT_SUPPRESS_LOG_WARNINGS
 };
 
 
@@ -5719,6 +5733,16 @@ struct my_option my_long_options[] =
   {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB,
    "Tells the master that updates to the given database should not be logged tothe binary log.",
    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"suppress_log_warnings", OPT_SUPPRESS_LOG_WARNINGS,
+   "List containing warnings to be suppressed from error log. The list must"
+   " be structured as follows: <LEVEL>:<CODE>,<LEVEL>:<CODE> ."
+   " LEVEL is one of: 'warning' or 'note'. CODE must be the numerical"
+   " representation of the warning that is to be suppressed. Multiple"
+   " suppressions can be specified, in which case, a comma becomes the."
+   " separator. Example: --suppress-log-warnings=warning:1592,note:1593",
+   (uchar **) &opt_suppress_log_warnings, 
+   (uchar **) &opt_suppress_log_warnings, 0, GET_STR_ALLOC, 
+   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
   {"binlog-row-event-max-size", OPT_BINLOG_ROWS_EVENT_MAX_SIZE,
    "The maximum size of a row-based binary log event in bytes. Rows will be "
    "grouped into events smaller than this size if possible. "
@@ -7942,6 +7966,25 @@ mysqld_get_one_option(int optid,
     binlog_filter->add_ignore_db(argument);
     break;
   }
+  case (int)OPT_SUPPRESS_LOG_WARNINGS:
+  {
+    if (argument != NULL)
+    {
+      if (suppress_log_warnings->set_suppressions(opt_suppress_log_warnings))
+      {
+        sql_print_error("Could not add log warning suppression filter '%s'!\n", argument);
+        return 1;
+      }
+    }
+    else
+    {
+      sql_print_error("Could not add log warning suppression. Option was used\
+                      but no argument was set!\n");
+      return 1;
+    }
+
+    break;
+  }
   case OPT_BINLOG_FORMAT:
   {
     int id;

=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc	2009-07-16 12:43:17 +0000
+++ b/sql/set_var.cc	2009-07-27 02:13:28 +0000
@@ -148,6 +148,10 @@ static void sys_default_general_log_path
 static bool sys_update_slow_log_path(THD *thd, set_var * var);
 static void sys_default_slow_log_path(THD *thd, enum_var_type type);
 
+static void sys_default_var_suppress_log_warnings(THD *thd, enum_var_type type);
+static int  sys_check_var_suppress_log_warnings(THD *thd, set_var *var);
+static bool sys_update_var_suppress_log_warnings(THD *thd, set_var *var);
+
 /*
   Variable definition list
 
@@ -892,7 +896,11 @@ sys_var_str sys_var_slow_log_path(&vars,
 				  opt_slow_logname);
 static sys_var_log_output sys_var_log_output_state(&vars, "log_output", &log_output_options,
 					    &log_output_typelib, 0);
-
+sys_var_str sys_var_suppress_log_warnings(&vars, "suppress_log_warnings",
+                                          sys_check_var_suppress_log_warnings,
+                                          sys_update_var_suppress_log_warnings,
+                                          sys_default_var_suppress_log_warnings,
+                                          (char*)opt_suppress_log_warnings);
 
 bool sys_var::check(THD *thd, set_var *var)
 {
@@ -916,6 +924,82 @@ bool sys_var_str::check(THD *thd, set_va
   Functions to check and update variables
 */
 
+static bool update_sys_var_suppress_log_warnings(sys_var_str *var_str, set_var *var)
+{
+  char *old_val= var_str->value;
+  char *new_val= NULL;
+  uint  new_len=  0;
+  bool res= FALSE;
+  char buff[256];
+  String str(buff, sizeof(buff), system_charset_info), *newval;
+  if (var)
+  {
+    /**
+      Per BUG#38124, one needs to fetch the new value through a call to
+      val_str, instead of accessing directly str_value.ptr(). This way,
+      we can assign other values than constant strings (for example, 
+      we can use user vars as the assigned value).
+    */
+    newval= var->value->val_str(&str);
+    new_val= newval->c_ptr();
+    new_len= strlen(new_val);
+  }
+
+  if (!(res= suppress_log_warnings->set_suppressions(new_val)))
+  {
+    var_str->value= my_strndup(new_val, new_len, MYF(0));
+    var_str->value_length= new_len;
+
+    if (old_val)
+      my_free(old_val, MYF(MY_ALLOW_ZERO_PTR));
+  }
+  else // reset to previous rules
+    suppress_log_warnings->set_suppressions(old_val);
+
+  return res;
+}
+
+static void sys_default_var_suppress_log_warnings(THD *thd, enum_var_type type)
+{
+  /**
+    Set default which is no suppressions.
+  */
+  (void) update_sys_var_suppress_log_warnings(&sys_var_suppress_log_warnings,
+                                              0);
+}
+
+static int sys_check_var_suppress_log_warnings(THD *thd, set_var *var)
+{
+  char *str_val= (char*) "";
+  char buff[256];
+  String str(buff, sizeof(buff), system_charset_info), *newval;
+  if (var)
+  {
+    /**
+      Per BUG#38124, one needs to fetch the new value through a call to
+      val_str, instead of accessing directly str_value.ptr(). This way,
+      we can assign other values than constant strings (for example, 
+      we can use user vars as the assigned value).
+    */
+    newval= var->value->val_str(&str);
+    str_val= newval->c_ptr();
+  }
+
+  /**
+    Verify whether the variable contents is a valid list.
+  */
+  return suppress_log_warnings->check_list((char*)str_val);
+}
+
+static bool sys_update_var_suppress_log_warnings(THD *thd, set_var *var)
+{
+  /**
+    Sets the variable and updates the suppression filters.
+  */
+  return update_sys_var_suppress_log_warnings(&sys_var_suppress_log_warnings,
+                                              var);
+}
+
 
 /*
   Update variables 'init_connect, init_slave'.
@@ -1295,7 +1379,6 @@ void fix_binlog_format_after_update(THD 
   thd->reset_current_stmt_binlog_row_based();
 }
 
-
 static void fix_max_binlog_size(THD *thd, enum_var_type type)
 {
   DBUG_ENTER("fix_max_binlog_size");

=== modified file 'sql/set_var.h'
--- a/sql/set_var.h	2009-06-19 09:29:21 +0000
+++ b/sql/set_var.h	2009-07-27 02:13:28 +0000
@@ -1440,7 +1440,8 @@ CHARSET_INFO *get_old_charset_by_name(co
 uchar* find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
 		NAMED_LIST **found);
 
-extern sys_var_str sys_var_general_log_path, sys_var_slow_log_path;
+extern sys_var_str sys_var_general_log_path, sys_var_slow_log_path,
+       sys_var_suppress_log_warnings;
 
 /* key_cache functions */
 KEY_CACHE *get_key_cache(LEX_STRING *cache_name);

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2009-07-24 16:04:55 +0000
+++ b/sql/sql_class.cc	2009-07-27 02:13:28 +0000
@@ -3716,9 +3716,9 @@ int THD::binlog_query(THD::enum_binlog_q
                  ER(ER_BINLOG_UNSAFE_STATEMENT));
     if (!(binlog_flags & BINLOG_FLAG_UNSAFE_STMT_PRINTED))
     {
-      sql_print_warning("%s Statement: %.*s",
-                        ER(ER_BINLOG_UNSAFE_STATEMENT),
-                        MYSQL_ERRMSG_SIZE, query_arg);
+      sql_print_or_suppress_warning(ER_BINLOG_UNSAFE_STATEMENT, "%s Statement: %.*s",
+                                    ER(ER_BINLOG_UNSAFE_STATEMENT),
+                                    MYSQL_ERRMSG_SIZE, query_arg);
       binlog_flags|= BINLOG_FLAG_UNSAFE_STMT_PRINTED;
     }
   }

=== modified file 'sql/sql_error.cc'
--- a/sql/sql_error.cc	2009-02-13 16:41:47 +0000
+++ b/sql/sql_error.cc	2009-07-27 02:13:28 +0000
@@ -258,3 +258,231 @@ bool mysqld_show_warnings(THD *thd, ulon
   my_eof(thd);
   DBUG_RETURN(FALSE);
 }
+
+/** ******** **/
+
+extern "C" uchar *get_key(const uchar *, size_t *, my_bool);
+extern "C" void free_ent(void* a);
+
+Suppress_Log_Warnings::Suppress_Log_Warnings()
+{ 
+  hash_inited= FALSE;
+  pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);
+} 
+
+Suppress_Log_Warnings::~Suppress_Log_Warnings()
+{
+  if (hash_inited)
+    hash_free(&h);
+
+  pthread_mutex_destroy(&lock);
+}
+
+bool Suppress_Log_Warnings::check_list(const char *list)
+{
+
+  /** allow to use set_suppressions as a hash resetter */
+  if (!list || strlen(list) == 0)
+    return FALSE;
+
+  char *buf = (char*)my_malloc(strlen(list) + 1, MYF(0));
+  bool res= FALSE;
+
+  const char *next= list;
+  while (next)
+  {
+    char *code=NULL, *col=NULL;
+    uint key_len= 0;
+    char *comma= strchr(next, ',');
+    int len= (comma ? comma-next : strlen(next)) + 1;
+    int level_len= 0;
+
+    strnmov(buf, next, len);
+    buf[len-1]= '\0';
+
+    col= strchr(buf, ':');
+    if (!col) 
+    {
+      res= TRUE;
+      goto end;
+    }
+
+    code= col+1;
+    key_len= strlen(code);
+    level_len= col - buf;
+    if (key_len == 0 ||   // empty key!
+        (level_len != 4 && level_len != 7))  // neither 'note' nor 'warning'
+    {
+      res= TRUE;
+      goto end;
+    }   
+
+    if (strncasecmp(buf, "note", 4) && 
+        strncasecmp(buf, "warning", 7))
+    {
+      res= TRUE;
+      goto end;
+    }    
+
+    /* @todo: check whether code is a number or not */
+
+    next = (comma ? comma+1 : NULL);
+  }
+
+end:
+  my_free(buf, MYF(0));
+  return res;
+}
+
+bool Suppress_Log_Warnings::set_suppressions(const char *list)
+{
+  bool res= FALSE;
+  if (check_list(list))
+    res= TRUE;
+  else
+  {
+    pthread_mutex_lock(&lock);
+
+    if (hash_inited)
+      my_hash_reset(&h);
+
+    if (list && strlen(list) > 0)
+    {
+      char *buf= (char*)my_malloc(strlen(list) + 1, MYF(0));
+      const char *next= list;
+      while (next && !res)
+      {
+        char *comma= strchr(next, ',');
+        int len= (comma ? comma-next : strlen(next)) + 1;
+        strnmov(buf, next, len);
+        buf[len-1]= '\0';
+        res= res || add_suppression(buf);
+        next = (comma ? comma+1 : NULL);
+      }
+
+      my_free(buf, MYF(0));
+    }
+
+    pthread_mutex_unlock(&lock);
+  }
+
+  return res;
+}
+
+bool Suppress_Log_Warnings::add_suppression(const char *ent)
+{
+  bool res= FALSE;
+  WARNING_ENT *e= NULL;
+  uint key_len= 0, mask= 0, ent_size= 0;
+  char *col= NULL, *code= NULL;
+
+  /**
+     not performing checks as list and entries have already been
+     checked in the the set_suppressions through check_list.
+  */
+  col= strchr(ent, ':');
+  code= col+1;
+  key_len= strlen(code);
+
+  /* decide which mask to use */
+  if (!strncasecmp(ent, "note", (col - ent)))
+    mask= NOTE_SUPPRESS_MASK;
+  else if (!strncasecmp(ent, "warning", (col - ent)))
+    mask= WARN_SUPPRESS_MASK;
+  else
+  {
+    DBUG_ASSERT(0);
+  }
+
+  if (!hash_inited)
+    init_hash();
+  else  /* check if there is already an entry for the given code */
+    e= (WARNING_ENT*) hash_search(&h, (const uchar *)code, key_len);
+
+  if (!e)
+  {
+    /* If there was no entry, then allocate memory, copy code string
+       as key and insert in hash.
+    */
+    ent_size= sizeof(WARNING_ENT) + key_len; // struct + key
+
+    e= (WARNING_ENT*) my_malloc(ent_size, MYF(MY_WME));
+    if (!e)
+    {
+      res= TRUE;
+      goto end;
+    }
+    memset(e, 0, ent_size);
+
+    /* save key properties */
+    e->code= (uchar *)e + (sizeof(WARNING_ENT));
+    strnmov((char*)e->code, code, key_len);
+    e->key_len= key_len;
+
+    /* finally, insert WARNING_ENT into hash */
+    if (my_hash_insert(&h, (uchar *)e))
+    {
+      res= TRUE;
+      goto end;
+    }
+  }
+
+  /* set the active flag */
+  e->supp_flags= (e->supp_flags | mask);
+
+end:
+  return res;
+}
+
+void 
+Suppress_Log_Warnings::init_hash()
+{
+  hash_init(&h, system_charset_info,WARNING_ENT_HASH_SIZE,0,0,
+            get_key, free_ent, 0); 
+  hash_inited = 1;
+}
+
+bool
+Suppress_Log_Warnings::is_suppression(uint code, uchar type_mask)
+{
+  bool res= FALSE;
+  if (hash_inited)
+  {
+    char s_code[NAME_LEN];
+    int2str(code, s_code, 10, 0);
+
+    pthread_mutex_lock(&lock);
+
+    WARNING_ENT* e= (WARNING_ENT*) 
+      hash_search(&h, (const uchar *)s_code, strlen(s_code));
+    if (e)
+      res= (e->supp_flags & type_mask);
+
+    pthread_mutex_unlock(&lock);
+  }
+  return res;
+}
+
+bool Suppress_Log_Warnings::is_suppress_note(uint code)
+{
+  return is_suppression(code, NOTE_SUPPRESS_MASK);
+}
+
+bool Suppress_Log_Warnings::is_suppress_warning(uint code)
+{ 
+  return is_suppression(code, WARN_SUPPRESS_MASK);
+}
+
+uchar *get_key(const uchar* a, size_t *len,
+               my_bool __attribute__((unused)))
+{
+  WARNING_ENT *e= (WARNING_ENT *) a;
+  *len= e->key_len;
+  return (uchar*)e->code;
+}
+
+void free_ent(void* a)
+{
+  WARNING_ENT *e= (WARNING_ENT *) a;
+  my_free((uchar*) e, MYF(0));
+}

=== modified file 'sql/sql_error.h'
--- a/sql/sql_error.h	2007-06-07 08:53:23 +0000
+++ b/sql/sql_error.h	2009-07-27 02:13:28 +0000
@@ -41,3 +41,159 @@ void mysql_reset_errors(THD *thd, bool f
 bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
 
 extern const LEX_STRING warning_level_names[];
+
+/**
+   Suppress Warnings data structures
+   =================================
+*/
+
+#define NOTE_SUPPRESS_MASK 0x1
+#define WARN_SUPPRESS_MASK 0x2
+
+/**
+   initial size of internal array used for hash. 
+*/
+#define WARNING_ENT_HASH_SIZE 16
+
+typedef struct st_warning_ent
+{
+  /**
+    This is the error code for which the suppress information is
+    stored. The code is used as a hash key when searching for
+    information on whether the warning should be suppressed or not.
+  */
+  uchar *code;
+
+  /**
+    These flags hold information on which LEVEL the output of warning
+    into log should be ignored.
+
+    supp_flags | NOTE_SUPPRESS_MASK => notes for this code should be
+                                       ignored
+
+    supp_flags | WARN_SUPPRESS_MASK => warnings for this code should
+                                       be ignored
+
+    They are independent, so one can set both for the same code,
+    meaning that both notes and warnings should be
+    suppressed. Example:
+
+    supp_flags = (supp_flags | NOTE_SUPPRESS_MASK |
+                               WARN_SUPPRESS_MASK);
+  */
+  uint supp_flags;
+
+  /**
+     The length of the code string (which is used as a key).
+  */
+  uint key_len;
+} WARNING_ENT;
+
+
+class Suppress_Log_Warnings
+{
+private:
+
+  /**
+     This hash holds data regarding warning codes and their suppress
+     information.
+
+     The warning code is used as the key for storing and retrieving
+     data.
+  */
+  HASH h;
+
+  /**
+     This flag indicates whether the hash has been initialized or not.
+  */
+  bool hash_inited;
+
+  /**
+     Mutex that synchronizes accesses to hash contents.
+  */
+  pthread_mutex_t lock;
+
+  /**
+     This is a private method and is used to search and evaluate
+     suppress information for the given warning code. It is called
+     from the public is_suppression methods.
+
+   */
+  bool is_suppression(uint code, uchar type_mask);
+
+  /**
+    Adds a single suppression. It must be represented as:
+    
+    <LEVEL>:<CODE> , for instance: warning:1592
+    
+    @return            true if adding the suppression was not 
+                       successfully completed, false otherwise.
+  */
+  bool add_suppression(const char *ent);
+
+  /**
+     This method initializes the hash. It should be called just once.
+   */
+  void init_hash();
+
+public:
+  /**
+    Sets multiple suppressions based on one list. The list must have
+    the following pattern:
+    
+    <LEVEL>:<CODE>,<LEVEL>:<CODE>
+
+    for instance:
+    
+    warning:1592,note:1592,warning:1593,note:1594
+    
+    @param[in] list    A list containing pairs of levels and codes to
+                       suppress. Elements in the list are separated by
+                       commas. Should this parameter be NULL or empty 
+                       string ("") then the internal state is reset to
+                       void, meaning that existent suppressing entries
+                       are discarded.
+
+    @return            true if adding the suppression was not successful, 
+                       false otherwise.
+  */
+  bool set_suppressions(const char *list);
+  
+  /**
+    Checks whether the given note code is to be suppressed
+    from the error log or not.
+    
+    @param[in] code   The code number to check if its corresponding note
+                      is to be suppressed or not.
+
+    @return           true if it should be suppressed, false otherwise.
+  */
+  bool is_suppress_note(uint code);
+  
+  /**
+    Checks whether the given warning code is to be suppressed
+    from the error log or not.
+    
+    @param[in] code   The code number to check if its corresponding
+                      warning is to be suppressed or not.
+
+    @return           true if it should be suppressed, false otherwise.
+  */
+  bool is_suppress_warning(uint code);
+
+  /**
+     Performs some basic checks on the list so that it finds whether
+     the list is according to the format expected or not.
+
+     @return          true if the list does not conform to specification, 
+                      false otherwise.
+  */
+  bool check_list(const char *list);
+  
+  Suppress_Log_Warnings();
+  ~Suppress_Log_Warnings();
+  Suppress_Log_Warnings(Suppress_Log_Warnings const&);
+  Suppress_Log_Warnings& operator=(Suppress_Log_Warnings const&);
+};
+
+extern Suppress_Log_Warnings *suppress_log_warnings;


Attachment: [text/bzr-bundle] bzr/luis.soares@sun.com-20090727021328-eyh1a93o45l9gjum.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (luis.soares:3043) Bug#46265Luis Soares27 Jul