From 5512100c6aa1cfc49cbfb369c6ddf4079b47238c Mon Sep 17 00:00:00 2001
From: "cmiller@zippy.cornsilk.net" <>
Date: Tue, 3 Oct 2006 13:38:25 -0400
Subject: Bug #14262: SP: DROP PROCEDURE|VIEW (maybe more) write to binlog too
 late \ 	(race cond)

It was possible for one thread to interrupt a Data Definition Language
statement and thereby get messages to the binlog out of order.  Consider:

Connection 1: Drop Foo x
Connection 2: Create or replace Foo x
Connection 2: Log "Create or replace Foo x"
Connection 1: Log "Drop Foo x"

Local end would have Foo x, but the replicated slaves would not.

The fix for this is to wrap all DDL and logging of a kind in the same mutex.
Since we already use mutexes for the various parts of altering the server,
this only entails moving the logging events down close to the action, inside
the mutex protection.
---
 sql/sql_view.cc | 47 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 43 insertions(+), 4 deletions(-)

(limited to 'sql/sql_view.cc')

diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 1561ade78af..a755a536b64 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -162,6 +162,7 @@ err:
   SYNOPSIS
     mysql_create_view()
     thd		- thread handler
+    views	- views to create
     mode	- VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
 
   RETURN VALUE
@@ -169,7 +170,7 @@ err:
      TRUE  Error
 */
 
-bool mysql_create_view(THD *thd,
+bool mysql_create_view(THD *thd, TABLE_LIST *views, 
                        enum_view_create_mode mode)
 {
   LEX *lex= thd->lex;
@@ -490,6 +491,37 @@ bool mysql_create_view(THD *thd,
   }
   VOID(pthread_mutex_lock(&LOCK_open));
   res= mysql_register_view(thd, view, mode);
+
+  if (mysql_bin_log.is_open())
+  {
+    String buff;
+    const LEX_STRING command[3]=
+      {{(char *)STRING_WITH_LEN("CREATE ")},
+       {(char *)STRING_WITH_LEN("ALTER ")},
+       {(char *)STRING_WITH_LEN("CREATE OR REPLACE ")}};
+
+    buff.append(command[thd->lex->create_view_mode].str,
+                command[thd->lex->create_view_mode].length);
+    view_store_options(thd, views, &buff);
+    buff.append(STRING_WITH_LEN("VIEW "));
+
+    /* Test if user supplied a db (ie: we did not use thd->db) */
+    if (views->db && views->db[0] &&
+        (thd->db == NULL || strcmp(views->db, thd->db)))
+    {
+      append_identifier(thd, &buff, views->db,
+                        views->db_length);
+      buff.append('.');
+    }
+    append_identifier(thd, &buff, views->table_name,
+                      views->table_name_length);
+    buff.append(STRING_WITH_LEN(" AS "));
+    buff.append(views->source.str, views->source.length);
+
+    Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE);
+    mysql_bin_log.write(&qinfo);
+  }
+
   VOID(pthread_mutex_unlock(&LOCK_open));
   if (view->revision != 1)
     query_cache_invalidate3(thd, view, 0);
@@ -1229,12 +1261,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
   bool type= 0;
   db_type not_used;
 
+  VOID(pthread_mutex_lock(&LOCK_open));
   for (view= views; view; view= view->next_local)
   {
     strxnmov(path, FN_REFLEN, mysql_data_home, "/", view->db, "/",
              view->table_name, reg_ext, NullS);
     (void) unpack_filename(path, path);
-    VOID(pthread_mutex_lock(&LOCK_open));
     if (access(path, F_OK) ||
 	(type= (mysql_frm_type(thd, path, &not_used) != FRMTYPE_VIEW)))
     {
@@ -1245,7 +1277,6 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
 	push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
 			    ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
 			    name);
-	VOID(pthread_mutex_unlock(&LOCK_open));
 	continue;
       }
       if (type)
@@ -1258,8 +1289,16 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
       goto err;
     query_cache_invalidate3(thd, view, 0);
     sp_cache_invalidate();
-    VOID(pthread_mutex_unlock(&LOCK_open));
   }
+
+  if (mysql_bin_log.is_open())
+  {
+    thd->clear_error();
+    Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+    mysql_bin_log.write(&qinfo);
+  }
+
+  VOID(pthread_mutex_unlock(&LOCK_open));
   send_ok(thd);
   DBUG_RETURN(FALSE);
 
-- 
cgit v1.2.1


From adea21fd1c811318929488a08d4fe086dd62dbbd Mon Sep 17 00:00:00 2001
From: "cmiller@zippy.cornsilk.net" <>
Date: Fri, 13 Oct 2006 10:57:50 -0400
Subject: Merge fix-up.

---
 sql/sql_view.cc | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

(limited to 'sql/sql_view.cc')

diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index a3e0f6b1e5a..82acab7129e 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -573,6 +573,19 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
     }
     append_identifier(thd, &buff, views->table_name,
                       views->table_name_length);
+    if (lex->view_list.elements)
+    {
+      List_iterator_fast<LEX_STRING> names(lex->view_list);
+      LEX_STRING *name;
+      int i;
+
+      for (i= 0; name= names++; i++)
+      {
+        buff.append(i ? ", " : "(");
+        append_identifier(thd, &buff, name->str, name->length);
+      }
+      buff.append(')');
+    }
     buff.append(STRING_WITH_LEN(" AS "));
     buff.append(views->source.str, views->source.length);
 
@@ -1378,7 +1391,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
       error= TRUE;
     query_cache_invalidate3(thd, view, 0);
     sp_cache_invalidate();
-
+  }
   if (mysql_bin_log.is_open())
   {
     thd->clear_error();
-- 
cgit v1.2.1


From 3a709f50b27acf9bce0fd6e5ddcd45ae2f277bee Mon Sep 17 00:00:00 2001
From: "cmiller@zippy.cornsilk.net" <>
Date: Tue, 17 Oct 2006 11:06:11 -0400
Subject: Fix previous bad patch for Bug#14262.

Remove table engine qualification where it's unnecessary.
---
 sql/sql_view.cc | 1 -
 1 file changed, 1 deletion(-)

(limited to 'sql/sql_view.cc')

diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 82acab7129e..245ef1a9f54 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1384,7 +1384,6 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
           non_existant_views.append(',');
         non_existant_views.append(String(view->table_name,system_charset_info));
       }
-      VOID(pthread_mutex_unlock(&LOCK_open));
       continue;
     }
     if (my_delete(path, MYF(MY_WME)))
-- 
cgit v1.2.1