From b7339445147894e86fb00b913d6320e22cf95d2f Mon Sep 17 00:00:00 2001
From: Michael Widenius <monty@askmonty.org>
Date: Fri, 2 Sep 2011 01:22:34 +0300
Subject: [PATCH] Added logging of all errors from
 my_read/my_write/my_pread/my_pwrite/my_open & my_malloc to mysqld error log
 if one sets log-warning to 10 or 11 The idea is that my_global_flags is ored
 to the MyFlags parameter for the above functions if the MY_WME flag is not
 set. As the my_global_flags has ME_JUST_INFO (mark error as 'note') and
 possible ME_NOREFRESH (write error to log) this will force mysqld to log the
 not critical error to the log as a note.

include/my_sys.h:
  Moved MY_SYNC_DIR to ensure it never clashes with ME_JUST_INFO
  Added my_global_flags
mysql-test/Makefile.am:
  Removed not used bugs directory
mysys/my_init.c:
  Added my_global_flags, a variable that is ored to MyFlags in a those mysys functions we want extra logging.
mysys/my_malloc.c:
  Added support for my_global_flags
mysys/my_open.c:
  Added support for my_global_flags
mysys/my_pread.c:
  Added support for my_global_flags
mysys/my_read.c:
  Added support for my_global_flags
mysys/my_static.c:
  Added my_global_flags
mysys/my_write.c:
  Added support for my_global_flags
sql/mysqld.cc:
  Set my_global_flags for warning levels 10 & 11
sql/sql_base.cc:
  Don't increment unhandled errors for notes or warnings.
---
 include/my_sys.h       |  4 ++--
 mysql-test/Makefile.am |  1 -
 mysys/my_init.c        |  2 ++
 mysys/my_malloc.c      |  6 +++++-
 mysys/my_open.c        | 12 +++++++++---
 mysys/my_pread.c       | 30 ++++++++++++++++++------------
 mysys/my_read.c        |  8 ++++++--
 mysys/my_static.c      |  1 +
 mysys/my_write.c       | 11 +++++++----
 sql/mysqld.cc          | 18 +++++++++++++++---
 sql/sql_base.cc        |  5 +++--
 11 files changed, 68 insertions(+), 30 deletions(-)

diff --git a/include/my_sys.h b/include/my_sys.h
index d391492983d..aa17fe365eb 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -49,7 +49,6 @@ extern int NEAR my_errno;		/* Last error in mysys */
 #define MY_WME		16	/* Write message on error */
 #define MY_WAIT_IF_FULL 32	/* Wait and try again if disk full error */
 #define MY_IGNORE_BADFD 32      /* my_sync: ignore 'bad descriptor' errors */
-#define MY_SYNC_DIR     1024    /* my_create/delete/rename: sync directory */
 #define MY_RAID         64      /* Support for RAID */
 #define MY_FULL_IO     512      /* For my_read - loop intil I/O is complete */
 #define MY_DONT_CHECK_FILESIZE 128 /* Option to init_io_cache() */
@@ -70,6 +69,7 @@ extern int NEAR my_errno;		/* Last error in mysys */
 #define MY_DONT_OVERWRITE_FILE 2048 /* my_copy: Don't overwrite file */
 #define MY_THREADSAFE 2048      /* my_seek(): lock fd mutex */
 #define MY_SYNC       4096      /* my_copy(): sync dst file */
+#define MY_SYNC_DIR   32768     /* my_create/delete/rename: sync directory */
 
 #define MY_CHECK_ERROR	1	/* Params to my_end; Check open-close */
 #define MY_GIVE_INFO	2	/* Give time info about process*/
@@ -255,7 +255,7 @@ extern ulong    my_file_total_opened;
 extern ulong    my_sync_count;
 extern uint	mysys_usage_id;
 extern my_bool	my_init_done;
-
+extern myf      my_global_flags;        /* Set to MY_WME for more error messages */
 					/* Point to current my_message() */
 extern void (*my_sigtstp_cleanup)(void),
 					/* Executed before jump to shell */
diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am
index 4ce17815f9f..b9318add0c6 100644
--- a/mysql-test/Makefile.am
+++ b/mysql-test/Makefile.am
@@ -84,7 +84,6 @@ TEST_DIRS = t r include std_data std_data/parts collections \
 	std_data/funcs_1 \
 	extra/binlog_tests/ extra/rpl_tests \
 	suite/binlog suite/binlog/t suite/binlog/r suite/binlog/std_data \
-	suite/bugs suite/bugs/data suite/bugs/t suite/bugs/r \
 	suite/federated \
 	suite/pbxt/t suite/pbxt/r suite/pbxt \
 	suite/vcol suite/vcol/t suite/vcol/r suite/vcol/inc \
diff --git a/mysys/my_init.c b/mysys/my_init.c
index e7ab9ba7a1f..0b0d7d85f15 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -77,6 +77,8 @@ my_bool my_init(void)
   mysys_usage_id++;
   my_umask= 0660;                       /* Default umask for new files */
   my_umask_dir= 0700;                   /* Default umask for new directories */
+  my_global_flags= 0;
+
   init_glob_errs();
   my_progname_short= "unknown";
   if (my_progname)
diff --git a/mysys/my_malloc.c b/mysys/my_malloc.c
index 330ef07ed30..25180edc06f 100644
--- a/mysys/my_malloc.c
+++ b/mysys/my_malloc.c
@@ -31,6 +31,8 @@ void *my_malloc(size_t size, myf my_flags)
   void* point;
   DBUG_ENTER("my_malloc");
   DBUG_PRINT("my",("size: %lu  my_flags: %d", (ulong) size, my_flags));
+  if (!(my_flags & (MY_WME | MY_FAE)))
+    my_flags|= my_global_flags;
 
   if (!size)
     size=1;					/* Safety */
@@ -48,7 +50,9 @@ void *my_malloc(size_t size, myf my_flags)
     if (my_flags & MY_FAE)
       error_handler_hook=fatal_error_handler_hook;
     if (my_flags & (MY_FAE+MY_WME))
-      my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG+ME_NOREFRESH),size);
+      my_error(EE_OUTOFMEMORY,
+               MYF(ME_BELL | ME_WAITTANG | ME_NOREFRESH | (my_flags & ME_JUST_INFO)),
+               size);
     DBUG_EXECUTE_IF("simulate_out_of_memory",
                     DBUG_SET("-d,simulate_out_of_memory"););
     if (my_flags & MY_FAE)
diff --git a/mysys/my_open.c b/mysys/my_open.c
index fe7f65c450b..3980e3a9a77 100644
--- a/mysys/my_open.c
+++ b/mysys/my_open.c
@@ -43,6 +43,9 @@ File my_open(const char *FileName, int Flags, myf MyFlags)
   DBUG_ENTER("my_open");
   DBUG_PRINT("my",("Name: '%s'  Flags: %d  MyFlags: %d",
 		   FileName, Flags, MyFlags));
+  if (!(MyFlags & (MY_WME | MY_FAE | MY_FFNF)))
+    MyFlags|= my_global_flags;
+
 #if defined(__WIN__)
   /* 
     Check that we don't try to open or create a file name that may
@@ -92,6 +95,8 @@ int my_close(File fd, myf MyFlags)
   int err;
   DBUG_ENTER("my_close");
   DBUG_PRINT("my",("fd: %d  MyFlags: %d",fd, MyFlags));
+  if (!(MyFlags & (MY_WME | MY_FAE)))
+    MyFlags|= my_global_flags;
 
   pthread_mutex_lock(&THR_LOCK_open);
   do
@@ -104,7 +109,8 @@ int my_close(File fd, myf MyFlags)
     DBUG_PRINT("error",("Got error %d on close",err));
     my_errno=errno;
     if (MyFlags & (MY_FAE | MY_WME))
-      my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),my_filename(fd),errno);
+      my_error(EE_BADCLOSE, MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))),
+               my_filename(fd),errno);
   }
   if ((uint) fd < my_file_limit && my_file_info[fd].type != UNOPEN)
   {
@@ -180,8 +186,8 @@ File my_register_filename(File fd, const char *FileName, enum file_type
   {
     if (my_errno == EMFILE)
       error_message_number= EE_OUT_OF_FILERESOURCES;
-    DBUG_PRINT("error",("print err: %d",error_message_number));
-    my_error(error_message_number, MYF(ME_BELL+ME_WAITTANG),
+    my_error(error_message_number,
+             MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))),
              FileName, my_errno);
   }
   DBUG_RETURN(-1);
diff --git a/mysys/my_pread.c b/mysys/my_pread.c
index 836f5a92963..5d991f849c9 100644
--- a/mysys/my_pread.c
+++ b/mysys/my_pread.c
@@ -58,6 +58,9 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
 		   Filedes, ullstr(offset, llbuf), (long) Buffer,
                    (ulong)Count, MyFlags));
 #endif
+  if (!(MyFlags & (MY_WME | MY_FAE | MY_FNABP)))
+    MyFlags|= my_global_flags;
+
   for (;;)
   {
     errno= 0;    /* Linux, Windows don't reset this on EOF/success */
@@ -92,11 +95,13 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
       if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
       {
 	if (readbytes == (size_t) -1)
-	  my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+	  my_error(EE_READ,
+                   MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))),
 		   my_filename(Filedes),my_errno);
 	else if (MyFlags & (MY_NABP | MY_FNABP))
-	  my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
-		   my_filename(Filedes),my_errno);
+	  my_error(EE_EOFERR,
+                   MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))),
+                   my_filename(Filedes),my_errno);
       }
       if (readbytes == (size_t) -1 || (MyFlags & (MY_FNABP | MY_NABP)))
 	DBUG_RETURN(MY_FILE_ERROR);		/* Return with error */
@@ -143,6 +148,8 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
 #endif
   errors= 0;
   written= 0;
+  if (!(MyFlags & (MY_WME | MY_FAE | MY_FNABP)))
+    MyFlags|= my_global_flags;
 
   for (;;)
   {
@@ -183,20 +190,19 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
     if ((writenbytes && writenbytes != (size_t) -1) || my_errno == EINTR)
       continue;					/* Retry */
 #endif
+
+    /* Don't give a warning if it's ok that we only write part of the data */
     if (MyFlags & (MY_NABP | MY_FNABP))
     {
       if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
-      {
-	my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG),
-		 my_filename(Filedes),my_errno);
-      }
-      DBUG_RETURN(MY_FILE_ERROR);		/* Error on read */
+        my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))),
+                 my_filename(Filedes),my_errno);
+      DBUG_RETURN(MY_FILE_ERROR);		/* Error on write */
     }
-    else
-      break;					/* Return bytes written */
+    break;					/* Return bytes written */
   }
   DBUG_EXECUTE_IF("check", my_seek(Filedes, -1, SEEK_SET, MYF(0)););
   if (MyFlags & (MY_NABP | MY_FNABP))
-    DBUG_RETURN(0);			/* Want only errors */
-  DBUG_RETURN(writenbytes+written); /* purecov: inspected */
+    DBUG_RETURN(0);                             /* Want only errors */
+  DBUG_RETURN(writenbytes+written);           /* purecov: inspected */
 } /* my_pwrite */
diff --git a/mysys/my_read.c b/mysys/my_read.c
index 25ffe73d813..e2023b14337 100644
--- a/mysys/my_read.c
+++ b/mysys/my_read.c
@@ -40,6 +40,8 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
   DBUG_PRINT("my",("fd: %d  Buffer: 0x%lx  Count: %lu  MyFlags: %d",
                    Filedes, (long) Buffer, (ulong) Count, MyFlags));
   save_count= Count;
+  if (!(MyFlags & (MY_WME | MY_FAE | MY_FNABP)))
+    MyFlags|= my_global_flags;
 
   for (;;)
   {
@@ -64,10 +66,12 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
       if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
       {
         if (readbytes == (size_t) -1)
-          my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+          my_error(EE_READ,
+                   MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))),
                    my_filename(Filedes),my_errno);
         else if (MyFlags & (MY_NABP | MY_FNABP))
-          my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+          my_error(EE_EOFERR,
+                   MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))),
                    my_filename(Filedes),my_errno);
       }
       if (readbytes == (size_t) -1 ||
diff --git a/mysys/my_static.c b/mysys/my_static.c
index 08653d03d21..07e106cb1ea 100644
--- a/mysys/my_static.c
+++ b/mysys/my_static.c
@@ -32,6 +32,7 @@ char		NEAR curr_dir[FN_REFLEN]= {0},
 ulong		my_stream_opened=0,my_file_opened=0, my_tmp_file_created=0;
 ulong           my_file_total_opened= 0;
 int		NEAR my_umask=0664, NEAR my_umask_dir=0777;
+myf             my_global_flags;
 #ifndef THREAD
 int		NEAR my_errno=0;
 #endif
diff --git a/mysys/my_write.c b/mysys/my_write.c
index 52127545888..3ab9f21be16 100644
--- a/mysys/my_write.c
+++ b/mysys/my_write.c
@@ -28,6 +28,8 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
   DBUG_PRINT("my",("fd: %d  Buffer: 0x%lx  Count: %lu  MyFlags: %d",
 		   Filedes, (long) Buffer, (ulong) Count, MyFlags));
   errors=0; written=0;
+  if (!(MyFlags & (MY_WME | MY_FAE | MY_FNABP)))
+    MyFlags|= my_global_flags;
 
   /* The behavior of write(fd, buf, 0) is not portable */
   if (unlikely(!Count))
@@ -78,19 +80,20 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
     else
       continue;					/* Retry */
 #endif
+
+    /* Don't give a warning if it's ok that we only write part of the data */
     if (MyFlags & (MY_NABP | MY_FNABP))
     {
       if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
       {
-	my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
+	my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))),
 		 my_filename(Filedes),my_errno);
       }
       DBUG_RETURN(MY_FILE_ERROR);		/* Error on read */
     }
-    else
-      break;					/* Return bytes written */
+    break;					/* Return bytes written */
   }
   if (MyFlags & (MY_NABP | MY_FNABP))
-    DBUG_RETURN(0);			/* Want only errors */
+    DBUG_RETURN(0);                             /* Want only errors */
   DBUG_RETURN(writenbytes+written);
 } /* my_write */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index a24d60da596..7e656bbd3bd 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3032,7 +3032,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
   MYSQL_ERROR::enum_warning_level level;
   sql_print_message_func func;
   DBUG_ENTER("my_message_sql");
-  DBUG_PRINT("error", ("error: %u  message: '%s'", error, str));
+  DBUG_PRINT("error", ("error: %u  message: '%s'  Flag: %d", error, str, MyFlags));
 
   DBUG_ASSERT(str != NULL);
   /*
@@ -3076,7 +3076,10 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
       this could be improved by having a common stack of handlers.
     */
     if (thd->handle_error(error, str, level))
+    {
+      DBUG_PRINT("info", ("error handled by handle_error()"));
       DBUG_RETURN(0);
+    }
 
     if (level == MYSQL_ERROR::WARN_LEVEL_WARN)
       push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, error, str);
@@ -6495,8 +6498,7 @@ each time the SQL thread starts.",
    "log and this option just turns on --log-bin instead.",
    &opt_update_logname, &opt_update_logname, 0, GET_STR,
    OPT_ARG, 0, 0, 0, 0, 0, 0},
-  {"log-warnings", 'W', "Log some not critical warnings to the general log "
-   "file.",
+  {"log-warnings", 'W', "Log some not critical warnings to the general log file.  Value can be between 0-6; The higher value, the more warnings",
    &global_system_variables.log_warnings,
    &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, 0,
    0, 0, 0},
@@ -9419,6 +9421,16 @@ static int get_options(int *argc,char **argv)
   myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
   my_crc_dbug_check= opt_my_crc_dbug_check;
 
+  /*
+    Log mysys errors when we don't have a thd or thd->log_all_errors is set (recovery) to
+    the log.  This is mainly useful for debugging strange system errors.
+  */
+  if (global_system_variables.log_warnings >= 10)
+    my_global_flags= MY_WME | ME_JUST_INFO;
+  /* Log all errors not handled by thd->handle_error() to my_message_sql() */
+  if (global_system_variables.log_warnings >= 11)
+    my_global_flags|= ME_NOREFRESH;
+
   /* long_query_time is in microseconds */
   global_system_variables.long_query_time= max_system_variables.long_query_time=
     (longlong) (long_query_time * 1000000.0);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 0874ee16127..4826603c720 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -61,7 +61,7 @@ class Prelock_error_handler : public Internal_error_handler
 bool
 Prelock_error_handler::handle_error(uint sql_errno,
                                     const char * /* message */,
-                                    MYSQL_ERROR::enum_warning_level /* level */,
+                                    MYSQL_ERROR::enum_warning_level level,
                                     THD * /* thd */)
 {
   if (sql_errno == ER_NO_SUCH_TABLE)
@@ -70,7 +70,8 @@ Prelock_error_handler::handle_error(uint sql_errno,
     return TRUE;
   }
 
-  m_unhandled_errors++;
+  if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
+    m_unhandled_errors++;
   return FALSE;
 }
 
-- 
2.30.9