MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Greg Lehey Date:August 4 2006 7:57am
Subject:bk commit into 5.0 tree (grog:1.2232) BUG#11312
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of grog. When grog does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2006-08-04 17:27:12+09:30, grog@stripped +1 -0
  log_event.cc:
    
    BUG#11312: DELIMITER is not written to the binary log that causes
               syntax error
  
    Query_log_event::print(): Check contents of event for stored
                              procedure.  If found, emit DELIMITER
                              commands on either side.
    

  sql/log_event.cc@stripped, 2006-08-04 17:12:23+09:30, grog@stripped +91 -2
    BUG#11312: DELIMITER is not written to the binary log that causes syntax error
    Wrap stored procedure log events with DELIMITER statements.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	grog
# Host:	eucla.lemis.com
# Root:	/MySQL/5.0-Bug-11312

--- 1.210/sql/log_event.cc	2006-08-04 17:27:20 +09:30
+++ 1.211/sql/log_event.cc	2006-08-04 17:27:20 +09:30
@@ -15,8 +15,9 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 
-#ifndef MYSQL_CLIENT
-
+#ifdef MYSQL_CLIENT
+#include <ctype.h>
+#else
 #ifdef USE_PRAGMA_IMPLEMENTATION
 #pragma implementation                          // gcc: Class implementation
 #endif
@@ -1620,11 +1621,99 @@
   }
 }
 
+/*
+  Recognize a keyword.  This is asymmetric: the second parameter is expected to
+  be shorter, and usually a literal string.  It's inline so that the compiler
+  can optimize away the strlen() calls at compile time.
+
+  This function takes advantage of the property of my_strcasecmp() that it will
+  return 0 if the strings compare up to and including the length of the first
+  parameter, but not if it's the other way round.  Thus the parameter reversal.
+*/
+static inline int iskeyword(const char *a, const char *b)
+{
+  int len= strlen(b);
+
+  if ((strncasecmp(a, b, len) == 0)             /* got the word */
+      && (! isalnum(a[len])))                   /* and delimited */
+    return 1;
+  return 0;
+}
+
+
 void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
 {
+  int is_stored_proc= 0;                        /* no store proc until proven */
+  const char *c;                                /* pointer into query */
+
   print_query_header(file, print_event_info);
+
+  /*
+    The query may contain a stored procedure, in which case we need to wrap it
+    in DELIMITER quotes.  It seems a little overkill to do a complete lexical
+    analysis to determine whether this is a stored procedure or not.  What we do
+    here is:
+
+    - Look for CREATE.
+    - If we find CREATE, look for DEFINER next.
+    - If we find DEFINER, skip it and parameters; otherwise stay where we are.
+    - Look for FUNCTION or PROCEDURE next.
+
+    If this succeeds, we have a stored procedure.  It should be by itself in the
+    query, so we don't need to locate the end.
+  */
+  c= query;
+  while (isspace(*c))
+    c++;
+  if (iskeyword(c, "CREATE"))                   /* step 1: found CREATE */
+  {
+    c+= strlen("CREATE");                       /* skip CREATE, */
+    while (isspace(*c))                         /* skip white space */
+      c++;
+    /* Now check for DEFINER */
+    if (iskeyword(c, "DEFINER"))                /* DEFINER, skip it */
+    {
+      c+= strlen("DEFINER");                    /* skip DEFINER, */
+      while (isspace(*c))                       /* skip white space */
+        c++;
+      if (*c++ == '=')                          /* still on track */
+      {
+        while (isspace(*c))                     /* skip white space */
+          c++;
+        /*
+          Skip user info.  This can be either in the form 'user'@'host' or
+          CURRENT_USER
+        */
+        if (iskeyword(c, "CURRENT_USER"))       /* CURRENT_USER, skip it */
+          c+= strlen("CURRENT_USER");
+        else if (*c == '`')                     /* 'user'@'host' */
+        {
+          c++;
+          while (*c && *c++ != '`');            /* find end delimiter */
+          if (memcmp (c, "@`", 2) == 0)         /* @' as expected */
+          {
+            c+= 2;
+            while (*c && *c++ != '`');          /* skip to matching ` */
+            while (isspace(*c))                 /* skip white space */
+              c++;
+          }
+        }
+      }
+    }
+    /* Finally check for "PROCEDURE" or "FUNCTION" */
+    if (iskeyword(c, "PROCEDURE")
+        || iskeyword(c, "FUNCTION"))
+      /* OK, it's a stored procedure */
+    {
+      is_stored_proc = 1;
+      fputs("DELIMITER $$\n", file);
+    }
+  }
+  /* Write the meat of the query. */
   my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
   fputs(";\n", file);
+  if (is_stored_proc)
+    fputs("$$\nDELIMITER ;\n", file);
 }
 #endif /* MYSQL_CLIENT */
 
Thread
bk commit into 5.0 tree (grog:1.2232) BUG#11312Greg Lehey4 Aug