List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:April 8 2011 2:22pm
Subject:bzr commit into mysql-5.5 branch (alexander.nozdrin:3430) Bug#11763166
View as plain text  
#At file:///home/alik/MySQL/bzr/00/bug55847/mysql-5.5-bug55847/ based on revid:alexander.nozdrin@stripped

 3430 Alexander Nozdrin	2011-04-08
      A patch for Bug#11763166 (55847: SHOW WARNINGS returns empty
      result set when SQLEXCEPTION is active.
      
      The problem was in a hackish THD::no_warnings_for_error attribute.
      When it was set, an error was not written to Warning_info -- only
      Diagnostics_area state was changed. That means, Diagnostics_area
      might contain error state, which is not present in Warning_info.
      
      The user-visible problem was that in some cases SHOW WARNINGS
      returned empty result set (i.e. there were no warnings) while
      the previous SQL statement failed. According to the MySQL
      protocol errors must be presented in warning list.
      
      The main idea of this patch is to remove THD::no_warnings_for_error.
      There were few places where it was used:
        - sql_admin.cc, handling of REPAIR TABLE USE_FRM.
        - sql_show.cc, when calling fill_schema_table_from_frm().
        - sql_show.cc, when calling fill_table().
      The fix is to either use internal-error-handlers, or to use
      temporary Warning_info storing warnings, which might be ignored.
      
      This patch is needed to fix Bug 11763162 (55843).

    modified:
      mysql-test/r/warnings.result
      mysql-test/t/warnings.test
      sql/sp_head.cc
      sql/sql_admin.cc
      sql/sql_class.cc
      sql/sql_class.h
      sql/sql_error.cc
      sql/sql_error.h
      sql/sql_parse.cc
      sql/sql_prepare.cc
      sql/sql_show.cc
      sql/sql_trigger.cc
=== modified file 'mysql-test/r/warnings.result'
--- a/mysql-test/r/warnings.result	2010-02-24 13:52:27 +0000
+++ b/mysql-test/r/warnings.result	2011-04-08 14:22:10 +0000
@@ -316,3 +316,25 @@ SHOW ERRORS;
 Level	Code	Message
 Error	1051	Unknown table 't1'
 End of 5.0 tests
+
+-- Bug#55847
+
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+CREATE TABLE t1(a INT UNIQUE);
+CREATE FUNCTION f1(x INT) RETURNS INT
+BEGIN
+INSERT INTO t1 VALUES(x);
+INSERT INTO t1 VALUES(x);
+RETURN x;
+END|
+
+SHOW TABLES WHERE f1(11) = 11;
+ERROR 23000: Duplicate entry '11' for key 'a'
+
+SHOW WARNINGS;
+Level	Code	Message
+Error	1062	Duplicate entry '11' for key 'a'
+
+DROP TABLE t1;
+DROP FUNCTION f1;

=== modified file 'mysql-test/t/warnings.test'
--- a/mysql-test/t/warnings.test	2009-11-13 10:17:53 +0000
+++ b/mysql-test/t/warnings.test	2011-04-08 14:22:10 +0000
@@ -228,3 +228,43 @@ DROP TABLE t1;
 SHOW ERRORS;
 
 --echo End of 5.0 tests
+
+#
+# Bug#55847: SHOW WARNINGS returns empty result set when SQLEXCEPTION is active
+#
+
+--echo
+--echo -- Bug#55847
+--echo
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+
+CREATE TABLE t1(a INT UNIQUE);
+
+delimiter |;
+
+CREATE FUNCTION f1(x INT) RETURNS INT
+BEGIN
+  INSERT INTO t1 VALUES(x);
+  INSERT INTO t1 VALUES(x);
+  RETURN x;
+END|
+
+delimiter ;|
+
+--echo
+
+--error ER_DUP_ENTRY
+SHOW TABLES WHERE f1(11) = 11;
+
+--echo
+
+SHOW WARNINGS;
+
+--echo
+
+DROP TABLE t1;
+DROP FUNCTION f1;

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2011-02-16 16:27:35 +0000
+++ b/sql/sp_head.cc	2011-04-08 14:22:10 +0000
@@ -1,4 +1,4 @@
-/* Copyright 2002-2008 MySQL AB, 2008-2010 Sun Microsystems, Inc.
+/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -11,7 +11,7 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
 
 #include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
 #include "sql_priv.h"
@@ -1217,7 +1217,8 @@ sp_head::execute(THD *thd, bool merge_da
   String old_packet;
   Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer;
   Object_creation_ctx *saved_creation_ctx;
-  Warning_info *saved_warning_info, warning_info(thd->warning_info->warn_id());
+  Warning_info *saved_warning_info;
+  Warning_info warning_info(thd->warning_info->warn_id(), false);
 
   /*
     Just reporting a stack overrun error

=== modified file 'sql/sql_admin.cc'
--- a/sql/sql_admin.cc	2011-03-08 08:41:57 +0000
+++ b/sql/sql_admin.cc	2011-04-08 14:22:10 +0000
@@ -263,7 +263,7 @@ static bool mysql_admin_table(THD* thd,
                               const char *operator_name,
                               thr_lock_type lock_type,
                               bool open_for_modify,
-                              bool no_warnings_for_error,
+                              bool repair_table_use_frm,
                               uint extra_open_options,
                               int (*prepare_func)(THD *, TABLE_LIST *,
                                                   HA_CHECK_OPT *),
@@ -331,18 +331,43 @@ static bool mysql_admin_table(THD* thd,
       lex->query_tables= table;
       lex->query_tables_last= &table->next_global;
       lex->query_tables_own_last= 0;
-      /*
-        Under locked tables, we know that the table can be opened,
-        so any errors opening the table are logical errors.
-        In these cases it makes sense to report them.
-      */
-      if (!thd->locked_tables_mode)
-        thd->no_warnings_for_error= no_warnings_for_error;
+
       if (view_operator_func == NULL)
         table->required_type=FRMTYPE_TABLE;
 
-      open_error= open_and_lock_tables(thd, table, TRUE, 0);
-      thd->no_warnings_for_error= 0;
+      if (!thd->locked_tables_mode && repair_table_use_frm)
+      {
+        /*
+          If we're not under LOCK TABLES and we're executing REPAIR TABLE
+          USE_FRM, we need to ignore errors from open_and_lock_tables().
+          REPAIR TABLE USE_FRM is a heavy weapon used when a table is
+          critically damaged, so open_and_lock_tables() will most likely
+          report errors. Those errors are not interesting for the user
+          because it's already known that the table is badly damaged.
+        */
+
+        Warning_info wi(thd->query_id, false);
+        Warning_info *wi_saved= thd->warning_info;
+
+        thd->warning_info= &wi;
+
+        open_error= open_and_lock_tables(thd, table, TRUE, 0);
+
+        thd->warning_info= wi_saved;
+      }
+      else
+      {
+        /*
+          It's assumed that even if it is REPAIR TABLE USE_FRM, the table
+          can be opened if we're under LOCK TABLES (otherwise LOCK TABLES
+          would fail). Thus, the only errors we could have from
+          open_and_lock_tables() are logical ones, like incorrect locking
+          mode. It does make sense for the user to see such errors.
+        */
+
+        open_error= open_and_lock_tables(thd, table, TRUE, 0);
+      }
+
       table->next_global= save_next_global;
       table->next_local= save_next_local;
       thd->open_options&= ~extra_open_options;

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2011-01-27 13:25:27 +0000
+++ b/sql/sql_class.cc	2011-04-08 14:22:10 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -11,8 +11,7 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
 
 /*****************************************************************************
 **
@@ -522,7 +521,7 @@ THD::THD()
 #if defined(ENABLED_DEBUG_SYNC)
    debug_sync_control(0),
 #endif /* defined(ENABLED_DEBUG_SYNC) */
-   main_warning_info(0)
+   main_warning_info(0, false)
 {
   ulong tmp;
 
@@ -581,7 +580,7 @@ THD::THD()
   client_capabilities= 0;                       // minimalistic client
   ull=0;
   system_thread= NON_SYSTEM_THREAD;
-  cleanup_done= abort_on_warning= no_warnings_for_error= 0;
+  cleanup_done= abort_on_warning= 0;
   peer_port= 0;					// For SHOW PROCESSLIST
   transaction.m_pending_rows_event= 0;
   transaction.on= 1;
@@ -854,10 +853,6 @@ MYSQL_ERROR* THD::raise_condition(uint s
 
   query_cache_abort(&query_cache_tls);
 
-  /* FIXME: broken special case */
-  if (no_warnings_for_error && (level == MYSQL_ERROR::WARN_LEVEL_ERROR))
-    DBUG_RETURN(NULL);
-
   /* When simulating OOM, skip writing to error log to avoid mtr errors */
   DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_RETURN(NULL););
 

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2011-03-08 17:39:25 +0000
+++ b/sql/sql_class.h	2011-04-08 14:22:10 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -2089,7 +2089,6 @@ public:
   bool       enable_slow_log;   /* enable slow log for current statement */
   bool	     abort_on_warning;
   bool 	     got_warning;       /* Set on call to push_warning() */
-  bool	     no_warnings_for_error; /* no warnings on call to my_error() */
   /* set during loop of derived table processing */
   bool       derived_tables_processing;
   my_bool    tablespace_op;	/* This is TRUE in DISCARD/IMPORT TABLESPACE */
@@ -2807,6 +2806,7 @@ private:
 
   /** The current internal error handler for this thread, or NULL. */
   Internal_error_handler *m_internal_handler;
+
   /**
     The lex to hold the parsed tree of conventional (non-prepared) queries.
     Whereas for prepared and stored procedure statements we use an own lex

=== modified file 'sql/sql_error.cc'
--- a/sql/sql_error.cc	2010-11-12 14:20:12 +0000
+++ b/sql/sql_error.cc	2011-04-08 14:22:10 +0000
@@ -1,5 +1,4 @@
-/* Copyright (C) 1995-2002 MySQL AB,
-   Copyright (C) 2008-2009 Sun Microsystems, Inc
+/* Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -458,10 +457,11 @@ Diagnostics_area::disable_status()
   m_status= DA_DISABLED;
 }
 
-Warning_info::Warning_info(ulonglong warn_id_arg)
+Warning_info::Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings)
   :m_statement_warn_count(0),
   m_current_row_for_warning(1),
   m_warn_id(warn_id_arg),
+  m_allow_unlimited_warnings(allow_unlimited_warnings),
   m_read_only(FALSE)
 {
   /* Initialize sub structures */
@@ -543,7 +543,8 @@ MYSQL_ERROR *Warning_info::push_warning(
 
   if (! m_read_only)
   {
-    if (m_warn_list.elements < thd->variables.max_error_count)
+    if (m_allow_unlimited_warnings ||
+        m_warn_list.elements < thd->variables.max_error_count)
     {
       cond= new (& m_warn_root) MYSQL_ERROR(& m_warn_root);
       if (cond)
@@ -559,6 +560,20 @@ MYSQL_ERROR *Warning_info::push_warning(
   return cond;
 }
 
+MYSQL_ERROR *Warning_info::push_warning(THD *thd, const MYSQL_ERROR *sql_condition)
+{
+  MYSQL_ERROR *new_condition= push_warning(thd,
+                                           sql_condition->get_sql_errno(),
+                                           sql_condition->get_sqlstate(),
+                                           sql_condition->get_level(),
+                                           sql_condition->get_message_text());
+
+  if (new_condition)
+    new_condition->copy_opt_attributes(sql_condition);
+
+  return new_condition;
+}
+
 /*
   Push the warning to error list if there is still room in the list
 

=== modified file 'sql/sql_error.h'
--- a/sql/sql_error.h	2010-11-12 12:56:21 +0000
+++ b/sql/sql_error.h	2011-04-08 14:22:10 +0000
@@ -1,5 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB,
-   Copyright (C) 2008-2009 Sun Microsystems, Inc
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -12,7 +11,7 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
 
 #ifndef SQL_ERROR_H
 #define SQL_ERROR_H
@@ -323,10 +322,13 @@ class Warning_info
 {
   /** A memory root to allocate warnings and errors */
   MEM_ROOT           m_warn_root;
+
   /** List of warnings of all severities (levels). */
   List <MYSQL_ERROR> m_warn_list;
+
   /** A break down of the number of warnings per severity (level). */
   uint	             m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
+
   /**
     The number of warnings of the current statement. Warning_info
     life cycle differs from statement life cycle -- it may span
@@ -334,20 +336,25 @@ class Warning_info
     m_statement_warn_count 0, whereas m_warn_list is not empty.
   */
   uint	             m_statement_warn_count;
+
   /*
     Row counter, to print in errors and warnings. Not increased in
     create_sort_index(); may differ from examined_row_count.
   */
   ulong              m_current_row_for_warning;
-  /** Used to optionally clear warnings only once per statement.  */
+
+  /** Used to optionally clear warnings only once per statement. */
   ulonglong          m_warn_id;
 
+  /** Indicates if push_warning() should limit number of warnings. */
+  bool               m_allow_unlimited_warnings;
+
 private:
   Warning_info(const Warning_info &rhs); /* Not implemented */
   Warning_info& operator=(const Warning_info &rhs); /* Not implemented */
 public:
 
-  Warning_info(ulonglong warn_id_arg);
+  Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings);
   ~Warning_info();
 
   /**
@@ -384,19 +391,13 @@ public:
   void append_warnings(THD *thd, List<MYSQL_ERROR> *src)
   {
     MYSQL_ERROR *err;
-    MYSQL_ERROR *copy;
     List_iterator_fast<MYSQL_ERROR> it(*src);
     /*
       Don't use ::push_warning() to avoid invocation of condition
       handlers or escalation of warnings to errors.
     */
     while ((err= it++))
-    {
-      copy= Warning_info::push_warning(thd, err->get_sql_errno(), err->get_sqlstate(),
-                                       err->get_level(), err->get_message_text());
-      if (copy)
-        copy->copy_opt_attributes(err);
-    }
+      Warning_info::push_warning(thd, err);
   }
 
   /**
@@ -462,6 +463,9 @@ public:
                             MYSQL_ERROR::enum_warning_level level,
                             const char* msg);
 
+  /** Add a new condition to the current list. */
+  MYSQL_ERROR *push_warning(THD *thd, const MYSQL_ERROR *sql_condition);
+
   /**
     Set the read only status for this statement area.
     This is a privileged operation, reserved for the implementation of

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2011-03-08 17:39:25 +0000
+++ b/sql/sql_parse.cc	2011-04-08 14:22:10 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -7223,10 +7223,20 @@ bool parse_sql(THD *thd,
 
   bool mysql_parse_status= MYSQLparse(thd) != 0;
 
-  /* Check that if MYSQLparse() failed, thd->is_error() is set. */
+  /*
+    Check that if MYSQLparse() failed either thd->is_error() is set, or an
+    internal error handler is set.
+
+    The assert will not catch a situation where parsing fails without an
+    error reported if an error handler exists. The problem is that the
+    error handler might have intercepted the error, so thd->is_error() is
+    not set. However, there is no way to be 100% sure here (the error
+    handler might be for other errors than parsing one).
+  */
 
   DBUG_ASSERT(!mysql_parse_status ||
-              (mysql_parse_status && thd->is_error()));
+              (mysql_parse_status && thd->is_error()) ||
+              (mysql_parse_status && thd->get_internal_handler()));
 
   /* Reset parser state. */
 

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2011-03-15 12:57:36 +0000
+++ b/sql/sql_prepare.cc	2011-04-08 14:22:10 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -2842,7 +2842,8 @@ void mysql_stmt_get_longdata(THD *thd, c
   param= stmt->param_array[param_number];
 
   Diagnostics_area new_stmt_da, *save_stmt_da= thd->stmt_da;
-  Warning_info new_warnning_info(thd->query_id), *save_warinig_info= thd->warning_info;
+  Warning_info new_warnning_info(thd->query_id, false);
+  Warning_info *save_warinig_info= thd->warning_info;
 
   thd->stmt_da= &new_stmt_da;
   thd->warning_info= &new_warnning_info;
@@ -3900,7 +3901,7 @@ Ed_result_set::Ed_result_set(List<Ed_row
 */
 
 Ed_connection::Ed_connection(THD *thd)
-  :m_warning_info(thd->query_id),
+  :m_warning_info(thd->query_id, false),
   m_thd(thd),
   m_rsets(0),
   m_current_rset(0)

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2011-04-06 15:11:43 +0000
+++ b/sql/sql_show.cc	2011-04-08 14:22:10 +0000
@@ -3416,6 +3416,45 @@ end:
 
 
 /**
+  Trigger_error_handler is intended to intercept and silence SQL conditions
+  that might happen during trigger loading for SHOW statements.
+  The potential SQL conditions are:
+
+    - ER_PARSE_ERROR -- this error is thrown if a trigger definition file
+      is damaged or contains invalid CREATE TRIGGER statement. That should
+      not happen in normal life.
+
+    - ER_TRG_NO_DEFINER -- this warning is thrown when we're loading a
+      trigger created/imported in/from the version of MySQL, which does not
+      support trigger definers.
+
+    - ER_TRG_NO_CREATION_CTX -- this warning is thrown when we're loading a
+      trigger created/imported in/from the version of MySQL, which does not
+      support trigger creation contexts.
+*/
+
+class Trigger_error_handler : public Internal_error_handler
+{
+public:
+  bool handle_condition(THD *thd,
+                        uint sql_errno,
+                        const char* sqlstate,
+                        MYSQL_ERROR::enum_warning_level level,
+                        const char* msg,
+                        MYSQL_ERROR ** cond_hdl)
+  {
+    if (sql_errno == ER_PARSE_ERROR ||
+        sql_errno == ER_TRG_NO_DEFINER ||
+        sql_errno == ER_TRG_NO_CREATION_CTX)
+      return true;
+
+    return false;
+  }
+};
+
+
+
+/**
   @brief          Fill I_S tables whose data are retrieved
                   from frm files and storage engine
 
@@ -3570,7 +3609,6 @@ int get_all_tables(THD *thd, TABLE_LIST
         acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0))
 #endif
     {
-      thd->no_warnings_for_error= 1;
       List<LEX_STRING> table_names;
       int res= make_table_name_list(thd, &table_names, lex,
                                     &lookup_field_vals,
@@ -3619,9 +3657,23 @@ int get_all_tables(THD *thd, TABLE_LIST
             if (!(table_open_method & ~OPEN_FRM_ONLY) &&
                 !with_i_schema)
             {
-              if (!fill_schema_table_from_frm(thd, tables, schema_table, db_name,
-                                              table_name, schema_table_idx,
-                                              can_deadlock))
+              /*
+                Here we need to filter out warnings, which can happen
+                during loading of triggers in fill_schema_table_from_frm(),
+                because we don't need those warnings to pollute output of
+                SELECT from I_S / SHOW-statements.
+              */
+
+              Trigger_error_handler err_handler;
+              thd->push_internal_handler(&err_handler);
+
+              int res= fill_schema_table_from_frm(thd, tables, schema_table, db_name,
+                                                  table_name, schema_table_idx,
+                                                  can_deadlock);
+
+              thd->pop_internal_handler();
+
+              if (!res)
                 continue;
             }
 
@@ -3631,7 +3683,6 @@ int get_all_tables(THD *thd, TABLE_LIST
               Set the parent lex of 'sel' because it is needed by
               sel.init_query() which is called inside make_table_list.
             */
-            thd->no_warnings_for_error= 1;
             sel.parent_lex= lex;
             if (make_table_list(thd, &sel, db_name, table_name))
               goto err;
@@ -6675,6 +6726,92 @@ int make_schema_select(THD *thd, SELECT_
 }
 
 
+/**
+  Fill INFORMATION_SCHEMA-table, leave correct Diagnostics_area /
+  Warning_info state after itself.
+
+  This function is a wrapper around ST_SCHEMA_TABLE::fill_table(), which
+  may "partially silence" some errors. The thing is that during
+  fill_table() many errors might be emitted. These errors stem from the
+  nature of fill_table().
+
+  For example, SELECT ... FROM INFORMATION_SCHEMA.xxx WHERE TABLE_NAME = 'xxx'
+  results in a number of 'Table <db name>.xxx does not exist' errors,
+  because fill_table() tries to open the 'xxx' table in every possible
+  database.
+
+  Those errors are cleared (the error status is cleared from
+  Diagnostics_area) inside fill_table(), but they remain in Warning_info
+  (Warning_info is not cleared because it may contain useful warnings).
+
+  This function is responsible for making sure that Warning_info does not
+  contain warnings corresponding to the cleared errors.
+
+  @note: THD::no_warnings_for_error used to be set before calling
+  fill_table(), thus those errors didn't go to Warning_info. This is not
+  the case now (THD::no_warnings_for_error was eliminated as a hack), so we
+  need to take care of those warnings here.
+
+  @param thd            Thread context.
+  @param table_list     I_S table.
+  @param join_table     JOIN/SELECT table.
+
+  @return Error status.
+  @retval TRUE Error.
+  @retval FALSE Success.
+*/
+static bool do_fill_table(THD *thd,
+                          TABLE_LIST *table_list,
+                          JOIN_TAB *join_table)
+{
+  // NOTE: fill_table() may generate many "useless" warnings, which will be
+  // ignored afterwards. On the other hand, there might be "useful"
+  // warnings, which should be presented to the user. Warning_info usually
+  // stores no more than THD::variables.max_error_count warnings.
+  // The problem is that "useless warnings" may occupy all the slots in the
+  // Warning_info, so "usefull warnings" get rejected. In order to avoid
+  // that problem we create a Warning_info instance, which is capable of
+  // storing "unlimited" number of warnings.
+  Warning_info wi(thd->query_id, true);
+  Warning_info *wi_saved= thd->warning_info;
+
+  thd->warning_info= &wi;
+
+  bool res= table_list->schema_table->fill_table(
+    thd, table_list, join_table->select_cond);
+
+  thd->warning_info= wi_saved;
+
+  // Pass an error if any.
+
+  if (thd->stmt_da->is_error())
+  {
+    thd->warning_info->push_warning(thd,
+                                    thd->stmt_da->sql_errno(),
+                                    thd->stmt_da->get_sqlstate(),
+                                    MYSQL_ERROR::WARN_LEVEL_ERROR,
+                                    thd->stmt_da->message());
+  }
+
+  // Pass warnings (if any).
+  //
+  // Filter out warnings with WARN_LEVEL_ERROR level, because they
+  // correspond to the errors which were filtered out in fill_table().
+
+
+  List_iterator_fast<MYSQL_ERROR> it(wi.warn_list());
+  MYSQL_ERROR *err;
+
+  while ((err= it++))
+  {
+    if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR)
+      thd->warning_info->push_warning(thd, err);
+  }
+
+  return res;
+}
+
+
 /*
   Fill temporary schema tables before SELECT
 
@@ -6697,7 +6834,6 @@ bool get_schema_tables_result(JOIN *join
   bool result= 0;
   DBUG_ENTER("get_schema_tables_result");
 
-  thd->no_warnings_for_error= 1;
   for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++)
   {  
     if (!tab->table || !tab->table->pos_in_table_list)
@@ -6748,8 +6884,7 @@ bool get_schema_tables_result(JOIN *join
       else
         table_list->table->file->stats.records= 0;
 
-      if (table_list->schema_table->fill_table(thd, table_list,
-                                               tab->select_cond))
+      if (do_fill_table(thd, table_list, tab))
       {
         result= 1;
         join->error= 1;
@@ -6761,7 +6896,6 @@ bool get_schema_tables_result(JOIN *join
       table_list->schema_table_state= executed_place;
     }
   }
-  thd->no_warnings_for_error= 0;
   DBUG_RETURN(result);
 }
 

=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc	2011-03-10 08:07:57 +0000
+++ b/sql/sql_trigger.cc	2011-04-08 14:22:10 +0000
@@ -1225,13 +1225,12 @@ bool Table_triggers_list::check_n_load(T
 
           DBUG_RETURN(1); // EOM
         }
-        
-        if (!thd->no_warnings_for_error)
-          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                              ER_TRG_NO_CREATION_CTX,
-                              ER(ER_TRG_NO_CREATION_CTX),
-                              (const char*) db,
-                              (const char*) table_name);
+
+        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                            ER_TRG_NO_CREATION_CTX,
+                            ER(ER_TRG_NO_CREATION_CTX),
+                            (const char*) db,
+                            (const char*) table_name);
 
         if (!(trg_client_cs_name= alloc_lex_string(&table->mem_root)) ||
             !(trg_connection_cl_name= alloc_lex_string(&table->mem_root)) ||
@@ -1362,12 +1361,12 @@ bool Table_triggers_list::check_n_load(T
             MySQL, which does not support triggers definers. We should emit
             warning here.
           */
-          if (!thd->no_warnings_for_error)
-            push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                                ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER),
-                                (const char*) db,
-                                (const char*) sp->m_name.str);
-          
+
+          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                              ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER),
+                              (const char*) db,
+                              (const char*) sp->m_name.str);
+
           /*
             Set definer to the '' to correct displaying in the information
             schema.


Attachment: [text/bzr-bundle] bzr/alexander.nozdrin@oracle.com-20110408142210-l5nr6aug0pxwushy.bundle
Thread
bzr commit into mysql-5.5 branch (alexander.nozdrin:3430) Bug#11763166Alexander Nozdrin8 Apr