X-Account-Key: account4
X-UIDL: 1153746480.180772
X-Mozilla-Status: 0001
X-Mozilla-Status2: 00000000
X-Mozilla-Keys:                                                                                 
Return-Path: <commits-return-50236-marc.alff=mysql.com@lists.mysql.com>
Received: from mailget.mysql.com ([unix socket])
	 by mailget (Cyrus v2.3.1-Invoca-RPM-2.3.1-2.8.fc5) with LMTPA;
	 Wed, 23 Jul 2008 02:27:32 +0200
X-Sieve: CMU Sieve 2.3
Received: from mail.mysql.com (mail.mysql.com [10.100.1.21])
	by mailget.mysql.com (8.13.8/8.13.8) with ESMTP id m6N0RWkb010084
	for <malff@mailstore1.mysql.com>; Wed, 23 Jul 2008 02:27:32 +0200
Received: from mailgate-b.mysql.com (mailgate-b.mysql.com [10.128.18.33])
	by mail.mysql.com (8.13.3/8.13.3) with ESMTP id m6N0RUja007246
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK)
	for <marc.alff@mysql.com>; Wed, 23 Jul 2008 02:27:30 +0200
Received: from lists.mysql.com (lists.mysql.com [10.100.1.37])
	by mailgate-b.mysql.com (8.13.8/8.13.8) with SMTP id m6N0RTsx014181
	for <marc.alff@mysql.com>; Wed, 23 Jul 2008 02:27:29 +0200
Received: (qmail 23500 invoked by uid 510); 23 Jul 2008 00:27:28 -0000
Mailing-List: contact commits-help@lists.mysql.com; run by ezmlm
List-ID: <commits.mysql.com>
Precedence: bulk
List-Help: <mailto:commits-help@lists.mysql.com>
List-Unsubscribe: <mailto:commits-unsubscribe-marc.alff=mysql.com@lists.mysql.com>
List-Post: <mailto:commits@lists.mysql.com>
List-Archive: http://lists.mysql.com/commits/50236
Delivered-To: mailing list commits@lists.mysql.com
Received: (qmail 23475 invoked by uid 509); 23 Jul 2008 00:27:28 -0000
MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
From: Marc Alff <marc.alff@sun.com>
Subject: bzr commit into mysql-6.0-wl2110-review branch (marc.alff:2675) WL#2110
To: commits@lists.mysql.com
User-Agent: Bazaar (1.4)
X-CSetKey: marc.alff@sun.com-20080723002712-t4quq03kuea5ugcx
X-Worklog: 2110
X-bzr-action: commit
X-bzr-revid: marc.alff@sun.com-20080723002712-t4quq03kuea5ugcx
X-bzr-revno: 2675
Message-Id: <20080723002718.5EDB21DC614@lambda.WEBLAB>
Date: Tue, 22 Jul 2008 18:27:18 -0600 (MDT)
X-Cxn-Txn: 56108100,34985433

#At file:///home/malff/BZR-TREE/mysql-6.0-wl2110-review-part5/

 2675 Marc Alff	2008-07-22
      WL#2110 (Stored Procedures: Implement SIGNAL)
      
      Formal review part 5/10: Stored procedures
      
      This patch implements changes in stored procedures, to support RESIGNAL.
      In particular, a SQL condition caught by a stored procedure SQL HANDLER
      is preserved, so it can be re-thrown using the RESIGNAL statement in the
      HANDLER.
modified:
  sql/item.cc
  sql/sp_head.cc
  sql/sp_head.h
  sql/sp_pcontext.cc
  sql/sp_pcontext.h
  sql/sp_rcontext.cc
  sql/sp_rcontext.h

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2008-07-14 14:56:49 +0000
+++ b/sql/item.cc	2008-07-23 00:27:12 +0000
@@ -1106,7 +1106,7 @@ Item_splocal::Item_splocal(const LEX_STR
 Item *
 Item_splocal::this_item()
 {
-  DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+  DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
 
   return m_thd->spcont->get_item(m_var_idx);
 }
@@ -1114,7 +1114,7 @@ Item_splocal::this_item()
 const Item *
 Item_splocal::this_item() const
 {
-  DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+  DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
 
   return m_thd->spcont->get_item(m_var_idx);
 }
@@ -1123,7 +1123,7 @@ Item_splocal::this_item() const
 Item **
 Item_splocal::this_item_addr(THD *thd, Item **)
 {
-  DBUG_ASSERT(m_sp == thd->spcont->sp);
+  DBUG_ASSERT(m_sp == thd->spcont->m_sp);
 
   return thd->spcont->get_item_addr(m_var_idx);
 }
@@ -1158,7 +1158,7 @@ Item_case_expr::Item_case_expr(uint case
 Item *
 Item_case_expr::this_item()
 {
-  DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+  DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
 
   return m_thd->spcont->get_case_expr(m_case_expr_id);
 }
@@ -1168,7 +1168,7 @@ Item_case_expr::this_item()
 const Item *
 Item_case_expr::this_item() const
 {
-  DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+  DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
 
   return m_thd->spcont->get_case_expr(m_case_expr_id);
 }
@@ -1177,7 +1177,7 @@ Item_case_expr::this_item() const
 Item **
 Item_case_expr::this_item_addr(THD *thd, Item **)
 {
-  DBUG_ASSERT(m_sp == thd->spcont->sp);
+  DBUG_ASSERT(m_sp == thd->spcont->m_sp);
 
   return thd->spcont->get_case_expr_addr(m_case_expr_id);
 }

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2008-06-28 11:00:59 +0000
+++ b/sql/sp_head.cc	2008-07-23 00:27:12 +0000
@@ -1263,9 +1263,9 @@ sp_head::execute(THD *thd)
     */
     if (ctx)
     {
-      uint hf;
+      uint handler_index;
 
-      switch (ctx->found_handler(&hip, &hf)) {
+      switch (ctx->found_handler(& hip, & handler_index)) {
       case SP_HANDLER_NONE:
         break;
       case SP_HANDLER_CONTINUE:
@@ -1274,16 +1274,20 @@ sp_head::execute(THD *thd)
         ctx->push_hstack(i->get_cont_dest());
         /* Fall through */
       default:
+        if (thd->end_partial_result_set)
+          thd->protocol->end_partial_result_set(thd);
         ip= hip;
         err_status= FALSE;
         ctx->clear_handler();
-        ctx->enter_handler(hip);
+        ctx->enter_handler(hip, handler_index);
         thd->clear_error();
         thd->is_fatal_error= 0;
         thd->killed= THD::NOT_KILLED;
         thd->mysys_var->abort= 0;
         continue;
       }
+
+      thd->end_partial_result_set= FALSE;
     }
   } while (!err_status && !thd->killed && !thd->is_fatal_error);
 
@@ -1525,17 +1529,13 @@ sp_head::execute_trigger(THD *thd,
   init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
   thd->set_n_backup_active_arena(&call_arena, &backup_arena);
 
-  if (!(nctx= new sp_rcontext(m_pcont, 0, octx)) ||
+  if (!(nctx= new sp_rcontext(this, m_pcont, 0, octx)) ||
       nctx->init(thd))
   {
     err_status= TRUE;
     goto err_with_cleanup;
   }
 
-#ifndef DBUG_OFF
-  nctx->sp= this;
-#endif
-
   thd->spcont= nctx;
 
   err_status= execute(thd);
@@ -1642,7 +1642,7 @@ sp_head::execute_function(THD *thd, Item
   init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
   thd->set_n_backup_active_arena(&call_arena, &backup_arena);
 
-  if (!(nctx= new sp_rcontext(m_pcont, return_value_fld, octx)) ||
+  if (!(nctx= new sp_rcontext(this, m_pcont, return_value_fld, octx)) ||
       nctx->init(thd))
   {
     thd->restore_active_arena(&call_arena, &backup_arena);
@@ -1658,10 +1658,6 @@ sp_head::execute_function(THD *thd, Item
   */
   thd->restore_active_arena(&call_arena, &backup_arena);
 
-#ifndef DBUG_OFF
-  nctx->sp= this;
-#endif
-
   /* Pass arguments. */
   for (arg_no= 0; arg_no < argcount; arg_no++)
   {
@@ -1846,32 +1842,26 @@ sp_head::execute_procedure(THD *thd, Lis
   save_spcont= octx= thd->spcont;
   if (! octx)
   {				// Create a temporary old context
-    if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) ||
+    if (!(octx= new sp_rcontext(this, m_pcont, NULL, octx)) ||
         octx->init(thd))
     {
       delete octx; /* Delete octx if it was init() that failed. */
       DBUG_RETURN(TRUE);
     }
 
-#ifndef DBUG_OFF
-    octx->sp= 0;
-#endif
     thd->spcont= octx;
 
     /* set callers_arena to thd, for upper-level function to work */
     thd->spcont->callers_arena= thd;
   }
 
-  if (!(nctx= new sp_rcontext(m_pcont, NULL, octx)) ||
+  if (!(nctx= new sp_rcontext(this, m_pcont, NULL, octx)) ||
       nctx->init(thd))
   {
     delete nctx; /* Delete nctx if it was init() that failed. */
     thd->spcont= save_spcont;
     DBUG_RETURN(TRUE);
   }
-#ifndef DBUG_OFF
-  nctx->sp= this;
-#endif
 
   if (params > 0)
   {
@@ -3210,7 +3200,7 @@ sp_instr_hpush_jump::execute(THD *thd, u
   sp_cond_type_t *p;
 
   while ((p= li++))
-    thd->spcont->push_handler(p, m_ip+1, m_type, m_frame);
+    thd->spcont->push_handler(p, m_ip+1, m_type);
 
   *nextp= m_dest;
   DBUG_RETURN(0);

=== modified file 'sql/sp_head.h'
--- a/sql/sp_head.h	2008-07-07 23:15:08 +0000
+++ b/sql/sp_head.h	2008-07-23 00:27:12 +0000
@@ -152,8 +152,9 @@ class sp_head :private Query_arena
   sp_head(const sp_head &);	/**< Prevent use of these */
   void operator=(sp_head &);
 
-  MEM_ROOT main_mem_root;
 public:
+  MEM_ROOT main_mem_root;
+
   /** Possible values of m_flags */
   enum {
     HAS_RETURN= 1,              // For FUNCTIONs only: is set if has RETURN

=== modified file 'sql/sp_pcontext.cc'
--- a/sql/sp_pcontext.cc	2008-04-09 00:56:49 +0000
+++ b/sql/sp_pcontext.cc	2008-07-23 00:27:12 +0000
@@ -51,7 +51,7 @@ sp_cond_check(LEX_STRING *sqlstate)
 	(c < 'A' || 'Z' < c))
       return FALSE;
   }
-  if (strcmp(sqlstate->str, "00000") == 0)
+  if (strncmp(sqlstate->str, "00", 2) == 0)
     return FALSE;
   return TRUE;
 }

=== modified file 'sql/sp_pcontext.h'
--- a/sql/sp_pcontext.h	2007-06-10 10:43:57 +0000
+++ b/sql/sp_pcontext.h	2008-07-23 00:27:12 +0000
@@ -71,7 +71,7 @@ typedef struct sp_label
 typedef struct sp_cond_type
 {
   enum { number, state, warning, notfound, exception } type;
-  char sqlstate[6];
+  char sqlstate[SQLSTATE_LENGTH+1];
   uint mysqlerr;
 } sp_cond_type_t;
 

=== modified file 'sql/sp_rcontext.cc'
--- a/sql/sp_rcontext.cc	2008-01-23 22:36:57 +0000
+++ b/sql/sp_rcontext.cc	2008-07-23 00:27:12 +0000
@@ -29,10 +29,11 @@
 #include "sp_pcontext.h"
 
 
-sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx,
+sp_rcontext::sp_rcontext(sp_head *sp, sp_pcontext *root_parsing_ctx,
                          Field *return_value_fld,
                          sp_rcontext *prev_runtime_ctx)
-  :m_root_parsing_ctx(root_parsing_ctx),
+  :m_sp(sp),
+   m_root_parsing_ctx(root_parsing_ctx),
    m_var_table(0),
    m_var_items(0),
    m_return_value_fld(return_value_fld),
@@ -68,27 +69,37 @@ sp_rcontext::~sp_rcontext()
 
 bool sp_rcontext::init(THD *thd)
 {
+  uint i;
+  uint handler_count= m_root_parsing_ctx->max_handler_index();
+
   in_sub_stmt= thd->in_sub_stmt;
 
   if (init_var_table(thd) || init_var_items())
     return TRUE;
 
-  return
+  if (
     !(m_handler=
-      (sp_handler_t*)thd->alloc(m_root_parsing_ctx->max_handler_index() *
-                                sizeof(sp_handler_t))) ||
+      (sp_handler_t*)thd->alloc(handler_count * sizeof(sp_handler_t))) ||
+    !(m_raised_conditions=
+      (SQL_condition**)thd->alloc(handler_count * sizeof(SQL_condition*))) ||
     !(m_hstack=
-      (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() *
-                        sizeof(uint))) ||
+      (uint*)thd->alloc(handler_count * sizeof(uint))) ||
     !(m_in_handler=
-      (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() *
-                        sizeof(uint))) ||
+      (sp_active_handler_t*)thd->alloc(handler_count *
+                                       sizeof(sp_active_handler_t))) ||
     !(m_cstack=
       (sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursor_index() *
                               sizeof(sp_cursor*))) ||
     !(m_case_expr_holders=
       (Item_cache**)thd->calloc(m_root_parsing_ctx->get_num_case_exprs() *
-                               sizeof (Item_cache*)));
+                               sizeof (Item_cache*)))
+    )
+      return TRUE;
+
+  for (i = 0; i < handler_count; i++)
+    m_raised_conditions[i]= NULL;
+
+  return FALSE;
 }
 
 
@@ -194,13 +205,15 @@ sp_rcontext::set_return_value(THD *thd, 
 */
 
 bool
-sp_rcontext::find_handler(THD *thd, uint sql_errno,
-                          MYSQL_ERROR::enum_warning_level level)
+sp_rcontext::find_handler(THD *thd, const SQL_condition *cond)
 {
   if (m_hfound >= 0)
     return 1;			// Already got one
 
-  const char *sqlstate= mysql_errno_to_sqlstate(sql_errno);
+  uint sql_errno= cond->m_sql_errno;
+  MYSQL_ERROR::enum_warning_level level= cond->m_level;
+
+  const char *sqlstate= cond->get_sqlstate();
   int i= m_hcount, found= -1;
 
   /*
@@ -220,7 +233,7 @@ sp_rcontext::find_handler(THD *thd, uint
 
     /* Check active handlers, to avoid invoking one recursively */
     while (j--)
-      if (m_in_handler[j] == m_handler[i].handler)
+      if (m_in_handler[j].ip == m_handler[i].handler)
 	break;
     if (j >= 0)
       continue;                 // Already executing this handler
@@ -264,10 +277,16 @@ sp_rcontext::find_handler(THD *thd, uint
     */
     if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
         level == MYSQL_ERROR::WARN_LEVEL_ERROR)
-      return m_prev_runtime_ctx->find_handler(thd, sql_errno, level);
+      return m_prev_runtime_ctx->find_handler(thd, cond);
     return FALSE;
   }
+
   m_hfound= found;
+
+  SQL_condition *raised;
+  raised= SQL_condition::deep_copy(thd, & m_sp->main_mem_root, cond) ;
+  m_raised_conditions[m_hfound]= raised;
+
   return TRUE;
 }
 
@@ -293,22 +312,22 @@ sp_rcontext::find_handler(THD *thd, uint
     FALSE      if no handler was found.
 */
 bool
-sp_rcontext::handle_error(uint sql_errno,
-                          MYSQL_ERROR::enum_warning_level level,
-                          THD *thd)
+sp_rcontext::handle_condition(THD *thd, const SQL_condition *cond)
 {
-  MYSQL_ERROR::enum_warning_level elevated_level= level;
-
-
   /* Depending on the sql_mode of execution,
      warnings may be considered errors */
-  if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
+  if ((cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
       thd->really_abort_on_warning())
   {
-    elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+    SQL_condition elevated_cond(thd->mem_root);
+    elevated_cond.set(thd, cond->m_sql_errno,
+                      cond->get_message_text(),
+                      MYSQL_ERROR::WARN_LEVEL_ERROR,
+                      MYF(0));
+    return find_handler(thd, & elevated_cond);
   }
 
-  return find_handler(thd, sql_errno, elevated_level);
+  return find_handler(thd, cond);
 }
 
 void
@@ -335,7 +354,7 @@ sp_rcontext::pop_cursors(uint count)
 }
 
 void
-sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type, uint f)
+sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type)
 {
   DBUG_ENTER("sp_rcontext::push_handler");
   DBUG_ASSERT(m_hcount < m_root_parsing_ctx->max_handler_index());
@@ -343,7 +362,6 @@ sp_rcontext::push_handler(struct sp_cond
   m_handler[m_hcount].cond= cond;
   m_handler[m_hcount].handler= h;
   m_handler[m_hcount].type= type;
-  m_handler[m_hcount].foffset= f;
   m_hcount+= 1;
 
   DBUG_PRINT("info", ("m_hcount: %d", m_hcount));
@@ -382,11 +400,13 @@ sp_rcontext::pop_hstack()
 }
 
 void
-sp_rcontext::enter_handler(int hid)
+sp_rcontext::enter_handler(uint hip, uint hindex)
 {
   DBUG_ENTER("sp_rcontext::enter_handler");
   DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index());
-  m_in_handler[m_ihsp++]= hid;
+  m_in_handler[m_ihsp].ip= hip;
+  m_in_handler[m_ihsp].index= hindex;
+  m_ihsp++;
   DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
   DBUG_VOID_RETURN;
 }
@@ -396,11 +416,32 @@ sp_rcontext::exit_handler()
 {
   DBUG_ENTER("sp_rcontext::exit_handler");
   DBUG_ASSERT(m_ihsp);
+  uint hindex= m_in_handler[m_ihsp-1].index;
+  DBUG_ASSERT(m_raised_conditions[hindex]);
+  delete m_raised_conditions[hindex];
+  m_raised_conditions[hindex]= NULL;
   m_ihsp-= 1;
   DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp));
   DBUG_VOID_RETURN;
 }
 
+SQL_condition*
+sp_rcontext::raised_condition() const
+{
+  if (m_ihsp > 0)
+  {
+    uint hindex= m_in_handler[m_ihsp - 1].index;
+    SQL_condition *raised= m_raised_conditions[hindex];
+    DBUG_ASSERT(raised);
+    return raised;
+  }
+
+  if (m_prev_runtime_ctx)
+    return m_prev_runtime_ctx->raised_condition();
+
+  return NULL;
+}
+
 
 int
 sp_rcontext::set_variable(THD *thd, uint var_idx, Item **value)

=== modified file 'sql/sp_rcontext.h'
--- a/sql/sp_rcontext.h	2008-01-23 20:26:41 +0000
+++ b/sql/sp_rcontext.h	2008-07-23 00:27:12 +0000
@@ -34,12 +34,21 @@ class sp_instr_cpush;
 
 typedef struct
 {
+  /** Condition caught by this HANDLER. */
   struct sp_cond_type *cond;
-  uint handler;			// Location of handler
+  /** Location (instruction pointer) of the handler code. */
+  uint handler;
+  /** Handler type (EXIT, CONTINUE). */
   int type;
-  uint foffset;			// Frame offset for the handlers declare level
 } sp_handler_t;
 
+typedef struct
+{
+  /** Instruction pointer of the active handler. */
+  uint ip;
+  /** Handler index of the active handler. */
+  uint index;
+} sp_active_handler_t;
 
 /*
   This class is a runtime context of a Stored Routine. It is used in an
@@ -75,16 +84,10 @@ class sp_rcontext : public Sql_alloc
   */
   Query_arena *callers_arena;
 
-#ifndef DBUG_OFF
-  /*
-    The routine for which this runtime context is created. Used for checking
-    if correct runtime context is used for variable handling.
-  */
-  sp_head *sp;
-#endif
+  sp_head *m_sp;
 
-  sp_rcontext(sp_pcontext *root_parsing_ctx, Field *return_value_fld,
-              sp_rcontext *prev_runtime_ctx);
+  sp_rcontext(sp_head *sp, sp_pcontext *root_parsing_ctx,
+              Field *return_value_fld, sp_rcontext *prev_runtime_ctx);
   bool init(THD *thd);
 
   ~sp_rcontext();
@@ -107,31 +110,31 @@ class sp_rcontext : public Sql_alloc
     return m_return_value_set;
   }
 
-  void push_handler(struct sp_cond_type *cond, uint h, int type, uint f);
+  void push_handler(struct sp_cond_type *cond, uint h, int type);
 
   void pop_handlers(uint count);
 
   // Returns 1 if a handler was found, 0 otherwise.
   bool
-  find_handler(THD *thd, uint sql_errno,MYSQL_ERROR::enum_warning_level level);
+  find_handler(THD *thd, const SQL_condition *cond);
 
   // If there is an error handler for this error, handle it and return TRUE.
-  bool
-  handle_error(uint sql_errno,
-               MYSQL_ERROR::enum_warning_level level,
-               THD *thd);
+  bool handle_condition(THD *thd, const SQL_condition *cond);
+
 
   // Returns handler type and sets *ip to location if one was found
   inline int
-  found_handler(uint *ip, uint *fp)
+  found_handler(uint *ip, uint *index)
   {
     if (m_hfound < 0)
       return SP_HANDLER_NONE;
     *ip= m_handler[m_hfound].handler;
-    *fp= m_handler[m_hfound].foffset;
+    *index= m_hfound;
     return m_handler[m_hfound].type;
   }
 
+  SQL_condition* raised_condition() const;
+
   // Returns true if we found a handler in this context
   inline bool
   found_handler_here()
@@ -150,7 +153,12 @@ class sp_rcontext : public Sql_alloc
 
   uint pop_hstack();
 
-  void enter_handler(int hid);
+  /**
+    Enter a SQL exception handler.
+    @param hip the handler instruction pointer
+    @param index the handler index
+  */
+  void enter_handler(uint hip, uint index);
 
   void exit_handler();
 
@@ -214,10 +222,18 @@ private:
   bool in_sub_stmt;
 
   sp_handler_t *m_handler;      // Visible handlers
+
+  /**
+    SQL conditions caught by each handler.
+    This is an array indexed by handler index.
+  */
+  SQL_condition ** m_raised_conditions;
+
   uint m_hcount;                // Stack pointer for m_handler
   uint *m_hstack;               // Return stack for continue handlers
   uint m_hsp;                   // Stack pointer for m_hstack
-  uint *m_in_handler;           // Active handler, for recursion check
+  /** Active handler stack. */
+  sp_active_handler_t *m_in_handler;
   uint m_ihsp;                  // Stack pointer for m_in_handler
   int m_hfound;                 // Set by find_handler; -1 if not found
 


-- 
MySQL Code Commits Mailing List
For list archives: http://lists.mysql.com/commits
To unsubscribe:    http://lists.mysql.com/commits?unsub=marc.alff@mysql.com


