List:Commits« Previous MessageNext Message »
From:Marc Alff Date:May 16 2012 5:46pm
Subject:bzr push into mysql-trunk-pfs-tuning branch (marc.alff:3517)
View as plain text  
 3517 Marc Alff	2012-05-16 [merge]
      merge

=== modified file 'include/my_pthread.h'
--- a/include/my_pthread.h	2011-12-09 21:08:37 +0000
+++ b/include/my_pthread.h	2012-05-16 17:27:18 +0000
@@ -815,6 +815,7 @@ extern int pthread_dummy(int);
 #endif
 #endif
 
+#include <pfs_thread_provider.h>
 #include <mysql/psi/mysql_thread.h>
 
 #define INSTRUMENT_ME 0

=== modified file 'include/mysql/psi/mysql_file.h'
--- a/include/mysql/psi/mysql_file.h	2012-05-15 09:42:30 +0000
+++ b/include/mysql/psi/mysql_file.h	2012-05-16 17:27:18 +0000
@@ -43,6 +43,10 @@
 
 #include "mysql/psi/psi.h"
 
+#ifndef PSI_FILE_CALL
+#define PSI_FILE_CALL(M) PSI_DYNAMIC_CALL(M)
+#endif
+
 /**
   @defgroup File_instrumentation File Instrumentation
   @ingroup Instrumentation_interface

=== modified file 'include/mysql/psi/mysql_idle.h'
--- a/include/mysql/psi/mysql_idle.h	2012-05-15 09:42:30 +0000
+++ b/include/mysql/psi/mysql_idle.h	2012-05-16 17:27:18 +0000
@@ -23,6 +23,10 @@
 
 #include "mysql/psi/psi.h"
 
+#ifndef PSI_IDLE_CALL
+#define PSI_IDLE_CALL(M) PSI_DYNAMIC_CALL(M)
+#endif
+
 /**
   @defgroup Idle_instrumentation Idle Instrumentation
   @ingroup Instrumentation_interface

=== modified file 'include/mysql/psi/mysql_socket.h'
--- a/include/mysql/psi/mysql_socket.h	2012-05-15 09:42:30 +0000
+++ b/include/mysql/psi/mysql_socket.h	2012-05-16 17:27:18 +0000
@@ -42,6 +42,10 @@ Foundation, Inc., 51 Franklin St, Fifth
 
 #include "mysql/psi/psi.h"
 
+#ifndef PSI_SOCKET_CALL
+#define PSI_SOCKET_CALL(M) PSI_DYNAMIC_CALL(M)
+#endif
+
 /**
   @defgroup Socket_instrumentation Socket Instrumentation
   @ingroup Instrumentation_interface

=== modified file 'include/mysql/psi/mysql_stage.h'
--- a/include/mysql/psi/mysql_stage.h	2012-05-15 09:42:30 +0000
+++ b/include/mysql/psi/mysql_stage.h	2012-05-16 17:27:18 +0000
@@ -23,6 +23,10 @@
 
 #include "mysql/psi/psi.h"
 
+#ifndef PSI_STAGE_CALL
+#define PSI_STAGE_CALL(M) PSI_DYNAMIC_CALL(M)
+#endif
+
 /**
   @defgroup Stage_instrumentation Stage Instrumentation
   @ingroup Instrumentation_interface

=== modified file 'include/mysql/psi/mysql_statement.h'
--- a/include/mysql/psi/mysql_statement.h	2012-05-15 09:42:30 +0000
+++ b/include/mysql/psi/mysql_statement.h	2012-05-16 17:27:18 +0000
@@ -23,6 +23,10 @@
 
 #include "mysql/psi/psi.h"
 
+#ifndef PSI_STATEMENT_CALL
+#define PSI_STATEMENT_CALL(M) PSI_DYNAMIC_CALL(M)
+#endif
+
 /**
   @defgroup Statement_instrumentation Statement Instrumentation
   @ingroup Instrumentation_interface

=== modified file 'include/mysql/psi/mysql_table.h'
--- a/include/mysql/psi/mysql_table.h	2012-05-15 09:42:30 +0000
+++ b/include/mysql/psi/mysql_table.h	2012-05-16 17:27:18 +0000
@@ -23,6 +23,10 @@
 
 #include "mysql/psi/psi.h"
 
+#ifndef PSI_TABLE_CALL
+#define PSI_TABLE_CALL(M) PSI_DYNAMIC_CALL(M)
+#endif
+
 /**
   @defgroup Table_instrumentation Table Instrumentation
   @ingroup Instrumentation_interface

=== modified file 'include/mysql/psi/mysql_thread.h'
--- a/include/mysql/psi/mysql_thread.h	2012-05-15 09:42:30 +0000
+++ b/include/mysql/psi/mysql_thread.h	2012-05-16 17:27:18 +0000
@@ -56,6 +56,22 @@
 
 #include "mysql/psi/psi.h"
 
+#ifndef PSI_MUTEX_CALL
+#define PSI_MUTEX_CALL(M) PSI_DYNAMIC_CALL(M)
+#endif
+
+#ifndef PSI_RWLOCK_CALL
+#define PSI_RWLOCK_CALL(M) PSI_DYNAMIC_CALL(M)
+#endif
+
+#ifndef PSI_COND_CALL
+#define PSI_COND_CALL(M) PSI_DYNAMIC_CALL(M)
+#endif
+
+#ifndef PSI_THREAD_CALL
+#define PSI_THREAD_CALL(M) PSI_DYNAMIC_CALL(M)
+#endif
+
 /**
   @defgroup Thread_instrumentation Thread Instrumentation
   @ingroup Instrumentation_interface

=== modified file 'include/mysql/psi/psi.h'
--- a/include/mysql/psi/psi.h	2012-05-15 09:42:30 +0000
+++ b/include/mysql/psi/psi.h	2012-05-16 17:27:18 +0000
@@ -17,16 +17,7 @@
 #define MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H
 
 #ifdef EMBEDDED_LIBRARY
-#define DISABLE_PSI_MUTEX
-#define DISABLE_PSI_RWLOCK
-#define DISABLE_PSI_COND
-#define DISABLE_PSI_FILE
-#define DISABLE_PSI_TABLE
-#define DISABLE_PSI_SOCKET
-#define DISABLE_PSI_STAGE
-#define DISABLE_PSI_STATEMENT
-#define DISABLE_PSI_IDLE
-#define DISABLE_PSI_STATEMENT_DIGEST
+#define DISABLE_ALL_PSI
 #endif /* EMBEDDED_LIBRARY */
 
 #ifndef MY_GLOBAL_INCLUDED
@@ -40,6 +31,13 @@
 #error "You must include my_global.h in the code for the build to be correct."
 #endif
 
+/*
+  MAINTAINER:
+  The following pattern:
+    typedef struct XYZ XYZ;
+  is not needed in C++, but required for C.
+*/
+
 C_MODE_START
 
 struct TABLE_SHARE;
@@ -171,6 +169,19 @@ typedef struct PSI_bootstrap PSI_bootstr
 
 #ifdef HAVE_PSI_INTERFACE
 
+#ifdef DISABLE_ALL_PSI
+#define DISABLE_PSI_MUTEX
+#define DISABLE_PSI_RWLOCK
+#define DISABLE_PSI_COND
+#define DISABLE_PSI_FILE
+#define DISABLE_PSI_TABLE
+#define DISABLE_PSI_SOCKET
+#define DISABLE_PSI_STAGE
+#define DISABLE_PSI_STATEMENT
+#define DISABLE_PSI_IDLE
+#define DISABLE_PSI_STATEMENT_DIGEST
+#endif
+
 /**
   @def DISABLE_PSI_MUTEX
   Compiling option to disable the mutex instrumentation.
@@ -593,7 +604,7 @@ typedef unsigned int PSI_socket_key;
 #define PSI_FLAG_GLOBAL (1 << 0)
 
 /**
-  Global flag.
+  Mutable flag.
   This flag indicate that an instrumentation point is a general placeholder,
   that can mutate into a more specific instrumentation point.
 */
@@ -632,6 +643,7 @@ struct PSI_mutex_info_v1
   */
   int m_flags;
 };
+typedef struct PSI_mutex_info_v1 PSI_mutex_info_v1;
 
 /**
   Rwlock information.
@@ -654,6 +666,7 @@ struct PSI_rwlock_info_v1
   */
   int m_flags;
 };
+typedef struct PSI_rwlock_info_v1 PSI_rwlock_info_v1;
 
 /**
   Condition information.
@@ -676,6 +689,7 @@ struct PSI_cond_info_v1
   */
   int m_flags;
 };
+typedef struct PSI_cond_info_v1 PSI_cond_info_v1;
 
 /**
   Thread instrument information.
@@ -698,6 +712,7 @@ struct PSI_thread_info_v1
   */
   int m_flags;
 };
+typedef struct PSI_thread_info_v1 PSI_thread_info_v1;
 
 /**
   File instrument information.
@@ -720,6 +735,7 @@ struct PSI_file_info_v1
   */
   int m_flags;
 };
+typedef struct PSI_file_info_v1 PSI_file_info_v1;
 
 /**
   Stage instrument information.
@@ -735,6 +751,7 @@ struct PSI_stage_info_v1
   /** The flags of the stage instrument to register. */
   int m_flags;
 };
+typedef struct PSI_stage_info_v1 PSI_stage_info_v1;
 
 /**
   Statement instrument information.
@@ -750,6 +767,7 @@ struct PSI_statement_info_v1
   /** The flags of the statement instrument to register. */
   int m_flags;
 };
+typedef struct PSI_statement_info_v1 PSI_statement_info_v1;
 
 /**
   Socket instrument information.
@@ -772,6 +790,7 @@ struct PSI_socket_info_v1
   */
   int m_flags;
 };
+typedef struct PSI_socket_info_v1 PSI_socket_info_v1;
 
 /**
   State data storage for @c start_idle_wait_v1_t.
@@ -795,6 +814,7 @@ struct PSI_idle_locker_state_v1
   /** Internal data. */
   void *m_wait;
 };
+typedef struct PSI_idle_locker_state_v1 PSI_idle_locker_state_v1;
 
 /**
   State data storage for @c start_mutex_wait_v1_t.
@@ -822,6 +842,7 @@ struct PSI_mutex_locker_state_v1
   /** Internal data. */
   void *m_wait;
 };
+typedef struct PSI_mutex_locker_state_v1 PSI_mutex_locker_state_v1;
 
 /**
   State data storage for @c start_rwlock_rdwait_v1_t, @c start_rwlock_wrwait_v1_t.
@@ -850,6 +871,7 @@ struct PSI_rwlock_locker_state_v1
   /** Internal data. */
   void *m_wait;
 };
+typedef struct PSI_rwlock_locker_state_v1 PSI_rwlock_locker_state_v1;
 
 /**
   State data storage for @c start_cond_wait_v1_t.
@@ -879,6 +901,7 @@ struct PSI_cond_locker_state_v1
   /** Internal data. */
   void *m_wait;
 };
+typedef struct PSI_cond_locker_state_v1 PSI_cond_locker_state_v1;
 
 /**
   State data storage for @c get_thread_file_name_locker_v1_t.
@@ -910,6 +933,7 @@ struct PSI_file_locker_state_v1
   /** Internal data. */
   void *m_wait;
 };
+typedef struct PSI_file_locker_state_v1 PSI_file_locker_state_v1;
 
 /**
   State data storage for @c start_table_io_wait_v1_t,
@@ -947,6 +971,7 @@ struct PSI_table_locker_state_v1
   */
   uint m_index;
 };
+typedef struct PSI_table_locker_state_v1 PSI_table_locker_state_v1;
 
 #define PSI_MAX_DIGEST_STORAGE_SIZE 1024
 
@@ -1032,6 +1057,7 @@ struct PSI_statement_locker_state_v1
   /** Statement digest. */
   PSI_digest_locker_state m_digest_state;
 };
+typedef struct PSI_statement_locker_state_v1 PSI_statement_locker_state_v1;
 
 /**
   State data storage for @c start_socket_wait_v1_t.
@@ -1065,6 +1091,7 @@ struct PSI_socket_locker_state_v1
   /** Internal data. */
   void *m_wait;
 };
+typedef struct PSI_socket_locker_state_v1 PSI_socket_locker_state_v1;
 
 /* Using typedef to make reuse between PSI_v1 and PSI_v2 easier later. */
 
@@ -1325,8 +1352,8 @@ typedef void (*set_thread_user_v1_t)(con
   @param host the host name
   @param host_len the host name length
 */
-typedef void (*set_thread_user_host_v1_t)(const char *user, int user_len,
-                                          const char *host, int host_len);
+typedef void (*set_thread_account_v1_t)(const char *user, int user_len,
+                                        const char *host, int host_len);
 
 /**
   Assign a current database to the instrumented thread.
@@ -1937,8 +1964,8 @@ struct PSI_v1
   get_thread_v1_t get_thread;
   /** @sa set_thread_user_v1_t. */
   set_thread_user_v1_t set_thread_user;
-  /** @sa set_thread_user_host_v1_t. */
-  set_thread_user_host_v1_t set_thread_user_host;
+  /** @sa set_thread_account_v1_t. */
+  set_thread_account_v1_t set_thread_account;
   /** @sa set_thread_db_v1_t. */
   set_thread_db_v1_t set_thread_db;
   /** @sa set_thread_command_v1_t. */
@@ -2328,46 +2355,6 @@ extern MYSQL_PLUGIN_IMPORT PSI *PSI_serv
   make a dynamic call using the PSI_server function pointer.
 */
 
-#ifndef PSI_MUTEX_CALL
-#define PSI_MUTEX_CALL(M) PSI_DYNAMIC_CALL(M)
-#endif
-
-#ifndef PSI_RWLOCK_CALL
-#define PSI_RWLOCK_CALL(M) PSI_DYNAMIC_CALL(M)
-#endif
-
-#ifndef PSI_COND_CALL
-#define PSI_COND_CALL(M) PSI_DYNAMIC_CALL(M)
-#endif
-
-#ifndef PSI_THREAD_CALL
-#define PSI_THREAD_CALL(M) PSI_DYNAMIC_CALL(M)
-#endif
-
-#ifndef PSI_FILE_CALL
-#define PSI_FILE_CALL(M) PSI_DYNAMIC_CALL(M)
-#endif
-
-#ifndef PSI_SOCKET_CALL
-#define PSI_SOCKET_CALL(M) PSI_DYNAMIC_CALL(M)
-#endif
-
-#ifndef PSI_STAGE_CALL
-#define PSI_STAGE_CALL(M) PSI_DYNAMIC_CALL(M)
-#endif
-
-#ifndef PSI_STATEMENT_CALL
-#define PSI_STATEMENT_CALL(M) PSI_DYNAMIC_CALL(M)
-#endif
-
-#ifndef PSI_TABLE_CALL
-#define PSI_TABLE_CALL(M) PSI_DYNAMIC_CALL(M)
-#endif
-
-#ifndef PSI_IDLE_CALL
-#define PSI_IDLE_CALL(M) PSI_DYNAMIC_CALL(M)
-#endif
-
 #define PSI_DYNAMIC_CALL(M) PSI_server->M
 
 /** @} */

=== modified file 'include/mysql/psi/psi_abi_v1.h.pp'
--- a/include/mysql/psi/psi_abi_v1.h.pp	2012-05-02 08:36:41 +0000
+++ b/include/mysql/psi/psi_abi_v1.h.pp	2012-05-16 17:27:18 +0000
@@ -135,48 +135,56 @@ struct PSI_mutex_info_v1
   const char *m_name;
   int m_flags;
 };
+typedef struct PSI_mutex_info_v1 PSI_mutex_info_v1;
 struct PSI_rwlock_info_v1
 {
   PSI_rwlock_key *m_key;
   const char *m_name;
   int m_flags;
 };
+typedef struct PSI_rwlock_info_v1 PSI_rwlock_info_v1;
 struct PSI_cond_info_v1
 {
   PSI_cond_key *m_key;
   const char *m_name;
   int m_flags;
 };
+typedef struct PSI_cond_info_v1 PSI_cond_info_v1;
 struct PSI_thread_info_v1
 {
   PSI_thread_key *m_key;
   const char *m_name;
   int m_flags;
 };
+typedef struct PSI_thread_info_v1 PSI_thread_info_v1;
 struct PSI_file_info_v1
 {
   PSI_file_key *m_key;
   const char *m_name;
   int m_flags;
 };
+typedef struct PSI_file_info_v1 PSI_file_info_v1;
 struct PSI_stage_info_v1
 {
   PSI_stage_key m_key;
   const char *m_name;
   int m_flags;
 };
+typedef struct PSI_stage_info_v1 PSI_stage_info_v1;
 struct PSI_statement_info_v1
 {
   PSI_statement_key m_key;
   const char *m_name;
   int m_flags;
 };
+typedef struct PSI_statement_info_v1 PSI_statement_info_v1;
 struct PSI_socket_info_v1
 {
   PSI_socket_key *m_key;
   const char *m_name;
   int m_flags;
 };
+typedef struct PSI_socket_info_v1 PSI_socket_info_v1;
 struct PSI_idle_locker_state_v1
 {
   uint m_flags;
@@ -185,6 +193,7 @@ struct PSI_idle_locker_state_v1
   ulonglong (*m_timer)(void);
   void *m_wait;
 };
+typedef struct PSI_idle_locker_state_v1 PSI_idle_locker_state_v1;
 struct PSI_mutex_locker_state_v1
 {
   uint m_flags;
@@ -195,6 +204,7 @@ struct PSI_mutex_locker_state_v1
   ulonglong (*m_timer)(void);
   void *m_wait;
 };
+typedef struct PSI_mutex_locker_state_v1 PSI_mutex_locker_state_v1;
 struct PSI_rwlock_locker_state_v1
 {
   uint m_flags;
@@ -205,6 +215,7 @@ struct PSI_rwlock_locker_state_v1
   ulonglong (*m_timer)(void);
   void *m_wait;
 };
+typedef struct PSI_rwlock_locker_state_v1 PSI_rwlock_locker_state_v1;
 struct PSI_cond_locker_state_v1
 {
   uint m_flags;
@@ -216,6 +227,7 @@ struct PSI_cond_locker_state_v1
   ulonglong (*m_timer)(void);
   void *m_wait;
 };
+typedef struct PSI_cond_locker_state_v1 PSI_cond_locker_state_v1;
 struct PSI_file_locker_state_v1
 {
   uint m_flags;
@@ -227,6 +239,7 @@ struct PSI_file_locker_state_v1
   ulonglong (*m_timer)(void);
   void *m_wait;
 };
+typedef struct PSI_file_locker_state_v1 PSI_file_locker_state_v1;
 struct PSI_table_locker_state_v1
 {
   uint m_flags;
@@ -239,6 +252,7 @@ struct PSI_table_locker_state_v1
   void *m_wait;
   uint m_index;
 };
+typedef struct PSI_table_locker_state_v1 PSI_table_locker_state_v1;
 struct PSI_digest_storage
 {
   my_bool m_full;
@@ -280,6 +294,7 @@ struct PSI_statement_locker_state_v1
   ulong m_sort_scan;
   PSI_digest_locker_state m_digest_state;
 };
+typedef struct PSI_statement_locker_state_v1 PSI_statement_locker_state_v1;
 struct PSI_socket_locker_state_v1
 {
   uint m_flags;
@@ -293,6 +308,7 @@ struct PSI_socket_locker_state_v1
   int m_src_line;
   void *m_wait;
 };
+typedef struct PSI_socket_locker_state_v1 PSI_socket_locker_state_v1;
 typedef void (*register_mutex_v1_t)
   (const char *category, struct PSI_mutex_info_v1 *info, int count);
 typedef void (*register_rwlock_v1_t)
@@ -346,8 +362,8 @@ typedef void (*set_thread_id_v1_t)(struc
                                    unsigned long id);
 typedef struct PSI_thread* (*get_thread_v1_t)(void);
 typedef void (*set_thread_user_v1_t)(const char *user, int user_len);
-typedef void (*set_thread_user_host_v1_t)(const char *user, int user_len,
-                                          const char *host, int host_len);
+typedef void (*set_thread_account_v1_t)(const char *user, int user_len,
+                                        const char *host, int host_len);
 typedef void (*set_thread_db_v1_t)(const char* db, int db_len);
 typedef void (*set_thread_command_v1_t)(int command);
 typedef void (*set_thread_start_time_v1_t)(time_t start_time);
@@ -531,7 +547,7 @@ struct PSI_v1
   set_thread_id_v1_t set_thread_id;
   get_thread_v1_t get_thread;
   set_thread_user_v1_t set_thread_user;
-  set_thread_user_host_v1_t set_thread_user_host;
+  set_thread_account_v1_t set_thread_account;
   set_thread_db_v1_t set_thread_db;
   set_thread_command_v1_t set_thread_command;
   set_thread_start_time_v1_t set_thread_start_time;

=== added file 'include/pfs_file_provider.h'
--- a/include/pfs_file_provider.h	1970-01-01 00:00:00 +0000
+++ b/include/pfs_file_provider.h	2012-05-16 17:27:18 +0000
@@ -0,0 +1,80 @@
+/* Copyright (c) 2012, 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
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef PFS_FILE_PROVIDER_H
+#define PFS_FILE_PROVIDER_H
+
+/**
+  @file include/pfs_file_provider.h
+  Performance schema instrumentation (declarations).
+*/
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+#ifdef MYSQL_SERVER
+#ifndef EMBEDDED_LIBRARY
+#ifndef MYSQL_DYNAMIC_PLUGIN
+
+#include "mysql/psi/psi.h"
+
+#define PSI_FILE_CALL(M) pfs_ ## M ## _v1
+
+C_MODE_START
+
+void pfs_register_file_v1(const char *category,
+                          PSI_file_info_v1 *info,
+                          int count);
+
+void pfs_create_file_v1(PSI_file_key key, const char *name, File file);
+
+PSI_file_locker*
+pfs_get_thread_file_name_locker_v1(PSI_file_locker_state *state,
+                                   PSI_file_key key,
+                                   PSI_file_operation op,
+                                   const char *name, const void *identity);
+
+PSI_file_locker*
+pfs_get_thread_file_stream_locker_v1(PSI_file_locker_state *state,
+                                     PSI_file *file, PSI_file_operation op);
+
+PSI_file_locker*
+pfs_get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state,
+                                         File file, PSI_file_operation op);
+
+PSI_file* pfs_start_file_open_wait_v1(PSI_file_locker *locker,
+                                      const char *src_file,
+                                      uint src_line);
+
+void pfs_end_file_open_wait_v1(PSI_file_locker *locker);
+
+void pfs_end_file_open_wait_and_bind_to_descriptor_v1
+  (PSI_file_locker *locker, File file);
+
+void pfs_start_file_wait_v1(PSI_file_locker *locker,
+                            size_t count,
+                            const char *src_file,
+                            uint src_line);
+
+void pfs_end_file_wait_v1(PSI_file_locker *locker,
+                          size_t byte_count);
+
+C_MODE_END
+
+#endif /* EMBEDDED_LIBRARY */
+#endif /* MYSQL_DYNAMIC_PLUGIN */
+#endif /* MYSQL_SERVER */
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
+#endif
+

=== added file 'include/pfs_idle_provider.h'
--- a/include/pfs_idle_provider.h	1970-01-01 00:00:00 +0000
+++ b/include/pfs_idle_provider.h	2012-05-16 17:27:18 +0000
@@ -0,0 +1,48 @@
+/* Copyright (c) 2012, 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
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef PFS_IDLE_PROVIDER_H
+#define PFS_IDLE_PROVIDER_H
+
+/**
+  @file include/pfs_idle_provider.h
+  Performance schema instrumentation (declarations).
+*/
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+#ifdef MYSQL_SERVER
+#ifndef EMBEDDED_LIBRARY
+#ifndef MYSQL_DYNAMIC_PLUGIN
+
+#include "mysql/psi/psi.h"
+
+#define PSI_IDLE_CALL(M) pfs_ ## M ## _v1
+
+C_MODE_START
+
+PSI_idle_locker*
+pfs_start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_line);
+
+void pfs_end_idle_wait_v1(PSI_idle_locker* locker);
+
+C_MODE_END
+
+#endif /* MYSQL_DYNAMIC_PLUGIN */
+#endif /* EMBEDDED_LIBRARY */
+#endif /* MYSQL_SERVER */
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
+#endif
+

=== added file 'include/pfs_socket_provider.h'
--- a/include/pfs_socket_provider.h	1970-01-01 00:00:00 +0000
+++ b/include/pfs_socket_provider.h	2012-05-16 17:27:18 +0000
@@ -0,0 +1,70 @@
+/* Copyright (c) 2012, 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
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef PFS_SOCKET_PROVIDER_H
+#define PFS_SOCKET_PROVIDER_H
+
+/**
+  @file include/pfs_socket_provider.h
+  Performance schema instrumentation (declarations).
+*/
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+#ifdef MYSQL_SERVER
+#ifndef EMBEDDED_LIBRARY
+#ifndef MYSQL_DYNAMIC_PLUGIN
+
+#include "mysql/psi/psi.h"
+
+#define PSI_SOCKET_CALL(M) pfs_ ## M ## _v1
+
+C_MODE_START
+
+void pfs_register_socket_v1(const char *category,
+                            PSI_socket_info_v1 *info,
+                            int count);
+
+PSI_socket*
+pfs_init_socket_v1(PSI_socket_key key, const my_socket *fd);
+
+void pfs_destroy_socket_v1(PSI_socket *socket);
+
+PSI_socket_locker*
+pfs_start_socket_wait_v1(PSI_socket_locker_state *state,
+                         PSI_socket *socket,
+                         PSI_socket_operation op,
+                         size_t count,
+                         const char *src_file, uint src_line);
+
+void pfs_end_socket_wait_v1(PSI_socket_locker *locker, size_t byte_count);
+
+void pfs_set_socket_state_v1(PSI_socket *socket, PSI_socket_state state);
+
+void pfs_set_socket_info_v1(PSI_socket *socket,
+                            const my_socket *fd,
+                            const struct sockaddr *addr,
+                            socklen_t addr_len);
+
+void pfs_set_socket_thread_owner_v1(PSI_socket *socket);
+
+C_MODE_END
+
+#endif /* EMBEDDED_LIBRARY */
+#endif /* MYSQL_DYNAMIC_PLUGIN */
+#endif /* MYSQL_SERVER */
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
+#endif
+

=== added file 'include/pfs_stage_provider.h'
--- a/include/pfs_stage_provider.h	1970-01-01 00:00:00 +0000
+++ b/include/pfs_stage_provider.h	2012-05-16 17:27:18 +0000
@@ -0,0 +1,51 @@
+/* Copyright (c) 2012, 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
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef PFS_STAGE_PROVIDER_H
+#define PFS_STAGE_PROVIDER_H
+
+/**
+  @file include/pfs_stage_provider.h
+  Performance schema instrumentation (declarations).
+*/
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+#ifdef MYSQL_SERVER
+#ifndef EMBEDDED_LIBRARY
+#ifndef MYSQL_DYNAMIC_PLUGIN
+
+#include "mysql/psi/psi.h"
+
+#define PSI_STAGE_CALL(M) pfs_ ## M ## _v1
+
+C_MODE_START
+
+void pfs_register_stage_v1(const char *category,
+                           PSI_stage_info_v1 **info_array,
+                           int count);
+
+void pfs_start_stage_v1(PSI_stage_key key, const char *src_file, int src_line);
+
+void pfs_end_stage_v1();
+
+C_MODE_END
+
+#endif /* MYSQL_DYNAMIC_PLUGIN */
+#endif /* EMBEDDED_LIBRARY */
+#endif /* MYSQL_SERVER */
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
+#endif
+

=== added file 'include/pfs_statement_provider.h'
--- a/include/pfs_statement_provider.h	1970-01-01 00:00:00 +0000
+++ b/include/pfs_statement_provider.h	2012-05-16 17:27:18 +0000
@@ -0,0 +1,117 @@
+/* Copyright (c) 2012, 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
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef PFS_STATEMENT_PROVIDER_H
+#define PFS_STATEMENT_PROVIDER_H
+
+/**
+  @file include/pfs_statement_provider.h
+  Performance schema instrumentation (declarations).
+*/
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+#ifdef MYSQL_SERVER
+#ifndef EMBEDDED_LIBRARY
+#ifndef MYSQL_DYNAMIC_PLUGIN
+
+#include "mysql/psi/psi.h"
+
+#define PSI_STATEMENT_CALL(M) pfs_ ## M ## _v1
+
+C_MODE_START
+
+void pfs_register_statement_v1(const char *category,
+                               PSI_statement_info_v1 *info,
+                               int count);
+
+PSI_statement_locker*
+pfs_get_thread_statement_locker_v1(PSI_statement_locker_state *state,
+                                   PSI_statement_key key,
+                                   const void *charset);
+
+PSI_statement_locker*
+pfs_refine_statement_v1(PSI_statement_locker *locker,
+                        PSI_statement_key key);
+
+void pfs_start_statement_v1(PSI_statement_locker *locker,
+                            const char *db, uint db_len,
+                            const char *src_file, uint src_line);
+
+void pfs_set_statement_text_v1(PSI_statement_locker *locker,
+                               const char *text, uint text_len);
+
+void pfs_set_statement_lock_time_v1(PSI_statement_locker *locker,
+                                    ulonglong count);
+
+void pfs_set_statement_rows_sent_v1(PSI_statement_locker *locker,
+                                    ulonglong count);
+
+void pfs_set_statement_rows_examined_v1(PSI_statement_locker *locker,
+                                        ulonglong count);
+
+void pfs_inc_statement_created_tmp_disk_tables_v1(PSI_statement_locker *locker,
+                                                  ulong count);
+
+void pfs_inc_statement_created_tmp_tables_v1(PSI_statement_locker *locker,
+                                             ulong count);
+
+void pfs_inc_statement_select_full_join_v1(PSI_statement_locker *locker,
+                                           ulong count);
+
+void pfs_inc_statement_select_full_range_join_v1(PSI_statement_locker *locker,
+                                                 ulong count);
+
+void pfs_inc_statement_select_range_v1(PSI_statement_locker *locker,
+                                       ulong count);
+
+void pfs_inc_statement_select_range_check_v1(PSI_statement_locker *locker,
+                                             ulong count);
+
+void pfs_inc_statement_select_scan_v1(PSI_statement_locker *locker,
+                                      ulong count);
+
+void pfs_inc_statement_sort_merge_passes_v1(PSI_statement_locker *locker,
+                                            ulong count);
+
+void pfs_inc_statement_sort_range_v1(PSI_statement_locker *locker,
+                                     ulong count);
+
+void pfs_inc_statement_sort_rows_v1(PSI_statement_locker *locker,
+                                    ulong count);
+
+void pfs_inc_statement_sort_scan_v1(PSI_statement_locker *locker,
+                                    ulong count);
+
+void pfs_set_statement_no_index_used_v1(PSI_statement_locker *locker);
+
+void pfs_set_statement_no_good_index_used_v1(PSI_statement_locker *locker);
+
+void pfs_end_statement_v1(PSI_statement_locker *locker, void *stmt_da);
+
+PSI_digest_locker *pfs_digest_start_v1(PSI_statement_locker *locker);
+
+PSI_digest_locker *pfs_digest_add_token_v1(PSI_digest_locker *locker,
+                                           uint token,
+                                           OPAQUE_LEX_YYSTYPE *yylval);
+
+C_MODE_END
+
+#endif /* MYSQL_DYNAMIC_PLUGIN */
+#endif /* EMBEDDED_LIBRARY */
+#endif /* MYSQL_SERVER */
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
+#endif
+

=== added file 'include/pfs_table_provider.h'
--- a/include/pfs_table_provider.h	1970-01-01 00:00:00 +0000
+++ b/include/pfs_table_provider.h	2012-05-16 17:27:18 +0000
@@ -0,0 +1,81 @@
+/* Copyright (c) 2012, 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
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef PFS_TABLE_PROVIDER_H
+#define PFS_TABLE_PROVIDER_H
+
+/**
+  @file include/pfs_table_provider.h
+  Performance schema instrumentation (declarations).
+*/
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+#ifdef MYSQL_SERVER
+#ifndef EMBEDDED_LIBRARY
+#ifndef MYSQL_DYNAMIC_PLUGIN
+
+#include "mysql/psi/psi.h"
+
+#define PSI_TABLE_CALL(M) pfs_ ## M ## _v1
+
+C_MODE_START
+
+PSI_table_share*
+pfs_get_table_share_v1(my_bool temporary, struct TABLE_SHARE *share);
+
+void pfs_release_table_share_v1(PSI_table_share* share);
+
+void
+pfs_drop_table_share_v1(my_bool temporary,
+                        const char *schema_name, int schema_name_length,
+                        const char *table_name, int table_name_length);
+
+PSI_table*
+pfs_open_table_v1(PSI_table_share *share, const void *identity);
+
+void pfs_unbind_table_v1(PSI_table *table);
+
+PSI_table *
+pfs_rebind_table_v1(PSI_table_share *share, const void *identity, PSI_table *table);
+
+void pfs_close_table_v1(PSI_table *table);
+
+PSI_table_locker*
+pfs_start_table_io_wait_v1(PSI_table_locker_state *state,
+                           PSI_table *table,
+                           PSI_table_io_operation op,
+                           uint index,
+                           const char *src_file, uint src_line);
+
+PSI_table_locker*
+pfs_start_table_lock_wait_v1(PSI_table_locker_state *state,
+                             PSI_table *table,
+                             PSI_table_lock_operation op,
+                             ulong op_flags,
+                             const char *src_file, uint src_line);
+
+void pfs_end_table_io_wait_v1(PSI_table_locker* locker);
+
+void pfs_end_table_lock_wait_v1(PSI_table_locker* locker);
+
+C_MODE_END
+
+#endif /* MYSQL_DYNAMIC_PLUGIN */
+#endif /* EMBEDDED_LIBRARY */
+#endif /* MYSQL_SERVER */
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
+#endif
+

=== added file 'include/pfs_thread_provider.h'
--- a/include/pfs_thread_provider.h	1970-01-01 00:00:00 +0000
+++ b/include/pfs_thread_provider.h	2012-05-16 17:27:18 +0000
@@ -0,0 +1,163 @@
+/* Copyright (c) 2012, 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
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software Foundation,
+  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef PFS_THREAD_PROVIDER_H
+#define PFS_THREAD_PROVIDER_H
+
+/**
+  @file include/pfs_thread_provider.h
+  Performance schema instrumentation (declarations).
+*/
+
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+#ifdef MYSQL_SERVER
+#ifndef EMBEDDED_LIBRARY
+#ifndef MYSQL_DYNAMIC_PLUGIN
+
+#include "mysql/psi/psi.h"
+
+#define PSI_MUTEX_CALL(M) pfs_ ## M ## _v1
+#define PSI_RWLOCK_CALL(M) pfs_ ## M ## _v1
+#define PSI_COND_CALL(M) pfs_ ## M ## _v1
+#define PSI_THREAD_CALL(M) pfs_ ## M ## _v1
+
+C_MODE_START
+
+void pfs_register_mutex_v1(const char *category,
+                           PSI_mutex_info_v1 *info,
+                           int count);
+
+void pfs_register_rwlock_v1(const char *category,
+                            PSI_rwlock_info_v1 *info,
+                            int count);
+
+void pfs_register_cond_v1(const char *category,
+                          PSI_cond_info_v1 *info,
+                          int count);
+
+void pfs_register_thread_v1(const char *category,
+                            PSI_thread_info_v1 *info,
+                            int count);
+
+PSI_mutex*
+pfs_init_mutex_v1(PSI_mutex_key key, const void *identity);
+
+void pfs_destroy_mutex_v1(PSI_mutex* mutex);
+
+PSI_rwlock*
+pfs_init_rwlock_v1(PSI_rwlock_key key, const void *identity);
+
+void pfs_destroy_rwlock_v1(PSI_rwlock* rwlock);
+
+PSI_cond*
+pfs_init_cond_v1(PSI_cond_key key, const void *identity);
+
+void pfs_destroy_cond_v1(PSI_cond* cond);
+
+int pfs_spawn_thread_v1(PSI_thread_key key,
+                        pthread_t *thread, const pthread_attr_t *attr,
+                        void *(*start_routine)(void*), void *arg);
+
+PSI_thread*
+pfs_new_thread_v1(PSI_thread_key key, const void *identity, ulong thread_id);
+
+void pfs_set_thread_id_v1(PSI_thread *thread, unsigned long id);
+
+PSI_thread*
+pfs_get_thread_v1(void);
+
+void pfs_set_thread_user_v1(const char *user, int user_len);
+
+void pfs_set_thread_account_v1(const char *user, int user_len,
+                               const char *host, int host_len);
+
+void pfs_set_thread_db_v1(const char* db, int db_len);
+
+void pfs_set_thread_command_v1(int command);
+
+void pfs_set_thread_start_time_v1(time_t start_time);
+
+void pfs_set_thread_state_v1(const char* state);
+
+void pfs_set_thread_info_v1(const char* info, int info_len);
+
+void pfs_set_thread_v1(PSI_thread* thread);
+
+void pfs_delete_current_thread_v1(void);
+
+void pfs_delete_thread_v1(PSI_thread *thread);
+
+PSI_mutex_locker*
+pfs_start_mutex_wait_v1(PSI_mutex_locker_state *state,
+                        PSI_mutex *mutex, PSI_mutex_operation op,
+                        const char *src_file, uint src_line);
+
+PSI_rwlock_locker*
+pfs_start_rwlock_rdwait_v1(PSI_rwlock_locker_state *state,
+                           PSI_rwlock *rwlock,
+                           PSI_rwlock_operation op,
+                           const char *src_file, uint src_line);
+
+PSI_rwlock_locker*
+pfs_start_rwlock_wrwait_v1(PSI_rwlock_locker_state *state,
+                           PSI_rwlock *rwlock,
+                           PSI_rwlock_operation op,
+                           const char *src_file, uint src_line);
+
+PSI_cond_locker*
+pfs_start_cond_wait_v1(PSI_cond_locker_state *state,
+                       PSI_cond *cond, PSI_mutex *mutex,
+                       PSI_cond_operation op,
+                       const char *src_file, uint src_line);
+
+PSI_table_locker*
+pfs_start_table_io_wait_v1(PSI_table_locker_state *state,
+                           PSI_table *table,
+                           PSI_table_io_operation op,
+                           uint index,
+                           const char *src_file, uint src_line);
+
+PSI_table_locker*
+pfs_start_table_lock_wait_v1(PSI_table_locker_state *state,
+                             PSI_table *table,
+                             PSI_table_lock_operation op,
+                             ulong op_flags,
+                             const char *src_file, uint src_line);
+
+void pfs_unlock_mutex_v1(PSI_mutex *mutex);
+
+void pfs_unlock_rwlock_v1(PSI_rwlock *rwlock);
+
+void pfs_signal_cond_v1(PSI_cond* cond);
+
+void pfs_broadcast_cond_v1(PSI_cond* cond);
+
+void pfs_end_mutex_wait_v1(PSI_mutex_locker* locker, int rc);
+
+void pfs_end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc);
+
+void pfs_end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc);
+
+void pfs_end_cond_wait_v1(PSI_cond_locker* locker, int rc);
+
+C_MODE_END
+
+#endif /* EMBEDDED_LIBRARY */
+#endif /* MYSQL_DYNAMIC_PLUGIN */
+#endif /* MYSQL_SERVER */
+#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
+#endif
+

=== modified file 'include/violite.h'
--- a/include/violite.h	2012-05-09 16:53:03 +0000
+++ b/include/violite.h	2012-05-16 17:27:18 +0000
@@ -22,9 +22,9 @@
 #define	vio_violite_h_
 
 #include "my_net.h"   /* needed because of struct in_addr */
+#include <pfs_socket_provider.h>
 #include <mysql/psi/mysql_socket.h>
 
-
 /* Simple vio interface in C;  The functions are implemented in violite.c */
 
 #ifdef	__cplusplus

=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt	2012-04-02 14:31:07 +0000
+++ b/sql/CMakeLists.txt	2012-05-16 13:58:54 +0000
@@ -110,6 +110,7 @@ SET(SQL_SHARED_SOURCES
   sp.cc
   sp_cache.cc
   sp_head.cc
+  sp_instr.cc
   sp_pcontext.cc 
   sp_rcontext.cc
   spatial.cc

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2012-05-16 14:19:34 +0000
+++ b/sql/handler.cc	2012-05-16 17:45:57 +0000
@@ -36,6 +36,7 @@
 #include "transaction.h"
 #include <errno.h>
 #include "probes_mysql.h"
+#include <pfs_table_provider.h>
 #include <mysql/psi/mysql_table.h>
 #include "debug_sync.h"         // DEBUG_SYNC
 #include <my_bit.h>

=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc	2012-02-02 09:12:43 +0000
+++ b/sql/mdl.cc	2012-05-16 17:27:18 +0000
@@ -20,6 +20,7 @@
 #include <mysqld_error.h>
 #include <mysql/plugin.h>
 #include <mysql/service_thd_wait.h>
+#include <pfs_stage_provider.h>
 #include <mysql/psi/mysql_stage.h>
 
 #ifdef HAVE_PSI_INTERFACE

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2012-05-15 09:42:30 +0000
+++ b/sql/mysqld.cc	2012-05-16 17:27:18 +0000
@@ -79,10 +79,13 @@
 
 #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
 #include "../storage/perfschema/pfs_server.h"
+#include <pfs_idle_provider.h>
 #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+
 #include <mysql/psi/mysql_idle.h>
 #include <mysql/psi/mysql_socket.h>
 #include <mysql/psi/mysql_statement.h>
+
 #include "mysql_com_server.h"
 
 #include "keycaches.h"
@@ -4812,6 +4815,9 @@ int win_main(int argc, char **argv)
 int mysqld_main(int argc, char **argv)
 #endif
 {
+#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+  pre_initialize_performance_schema();
+#endif /*WITH_PERFSCHEMA_STORAGE_ENGINE */
   /*
     Perform basic thread library and malloc initialization,
     to be able to read defaults files and parse options.

=== modified file 'sql/mysqld.h'
--- a/sql/mysqld.h	2012-05-04 10:00:43 +0000
+++ b/sql/mysqld.h	2012-05-16 17:27:18 +0000
@@ -21,6 +21,7 @@
 #include "my_decimal.h"                         /* my_decimal */
 #include "mysql_com.h"                     /* SERVER_VERSION_LENGTH */
 #include "my_atomic.h"                     /* my_atomic_rwlock_t */
+#include "pfs_file_provider.h"
 #include "mysql/psi/mysql_file.h"          /* MYSQL_FILE */
 #include "sql_list.h"                      /* I_List */
 #include "sql_cmd.h"                       /* SQLCOM_END */

=== modified file 'sql/sp.cc'
--- a/sql/sp.cc	2012-05-16 11:03:43 +0000
+++ b/sql/sp.cc	2012-05-16 13:58:54 +0000
@@ -2664,3 +2664,61 @@ error:
   result_field->set_null();
   return true;
 }
+
+
+/**
+  Return a string representation of the Item value.
+
+  @param thd  Thread context.
+  @param str  String buffer for representation of the value.
+
+  @note
+    If the item has a string result type, the string is escaped
+    according to its character set.
+
+  @retval NULL      on error
+  @retval non-NULL  a pointer to valid a valid string on success
+*/
+String *sp_get_item_value(THD *thd, Item *item, String *str)
+{
+  switch (item->result_type()) {
+  case REAL_RESULT:
+  case INT_RESULT:
+  case DECIMAL_RESULT:
+    if (item->field_type() != MYSQL_TYPE_BIT)
+      return item->val_str(str);
+    else {/* Bit type is handled as binary string */}
+  case STRING_RESULT:
+    {
+      String *result= item->val_str(str);
+
+      if (!result)
+        return NULL;
+
+      {
+        char buf_holder[STRING_BUFFER_USUAL_SIZE];
+        String buf(buf_holder, sizeof(buf_holder), result->charset());
+        const CHARSET_INFO *cs= thd->variables.character_set_client;
+
+        /* We must reset length of the buffer, because of String specificity. */
+        buf.length(0);
+
+        buf.append('_');
+        buf.append(result->charset()->csname);
+        if (cs->escape_with_backslash_is_dangerous)
+          buf.append(' ');
+        append_query_string(thd, cs, result, &buf);
+        buf.append(" COLLATE '");
+        buf.append(item->collation.collation->name);
+        buf.append('\'');
+        str->copy(buf);
+
+        return str;
+      }
+    }
+
+  case ROW_RESULT:
+  default:
+    return NULL;
+  }
+}

=== modified file 'sql/sp.h'
--- a/sql/sp.h	2012-05-16 11:03:43 +0000
+++ b/sql/sp.h	2012-05-16 13:58:54 +0000
@@ -218,6 +218,8 @@ Item *sp_prepare_func_item(THD* thd, Ite
 
 bool sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr);
 
+String *sp_get_item_value(THD *thd, Item *item, String *str);
+
 ///////////////////////////////////////////////////////////////////////////
 
 #endif /* _SP_H_ */

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2012-05-16 12:36:41 +0000
+++ b/sql/sp_head.cc	2012-05-16 13:58:54 +0000
@@ -28,6 +28,7 @@
 #include "log_event.h"         // append_query_string, Query_log_event
 
 #include "sp_head.h"
+#include "sp_instr.h"
 #include "sp.h"
 #include "sp_pcontext.h"
 #include "sp_rcontext.h"
@@ -41,12 +42,6 @@
 
 #include <my_user.h>           // parse_user
 
-#include <algorithm>
-
-// Sufficient max length of printed destinations and frame offsets (all uints).
-#define SP_INSTR_UINT_MAXLEN  8
-#define SP_STMT_PRINT_MAXLEN 40
-
 /**
   SP_TABLE represents all instances of one table in an optimized multi-set of
   tables used by a stored program.
@@ -137,279 +132,6 @@ static bool sp_update_sp_used_routines(H
   return false;
 }
 
-
-/**
-  Return a string representation of the Item value.
-
-  @param thd  Thread context.
-  @param str  String buffer for representation of the value.
-
-  @note
-    If the item has a string result type, the string is escaped
-    according to its character set.
-
-  @retval NULL      on error
-  @retval non-NULL  a pointer to valid a valid string on success
-*/
-
-static String *sp_get_item_value(THD *thd, Item *item, String *str)
-{
-  switch (item->result_type()) {
-  case REAL_RESULT:
-  case INT_RESULT:
-  case DECIMAL_RESULT:
-    if (item->field_type() != MYSQL_TYPE_BIT)
-      return item->val_str(str);
-    else {/* Bit type is handled as binary string */}
-  case STRING_RESULT:
-    {
-      String *result= item->val_str(str);
-
-      if (!result)
-        return NULL;
-
-      {
-        char buf_holder[STRING_BUFFER_USUAL_SIZE];
-        String buf(buf_holder, sizeof(buf_holder), result->charset());
-        const CHARSET_INFO *cs= thd->variables.character_set_client;
-
-        /* We must reset length of the buffer, because of String specificity. */
-        buf.length(0);
-
-        buf.append('_');
-        buf.append(result->charset()->csname);
-        if (cs->escape_with_backslash_is_dangerous)
-          buf.append(' ');
-        append_query_string(thd, cs, result, &buf);
-        buf.append(" COLLATE '");
-        buf.append(item->collation.collation->name);
-        buf.append('\'');
-        str->copy(buf);
-
-        return str;
-      }
-    }
-
-  case ROW_RESULT:
-  default:
-    return NULL;
-  }
-}
-
-
-static int cmp_splocal_locations(Item_splocal * const *a,
-                                 Item_splocal * const *b)
-{
-  return (int)((*a)->pos_in_query - (*b)->pos_in_query);
-}
-
-
-/*
-  StoredRoutinesBinlogging
-  This paragraph applies only to statement-based binlogging. Row-based
-  binlogging does not need anything special like this.
-
-  Top-down overview:
-
-  1. Statements
-
-  Statements that have is_update_query(stmt) == TRUE are written into the
-  binary log verbatim.
-  Examples:
-    UPDATE tbl SET tbl.x = spfunc_w_side_effects()
-    UPDATE tbl SET tbl.x=1 WHERE spfunc_w_side_effect_that_returns_false(tbl.y)
-
-  Statements that have is_update_query(stmt) == FALSE (e.g. SELECTs) are not
-  written into binary log. Instead we catch function calls the statement
-  makes and write it into binary log separately (see #3).
-
-  2. PROCEDURE calls
-
-  CALL statements are not written into binary log. Instead
-  * Any FUNCTION invocation (in SET, IF, WHILE, OPEN CURSOR and other SP
-    instructions) is written into binlog separately.
-
-  * Each statement executed in SP is binlogged separately, according to rules
-    in #1, with the exception that we modify query string: we replace uses
-    of SP local variables with NAME_CONST('spvar_name', <spvar-value>) calls.
-    This substitution is done in subst_spvars().
-
-  3. FUNCTION calls
-
-  In sp_head::execute_function(), we check
-   * If this function invocation is done from a statement that is written
-     into the binary log.
-   * If there were any attempts to write events to the binary log during
-     function execution (grep for start_union_events and stop_union_events)
-
-   If the answers are No and Yes, we write the function call into the binary
-   log as "SELECT spfunc(<param1value>, <param2value>, ...)"
-
-
-  4. Miscellaneous issues.
-
-  4.1 User variables.
-
-  When we call mysql_bin_log.write() for an SP statement, thd->user_var_events
-  must hold set<{var_name, value}> pairs for all user variables used during
-  the statement execution.
-  This set is produced by tracking user variable reads during statement
-  execution.
-
-  For SPs, this has the following implications:
-  1) thd->user_var_events may contain events from several SP statements and
-     needs to be valid after execution of these statements was finished. In
-     order to achieve that, we
-     * Allocate user_var_events array elements on appropriate mem_root (grep
-       for user_var_events_alloc).
-     * Use is_query_in_union() to determine if user_var_event is created.
-
-  2) We need to empty thd->user_var_events after we have wrote a function
-     call. This is currently done by making
-     reset_dynamic(&thd->user_var_events);
-     calls in several different places. (TODO consider moving this into
-     mysql_bin_log.write() function)
-
-  4.2 Auto_increment storage in binlog
-
-  As we may write two statements to binlog from one single logical statement
-  (case of "SELECT func1(),func2()": it is binlogged as "SELECT func1()" and
-  then "SELECT func2()"), we need to reset auto_increment binlog variables
-  after each binlogged SELECT. Otherwise, the auto_increment value of the
-  first SELECT would be used for the second too.
-*/
-
-
-/**
-  Replace thd->query{_length} with a string that one can write to
-  the binlog.
-
-  The binlog-suitable string is produced by replacing references to SP local
-  variables with NAME_CONST('sp_var_name', value) calls.
-
-  @param thd        Current thread.
-  @param instr      Instruction (we look for Item_splocal instances in
-                    instr->free_list)
-  @param query_str  Original query string
-
-  @retval false on success.
-  thd->query{_length} either has been appropriately replaced or there
-  is no need for replacements.
-
-  @retval true in case of out of memory error.
-*/
-
-static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
-{
-  Dynamic_array<Item_splocal*> sp_vars_uses;
-  char *pbuf, *cur, buffer[512];
-  String qbuf(buffer, sizeof(buffer), &my_charset_bin);
-  int prev_pos, res, buf_len;
-
-  /* Find all instances of Item_splocal used in this statement */
-  for (Item *item= instr->free_list; item; item= item->next)
-  {
-    if (item->is_splocal())
-    {
-      Item_splocal *item_spl= (Item_splocal*)item;
-      if (item_spl->pos_in_query)
-        sp_vars_uses.append(item_spl);
-    }
-  }
-
-  if (!sp_vars_uses.elements())
-    return false;
-
-  /* Sort SP var refs by their occurrences in the query */
-  sp_vars_uses.sort(cmp_splocal_locations);
-
-  /*
-    Construct a statement string where SP local var refs are replaced
-    with "NAME_CONST(name, value)"
-  */
-  qbuf.length(0);
-  cur= query_str->str;
-  prev_pos= res= 0;
-  thd->query_name_consts= 0;
-
-  for (Item_splocal **splocal= sp_vars_uses.front(); 
-       splocal <= sp_vars_uses.back(); splocal++)
-  {
-    Item *val;
-
-    char str_buffer[STRING_BUFFER_USUAL_SIZE];
-    String str_value_holder(str_buffer, sizeof(str_buffer),
-                            &my_charset_latin1);
-    String *str_value;
-
-    /* append the text between sp ref occurrences */
-    res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos);
-    prev_pos= (*splocal)->pos_in_query + (*splocal)->len_in_query;
-
-    res|= (*splocal)->fix_fields(thd, (Item **) splocal);
-    if (res)
-      break;
-
-    if ((*splocal)->limit_clause_param)
-    {
-      res|= qbuf.append_ulonglong((*splocal)->val_uint());
-      if (res)
-        break;
-      continue;
-    }
-
-    /* append the spvar substitute */
-    res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('"));
-    res|= qbuf.append((*splocal)->m_name);
-    res|= qbuf.append(STRING_WITH_LEN("',"));
-
-    if (res)
-      break;
-
-    val= (*splocal)->this_item();
-    str_value= sp_get_item_value(thd, val, &str_value_holder);
-    if (str_value)
-      res|= qbuf.append(*str_value);
-    else
-      res|= qbuf.append(STRING_WITH_LEN("NULL"));
-    res|= qbuf.append(')');
-    if (res)
-      break;
-
-    thd->query_name_consts++;
-  }
-  if (res ||
-      qbuf.append(cur + prev_pos, query_str->length - prev_pos))
-    return true;
-
-  /*
-    Allocate additional space at the end of the new query string for the
-    query_cache_send_result_to_client function.
-
-    The query buffer layout is:
-       buffer :==
-            <statement>   The input statement(s)
-            '\0'          Terminating null char
-            <length>      Length of following current database name (size_t)
-            <db_name>     Name of current database
-            <flags>       Flags struct
-  */
-  buf_len= qbuf.length() + 1 + sizeof(size_t) + thd->db_length + 
-           QUERY_CACHE_FLAGS_SIZE + 1;
-  if ((pbuf= (char *) alloc_root(thd->mem_root, buf_len)))
-  {
-    memcpy(pbuf, qbuf.ptr(), qbuf.length());
-    pbuf[qbuf.length()]= 0;
-    memcpy(pbuf+qbuf.length()+1, (char *) &thd->db_length, sizeof(size_t));
-  }
-  else
-    return true;
-
-  thd->set_query(pbuf, qbuf.length());
-
-  return false;
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // sp_name implementation.
 ///////////////////////////////////////////////////////////////////////////
@@ -2002,7 +1724,7 @@ bool sp_head::show_routine_code(THD *thd
     if (ip != i->get_ip())
     {
       const char *format= "Instruction at position %u has m_ip=%u";
-      char tmp[sizeof(format) + 2*SP_INSTR_UINT_MAXLEN + 1];
+      char tmp[sizeof(format) + 2 * sizeof(uint) + 1];
 
       sprintf(tmp, format, ip, i->get_ip());
       /*
@@ -2322,1408 +2044,3 @@ void sp_parser_data::process_new_sp_inst
 
   thd->free_list= NULL;
 }
-
-
-///////////////////////////////////////////////////////////////////////////
-// sp_lex_instr implementation.
-///////////////////////////////////////////////////////////////////////////
-
-
-bool sp_lex_instr::reset_lex_and_exec_core(THD *thd,
-                                           uint *nextp,
-                                           bool open_tables)
-{
-  bool rc= false;
-
-  /*
-    The flag is saved at the entry to the following substatement.
-    It's reset further in the common code part.
-    It's merged with the saved parent's value at the exit of this func.
-  */
-
-  unsigned int parent_unsafe_rollback_flags=
-    thd->transaction.stmt.get_unsafe_rollback_flags();
-  thd->transaction.stmt.reset_unsafe_rollback_flags();
-
-  /* Check pre-conditions. */
-
-  DBUG_ASSERT(!thd->derived_tables);
-  DBUG_ASSERT(thd->change_list.is_empty());
-
-  /*
-    Use our own lex.
-
-    Although it is saved/restored in sp_head::execute() when we are
-    entering/leaving routine, it's still should be saved/restored here,
-    in order to properly behave in case of ER_NEED_REPREPARE error
-    (when ER_NEED_REPREPARE happened, and we failed to re-parse the query).
-  */
-
-  LEX *lex_saved= thd->lex;
-  thd->lex= m_lex;
-
-  /* Set new query id. */
-
-  thd->set_query_id(next_query_id());
-
-  if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
-  {
-    /*
-      This statement will enter/leave prelocked mode on its own.
-      Entering prelocked mode changes table list and related members
-      of LEX, so we'll need to restore them.
-    */
-    if (m_lex_query_tables_own_last)
-    {
-      /*
-        We've already entered/left prelocked mode with this statement.
-        Attach the list of tables that need to be prelocked and mark m_lex
-        as having such list attached.
-      */
-      *m_lex_query_tables_own_last= m_prelocking_tables;
-      m_lex->mark_as_requiring_prelocking(m_lex_query_tables_own_last);
-    }
-  }
-
-  /* Reset LEX-object before re-use. */
-
-  reinit_stmt_before_use(thd, m_lex);
-
-  /* Open tables if needed. */
-
-  if (open_tables)
-  {
-    /*
-      IF, CASE, DECLARE, SET, RETURN, have 'open_tables' true; they may
-      have a subquery in parameter and are worth tracing. They don't
-      correspond to a SQL command so we pretend that they are SQLCOM_SELECT.
-    */
-    Opt_trace_start ots(thd, m_lex->query_tables, SQLCOM_SELECT,
-                        &m_lex->var_list, NULL, 0, this,
-                        thd->variables.character_set_client);
-    Opt_trace_object trace_command(&thd->opt_trace);
-    Opt_trace_array trace_command_steps(&thd->opt_trace, "steps");
-
-    /*
-      Check whenever we have access to tables for this statement
-      and open and lock them before executing instructions core function.
-      If we are not opening any tables, we don't need to check permissions
-      either.
-    */
-    if (m_lex->query_tables)
-      rc= (open_temporary_tables(thd, m_lex->query_tables) ||
-            check_table_access(thd, SELECT_ACL, m_lex->query_tables, false,
-                               UINT_MAX, false));
-
-    if (!rc)
-      rc= open_and_lock_tables(thd, m_lex->query_tables, true, 0);
-
-    if (!rc)
-    {
-      rc= exec_core(thd, nextp);
-      DBUG_PRINT("info",("exec_core returned: %d", rc));
-    }
-
-    /*
-      Call after unit->cleanup() to close open table
-      key read.
-    */
-
-    m_lex->unit.cleanup();
-
-    /* Here we also commit or rollback the current statement. */
-
-    if (! thd->in_sub_stmt)
-    {
-      thd->get_stmt_da()->set_overwrite_status(true);
-      thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
-      thd->get_stmt_da()->set_overwrite_status(false);
-    }
-    thd_proc_info(thd, "closing tables");
-    close_thread_tables(thd);
-    thd_proc_info(thd, 0);
-
-    if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
-      thd->mdl_context.release_transactional_locks();
-    else if (! thd->in_sub_stmt)
-      thd->mdl_context.release_statement_locks();
-  }
-  else
-  {
-    rc= exec_core(thd, nextp);
-    DBUG_PRINT("info",("exec_core returned: %d", rc));
-  }
-
-  if (m_lex->query_tables_own_last)
-  {
-    /*
-      We've entered and left prelocking mode when executing statement
-      stored in m_lex.
-      m_lex->query_tables(->next_global)* list now has a 'tail' - a list
-      of tables that are added for prelocking. (If this is the first
-      execution, the 'tail' was added by open_tables(), otherwise we've
-      attached it above in this function).
-      Now we'll save the 'tail', and detach it.
-    */
-    m_lex_query_tables_own_last= m_lex->query_tables_own_last;
-    m_prelocking_tables= *m_lex_query_tables_own_last;
-    *m_lex_query_tables_own_last= NULL;
-    m_lex->mark_as_requiring_prelocking(NULL);
-  }
-
-  /* Rollback changes to the item tree during execution. */
-
-  thd->rollback_item_tree_changes();
-
-  /*
-    Update the state of the active arena if no errors on
-    open_tables stage.
-  */
-
-  if (!rc || !thd->is_error() ||
-      (thd->get_stmt_da()->sql_errno() != ER_CANT_REOPEN_TABLE &&
-       thd->get_stmt_da()->sql_errno() != ER_NO_SUCH_TABLE &&
-       thd->get_stmt_da()->sql_errno() != ER_UPDATE_TABLE_USED))
-    thd->stmt_arena->state= Query_arena::STMT_EXECUTED;
-
-  /*
-    Merge here with the saved parent's values
-    what is needed from the substatement gained
-  */
-
-  thd->transaction.stmt.add_unsafe_rollback_flags(parent_unsafe_rollback_flags);
-
-  /* Restore original lex. */
-
-  thd->lex= lex_saved;
-
-  /*
-    Unlike for PS we should not call Item's destructors for newly created
-    items after execution of each instruction in stored routine. This is
-    because SP often create Item (like Item_int, Item_string etc...) when
-    they want to store some value in local variable, pass return value and
-    etc... So their life time should be longer than one instruction.
-
-    cleanup_items() is called in sp_head::execute()
-  */
-
-  return rc || thd->is_error();
-}
-
-LEX *sp_lex_instr::parse_expr(THD *thd, sp_head *sp)
-{
-  String sql_query;
-  sql_query.set_charset(system_charset_info);
-
-  get_query(&sql_query);
-
-  if (sql_query.length() == 0)
-  {
-    // The instruction has returned zero-length query string. That means, the
-    // re-preparation of the instruction is not possible. We should not come
-    // here in the normal life.
-    DBUG_ASSERT(false);
-    my_error(ER_UNKNOWN_ERROR, MYF(0));
-    return NULL;
-  }
-
-  // Prepare parser state. It can be done just before parse_sql(), do it here
-  // only to simplify exit in case of failure (out-of-memory error).
-
-  Parser_state parser_state;
-
-  if (parser_state.init(thd, sql_query.c_ptr(), sql_query.length()))
-    return NULL;
-
-  // Cleanup current THD from previously held objects before new parsing.
-
-  cleanup_before_parsing(thd);
-
-  // Switch mem-roots. We need to store new LEX and its Items in the persistent
-  // SP-memory (memory which is not freed between executions).
-
-  MEM_ROOT *execution_mem_root= thd->mem_root;
-
-  thd->mem_root= thd->sp_runtime_ctx->sp->get_persistent_mem_root();
-
-  // Switch THD::free_list. It's used to remember the newly created set of Items
-  // during parsing. We should clean those items after each execution.
-
-  Item *execution_free_list= thd->free_list;
-  thd->free_list= NULL;
-
-  // Create a new LEX and intialize it.
-
-  LEX *lex_saved= thd->lex;
-
-  thd->lex= new (thd->mem_root) st_lex_local;
-  lex_start(thd);
-
-  thd->lex->sphead= sp;
-  thd->lex->set_sp_current_parsing_ctx(get_parsing_ctx());
-  sp->m_parser_data.set_current_stmt_start_ptr(sql_query.c_ptr());
-
-  // Parse the just constructed SELECT-statement.
-
-  bool parsing_failed= parse_sql(thd, &parser_state, NULL);
-
-  if (!parsing_failed)
-  {
-    thd->lex->set_trg_event_type_for_tables();
-
-    if (sp->m_type == SP_TYPE_TRIGGER)
-    {
-      /*
-        Also let us bind these objects to Field objects in table being opened.
-
-        We ignore errors of setup_field() here, because if even something is
-        wrong we still will be willing to open table to perform some operations
-        (e.g.  SELECT)... Anyway some things can be checked only during trigger
-        execution.
-      */
-
-      Table_triggers_list *ttl= sp->m_trg_list;
-      int event= sp->m_trg_chistics.event;
-      int action_time= sp->m_trg_chistics.action_time;
-      GRANT_INFO *grant_table= &ttl->subject_table_grants[event][action_time];
-
-      for (Item_trigger_field *trg_field= sp->m_trg_table_fields.first;
-           trg_field;
-           trg_field= trg_field->next_trg_field)
-      {
-        trg_field->setup_field(thd, ttl->trigger_table, grant_table);
-      }
-    }
-
-    // Call after-parsing callback.
-
-    parsing_failed= on_after_expr_parsing(thd);
-
-    // Append newly created Items to the list of Items, owned by this
-    // instruction.
-
-    free_list= thd->free_list;
-  }
-
-  // Restore THD::lex.
-
-  thd->lex->sphead= NULL;
-  thd->lex->set_sp_current_parsing_ctx(NULL);
-
-  LEX *expr_lex= thd->lex;
-  thd->lex= lex_saved;
-
-  // Restore execution mem-root and THD::free_list.
-
-  thd->mem_root= execution_mem_root;
-  thd->free_list= execution_free_list;
-
-  // That's it.
-
-  return parsing_failed ? NULL : expr_lex;
-}
-
-bool sp_lex_instr::validate_lex_and_execute_core(THD *thd,
-                                                 uint *nextp,
-                                                 bool open_tables)
-{
-  Reprepare_observer reprepare_observer;
-  int reprepare_attempt= 0;
-
-  while (true)
-  {
-    if (is_invalid())
-    {
-      LEX *lex= parse_expr(thd, thd->sp_runtime_ctx->sp);
-
-      if (!lex)
-        return true;
-
-      set_lex(lex, true);
-
-      m_first_execution= true;
-    }
-
-    /*
-      Install the metadata observer. If some metadata version is
-      different from prepare time and an observer is installed,
-      the observer method will be invoked to push an error into
-      the error stack.
-    */
-    Reprepare_observer *stmt_reprepare_observer= NULL;
-
-    /*
-      Meta-data versions are stored in the LEX-object on the first execution.
-      Thus, the reprepare observer should not be installed for the first
-      execution, because it will always be triggered.
-
-      Then, the reprepare observer should be installed for the statements, which
-      are marked by CF_REEXECUTION_FRAGILE (@sa CF_REEXECUTION_FRAGILE) or if
-      the SQL-command is SQLCOM_END, which means that the LEX-object is
-      representing an expression, so the exact SQL-command does not matter.
-    */
-
-    if (!m_first_execution &&
-        (sql_command_flags[m_lex->sql_command] & CF_REEXECUTION_FRAGILE ||
-         m_lex->sql_command == SQLCOM_END))
-    {
-      reprepare_observer.reset_reprepare_observer();
-      stmt_reprepare_observer= &reprepare_observer;
-    }
-
-    thd->push_reprepare_observer(stmt_reprepare_observer);
-
-    bool rc= reset_lex_and_exec_core(thd, nextp, open_tables);
-
-    thd->pop_reprepare_observer();
-
-    m_first_execution= false;
-
-    if (!rc)
-      return false;
-
-    /*
-      Here is why we need all the checks below:
-        - if the reprepare observer is not set, we've got an error, which should
-          be raised to the user;
-        - if we've got fatal error, it should be raised to the user;
-        - if our thread got killed during execution, the error should be raised
-          to the user;
-        - if we've got an error, different from ER_NEED_REPREPARE, we need to
-          raise it to the user;
-        - we take only 3 attempts to reprepare the query, otherwise we might end
-          up in the endless loop.
-    */
-    if (stmt_reprepare_observer &&
-        !thd->is_fatal_error &&
-        !thd->killed &&
-        thd->get_stmt_da()->sql_errno() == ER_NEED_REPREPARE &&
-        reprepare_attempt++ < 3)
-    {
-      DBUG_ASSERT(stmt_reprepare_observer->is_invalidated());
-
-      thd->clear_error();
-      free_lex();
-      invalidate();
-    }
-    else
-      return true;
-  }
-}
-
-
-void sp_lex_instr::set_lex(LEX *lex, bool is_lex_owner)
-{
-  free_lex();
-
-  m_lex= lex;
-  m_is_lex_owner= is_lex_owner;
-  m_lex_query_tables_own_last= NULL;
-
-  if (m_lex)
-    m_lex->sp_lex_in_use= true;
-}
-
-
-void sp_lex_instr::free_lex()
-{
-  if (!m_is_lex_owner || !m_lex)
-    return;
-
-  /* Prevent endless recursion. */
-  m_lex->sphead= NULL;
-  lex_end(m_lex);
-  delete (st_lex_local *) m_lex;
-
-  m_lex= NULL;
-  m_is_lex_owner= false;
-  m_lex_query_tables_own_last= NULL;
-}
-
-
-void sp_lex_instr::cleanup_before_parsing(THD *thd)
-{
-  /*
-    Destroy items in the instruction's free list before re-parsing the
-    statement query string (and thus, creating new items).
-  */
-  Item *p= free_list;
-  while (p)
-  {
-    Item *next= p->next;
-    p->delete_self();
-    p= next;
-  }
-
-  free_list= NULL;
-
-  // Remove previously stored trigger-field items.
-  sp_head *sp= thd->sp_runtime_ctx->sp;
-
-  if (sp->m_type == SP_TYPE_TRIGGER)
-    sp->m_trg_table_fields.empty();
-}
-
-
-void sp_lex_instr::get_query(String *sql_query) const
-{
-  LEX_STRING expr_query= this->get_expr_query();
-
-  if (!expr_query.str)
-  {
-    sql_query->length(0);
-    return;
-  }
-
-  sql_query->append("SELECT ");
-  sql_query->append(expr_query.str, expr_query.length);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_stmt implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_stmt::execute(THD *thd, uint *nextp)
-{
-  bool need_subst= false;
-  bool rc= false;
-
-  DBUG_PRINT("info", ("query: '%.*s'", (int) m_query.length, m_query.str));
-
-  const CSET_STRING query_backup= thd->query_string;
-
-#if defined(ENABLED_PROFILING)
-  /* This SP-instr is profilable and will be captured. */
-  thd->profiling.set_query_source(m_query.str, m_query.length);
-#endif
-
-  /*
-    If we can't set thd->query_string at all, we give up on this statement.
-  */
-  if (alloc_query(thd, m_query.str, m_query.length))
-    return true;
-
-  /*
-    Check whether we actually need a substitution of SP variables with
-    NAME_CONST(...) (using subst_spvars()).
-    If both of the following apply, we won't need to substitute:
-
-    - general log is off
-
-    - binary logging is off, or not in statement mode
-
-    We don't have to substitute on behalf of the query cache as
-    queries with SP vars are not cached, anyway.
-
-    query_name_consts is used elsewhere in a special case concerning
-    CREATE TABLE, but we do not need to do anything about that here.
-
-    The slow query log is another special case: we won't know whether a
-    query qualifies for the slow query log until after it's been
-    executed. We assume that most queries are not slow, so we do not
-    pre-emptively substitute just for the slow query log. If a query
-    ends up being slow after all and we haven't done the substitution
-    already for any of the above (general log etc.), we'll do the
-    substitution immediately before writing to the log.
-  */
-
-  need_subst= ((thd->variables.option_bits & OPTION_LOG_OFF) &&
-               (!(thd->variables.option_bits & OPTION_BIN_LOG) ||
-                !mysql_bin_log.is_open() ||
-                thd->is_current_stmt_binlog_format_row())) ? FALSE : TRUE;
-
-  /*
-    If we need to do a substitution but can't (OOM), give up.
-  */
-
-  if (need_subst && subst_spvars(thd, this, &m_query))
-    return true;
-
-  /*
-    (the order of query cache and subst_spvars calls is irrelevant because
-    queries with SP vars can't be cached)
-  */
-  if (unlikely((thd->variables.option_bits & OPTION_LOG_OFF)==0))
-    general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
-
-  if (query_cache_send_result_to_client(thd, thd->query(),
-                                        thd->query_length()) <= 0)
-  {
-    rc= validate_lex_and_execute_core(thd, nextp, false);
-
-    if (thd->get_stmt_da()->is_eof())
-    {
-      /* Finalize server status flags after executing a statement. */
-      thd->update_server_status();
-
-      thd->protocol->end_statement();
-    }
-
-    query_cache_end_of_result(thd);
-
-    if (!rc && unlikely(log_slow_applicable(thd)))
-    {
-      /*
-        We actually need to write the slow log. Check whether we already
-        called subst_spvars() above, otherwise, do it now.  In the highly
-        unlikely event of subst_spvars() failing (OOM), we'll try to log
-        the unmodified statement instead.
-      */
-      if (!need_subst)
-        rc= subst_spvars(thd, this, &m_query);
-      log_slow_do(thd);
-    }
-
-    /*
-      With the current setup, a subst_spvars() and a mysql_rewrite_query()
-      (rewriting passwords etc.) will not both happen to a query.
-      If this ever changes, we give the engineer pause here so they will
-      double-check whether the potential conflict they created is a
-      problem.
-    */
-    DBUG_ASSERT((thd->query_name_consts == 0) ||
-                (thd->rewritten_query.length() == 0));
-  }
-  else
-    *nextp= get_ip() + 1;
-
-  thd->set_query(query_backup);
-  thd->query_name_consts= 0;
-
-  if (!thd->is_error())
-    thd->get_stmt_da()->reset_diagnostics_area();
-
-  return rc || thd->is_error();
-}
-
-
-void sp_instr_stmt::print(String *str)
-{
-  /* stmt CMD "..." */
-  if (str->reserve(SP_STMT_PRINT_MAXLEN + SP_INSTR_UINT_MAXLEN + 8))
-    return;
-  str->qs_append(STRING_WITH_LEN("stmt"));
-  str->qs_append(STRING_WITH_LEN(" \""));
-
-  /*
-    Print the query string (but not too much of it), just to indicate which
-    statement it is.
-  */
-  uint len= m_query.length;
-  if (len > SP_STMT_PRINT_MAXLEN)
-    len= SP_STMT_PRINT_MAXLEN-3;
-
-  /* Copy the query string and replace '\n' with ' ' in the process */
-  for (uint i= 0 ; i < len ; i++)
-  {
-    char c= m_query.str[i];
-    if (c == '\n')
-      c= ' ';
-    str->qs_append(c);
-  }
-  if (m_query.length > SP_STMT_PRINT_MAXLEN)
-    str->qs_append(STRING_WITH_LEN("...")); /* Indicate truncated string */
-  str->qs_append('"');
-}
-
-
-bool sp_instr_stmt::exec_core(THD *thd, uint *nextp)
-{
-  MYSQL_QUERY_EXEC_START(thd->query(),
-                         thd->thread_id,
-                         (char *) (thd->db ? thd->db : ""),
-                         &thd->security_ctx->priv_user[0],
-                         (char *)thd->security_ctx->host_or_ip,
-                         3);
-
-  bool rc= mysql_execute_command(thd);
-
-  MYSQL_QUERY_EXEC_DONE(rc);
-
-  *nextp= get_ip() + 1;
-
-  return rc;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_set implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_set::exec_core(THD *thd, uint *nextp)
-{
-  *nextp= get_ip() + 1;
-
-  if (!thd->sp_runtime_ctx->set_variable(thd, m_offset, &m_value_item))
-    return false;
-
-  /* Failed to evaluate the value. Reset the variable to NULL. */
-
-  if (thd->sp_runtime_ctx->set_variable(thd, m_offset, 0))
-  {
-    /* If this also failed, let's abort. */
-    my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
-  }
-
-  return true;
-}
-
-void sp_instr_set::print(String *str)
-{
-  /* set name@offset ... */
-  int rsrv = SP_INSTR_UINT_MAXLEN+6;
-  sp_variable *var = m_parsing_ctx->find_variable(m_offset);
-
-  /* 'var' should always be non-null, but just in case... */
-  if (var)
-    rsrv+= var->name.length;
-  if (str->reserve(rsrv))
-    return;
-  str->qs_append(STRING_WITH_LEN("set "));
-  if (var)
-  {
-    str->qs_append(var->name.str, var->name.length);
-    str->qs_append('@');
-  }
-  str->qs_append(m_offset);
-  str->qs_append(' ');
-  m_value_item->print(str, QT_ORDINARY);
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_set_trigger_field implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp)
-{
-  *nextp= get_ip() + 1;
-  thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
-  return m_trigger_field->set_value(thd, &m_value_item);
-}
-
-void sp_instr_set_trigger_field::print(String *str)
-{
-  str->append(STRING_WITH_LEN("set_trigger_field "));
-  m_trigger_field->print(str, QT_ORDINARY);
-  str->append(STRING_WITH_LEN(":="));
-  m_value_item->print(str, QT_ORDINARY);
-}
-
-bool sp_instr_set_trigger_field::on_after_expr_parsing(THD *thd)
-{
-  DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
-
-  m_value_item= thd->lex->select_lex.item_list.head();
-
-  DBUG_ASSERT(!m_trigger_field);
-
-  m_trigger_field=
-    new (thd->mem_root) Item_trigger_field(thd->lex->current_context(),
-                                           Item_trigger_field::NEW_ROW,
-                                           m_trigger_field_name.str,
-                                           UPDATE_ACL,
-                                           false);
-
-  return m_value_item == NULL || m_trigger_field == NULL;
-}
-
-void sp_instr_set_trigger_field::cleanup_before_parsing(THD *thd)
-{
-  sp_lex_instr::cleanup_before_parsing(thd);
-
-  m_trigger_field= NULL;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_jump implementation.
-///////////////////////////////////////////////////////////////////////////
-
-void sp_instr_jump::print(String *str)
-{
-  /* jump dest */
-  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
-    return;
-  str->qs_append(STRING_WITH_LEN("jump "));
-  str->qs_append(m_dest);
-}
-
-uint sp_instr_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
-{
-  m_dest= opt_shortcut_jump(sp, this);
-  if (m_dest != get_ip() + 1)   /* Jumping to following instruction? */
-    m_marked= true;
-  m_optdest= sp->get_instr(m_dest);
-  return m_dest;
-}
-
-uint sp_instr_jump::opt_shortcut_jump(sp_head *sp, sp_instr *start)
-{
-  uint dest= m_dest;
-  sp_instr *i;
-
-  while ((i= sp->get_instr(dest)))
-  {
-    uint ndest;
-
-    if (start == i || this == i)
-      break;
-    ndest= i->opt_shortcut_jump(sp, start);
-    if (ndest == dest)
-      break;
-    dest= ndest;
-  }
-  return dest;
-}
-
-void sp_instr_jump::opt_move(uint dst, List<sp_branch_instr> *bp)
-{
-  if (m_dest > get_ip())
-    bp->push_back(this);      // Forward
-  else if (m_optdest)
-    m_dest= m_optdest->get_ip();  // Backward
-  m_ip= dst;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_jump_if_not class implementation
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
-{
-  DBUG_ASSERT(m_expr_item);
-
-  Item *item= sp_prepare_func_item(thd, &m_expr_item);
-
-  if (!item)
-    return true;
-
-  *nextp= item->val_bool() ? get_ip() + 1 : m_dest;
-
-  return false;
-}
-
-
-void sp_instr_jump_if_not::print(String *str)
-{
-  /* jump_if_not dest(cont) ... */
-  if (str->reserve(2*SP_INSTR_UINT_MAXLEN+14+32)) // Add some for the expr. too
-    return;
-  str->qs_append(STRING_WITH_LEN("jump_if_not "));
-  str->qs_append(m_dest);
-  str->qs_append('(');
-  str->qs_append(m_cont_dest);
-  str->qs_append(STRING_WITH_LEN(") "));
-  m_expr_item->print(str, QT_ORDINARY);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_lex_branch_instr implementation.
-///////////////////////////////////////////////////////////////////////////
-
-uint sp_lex_branch_instr::opt_mark(sp_head *sp, List<sp_instr> *leads)
-{
-  m_marked= true;
-
-  sp_instr *i= sp->get_instr(m_dest);
-
-  if (i)
-  {
-    m_dest= i->opt_shortcut_jump(sp, this);
-    m_optdest= sp->get_instr(m_dest);
-  }
-
-  sp->add_mark_lead(m_dest, leads);
-
-  i= sp->get_instr(m_cont_dest);
-
-  if (i)
-  {
-    m_cont_dest= i->opt_shortcut_jump(sp, this);
-    m_cont_optdest= sp->get_instr(m_cont_dest);
-  }
-
-  sp->add_mark_lead(m_cont_dest, leads);
-
-  return get_ip() + 1;
-}
-
-void sp_lex_branch_instr::opt_move(uint dst, List<sp_branch_instr> *bp)
-{
-  /*
-    cont. destinations may point backwards after shortcutting jumps
-    during the mark phase. If it's still pointing forwards, only
-    push this for backpatching if sp_instr_jump::opt_move() will not
-    do it (i.e. if the m_dest points backwards).
-   */
-  if (m_cont_dest > get_ip())
-  {                             // Forward
-    if (m_dest < get_ip())
-      bp->push_back(this);
-  }
-  else if (m_cont_optdest)
-    m_cont_dest= m_cont_optdest->get_ip(); // Backward
-
-  /* This will take care of m_dest and m_ip */
-  if (m_dest > get_ip())
-    bp->push_back(this);      // Forward
-  else if (m_optdest)
-    m_dest= m_optdest->get_ip();  // Backward
-  m_ip= dst;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_jump_case_when implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_jump_case_when::exec_core(THD *thd, uint *nextp)
-{
-  DBUG_ASSERT(m_eq_item);
-
-  Item *item= sp_prepare_func_item(thd, &m_eq_item);
-
-  if (!item)
-    return true;
-
-  *nextp= item->val_bool() ? get_ip() + 1 : m_dest;
-
-  return false;
-}
-
-
-void sp_instr_jump_case_when::print(String *str)
-{
-  /* jump_if_not dest(cont) ... */
-  if (str->reserve(2*SP_INSTR_UINT_MAXLEN+14+32)) // Add some for the expr. too
-    return;
-  str->qs_append(STRING_WITH_LEN("jump_if_not_case_when "));
-  str->qs_append(m_dest);
-  str->qs_append('(');
-  str->qs_append(m_cont_dest);
-  str->qs_append(STRING_WITH_LEN(") "));
-  m_eq_item->print(str, QT_ORDINARY);
-}
-
-bool sp_instr_jump_case_when::build_expr_items(THD *thd)
-{
-  // Setup CASE-expression item (m_case_expr_item).
-
-  m_case_expr_item= new Item_case_expr(m_case_expr_id);
-
-  if (!m_case_expr_item)
-    return true;
-
-#ifndef DBUG_OFF
-  m_case_expr_item->m_sp= thd->lex->sphead;
-#endif
-
-  // Setup WHEN-expression item (m_expr_item) if it is not already set.
-  //
-  // This function can be called in two cases:
-  //
-  //   - during initial (regular) parsing of SP. In this case we don't have
-  //     lex->select_lex (because it's not a SELECT statement), but
-  //     m_expr_item is already set in constructor.
-  //
-  //   - during re-parsing after meta-data change. In this case we've just
-  //     parsed aux-SELECT statement, so we need to take 1st (and the only one)
-  //     item from its list.
-
-  if (!m_expr_item)
-  {
-    DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
-
-    m_expr_item= thd->lex->select_lex.item_list.head();
-  }
-
-  // Setup main expression item (m_expr_item).
-
-  m_eq_item= new Item_func_eq(m_case_expr_item, m_expr_item);
-
-  if (!m_eq_item)
-    return true;
-
-  return false;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_freturn implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_freturn::exec_core(THD *thd, uint *nextp)
-{
-  /*
-    RETURN is a "procedure statement" (in terms of the SQL standard).
-    That means, Diagnostics Area should be clean before its execution.
-  */
-
-  Diagnostics_area *da= thd->get_stmt_da();
-  da->clear_warning_info(da->warning_info_id());
-
-  /*
-    Change <next instruction pointer>, so that this will be the last
-    instruction in the stored function.
-  */
-
-  *nextp= UINT_MAX;
-
-  /*
-    Evaluate the value of return expression and store it in current runtime
-    context.
-
-    NOTE: It's necessary to evaluate result item right here, because we must
-    do it in scope of execution the current context/block.
-  */
-
-  return thd->sp_runtime_ctx->set_return_value(thd, &m_expr_item);
-}
-
-void sp_instr_freturn::print(String *str)
-{
-  /* freturn type expr... */
-  if (str->reserve(1024+8+32)) // Add some for the expr. too
-    return;
-  str->qs_append(STRING_WITH_LEN("freturn "));
-  str->qs_append((uint) m_return_field_type);
-  str->qs_append(' ');
-  m_expr_item->print(str, QT_ORDINARY);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_hpush_jump implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
-{
-  *nextp= m_dest;
-
-  return thd->sp_runtime_ctx->push_handler(m_handler, get_ip() + 1);
-}
-
-
-void sp_instr_hpush_jump::print(String *str)
-{
-  /* hpush_jump dest fsize type */
-  if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 21))
-    return;
-
-  str->qs_append(STRING_WITH_LEN("hpush_jump "));
-  str->qs_append(m_dest);
-  str->qs_append(' ');
-  str->qs_append(m_frame);
-
-  switch (m_handler->type) {
-  case sp_handler::EXIT:
-    str->qs_append(STRING_WITH_LEN(" EXIT"));
-    break;
-  case sp_handler::CONTINUE:
-    str->qs_append(STRING_WITH_LEN(" CONTINUE"));
-    break;
-  default:
-    // The handler type must be either CONTINUE or EXIT.
-    DBUG_ASSERT(0);
-  }
-}
-
-
-uint sp_instr_hpush_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
-{
-  m_marked= true;
-
-  sp_instr *i= sp->get_instr(m_dest);
-
-  if (i)
-  {
-    m_dest= i->opt_shortcut_jump(sp, this);
-    m_optdest= sp->get_instr(m_dest);
-  }
-
-  sp->add_mark_lead(m_dest, leads);
-
-  /*
-    For continue handlers, all instructions in the scope of the handler
-    are possible leads. For example, the instruction after freturn might
-    be executed if the freturn triggers the condition handled by the
-    continue handler.
-
-    m_dest marks the start of the handler scope. It's added as a lead
-    above, so we start on m_dest+1 here.
-    m_opt_hpop is the hpop marking the end of the handler scope.
-  */
-  if (m_handler->type == sp_handler::CONTINUE)
-  {
-    for (uint scope_ip= m_dest+1; scope_ip <= m_opt_hpop; scope_ip++)
-      sp->add_mark_lead(scope_ip, leads);
-  }
-
-  return get_ip() + 1;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_hpop implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_hpop::execute(THD *thd, uint *nextp)
-{
-  thd->sp_runtime_ctx->pop_handlers(m_count);
-  *nextp= get_ip() + 1;
-  return false;
-}
-
-void sp_instr_hpop::print(String *str)
-{
-  /* hpop count */
-  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
-    return;
-  str->qs_append(STRING_WITH_LEN("hpop "));
-  str->qs_append(m_count);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_hreturn implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_hreturn::execute(THD *thd, uint *nextp)
-{
-  // NOTE: we must call sp_rcontext::exit_handler() even if m_dest is set.
-
-  uint continue_ip= thd->sp_runtime_ctx->exit_handler(thd->get_stmt_da());
-
-  *nextp= m_dest ? m_dest : continue_ip;
-
-  return false;
-}
-
-
-void sp_instr_hreturn::print(String *str)
-{
-  /* hreturn framesize dest */
-  if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 9))
-    return;
-  str->qs_append(STRING_WITH_LEN("hreturn "));
-  if (m_dest)
-  {
-    // NOTE: this is legacy: hreturn instruction for EXIT handler
-    // should print out 0 as frame index.
-    str->qs_append(STRING_WITH_LEN("0 "));
-    str->qs_append(m_dest);
-  }
-  else
-  {
-    str->qs_append(m_frame);
-  }
-}
-
-
-uint sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads)
-{
-  m_marked= true;
-
-  if (m_dest)
-  {
-    /*
-      This is an EXIT handler; next instruction step is in m_dest.
-     */
-    return m_dest;
-  }
-
-  /*
-    This is a CONTINUE handler; next instruction step will come from
-    the handler stack and not from opt_mark.
-   */
-  return UINT_MAX;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_cpush implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_cpush::execute(THD *thd, uint *nextp)
-{
-  *nextp= get_ip() + 1;
-
-  // sp_instr_cpush::execute() just registers the cursor in the runtime context.
-
-  return thd->sp_runtime_ctx->push_cursor(this);
-}
-
-
-bool sp_instr_cpush::exec_core(THD *thd, uint *nextp)
-{
-  sp_cursor *c= thd->sp_runtime_ctx->get_cursor(m_cursor_idx);
-
-  // sp_instr_cpush::exec_core() opens the cursor (it's called from
-  // sp_instr_copen::execute().
-
-  return c ? c->open(thd) : true;
-}
-
-
-void sp_instr_cpush::print(String *str)
-{
-  const LEX_STRING *cursor_name= m_parsing_ctx->find_cursor(m_cursor_idx);
-
-  uint rsrv= SP_INSTR_UINT_MAXLEN + 7 + m_cursor_query.length + 1;
-
-  if (cursor_name)
-    rsrv+= cursor_name->length;
-  if (str->reserve(rsrv))
-    return;
-  str->qs_append(STRING_WITH_LEN("cpush "));
-  if (cursor_name)
-  {
-    str->qs_append(cursor_name->str, cursor_name->length);
-    str->qs_append('@');
-  }
-  str->qs_append(m_cursor_idx);
-
-  str->qs_append(':');
-  str->qs_append(m_cursor_query.str, m_cursor_query.length);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_cpop implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_cpop::execute(THD *thd, uint *nextp)
-{
-  thd->sp_runtime_ctx->pop_cursors(m_count);
-  *nextp= get_ip() + 1;
-
-  return false;
-}
-
-
-void sp_instr_cpop::print(String *str)
-{
-  /* cpop count */
-  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
-    return;
-  str->qs_append(STRING_WITH_LEN("cpop "));
-  str->qs_append(m_count);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_copen implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_copen::execute(THD *thd, uint *nextp)
-{
-  *nextp= get_ip() + 1;
-
-  // Get the cursor pointer.
-
-  sp_cursor *c= thd->sp_runtime_ctx->get_cursor(m_cursor_idx);
-
-  if (!c)
-    return true;
-
-  // Retrieve sp_instr_cpush instance.
-
-  sp_instr_cpush *push_instr= c->get_push_instr();
-
-  // Switch Statement Arena to the sp_instr_cpush object. It contains the
-  // free_list of the query, so new items (if any) are stored in the right
-  // free_list, and we can cleanup after each open.
-
-  Query_arena *stmt_arena_saved= thd->stmt_arena;
-  thd->stmt_arena= push_instr;
-
-  // Switch to the cursor's lex and execute sp_instr_cpush::exec_core().
-  // sp_instr_cpush::exec_core() is *not* executed during
-  // sp_instr_cpush::execute(). sp_instr_cpush::exec_core() is intended to be
-  // executed on cursor opening.
-
-  bool rc= push_instr->validate_lex_and_execute_core(thd, nextp, false);
-
-  // Cleanup the query's items.
-
-  if (push_instr->free_list)
-    cleanup_items(push_instr->free_list);
-
-  // Restore Statement Arena.
-
-  thd->stmt_arena= stmt_arena_saved;
-
-  return rc;
-}
-
-
-void sp_instr_copen::print(String *str)
-{
-  const LEX_STRING *cursor_name= m_parsing_ctx->find_cursor(m_cursor_idx);
-
-  /* copen name@offset */
-  uint rsrv= SP_INSTR_UINT_MAXLEN+7;
-
-  if (cursor_name)
-    rsrv+= cursor_name->length;
-  if (str->reserve(rsrv))
-    return;
-  str->qs_append(STRING_WITH_LEN("copen "));
-  if (cursor_name)
-  {
-    str->qs_append(cursor_name->str, cursor_name->length);
-    str->qs_append('@');
-  }
-  str->qs_append(m_cursor_idx);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_cclose implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_cclose::execute(THD *thd, uint *nextp)
-{
-  *nextp= get_ip() + 1;
-
-  sp_cursor *c= thd->sp_runtime_ctx->get_cursor(m_cursor_idx);
-
-  return c ? c->close(thd) : true;
-}
-
-
-void sp_instr_cclose::print(String *str)
-{
-  const LEX_STRING *cursor_name= m_parsing_ctx->find_cursor(m_cursor_idx);
-
-  /* cclose name@offset */
-  uint rsrv= SP_INSTR_UINT_MAXLEN+8;
-
-  if (cursor_name)
-    rsrv+= cursor_name->length;
-  if (str->reserve(rsrv))
-    return;
-  str->qs_append(STRING_WITH_LEN("cclose "));
-  if (cursor_name)
-  {
-    str->qs_append(cursor_name->str, cursor_name->length);
-    str->qs_append('@');
-  }
-  str->qs_append(m_cursor_idx);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_cfetch implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_cfetch::execute(THD *thd, uint *nextp)
-{
-  *nextp= get_ip() + 1;
-
-  sp_cursor *c= thd->sp_runtime_ctx->get_cursor(m_cursor_idx);
-
-  return c ? c->fetch(thd, &m_varlist) : true;
-}
-
-
-void sp_instr_cfetch::print(String *str)
-{
-  List_iterator_fast<sp_variable> li(m_varlist);
-  sp_variable *pv;
-  const LEX_STRING *cursor_name= m_parsing_ctx->find_cursor(m_cursor_idx);
-
-  /* cfetch name@offset vars... */
-  uint rsrv= SP_INSTR_UINT_MAXLEN+8;
-
-  if (cursor_name)
-    rsrv+= cursor_name->length;
-  if (str->reserve(rsrv))
-    return;
-  str->qs_append(STRING_WITH_LEN("cfetch "));
-  if (cursor_name)
-  {
-    str->qs_append(cursor_name->str, cursor_name->length);
-    str->qs_append('@');
-  }
-  str->qs_append(m_cursor_idx);
-  while ((pv= li++))
-  {
-    if (str->reserve(pv->name.length+SP_INSTR_UINT_MAXLEN+2))
-      return;
-    str->qs_append(' ');
-    str->qs_append(pv->name.str, pv->name.length);
-    str->qs_append('@');
-    str->qs_append(pv->offset);
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_error implementation.
-///////////////////////////////////////////////////////////////////////////
-
-void sp_instr_error::print(String *str)
-{
-  /* error code */
-  if (str->reserve(SP_INSTR_UINT_MAXLEN+6))
-    return;
-  str->qs_append(STRING_WITH_LEN("error "));
-  str->qs_append(m_errcode);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// sp_instr_set_case_expr implementation.
-///////////////////////////////////////////////////////////////////////////
-
-bool sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
-{
-  *nextp= get_ip() + 1;
-
-  sp_rcontext *rctx= thd->sp_runtime_ctx;
-
-  if (rctx->set_case_expr(thd, m_case_expr_id, &m_expr_item) &&
-      !rctx->get_case_expr(m_case_expr_id))
-  {
-    // Failed to evaluate the value, the case expression is still not
-    // initialized. Set to NULL so we can continue.
-
-    Item *null_item= new Item_null();
-
-    if (!null_item || rctx->set_case_expr(thd, m_case_expr_id, &null_item))
-    {
-      // If this also failed, we have to abort.
-      my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
-    }
-
-    return true;
-  }
-
-  return false;
-}
-
-
-void sp_instr_set_case_expr::print(String *str)
-{
-  /* set_case_expr (cont) id ... */
-  str->reserve(2*SP_INSTR_UINT_MAXLEN+18+32); // Add some extra for expr too
-  str->qs_append(STRING_WITH_LEN("set_case_expr ("));
-  str->qs_append(m_cont_dest);
-  str->qs_append(STRING_WITH_LEN(") "));
-  str->qs_append(m_case_expr_id);
-  str->qs_append(' ');
-  m_expr_item->print(str, QT_ORDINARY);
-}
-
-uint sp_instr_set_case_expr::opt_mark(sp_head *sp, List<sp_instr> *leads)
-{
-  m_marked= true;
-
-  sp_instr *i= sp->get_instr(m_cont_dest);
-
-  if (i)
-  {
-    m_cont_dest= i->opt_shortcut_jump(sp, this);
-    m_cont_optdest= sp->get_instr(m_cont_dest);
-  }
-
-  sp->add_mark_lead(m_cont_dest, leads);
-  return get_ip() + 1;
-}
-
-void sp_instr_set_case_expr::opt_move(uint dst, List<sp_branch_instr> *bp)
-{
-  if (m_cont_dest > get_ip())
-    bp->push_back(this);        // Forward
-  else if (m_cont_optdest)
-    m_cont_dest= m_cont_optdest->get_ip(); // Backward
-  m_ip= dst;
-}

=== modified file 'sql/sp_head.h'
--- a/sql/sp_head.h	2012-05-16 12:36:41 +0000
+++ b/sql/sp_head.h	2012-05-16 13:58:54 +0000
@@ -26,8 +26,6 @@
 #include "set_var.h"                            // Item
 #include "sp_pcontext.h"                        // sp_pcontext
 
-#include <stddef.h>
-
 /**
   @defgroup Stored_Routines Stored Routines
   @ingroup Runtime_Environment
@@ -41,6 +39,21 @@ class sp_lex_branch_instr;
 ///////////////////////////////////////////////////////////////////////////
 
 /**
+  sp_printable defines an interface which should be implemented if a class wants
+  report some internal information about its state.
+*/
+class sp_printable
+{
+public:
+  virtual void print(String *str) = 0;
+
+  virtual ~sp_printable()
+  { }
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
   Stored_program_creation_ctx -- base class for creation context of stored
   programs (stored routines, triggers, events).
 */
@@ -998,1404 +1011,6 @@ private:
 };
 
 ///////////////////////////////////////////////////////////////////////////
-//
-// "Instructions"...
-//
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_printable defines an interface which should be implemented if a class wants
-  report some internal information about its state.
-*/
-class sp_printable
-{
-public:
-  virtual void print(String *str) = 0;
-
-  virtual ~sp_printable()
-  { }
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  An interface for all SP-instructions with destinations that
-  need to be updated by the SP-optimizer.
-*/
-class sp_branch_instr
-{
-public:
-  /**
-    Update the destination; used by the SP-instruction-optimizer.
-
-    @param old_dest current (old) destination (instruction pointer).
-    @param new_dest new destination (instruction pointer).
-  */
-  virtual void set_destination(uint old_dest, uint new_dest) = 0;
-
-  /**
-    Update all instruction with the given label in the backpatch list to
-    the specified instruction pointer.
-
-    @param dest     destination instruction pointer.
-  */
-  virtual void backpatch(uint dest) = 0;
-
-  virtual ~sp_branch_instr()
-  { }
-};
-
-/**
-  Base class for every SP-instruction. sp_instr defines interface and provides
-  base implementation.
-*/
-class sp_instr : public Query_arena,
-                 public Sql_alloc,
-                 public sp_printable
-{
-public:
-  sp_instr(uint ip, sp_pcontext *ctx)
-   :Query_arena(0, STMT_INITIALIZED_FOR_SP),
-    m_marked(false),
-    m_ip(ip),
-    m_parsing_ctx(ctx)
-  { }
-
-  virtual ~sp_instr()
-  { free_items(); }
-
-  /**
-    Execute this instruction
-
-    @param thd         Thread context
-    @param[out] nextp  index of the next instruction to execute. (For most
-                       instructions this will be the instruction following this
-                       one). Note that this parameter is undefined in case of
-                       errors, use get_cont_dest() to find the continuation
-                       instruction for CONTINUE error handlers.
-
-    @return Error status.
-  */
-  virtual bool execute(THD *thd, uint *nextp) = 0;
-
-  uint get_ip() const
-  { return m_ip; }
-
-  /**
-    Get the continuation destination (instruction pointer for the CONTINUE
-    HANDLER) of this instruction.
-    @return the continuation destination
-  */
-  virtual uint get_cont_dest() const
-  { return get_ip() + 1; }
-
-  sp_pcontext *get_parsing_ctx() const
-  { return m_parsing_ctx; }
-
-  ///////////////////////////////////////////////////////////////////////////
-  // The following operations are used solely for SP-code-optimizer.
-  ///////////////////////////////////////////////////////////////////////////
-
-  /**
-    Mark this instruction as reachable during optimization and return the
-    index to the next instruction. Jump instruction will add their
-    destination to the leads list.
-  */
-  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
-  {
-    m_marked= true;
-    return get_ip() + 1;
-  }
-
-  /**
-    Short-cut jumps to jumps during optimization. This is used by the
-    jump instructions' opt_mark() methods. 'start' is the starting point,
-    used to prevent the mark sweep from looping for ever. Return the
-    end destination.
-  */
-  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
-  { return get_ip(); }
-
-  /**
-    Inform the instruction that it has been moved during optimization.
-    Most instructions will simply update its index, but jump instructions
-    must also take care of their destination pointers. Forward jumps get
-    pushed to the backpatch list 'ibp'.
-  */
-  virtual void opt_move(uint dst, List<sp_branch_instr> *ibp)
-  { m_ip= dst; }
-
-  bool opt_is_marked() const
-  { return m_marked; }
-
-protected:
-  /// Show if this instruction is reachable within the SP
-  /// (used by SP-optimizer).
-  bool m_marked;
-
-  /// Instruction pointer.
-  uint m_ip;
-
-  /// Instruction parsing context.
-  sp_pcontext *m_parsing_ctx;
-
-private:
-  // Prevent use of copy constructor and assignment operator.
-  sp_instr(const sp_instr &);
-  void operator= (sp_instr &);
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_lex_instr is a class providing the interface and base implementation
-  for SP-instructions, whose execution is based on expression evaluation.
-
-  sp_lex_instr keeps LEX-object to be able to evaluate the expression.
-
-  sp_lex_instr also provides possibility to re-parse the original query
-  string if for some reason the LEX-object is not valid any longer.
-*/
-class sp_lex_instr : public sp_instr
-{
-public:
-  sp_lex_instr(uint ip, sp_pcontext *ctx, LEX *lex, bool is_lex_owner)
-   :sp_instr(ip, ctx),
-    m_lex(NULL),
-    m_is_lex_owner(false),
-    m_first_execution(true),
-    m_prelocking_tables(NULL),
-    m_lex_query_tables_own_last(NULL)
-  {
-    set_lex(lex, is_lex_owner);
-  }
-
-  virtual ~sp_lex_instr()
-  { free_lex(); }
-
-  /**
-    Make a few attempts to execute the instruction.
-
-    Basically, this operation does the following things:
-      - install Reprepare_observer to catch metadata changes (if any);
-      - calls reset_lex_and_exec_core() to execute the instruction;
-      - if the execution fails due to a change in metadata, re-parse the
-        instruction's SQL-statement and repeat execution.
-
-    @param      thd           Thread context.
-    @param[out] nextp         Next instruction pointer
-    @param      open_tables   Flag to specify if the function should check read
-                              access to tables in LEX's table list and open and
-                              lock them (used in instructions which need to
-                              calculate some expression and don't execute
-                              complete statement).
-
-    @return Error status.
-  */
-  bool validate_lex_and_execute_core(THD *thd, uint *nextp, bool open_tables);
-
-private:
-  /**
-    Prepare LEX and thread for execution of instruction, if requested open
-    and lock LEX's tables, execute instruction's core function, perform
-    cleanup afterwards.
-
-    @param thd           thread context
-    @param nextp[out]    next instruction pointer
-    @param open_tables   if TRUE then check read access to tables in LEX's table
-                         list and open and lock them (used in instructions which
-                         need to calculate some expression and don't execute
-                         complete statement).
-
-    @note
-      We are not saving/restoring some parts of THD which may need this because
-      we do this once for whole routine execution in sp_head::execute().
-
-    @return Error status.
-  */
-  bool reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables);
-
-  /**
-    (Re-)parse the query corresponding to this instruction and return a new
-    LEX-object.
-
-    @param thd  Thread context.
-    @param sp   The stored program.
-
-    @return new LEX-object or NULL in case of failure.
-  */
-  LEX *parse_expr(THD *thd, sp_head *sp);
-
-  /**
-     Set LEX-object.
-
-     Previously assigned LEX-object (if any) will be properly cleaned up
-     and destroyed.
-
-     @param lex          LEX-object to be used by this instance of sp_lex_instr.
-     @param is_lex_owner the flag specifying if this instance sp_lex_instr
-                         owns (and thus deletes when needed) passed LEX-object.
-  */
-  void set_lex(LEX *lex, bool is_lex_owner);
-
-  /**
-     Cleanup and destroy assigned LEX-object if needed.
-  */
-  void free_lex();
-
-public:
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp)
-  { return validate_lex_and_execute_core(thd, nextp, true); }
-
-protected:
-  /////////////////////////////////////////////////////////////////////////
-  // Interface (virtual) methods.
-  /////////////////////////////////////////////////////////////////////////
-
-  /**
-    Execute core function of instruction after all preparations
-    (e.g. setting of proper LEX, saving part of the thread context).
-
-    @param thd  Thread context.
-    @param nextp[out]    next instruction pointer
-
-    @return Error flag.
-  */
-  virtual bool exec_core(THD *thd, uint *nextp) = 0;
-
-  /**
-    @retval false if the object (i.e. LEX-object) is valid and exec_core() can be
-    just called.
-
-    @retval true if the object is not valid any longer, exec_core() can not be
-    called. The original query string should be re-parsed and a new LEX-object
-    should be used.
-  */
-  virtual bool is_invalid() const = 0;
-
-  /**
-    Invalidate the object.
-  */
-  virtual void invalidate() = 0;
-
-  /**
-    Return the query string, which can be passed to the parser. I.e. the
-    operation should return a valid SQL-statement query string.
-
-    @param[out] sql_query SQL-statement query string.
-  */
-  virtual void get_query(String *sql_query) const;
-
-  /**
-    @return the expression query string. This string can not be passed directly
-    to the parser as it is most likely not a valid SQL-statement.
-
-    @note as it can be seen in the get_query() implementation, get_expr_query()
-    might return EMPTY_STR. EMPTY_STR means that no query-expression is
-    available. That happens when class provides different implementation of
-    get_query(). Strictly speaking, this is a drawback of the current class
-    hierarchy.
-  */
-  virtual LEX_STRING get_expr_query() const
-  { return EMPTY_STR; }
-
-  /**
-    Callback function which is called after the statement query string is
-    successfully parsed, and the thread context has not been switched to the
-    outer context. The thread context contains new LEX-object corresponding to
-    the parsed query string.
-
-    @param thd  Thread context.
-
-    @return Error flag.
-  */
-  virtual bool on_after_expr_parsing(THD *thd)
-  { return false; }
-
-  /**
-    Destroy items in the free list before re-parsing the statement query
-    string (and thus, creating new items).
-
-    @param thd  Thread context.
-  */
-  virtual void cleanup_before_parsing(THD *thd);
-
-private:
-  /// LEX-object.
-  LEX *m_lex;
-
-  /**
-    Indicates whether this sp_lex_instr instance is responsible for
-    LEX-object deletion.
-  */
-  bool m_is_lex_owner;
-
-  /**
-    Indicates whether exec_core() has not been already called on the current
-    LEX-object.
-  */
-  bool m_first_execution;
-
-  /*****************************************************************************
-    Support for being able to execute this statement in two modes:
-    a) inside prelocked mode set by the calling procedure or its ancestor.
-    b) outside of prelocked mode, when this statement enters/leaves
-       prelocked mode itself.
-  *****************************************************************************/
-
-  /**
-    List of additional tables this statement needs to lock when it
-    enters/leaves prelocked mode on its own.
-  */
-  TABLE_LIST *m_prelocking_tables;
-
-  /**
-    The value m_lex->query_tables_own_last should be set to this when the
-    statement enters/leaves prelocked mode on its own.
-  */
-  TABLE_LIST **m_lex_query_tables_own_last;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_instr_stmt represents almost all conventional SQL-statements, which are
-  supported outside stored programs.
-
-  SET-statements, which deal with SP-variable or NEW/OLD trigger pseudo-rows are
-  not represented by this instruction.
-*/
-class sp_instr_stmt : public sp_lex_instr
-{
-public:
-  sp_instr_stmt(uint ip,
-                LEX *lex,
-                LEX_STRING query)
-   :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true),
-    m_query(query),
-    m_valid(true)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_lex_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool exec_core(THD *thd, uint *nextp);
-
-  virtual bool is_invalid() const
-  { return !m_valid; }
-
-  virtual void invalidate()
-  { m_valid= false; }
-
-  virtual void get_query(String *sql_query) const
-  { sql_query->append(m_query.str, m_query.length); }
-
-private:
-  /// Complete query of the SQL-statement.
-  LEX_STRING m_query;
-
-  /// Specify if the stored LEX-object is up-to-date.
-  bool m_valid;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_instr_set represents SET-statememnts, which deal with SP-variables.
-*/
-class sp_instr_set : public sp_lex_instr
-{
-public:
-  sp_instr_set(uint ip,
-               LEX *lex,
-	       uint offset,
-               Item *value_item,
-               LEX_STRING value_query,
-               bool is_lex_owner)
-   :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, is_lex_owner),
-    m_offset(offset),
-    m_value_item(value_item),
-    m_value_query(value_query)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_lex_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool exec_core(THD *thd, uint *nextp);
-
-  virtual bool is_invalid() const
-  { return m_value_item == NULL; }
-
-  virtual void invalidate()
-  { m_value_item= NULL; }
-
-  virtual bool on_after_expr_parsing(THD *thd)
-  {
-    DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
-
-    m_value_item= thd->lex->select_lex.item_list.head();
-
-    return false;
-  }
-
-  virtual LEX_STRING get_expr_query() const
-  { return m_value_query; }
-
-private:
-  /// Frame offset.
-  uint m_offset;
-
-  /// Value expression item of the SET-statement.
-  Item *m_value_item;
-
-  /// SQL-query corresponding to the value expression.
-  LEX_STRING m_value_query;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_instr_set_trigger_field represents SET-statements, which deal with NEW/OLD
-  trigger pseudo-rows.
-*/
-class sp_instr_set_trigger_field : public sp_lex_instr
-{
-public:
-  sp_instr_set_trigger_field(uint ip,
-                             LEX *lex,
-                             LEX_STRING trigger_field_name,
-                             Item_trigger_field *trigger_field,
-                             Item *value_item,
-                             LEX_STRING value_query)
-   :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true),
-    m_trigger_field_name(trigger_field_name),
-    m_trigger_field(trigger_field),
-    m_value_item(value_item),
-    m_value_query(value_query)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_lex_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool exec_core(THD *thd, uint *nextp);
-
-  virtual bool is_invalid() const
-  { return m_value_item == NULL; }
-
-  virtual void invalidate()
-  { m_value_item= NULL; }
-
-  virtual bool on_after_expr_parsing(THD *thd);
-
-  virtual void cleanup_before_parsing(THD *thd);
-
-  virtual LEX_STRING get_expr_query() const
-  { return m_value_query; }
-
-private:
-  /// Trigger field name ("field_name" of the "NEW.field_name").
-  LEX_STRING m_trigger_field_name;
-
-  /// Item corresponding to the NEW/OLD trigger field.
-  Item_trigger_field *m_trigger_field;
-
-  /// Value expression item of the SET-statement.
-  Item *m_value_item;
-
-  /// SQL-query corresponding to the value expression.
-  LEX_STRING m_value_query;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_instr_freturn represents RETURN statement in stored functions.
-*/
-class sp_instr_freturn : public sp_lex_instr
-{
-public:
-  sp_instr_freturn(uint ip,
-                   LEX *lex,
-		   Item *expr_item,
-                   LEX_STRING expr_query,
-                   enum enum_field_types return_field_type)
-   :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true),
-    m_expr_item(expr_item),
-    m_expr_query(expr_query),
-    m_return_field_type(return_field_type)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
-  {
-    m_marked= true;
-    return UINT_MAX;
-  }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_lex_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool exec_core(THD *thd, uint *nextp);
-
-  virtual bool is_invalid() const
-  { return m_expr_item == NULL; }
-
-  virtual void invalidate()
-  {
-    // it's already deleted.
-    m_expr_item= NULL;
-  }
-
-  virtual bool on_after_expr_parsing(THD *thd)
-  {
-    DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
-
-    m_expr_item= thd->lex->select_lex.item_list.head();
-
-    return false;
-  }
-
-  virtual LEX_STRING get_expr_query() const
-  { return m_expr_query; }
-
-private:
-  /// RETURN-expression item.
-  Item *m_expr_item;
-
-  /// SQL-query corresponding to the RETURN-expression.
-  LEX_STRING m_expr_query;
-
-  /// RETURN-field type code.
-  enum enum_field_types m_return_field_type;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  This is base class for all kinds of jump instructions.
-
-  @note this is the only class, we directly construct instances of, that has
-  subclasses. We also redefine sp_instr_jump behavior in those subclasses.
-
-  @todo later we will consider introducing a new class, which will be the base
-  for sp_instr_jump, sp_instr_set_case_expr and sp_instr_jump_case_when.
-  Something like sp_regular_branch_instr (similar to sp_lex_branch_instr).
-*/
-class sp_instr_jump : public sp_instr,
-                      public sp_branch_instr
-{
-public:
-  sp_instr_jump(uint ip, sp_pcontext *ctx)
-   :sp_instr(ip, ctx),
-    m_dest(0),
-    m_optdest(NULL)
-  { }
-
-  sp_instr_jump(uint ip, sp_pcontext *ctx, uint dest)
-   :sp_instr(ip, ctx),
-    m_dest(dest),
-    m_optdest(NULL)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp)
-  {
-    *nextp= m_dest;
-    return false;
-  }
-
-  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
-
-  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start);
-
-  virtual void opt_move(uint dst, List<sp_branch_instr> *ibp);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_branch_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void set_destination(uint old_dest, uint new_dest)
-  {
-    if (m_dest == old_dest)
-      m_dest= new_dest;
-  }
-
-  virtual void backpatch(uint dest)
-  {
-    /* Calling backpatch twice is a logic flaw in jump resolution. */
-    DBUG_ASSERT(m_dest == 0);
-    m_dest= dest;
-  }
-
-protected:
-  /// Where we will go.
-  uint m_dest;
-
-  // The following attribute is used by SP-optimizer.
-  sp_instr *m_optdest;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_lex_branch_instr is a base class for SP-instructions, which might perform
-  conditional jump depending on the value of an SQL-expression.
-*/
-class sp_lex_branch_instr : public sp_lex_instr,
-                            public sp_branch_instr
-{
-protected:
-  sp_lex_branch_instr(uint ip, sp_pcontext *ctx, LEX *lex,
-                      Item *expr_item, LEX_STRING expr_query)
-   :sp_lex_instr(ip, ctx, lex, true),
-    m_dest(0),
-    m_cont_dest(0),
-    m_optdest(NULL),
-    m_cont_optdest(NULL),
-    m_expr_item(expr_item),
-    m_expr_query(expr_query)
-  { }
-
-  sp_lex_branch_instr(uint ip, sp_pcontext *ctx, LEX *lex,
-                      Item *expr_item, LEX_STRING expr_query,
-                      uint dest)
-   :sp_lex_instr(ip, ctx, lex, true),
-    m_dest(dest),
-    m_cont_dest(0),
-    m_optdest(NULL),
-    m_cont_optdest(NULL),
-    m_expr_item(expr_item),
-    m_expr_query(expr_query)
-  { }
-
-public:
-  void set_cont_dest(uint cont_dest)
-  { m_cont_dest= cont_dest; }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
-
-  virtual void opt_move(uint dst, List<sp_branch_instr> *ibp);
-
-  virtual uint get_cont_dest() const
-  { return m_cont_dest; }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_lex_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool is_invalid() const
-  { return m_expr_item == NULL; }
-
-  virtual void invalidate()
-  { m_expr_item= NULL; /* it's already deleted. */ }
-
-  virtual LEX_STRING get_expr_query() const
-  { return m_expr_query; }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_branch_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void set_destination(uint old_dest, uint new_dest)
-  {
-    if (m_dest == old_dest)
-      m_dest= new_dest;
-
-    if (m_cont_dest == old_dest)
-      m_cont_dest= new_dest;
-  }
-
-  virtual void backpatch(uint dest)
-  {
-    /* Calling backpatch twice is a logic flaw in jump resolution. */
-    DBUG_ASSERT(m_dest == 0);
-    m_dest= dest;
-  }
-
-protected:
-  /// Where we will go.
-  uint m_dest;
-
-  /// Where continue handlers will go.
-  uint m_cont_dest;
-
-  // The following attributes are used by SP-optimizer.
-  sp_instr *m_optdest;
-  sp_instr *m_cont_optdest;
-
-  /// Expression item.
-  Item *m_expr_item;
-
-  /// SQL-query corresponding to the expression.
-  LEX_STRING m_expr_query;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_instr_jump_if_not implements SP-instruction, which does the jump if its
-  SQL-expression is false.
-*/
-class sp_instr_jump_if_not : public sp_lex_branch_instr
-{
-public:
-  sp_instr_jump_if_not(uint ip,
-                       LEX *lex,
-                       Item *expr_item,
-                       LEX_STRING expr_query)
-   :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
-                        expr_item, expr_query)
-  { }
-
-  sp_instr_jump_if_not(uint ip,
-                       LEX *lex,
-                       Item *expr_item,
-                       LEX_STRING expr_query,
-                       uint dest)
-   :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
-                        expr_item, expr_query, dest)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_lex_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool exec_core(THD *thd, uint *nextp);
-
-  virtual bool on_after_expr_parsing(THD *thd)
-  {
-    DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
-
-    m_expr_item= thd->lex->select_lex.item_list.head();
-
-    return false;
-  }
-};
-
-///////////////////////////////////////////////////////////////////////////
-// Instructions used for the "simple CASE" implementation.
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_instr_set_case_expr is used in the "simple CASE" implementation to evaluate
-  and store the CASE-expression in the runtime context.
-*/
-class sp_instr_set_case_expr : public sp_lex_branch_instr
-{
-public:
-  sp_instr_set_case_expr(uint ip,
-                         LEX *lex,
-                         uint case_expr_id,
-                         Item *case_expr_item,
-                         LEX_STRING case_expr_query)
-   :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
-                        case_expr_item, case_expr_query),
-    m_case_expr_id(case_expr_id)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
-
-  virtual void opt_move(uint dst, List<sp_branch_instr> *ibp);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_branch_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  /*
-    NOTE: set_destination() and backpatch() are overriden here just because the
-    m_dest attribute is not used by this class, so there is no need to do
-    anything about it.
-
-    @todo These operations probably should be left as they are (i.e. do not
-    override them here). The m_dest attribute would be set and not used, but
-    that should not be a big deal.
-
-    @todo This also indicates deficiency of the current SP-istruction class
-    hierarchy.
-  */
-
-  virtual void set_destination(uint old_dest, uint new_dest)
-  {
-    if (m_cont_dest == old_dest)
-      m_cont_dest= new_dest;
-  }
-
-  virtual void backpatch(uint dest)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_lex_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool exec_core(THD *thd, uint *nextp);
-
-  virtual bool on_after_expr_parsing(THD *thd)
-  {
-    DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
-
-    m_expr_item= thd->lex->select_lex.item_list.head();
-
-    return false;
-  }
-
-private:
-  /// Identifier (index) of the CASE-expression in the runtime context.
-  uint m_case_expr_id;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_instr_jump_case_when instruction is used in the "simple CASE"
-  implementation. It's a jump instruction with the following condition:
-    (CASE-expression = WHEN-expression)
-  CASE-expression is retrieved from sp_rcontext;
-  WHEN-expression is kept by this instruction.
-*/
-class sp_instr_jump_case_when : public sp_lex_branch_instr
-{
-public:
-  sp_instr_jump_case_when(uint ip,
-                          LEX *lex,
-                          int case_expr_id,
-                          Item *when_expr_item,
-                          LEX_STRING when_expr_query)
-   :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
-                        when_expr_item, when_expr_query),
-    m_case_expr_id(case_expr_id)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_lex_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool exec_core(THD *thd, uint *nextp);
-
-  virtual void invalidate()
-  {
-    // Items should be already deleted in lex-keeper.
-    m_case_expr_item= NULL;
-    m_eq_item= NULL;
-    m_expr_item= NULL; // it's a WHEN-expression.
-  }
-
-  virtual bool on_after_expr_parsing(THD *thd)
-  { return build_expr_items(thd); }
-
-private:
-  /**
-    Build CASE-expression item tree:
-      Item_func_eq(case-expression, when-i-expression)
-
-    This function is used for the following form of CASE statement:
-      CASE case-expression
-        WHEN when-1-expression THEN ...
-        WHEN when-2-expression THEN ...
-        ...
-        WHEN when-n-expression THEN ...
-      END CASE
-
-    The thing is that after the parsing we have an item (item tree) for the
-    case-expression and for each when-expression. Here we build jump
-    conditions: expressions like (case-expression = when-i-expression).
-
-    @param thd  Thread context.
-
-    @return Error flag.
-  */
-  bool build_expr_items(THD *thd);
-
-private:
-  /// Identifier (index) of the CASE-expression in the runtime context.
-  int m_case_expr_id;
-
-  /// Item representing the CASE-expression.
-  Item_case_expr *m_case_expr_item;
-
-  /**
-    Item corresponding to the main item of the jump-condition-expression:
-    it's the equal function (=) in the (case-expression = when-i-expression)
-    expression.
-  */
-  Item *m_eq_item;
-};
-
-///////////////////////////////////////////////////////////////////////////
-// SQL-condition handler instructions.
-///////////////////////////////////////////////////////////////////////////
-
-class sp_instr_hpush_jump : public sp_instr_jump
-{
-public:
-  sp_instr_hpush_jump(uint ip,
-                      sp_pcontext *ctx,
-                      sp_handler *handler)
-   :sp_instr_jump(ip, ctx),
-    m_handler(handler),
-    m_opt_hpop(0),
-    m_frame(ctx->current_var_count())
-  {
-    DBUG_ASSERT(m_handler->condition_values.elements == 0);
-  }
-
-  virtual ~sp_instr_hpush_jump()
-  {
-    m_handler->condition_values.empty();
-    m_handler= NULL;
-  }
-
-  void add_condition(sp_condition_value *condition_value)
-  { m_handler->condition_values.push_back(condition_value); }
-
-  sp_handler *get_handler()
-  { return m_handler; }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp);
-
-  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
-
-  /** Override sp_instr_jump's shortcut; we stop here. */
-  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
-  { return get_ip(); }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_branch_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void backpatch(uint dest)
-  {
-    DBUG_ASSERT(!m_dest || !m_opt_hpop);
-    if (!m_dest)
-      m_dest= dest;
-    else
-      m_opt_hpop= dest;
-  }
-
-private:
-  /// Handler.
-  sp_handler *m_handler;
-
-  /// hpop marking end of handler scope.
-  uint m_opt_hpop;
-
-  // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in
-  // debug version only). It's used in print().
-  uint m_frame;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-class sp_instr_hpop : public sp_instr
-{
-public:
-  sp_instr_hpop(uint ip, sp_pcontext *ctx, uint count)
-    : sp_instr(ip, ctx), m_count(count)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp);
-
-private:
-  /// How many handlers this instruction should pop.
-  uint m_count;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-class sp_instr_hreturn : public sp_instr_jump
-{
-public:
-  sp_instr_hreturn(uint ip, sp_pcontext *ctx)
-   :sp_instr_jump(ip, ctx),
-    m_frame(ctx->current_var_count())
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp);
-
-  /** Override sp_instr_jump's shortcut; we stop here. */
-  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
-  { return get_ip(); }
-
-  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
-
-private:
-  // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in
-  // debug version only). It's used in print().
-  uint m_frame;
-};
-
-///////////////////////////////////////////////////////////////////////////
-// Cursor implementation.
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_instr_cpush corresponds to DECLARE CURSOR, implements DECLARE CURSOR and
-  OPEN.
-
-  This is the most important instruction in cursor implementation. It is created
-  and added to sp_head when DECLARE CURSOR is being parsed. The arena of this
-  instruction contains LEX-object for the cursor's SELECT-statement.
-
-  This instruction is actually used to open the cursor.
-
-  execute() operation "implements" DECLARE CURSOR statement -- it merely pushes
-  a new cursor object into the stack in sp_rcontext object.
-
-  exec_core() operation implements OPEN statement. It is important to implement
-  OPEN statement in this instruction, because OPEN may lead to re-parsing of the
-  SELECT-statement. So, the original Arena and parsing context must be used.
-*/
-class sp_instr_cpush : public sp_lex_instr
-{
-public:
-  sp_instr_cpush(uint ip,
-                 sp_pcontext *ctx,
-                 LEX *cursor_lex,
-                 LEX_STRING cursor_query,
-                 int cursor_idx)
-   :sp_lex_instr(ip, ctx, cursor_lex, true),
-    m_cursor_query(cursor_query),
-    m_valid(true),
-    m_cursor_idx(cursor_idx)
-  {
-    // Cursor can't be stored in Query Cache, so we should prevent opening QC
-    // for try to write results which are absent.
-
-    cursor_lex->safe_to_cache_query= false;
-  }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // Query_arena implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  /**
-    This call is used to cleanup the instruction when a sensitive
-    cursor is closed. For now stored procedures always use materialized
-    cursors and the call is not used.
-  */
-  virtual void cleanup_stmt()
-  { /* no op */ }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_lex_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool exec_core(THD *thd, uint *nextp);
-
-  virtual bool is_invalid() const
-  { return !m_valid; }
-
-  virtual void invalidate()
-  { m_valid= false; }
-
-  virtual void get_query(String *sql_query) const
-  { sql_query->append(m_cursor_query.str, m_cursor_query.length); }
-
-private:
-  /// This attribute keeps the cursor SELECT statement.
-  LEX_STRING m_cursor_query;
-
-  /// Flag if the LEX-object of this instruction is valid or not.
-  /// The LEX-object is not valid when metadata have changed.
-  bool m_valid;
-
-  /// Used to identify the cursor in the sp_rcontext.
-  int m_cursor_idx;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_instr_cpop instruction is added at the end of BEGIN..END block.
-  It's used to remove declared cursors so that they are not visible any longer.
-*/
-class sp_instr_cpop : public sp_instr
-{
-public:
-  sp_instr_cpop(uint ip, sp_pcontext *ctx, uint count)
-   :sp_instr(ip, ctx),
-    m_count(count)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp);
-
-private:
-  uint m_count;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_instr_copen represents OPEN statement (opens the cursor).
-  However, the actual implementation is in sp_instr_cpush::exec_core().
-*/
-class sp_instr_copen : public sp_instr
-{
-public:
-  sp_instr_copen(uint ip, sp_pcontext *ctx, int cursor_idx)
-   :sp_instr(ip, ctx),
-    m_cursor_idx(cursor_idx)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp);
-
-private:
-  /// Used to identify the cursor in the sp_rcontext.
-  int m_cursor_idx;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  The instruction corresponds to the CLOSE statement.
-  It just forwards the close-call to the appropriate sp_cursor object in the
-  sp_rcontext.
-*/
-class sp_instr_cclose : public sp_instr
-{
-public:
-  sp_instr_cclose(uint ip, sp_pcontext *ctx, int cursor_idx)
-   :sp_instr(ip, ctx),
-    m_cursor_idx(cursor_idx)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp);
-
-private:
-  /// Used to identify the cursor in the sp_rcontext.
-  int m_cursor_idx;
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  The instruction corresponds to the FETCH statement.
-  It just forwards the close-call to the appropriate sp_cursor object in the
-  sp_rcontext.
-*/
-class sp_instr_cfetch : public sp_instr
-{
-public:
-  sp_instr_cfetch(uint ip, sp_pcontext *ctx, int cursor_idx)
-   :sp_instr(ip, ctx),
-    m_cursor_idx(cursor_idx)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp);
-
-  void add_to_varlist(sp_variable *var)
-  { m_varlist.push_back(var); }
-
-private:
-  /// List of SP-variables to store fetched values.
-  List<sp_variable> m_varlist;
-
-  /// Used to identify the cursor in the sp_rcontext.
-  int m_cursor_idx;
-};
-
-///////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////
-
-/**
-  sp_instr_error just throws an SQL-condition if the execution flow comes to it.
-  It's used in the CASE implementation to perform runtime-check that the
-  CASE-expression is handled by some WHEN/ELSE clause.
-*/
-class sp_instr_error : public sp_instr
-{
-public:
-  sp_instr_error(uint ip, sp_pcontext *ctx, int errcode)
-   :sp_instr(ip, ctx),
-    m_errcode(errcode)
-  { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_printable implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual void print(String *str);
-
-  /////////////////////////////////////////////////////////////////////////
-  // sp_instr implementation.
-  /////////////////////////////////////////////////////////////////////////
-
-  virtual bool execute(THD *thd, uint *nextp)
-  {
-    my_message(m_errcode, ER(m_errcode), MYF(0));
-    *nextp= get_ip() + 1;
-    return true;
-  }
-
-  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
-  {
-    m_marked= true;
-    return UINT_MAX;
-  }
-
-private:
-  /// The error code, which should be raised by this instruction.
-  int m_errcode;
-};
-
-///////////////////////////////////////////////////////////////////////////
 
 /**
   @} (end of group Stored_Routines)

=== added file 'sql/sp_instr.cc'
--- a/sql/sp_instr.cc	1970-01-01 00:00:00 +0000
+++ b/sql/sp_instr.cc	2012-05-16 13:58:54 +0000
@@ -0,0 +1,1708 @@
+/* Copyright (c) 2012, 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
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#include "my_global.h"    // NO_EMBEDDED_ACCESS_CHECKS
+#include "sql_priv.h"
+#include "sp_instr.h"
+#include "item.h"         // Item_splocal
+#include "opt_trace.h"    // opt_trace_disable_etc
+#include "probes_mysql.h" // MYSQL_QUERY_EXEC_START
+#include "sp_head.h"      // sp_head
+#include "sp.h"           // sp_get_item_value
+#include "sp_rcontext.h"  // sp_rcontext
+#include "sql_acl.h"      // SELECT_ACL
+#include "sql_base.h"     // open_temporary_tables
+#include "sql_parse.h"    // check_table_access
+#include "sql_prepare.h"  // reinit_stmt_before_use
+#include "transaction.h"  // trans_commit_stmt
+
+#include <algorithm>
+
+///////////////////////////////////////////////////////////////////////////
+// Static function implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+static int cmp_splocal_locations(Item_splocal * const *a,
+                                 Item_splocal * const *b)
+{
+  return (int)((*a)->pos_in_query - (*b)->pos_in_query);
+}
+
+
+/*
+  StoredRoutinesBinlogging
+  This paragraph applies only to statement-based binlogging. Row-based
+  binlogging does not need anything special like this.
+
+  Top-down overview:
+
+  1. Statements
+
+  Statements that have is_update_query(stmt) == TRUE are written into the
+  binary log verbatim.
+  Examples:
+    UPDATE tbl SET tbl.x = spfunc_w_side_effects()
+    UPDATE tbl SET tbl.x=1 WHERE spfunc_w_side_effect_that_returns_false(tbl.y)
+
+  Statements that have is_update_query(stmt) == FALSE (e.g. SELECTs) are not
+  written into binary log. Instead we catch function calls the statement
+  makes and write it into binary log separately (see #3).
+
+  2. PROCEDURE calls
+
+  CALL statements are not written into binary log. Instead
+  * Any FUNCTION invocation (in SET, IF, WHILE, OPEN CURSOR and other SP
+    instructions) is written into binlog separately.
+
+  * Each statement executed in SP is binlogged separately, according to rules
+    in #1, with the exception that we modify query string: we replace uses
+    of SP local variables with NAME_CONST('spvar_name', <spvar-value>) calls.
+    This substitution is done in subst_spvars().
+
+  3. FUNCTION calls
+
+  In sp_head::execute_function(), we check
+   * If this function invocation is done from a statement that is written
+     into the binary log.
+   * If there were any attempts to write events to the binary log during
+     function execution (grep for start_union_events and stop_union_events)
+
+   If the answers are No and Yes, we write the function call into the binary
+   log as "SELECT spfunc(<param1value>, <param2value>, ...)"
+
+
+  4. Miscellaneous issues.
+
+  4.1 User variables.
+
+  When we call mysql_bin_log.write() for an SP statement, thd->user_var_events
+  must hold set<{var_name, value}> pairs for all user variables used during
+  the statement execution.
+  This set is produced by tracking user variable reads during statement
+  execution.
+
+  For SPs, this has the following implications:
+  1) thd->user_var_events may contain events from several SP statements and
+     needs to be valid after execution of these statements was finished. In
+     order to achieve that, we
+     * Allocate user_var_events array elements on appropriate mem_root (grep
+       for user_var_events_alloc).
+     * Use is_query_in_union() to determine if user_var_event is created.
+
+  2) We need to empty thd->user_var_events after we have wrote a function
+     call. This is currently done by making
+     reset_dynamic(&thd->user_var_events);
+     calls in several different places. (TODO consider moving this into
+     mysql_bin_log.write() function)
+
+  4.2 Auto_increment storage in binlog
+
+  As we may write two statements to binlog from one single logical statement
+  (case of "SELECT func1(),func2()": it is binlogged as "SELECT func1()" and
+  then "SELECT func2()"), we need to reset auto_increment binlog variables
+  after each binlogged SELECT. Otherwise, the auto_increment value of the
+  first SELECT would be used for the second too.
+*/
+
+/**
+  Replace thd->query{_length} with a string that one can write to
+  the binlog.
+
+  The binlog-suitable string is produced by replacing references to SP local
+  variables with NAME_CONST('sp_var_name', value) calls.
+
+  @param thd        Current thread.
+  @param instr      Instruction (we look for Item_splocal instances in
+                    instr->free_list)
+  @param query_str  Original query string
+
+  @retval false on success.
+  thd->query{_length} either has been appropriately replaced or there
+  is no need for replacements.
+
+  @retval true in case of out of memory error.
+*/
+static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
+{
+  Dynamic_array<Item_splocal*> sp_vars_uses;
+  char *pbuf, *cur, buffer[512];
+  String qbuf(buffer, sizeof(buffer), &my_charset_bin);
+  int prev_pos, res, buf_len;
+
+  /* Find all instances of Item_splocal used in this statement */
+  for (Item *item= instr->free_list; item; item= item->next)
+  {
+    if (item->is_splocal())
+    {
+      Item_splocal *item_spl= (Item_splocal*)item;
+      if (item_spl->pos_in_query)
+        sp_vars_uses.append(item_spl);
+    }
+  }
+
+  if (!sp_vars_uses.elements())
+    return false;
+
+  /* Sort SP var refs by their occurrences in the query */
+  sp_vars_uses.sort(cmp_splocal_locations);
+
+  /*
+    Construct a statement string where SP local var refs are replaced
+    with "NAME_CONST(name, value)"
+  */
+  qbuf.length(0);
+  cur= query_str->str;
+  prev_pos= res= 0;
+  thd->query_name_consts= 0;
+
+  for (Item_splocal **splocal= sp_vars_uses.front(); 
+       splocal <= sp_vars_uses.back(); splocal++)
+  {
+    Item *val;
+
+    char str_buffer[STRING_BUFFER_USUAL_SIZE];
+    String str_value_holder(str_buffer, sizeof(str_buffer),
+                            &my_charset_latin1);
+    String *str_value;
+
+    /* append the text between sp ref occurrences */
+    res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos);
+    prev_pos= (*splocal)->pos_in_query + (*splocal)->len_in_query;
+
+    res|= (*splocal)->fix_fields(thd, (Item **) splocal);
+    if (res)
+      break;
+
+    if ((*splocal)->limit_clause_param)
+    {
+      res|= qbuf.append_ulonglong((*splocal)->val_uint());
+      if (res)
+        break;
+      continue;
+    }
+
+    /* append the spvar substitute */
+    res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('"));
+    res|= qbuf.append((*splocal)->m_name);
+    res|= qbuf.append(STRING_WITH_LEN("',"));
+
+    if (res)
+      break;
+
+    val= (*splocal)->this_item();
+    str_value= sp_get_item_value(thd, val, &str_value_holder);
+    if (str_value)
+      res|= qbuf.append(*str_value);
+    else
+      res|= qbuf.append(STRING_WITH_LEN("NULL"));
+    res|= qbuf.append(')');
+    if (res)
+      break;
+
+    thd->query_name_consts++;
+  }
+  if (res ||
+      qbuf.append(cur + prev_pos, query_str->length - prev_pos))
+    return true;
+
+  /*
+    Allocate additional space at the end of the new query string for the
+    query_cache_send_result_to_client function.
+
+    The query buffer layout is:
+       buffer :==
+            <statement>   The input statement(s)
+            '\0'          Terminating null char
+            <length>      Length of following current database name (size_t)
+            <db_name>     Name of current database
+            <flags>       Flags struct
+  */
+  buf_len= qbuf.length() + 1 + sizeof(size_t) + thd->db_length + 
+           QUERY_CACHE_FLAGS_SIZE + 1;
+  if ((pbuf= (char *) alloc_root(thd->mem_root, buf_len)))
+  {
+    memcpy(pbuf, qbuf.ptr(), qbuf.length());
+    pbuf[qbuf.length()]= 0;
+    memcpy(pbuf+qbuf.length()+1, (char *) &thd->db_length, sizeof(size_t));
+  }
+  else
+    return true;
+
+  thd->set_query(pbuf, qbuf.length());
+
+  return false;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Sufficient max length of printed destinations and frame offsets (all uints).
+///////////////////////////////////////////////////////////////////////////
+
+#define SP_INSTR_UINT_MAXLEN  8
+#define SP_STMT_PRINT_MAXLEN 40
+
+///////////////////////////////////////////////////////////////////////////
+// sp_lex_instr implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_lex_instr::reset_lex_and_exec_core(THD *thd,
+                                           uint *nextp,
+                                           bool open_tables)
+{
+  bool rc= false;
+
+  /*
+    The flag is saved at the entry to the following substatement.
+    It's reset further in the common code part.
+    It's merged with the saved parent's value at the exit of this func.
+  */
+
+  unsigned int parent_unsafe_rollback_flags=
+    thd->transaction.stmt.get_unsafe_rollback_flags();
+  thd->transaction.stmt.reset_unsafe_rollback_flags();
+
+  /* Check pre-conditions. */
+
+  DBUG_ASSERT(!thd->derived_tables);
+  DBUG_ASSERT(thd->change_list.is_empty());
+
+  /*
+    Use our own lex.
+
+    Although it is saved/restored in sp_head::execute() when we are
+    entering/leaving routine, it's still should be saved/restored here,
+    in order to properly behave in case of ER_NEED_REPREPARE error
+    (when ER_NEED_REPREPARE happened, and we failed to re-parse the query).
+  */
+
+  LEX *lex_saved= thd->lex;
+  thd->lex= m_lex;
+
+  /* Set new query id. */
+
+  thd->set_query_id(next_query_id());
+
+  if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
+  {
+    /*
+      This statement will enter/leave prelocked mode on its own.
+      Entering prelocked mode changes table list and related members
+      of LEX, so we'll need to restore them.
+    */
+    if (m_lex_query_tables_own_last)
+    {
+      /*
+        We've already entered/left prelocked mode with this statement.
+        Attach the list of tables that need to be prelocked and mark m_lex
+        as having such list attached.
+      */
+      *m_lex_query_tables_own_last= m_prelocking_tables;
+      m_lex->mark_as_requiring_prelocking(m_lex_query_tables_own_last);
+    }
+  }
+
+  /* Reset LEX-object before re-use. */
+
+  reinit_stmt_before_use(thd, m_lex);
+
+  /* Open tables if needed. */
+
+  if (open_tables)
+  {
+    /*
+      IF, CASE, DECLARE, SET, RETURN, have 'open_tables' true; they may
+      have a subquery in parameter and are worth tracing. They don't
+      correspond to a SQL command so we pretend that they are SQLCOM_SELECT.
+    */
+    Opt_trace_start ots(thd, m_lex->query_tables, SQLCOM_SELECT,
+                        &m_lex->var_list, NULL, 0, this,
+                        thd->variables.character_set_client);
+    Opt_trace_object trace_command(&thd->opt_trace);
+    Opt_trace_array trace_command_steps(&thd->opt_trace, "steps");
+
+    /*
+      Check whenever we have access to tables for this statement
+      and open and lock them before executing instructions core function.
+      If we are not opening any tables, we don't need to check permissions
+      either.
+    */
+    if (m_lex->query_tables)
+      rc= (open_temporary_tables(thd, m_lex->query_tables) ||
+            check_table_access(thd, SELECT_ACL, m_lex->query_tables, false,
+                               UINT_MAX, false));
+
+    if (!rc)
+      rc= open_and_lock_tables(thd, m_lex->query_tables, true, 0);
+
+    if (!rc)
+    {
+      rc= exec_core(thd, nextp);
+      DBUG_PRINT("info",("exec_core returned: %d", rc));
+    }
+
+    /*
+      Call after unit->cleanup() to close open table
+      key read.
+    */
+
+    m_lex->unit.cleanup();
+
+    /* Here we also commit or rollback the current statement. */
+
+    if (! thd->in_sub_stmt)
+    {
+      thd->get_stmt_da()->set_overwrite_status(true);
+      thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+      thd->get_stmt_da()->set_overwrite_status(false);
+    }
+    thd_proc_info(thd, "closing tables");
+    close_thread_tables(thd);
+    thd_proc_info(thd, 0);
+
+    if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
+      thd->mdl_context.release_transactional_locks();
+    else if (! thd->in_sub_stmt)
+      thd->mdl_context.release_statement_locks();
+  }
+  else
+  {
+    rc= exec_core(thd, nextp);
+    DBUG_PRINT("info",("exec_core returned: %d", rc));
+  }
+
+  if (m_lex->query_tables_own_last)
+  {
+    /*
+      We've entered and left prelocking mode when executing statement
+      stored in m_lex.
+      m_lex->query_tables(->next_global)* list now has a 'tail' - a list
+      of tables that are added for prelocking. (If this is the first
+      execution, the 'tail' was added by open_tables(), otherwise we've
+      attached it above in this function).
+      Now we'll save the 'tail', and detach it.
+    */
+    m_lex_query_tables_own_last= m_lex->query_tables_own_last;
+    m_prelocking_tables= *m_lex_query_tables_own_last;
+    *m_lex_query_tables_own_last= NULL;
+    m_lex->mark_as_requiring_prelocking(NULL);
+  }
+
+  /* Rollback changes to the item tree during execution. */
+
+  thd->rollback_item_tree_changes();
+
+  /*
+    Update the state of the active arena if no errors on
+    open_tables stage.
+  */
+
+  if (!rc || !thd->is_error() ||
+      (thd->get_stmt_da()->sql_errno() != ER_CANT_REOPEN_TABLE &&
+       thd->get_stmt_da()->sql_errno() != ER_NO_SUCH_TABLE &&
+       thd->get_stmt_da()->sql_errno() != ER_UPDATE_TABLE_USED))
+    thd->stmt_arena->state= Query_arena::STMT_EXECUTED;
+
+  /*
+    Merge here with the saved parent's values
+    what is needed from the substatement gained
+  */
+
+  thd->transaction.stmt.add_unsafe_rollback_flags(parent_unsafe_rollback_flags);
+
+  /* Restore original lex. */
+
+  thd->lex= lex_saved;
+
+  /*
+    Unlike for PS we should not call Item's destructors for newly created
+    items after execution of each instruction in stored routine. This is
+    because SP often create Item (like Item_int, Item_string etc...) when
+    they want to store some value in local variable, pass return value and
+    etc... So their life time should be longer than one instruction.
+
+    cleanup_items() is called in sp_head::execute()
+  */
+
+  return rc || thd->is_error();
+}
+
+
+LEX *sp_lex_instr::parse_expr(THD *thd, sp_head *sp)
+{
+  String sql_query;
+  sql_query.set_charset(system_charset_info);
+
+  get_query(&sql_query);
+
+  if (sql_query.length() == 0)
+  {
+    // The instruction has returned zero-length query string. That means, the
+    // re-preparation of the instruction is not possible. We should not come
+    // here in the normal life.
+    DBUG_ASSERT(false);
+    my_error(ER_UNKNOWN_ERROR, MYF(0));
+    return NULL;
+  }
+
+  // Prepare parser state. It can be done just before parse_sql(), do it here
+  // only to simplify exit in case of failure (out-of-memory error).
+
+  Parser_state parser_state;
+
+  if (parser_state.init(thd, sql_query.c_ptr(), sql_query.length()))
+    return NULL;
+
+  // Cleanup current THD from previously held objects before new parsing.
+
+  cleanup_before_parsing(thd);
+
+  // Switch mem-roots. We need to store new LEX and its Items in the persistent
+  // SP-memory (memory which is not freed between executions).
+
+  MEM_ROOT *execution_mem_root= thd->mem_root;
+
+  thd->mem_root= thd->sp_runtime_ctx->sp->get_persistent_mem_root();
+
+  // Switch THD::free_list. It's used to remember the newly created set of Items
+  // during parsing. We should clean those items after each execution.
+
+  Item *execution_free_list= thd->free_list;
+  thd->free_list= NULL;
+
+  // Create a new LEX and intialize it.
+
+  LEX *lex_saved= thd->lex;
+
+  thd->lex= new (thd->mem_root) st_lex_local;
+  lex_start(thd);
+
+  thd->lex->sphead= sp;
+  thd->lex->set_sp_current_parsing_ctx(get_parsing_ctx());
+  sp->m_parser_data.set_current_stmt_start_ptr(sql_query.c_ptr());
+
+  // Parse the just constructed SELECT-statement.
+
+  bool parsing_failed= parse_sql(thd, &parser_state, NULL);
+
+  if (!parsing_failed)
+  {
+    thd->lex->set_trg_event_type_for_tables();
+
+    if (sp->m_type == SP_TYPE_TRIGGER)
+    {
+      /*
+        Also let us bind these objects to Field objects in table being opened.
+
+        We ignore errors of setup_field() here, because if even something is
+        wrong we still will be willing to open table to perform some operations
+        (e.g.  SELECT)... Anyway some things can be checked only during trigger
+        execution.
+      */
+
+      Table_triggers_list *ttl= sp->m_trg_list;
+      int event= sp->m_trg_chistics.event;
+      int action_time= sp->m_trg_chistics.action_time;
+      GRANT_INFO *grant_table= &ttl->subject_table_grants[event][action_time];
+
+      for (Item_trigger_field *trg_field= sp->m_trg_table_fields.first;
+           trg_field;
+           trg_field= trg_field->next_trg_field)
+      {
+        trg_field->setup_field(thd, ttl->trigger_table, grant_table);
+      }
+    }
+
+    // Call after-parsing callback.
+
+    parsing_failed= on_after_expr_parsing(thd);
+
+    // Append newly created Items to the list of Items, owned by this
+    // instruction.
+
+    free_list= thd->free_list;
+  }
+
+  // Restore THD::lex.
+
+  thd->lex->sphead= NULL;
+  thd->lex->set_sp_current_parsing_ctx(NULL);
+
+  LEX *expr_lex= thd->lex;
+  thd->lex= lex_saved;
+
+  // Restore execution mem-root and THD::free_list.
+
+  thd->mem_root= execution_mem_root;
+  thd->free_list= execution_free_list;
+
+  // That's it.
+
+  return parsing_failed ? NULL : expr_lex;
+}
+
+
+bool sp_lex_instr::validate_lex_and_execute_core(THD *thd,
+                                                 uint *nextp,
+                                                 bool open_tables)
+{
+  Reprepare_observer reprepare_observer;
+  int reprepare_attempt= 0;
+
+  while (true)
+  {
+    if (is_invalid())
+    {
+      LEX *lex= parse_expr(thd, thd->sp_runtime_ctx->sp);
+
+      if (!lex)
+        return true;
+
+      set_lex(lex, true);
+
+      m_first_execution= true;
+    }
+
+    /*
+      Install the metadata observer. If some metadata version is
+      different from prepare time and an observer is installed,
+      the observer method will be invoked to push an error into
+      the error stack.
+    */
+    Reprepare_observer *stmt_reprepare_observer= NULL;
+
+    /*
+      Meta-data versions are stored in the LEX-object on the first execution.
+      Thus, the reprepare observer should not be installed for the first
+      execution, because it will always be triggered.
+
+      Then, the reprepare observer should be installed for the statements, which
+      are marked by CF_REEXECUTION_FRAGILE (@sa CF_REEXECUTION_FRAGILE) or if
+      the SQL-command is SQLCOM_END, which means that the LEX-object is
+      representing an expression, so the exact SQL-command does not matter.
+    */
+
+    if (!m_first_execution &&
+        (sql_command_flags[m_lex->sql_command] & CF_REEXECUTION_FRAGILE ||
+         m_lex->sql_command == SQLCOM_END))
+    {
+      reprepare_observer.reset_reprepare_observer();
+      stmt_reprepare_observer= &reprepare_observer;
+    }
+
+    thd->push_reprepare_observer(stmt_reprepare_observer);
+
+    bool rc= reset_lex_and_exec_core(thd, nextp, open_tables);
+
+    thd->pop_reprepare_observer();
+
+    m_first_execution= false;
+
+    if (!rc)
+      return false;
+
+    /*
+      Here is why we need all the checks below:
+        - if the reprepare observer is not set, we've got an error, which should
+          be raised to the user;
+        - if we've got fatal error, it should be raised to the user;
+        - if our thread got killed during execution, the error should be raised
+          to the user;
+        - if we've got an error, different from ER_NEED_REPREPARE, we need to
+          raise it to the user;
+        - we take only 3 attempts to reprepare the query, otherwise we might end
+          up in the endless loop.
+    */
+    if (stmt_reprepare_observer &&
+        !thd->is_fatal_error &&
+        !thd->killed &&
+        thd->get_stmt_da()->sql_errno() == ER_NEED_REPREPARE &&
+        reprepare_attempt++ < 3)
+    {
+      DBUG_ASSERT(stmt_reprepare_observer->is_invalidated());
+
+      thd->clear_error();
+      free_lex();
+      invalidate();
+    }
+    else
+      return true;
+  }
+}
+
+
+void sp_lex_instr::set_lex(LEX *lex, bool is_lex_owner)
+{
+  free_lex();
+
+  m_lex= lex;
+  m_is_lex_owner= is_lex_owner;
+  m_lex_query_tables_own_last= NULL;
+
+  if (m_lex)
+    m_lex->sp_lex_in_use= true;
+}
+
+
+void sp_lex_instr::free_lex()
+{
+  if (!m_is_lex_owner || !m_lex)
+    return;
+
+  /* Prevent endless recursion. */
+  m_lex->sphead= NULL;
+  lex_end(m_lex);
+  delete (st_lex_local *) m_lex;
+
+  m_lex= NULL;
+  m_is_lex_owner= false;
+  m_lex_query_tables_own_last= NULL;
+}
+
+
+void sp_lex_instr::cleanup_before_parsing(THD *thd)
+{
+  /*
+    Destroy items in the instruction's free list before re-parsing the
+    statement query string (and thus, creating new items).
+  */
+  Item *p= free_list;
+  while (p)
+  {
+    Item *next= p->next;
+    p->delete_self();
+    p= next;
+  }
+
+  free_list= NULL;
+
+  // Remove previously stored trigger-field items.
+  sp_head *sp= thd->sp_runtime_ctx->sp;
+
+  if (sp->m_type == SP_TYPE_TRIGGER)
+    sp->m_trg_table_fields.empty();
+}
+
+
+void sp_lex_instr::get_query(String *sql_query) const
+{
+  LEX_STRING expr_query= this->get_expr_query();
+
+  if (!expr_query.str)
+  {
+    sql_query->length(0);
+    return;
+  }
+
+  sql_query->append("SELECT ");
+  sql_query->append(expr_query.str, expr_query.length);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_stmt implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_stmt::execute(THD *thd, uint *nextp)
+{
+  bool need_subst= false;
+  bool rc= false;
+
+  DBUG_PRINT("info", ("query: '%.*s'", (int) m_query.length, m_query.str));
+
+  const CSET_STRING query_backup= thd->query_string;
+
+#if defined(ENABLED_PROFILING)
+  /* This SP-instr is profilable and will be captured. */
+  thd->profiling.set_query_source(m_query.str, m_query.length);
+#endif
+
+  /*
+    If we can't set thd->query_string at all, we give up on this statement.
+  */
+  if (alloc_query(thd, m_query.str, m_query.length))
+    return true;
+
+  /*
+    Check whether we actually need a substitution of SP variables with
+    NAME_CONST(...) (using subst_spvars()).
+    If both of the following apply, we won't need to substitute:
+
+    - general log is off
+
+    - binary logging is off, or not in statement mode
+
+    We don't have to substitute on behalf of the query cache as
+    queries with SP vars are not cached, anyway.
+
+    query_name_consts is used elsewhere in a special case concerning
+    CREATE TABLE, but we do not need to do anything about that here.
+
+    The slow query log is another special case: we won't know whether a
+    query qualifies for the slow query log until after it's been
+    executed. We assume that most queries are not slow, so we do not
+    pre-emptively substitute just for the slow query log. If a query
+    ends up being slow after all and we haven't done the substitution
+    already for any of the above (general log etc.), we'll do the
+    substitution immediately before writing to the log.
+  */
+
+  need_subst= ((thd->variables.option_bits & OPTION_LOG_OFF) &&
+               (!(thd->variables.option_bits & OPTION_BIN_LOG) ||
+                !mysql_bin_log.is_open() ||
+                thd->is_current_stmt_binlog_format_row())) ? FALSE : TRUE;
+
+  /*
+    If we need to do a substitution but can't (OOM), give up.
+  */
+
+  if (need_subst && subst_spvars(thd, this, &m_query))
+    return true;
+
+  /*
+    (the order of query cache and subst_spvars calls is irrelevant because
+    queries with SP vars can't be cached)
+  */
+  if (unlikely((thd->variables.option_bits & OPTION_LOG_OFF)==0))
+    general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
+
+  if (query_cache_send_result_to_client(thd, thd->query(),
+                                        thd->query_length()) <= 0)
+  {
+    rc= validate_lex_and_execute_core(thd, nextp, false);
+
+    if (thd->get_stmt_da()->is_eof())
+    {
+      /* Finalize server status flags after executing a statement. */
+      thd->update_server_status();
+
+      thd->protocol->end_statement();
+    }
+
+    query_cache_end_of_result(thd);
+
+    if (!rc && unlikely(log_slow_applicable(thd)))
+    {
+      /*
+        We actually need to write the slow log. Check whether we already
+        called subst_spvars() above, otherwise, do it now.  In the highly
+        unlikely event of subst_spvars() failing (OOM), we'll try to log
+        the unmodified statement instead.
+      */
+      if (!need_subst)
+        rc= subst_spvars(thd, this, &m_query);
+      log_slow_do(thd);
+    }
+
+    /*
+      With the current setup, a subst_spvars() and a mysql_rewrite_query()
+      (rewriting passwords etc.) will not both happen to a query.
+      If this ever changes, we give the engineer pause here so they will
+      double-check whether the potential conflict they created is a
+      problem.
+    */
+    DBUG_ASSERT((thd->query_name_consts == 0) ||
+                (thd->rewritten_query.length() == 0));
+  }
+  else
+    *nextp= get_ip() + 1;
+
+  thd->set_query(query_backup);
+  thd->query_name_consts= 0;
+
+  if (!thd->is_error())
+    thd->get_stmt_da()->reset_diagnostics_area();
+
+  return rc || thd->is_error();
+}
+
+
+void sp_instr_stmt::print(String *str)
+{
+  /* stmt CMD "..." */
+  if (str->reserve(SP_STMT_PRINT_MAXLEN + SP_INSTR_UINT_MAXLEN + 8))
+    return;
+  str->qs_append(STRING_WITH_LEN("stmt"));
+  str->qs_append(STRING_WITH_LEN(" \""));
+
+  /*
+    Print the query string (but not too much of it), just to indicate which
+    statement it is.
+  */
+  uint len= m_query.length;
+  if (len > SP_STMT_PRINT_MAXLEN)
+    len= SP_STMT_PRINT_MAXLEN-3;
+
+  /* Copy the query string and replace '\n' with ' ' in the process */
+  for (uint i= 0 ; i < len ; i++)
+  {
+    char c= m_query.str[i];
+    if (c == '\n')
+      c= ' ';
+    str->qs_append(c);
+  }
+  if (m_query.length > SP_STMT_PRINT_MAXLEN)
+    str->qs_append(STRING_WITH_LEN("...")); /* Indicate truncated string */
+  str->qs_append('"');
+}
+
+
+bool sp_instr_stmt::exec_core(THD *thd, uint *nextp)
+{
+  MYSQL_QUERY_EXEC_START(thd->query(),
+                         thd->thread_id,
+                         (char *) (thd->db ? thd->db : ""),
+                         &thd->security_ctx->priv_user[0],
+                         (char *)thd->security_ctx->host_or_ip,
+                         3);
+
+  bool rc= mysql_execute_command(thd);
+
+  MYSQL_QUERY_EXEC_DONE(rc);
+
+  *nextp= get_ip() + 1;
+
+  return rc;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_set implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_set::exec_core(THD *thd, uint *nextp)
+{
+  *nextp= get_ip() + 1;
+
+  if (!thd->sp_runtime_ctx->set_variable(thd, m_offset, &m_value_item))
+    return false;
+
+  /* Failed to evaluate the value. Reset the variable to NULL. */
+
+  if (thd->sp_runtime_ctx->set_variable(thd, m_offset, 0))
+  {
+    /* If this also failed, let's abort. */
+    my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
+  }
+
+  return true;
+}
+
+
+void sp_instr_set::print(String *str)
+{
+  /* set name@offset ... */
+  int rsrv = SP_INSTR_UINT_MAXLEN+6;
+  sp_variable *var = m_parsing_ctx->find_variable(m_offset);
+
+  /* 'var' should always be non-null, but just in case... */
+  if (var)
+    rsrv+= var->name.length;
+  if (str->reserve(rsrv))
+    return;
+  str->qs_append(STRING_WITH_LEN("set "));
+  if (var)
+  {
+    str->qs_append(var->name.str, var->name.length);
+    str->qs_append('@');
+  }
+  str->qs_append(m_offset);
+  str->qs_append(' ');
+  m_value_item->print(str, QT_ORDINARY);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_set_trigger_field implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp)
+{
+  *nextp= get_ip() + 1;
+  thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
+  return m_trigger_field->set_value(thd, &m_value_item);
+}
+
+
+void sp_instr_set_trigger_field::print(String *str)
+{
+  str->append(STRING_WITH_LEN("set_trigger_field "));
+  m_trigger_field->print(str, QT_ORDINARY);
+  str->append(STRING_WITH_LEN(":="));
+  m_value_item->print(str, QT_ORDINARY);
+}
+
+
+bool sp_instr_set_trigger_field::on_after_expr_parsing(THD *thd)
+{
+  DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
+
+  m_value_item= thd->lex->select_lex.item_list.head();
+
+  DBUG_ASSERT(!m_trigger_field);
+
+  m_trigger_field=
+    new (thd->mem_root) Item_trigger_field(thd->lex->current_context(),
+                                           Item_trigger_field::NEW_ROW,
+                                           m_trigger_field_name.str,
+                                           UPDATE_ACL,
+                                           false);
+
+  return m_value_item == NULL || m_trigger_field == NULL;
+}
+
+
+void sp_instr_set_trigger_field::cleanup_before_parsing(THD *thd)
+{
+  sp_lex_instr::cleanup_before_parsing(thd);
+
+  m_trigger_field= NULL;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_jump implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+void sp_instr_jump::print(String *str)
+{
+  /* jump dest */
+  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
+    return;
+  str->qs_append(STRING_WITH_LEN("jump "));
+  str->qs_append(m_dest);
+}
+
+
+uint sp_instr_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
+{
+  m_dest= opt_shortcut_jump(sp, this);
+  if (m_dest != get_ip() + 1)   /* Jumping to following instruction? */
+    m_marked= true;
+  m_optdest= sp->get_instr(m_dest);
+  return m_dest;
+}
+
+
+uint sp_instr_jump::opt_shortcut_jump(sp_head *sp, sp_instr *start)
+{
+  uint dest= m_dest;
+  sp_instr *i;
+
+  while ((i= sp->get_instr(dest)))
+  {
+    uint ndest;
+
+    if (start == i || this == i)
+      break;
+    ndest= i->opt_shortcut_jump(sp, start);
+    if (ndest == dest)
+      break;
+    dest= ndest;
+  }
+  return dest;
+}
+
+
+void sp_instr_jump::opt_move(uint dst, List<sp_branch_instr> *bp)
+{
+  if (m_dest > get_ip())
+    bp->push_back(this);      // Forward
+  else if (m_optdest)
+    m_dest= m_optdest->get_ip();  // Backward
+  m_ip= dst;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_jump_if_not class implementation
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
+{
+  DBUG_ASSERT(m_expr_item);
+
+  Item *item= sp_prepare_func_item(thd, &m_expr_item);
+
+  if (!item)
+    return true;
+
+  *nextp= item->val_bool() ? get_ip() + 1 : m_dest;
+
+  return false;
+}
+
+
+void sp_instr_jump_if_not::print(String *str)
+{
+  /* jump_if_not dest(cont) ... */
+  if (str->reserve(2*SP_INSTR_UINT_MAXLEN+14+32)) // Add some for the expr. too
+    return;
+  str->qs_append(STRING_WITH_LEN("jump_if_not "));
+  str->qs_append(m_dest);
+  str->qs_append('(');
+  str->qs_append(m_cont_dest);
+  str->qs_append(STRING_WITH_LEN(") "));
+  m_expr_item->print(str, QT_ORDINARY);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_lex_branch_instr implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+uint sp_lex_branch_instr::opt_mark(sp_head *sp, List<sp_instr> *leads)
+{
+  m_marked= true;
+
+  sp_instr *i= sp->get_instr(m_dest);
+
+  if (i)
+  {
+    m_dest= i->opt_shortcut_jump(sp, this);
+    m_optdest= sp->get_instr(m_dest);
+  }
+
+  sp->add_mark_lead(m_dest, leads);
+
+  i= sp->get_instr(m_cont_dest);
+
+  if (i)
+  {
+    m_cont_dest= i->opt_shortcut_jump(sp, this);
+    m_cont_optdest= sp->get_instr(m_cont_dest);
+  }
+
+  sp->add_mark_lead(m_cont_dest, leads);
+
+  return get_ip() + 1;
+}
+
+
+void sp_lex_branch_instr::opt_move(uint dst, List<sp_branch_instr> *bp)
+{
+  /*
+    cont. destinations may point backwards after shortcutting jumps
+    during the mark phase. If it's still pointing forwards, only
+    push this for backpatching if sp_instr_jump::opt_move() will not
+    do it (i.e. if the m_dest points backwards).
+   */
+  if (m_cont_dest > get_ip())
+  {                             // Forward
+    if (m_dest < get_ip())
+      bp->push_back(this);
+  }
+  else if (m_cont_optdest)
+    m_cont_dest= m_cont_optdest->get_ip(); // Backward
+
+  /* This will take care of m_dest and m_ip */
+  if (m_dest > get_ip())
+    bp->push_back(this);      // Forward
+  else if (m_optdest)
+    m_dest= m_optdest->get_ip();  // Backward
+  m_ip= dst;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_jump_case_when implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_jump_case_when::exec_core(THD *thd, uint *nextp)
+{
+  DBUG_ASSERT(m_eq_item);
+
+  Item *item= sp_prepare_func_item(thd, &m_eq_item);
+
+  if (!item)
+    return true;
+
+  *nextp= item->val_bool() ? get_ip() + 1 : m_dest;
+
+  return false;
+}
+
+
+void sp_instr_jump_case_when::print(String *str)
+{
+  /* jump_if_not dest(cont) ... */
+  if (str->reserve(2*SP_INSTR_UINT_MAXLEN+14+32)) // Add some for the expr. too
+    return;
+  str->qs_append(STRING_WITH_LEN("jump_if_not_case_when "));
+  str->qs_append(m_dest);
+  str->qs_append('(');
+  str->qs_append(m_cont_dest);
+  str->qs_append(STRING_WITH_LEN(") "));
+  m_eq_item->print(str, QT_ORDINARY);
+}
+
+
+bool sp_instr_jump_case_when::build_expr_items(THD *thd)
+{
+  // Setup CASE-expression item (m_case_expr_item).
+
+  m_case_expr_item= new Item_case_expr(m_case_expr_id);
+
+  if (!m_case_expr_item)
+    return true;
+
+#ifndef DBUG_OFF
+  m_case_expr_item->m_sp= thd->lex->sphead;
+#endif
+
+  // Setup WHEN-expression item (m_expr_item) if it is not already set.
+  //
+  // This function can be called in two cases:
+  //
+  //   - during initial (regular) parsing of SP. In this case we don't have
+  //     lex->select_lex (because it's not a SELECT statement), but
+  //     m_expr_item is already set in constructor.
+  //
+  //   - during re-parsing after meta-data change. In this case we've just
+  //     parsed aux-SELECT statement, so we need to take 1st (and the only one)
+  //     item from its list.
+
+  if (!m_expr_item)
+  {
+    DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
+
+    m_expr_item= thd->lex->select_lex.item_list.head();
+  }
+
+  // Setup main expression item (m_expr_item).
+
+  m_eq_item= new Item_func_eq(m_case_expr_item, m_expr_item);
+
+  if (!m_eq_item)
+    return true;
+
+  return false;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_freturn implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_freturn::exec_core(THD *thd, uint *nextp)
+{
+  /*
+    RETURN is a "procedure statement" (in terms of the SQL standard).
+    That means, Diagnostics Area should be clean before its execution.
+  */
+
+  Diagnostics_area *da= thd->get_stmt_da();
+  da->clear_warning_info(da->warning_info_id());
+
+  /*
+    Change <next instruction pointer>, so that this will be the last
+    instruction in the stored function.
+  */
+
+  *nextp= UINT_MAX;
+
+  /*
+    Evaluate the value of return expression and store it in current runtime
+    context.
+
+    NOTE: It's necessary to evaluate result item right here, because we must
+    do it in scope of execution the current context/block.
+  */
+
+  return thd->sp_runtime_ctx->set_return_value(thd, &m_expr_item);
+}
+
+
+void sp_instr_freturn::print(String *str)
+{
+  /* freturn type expr... */
+  if (str->reserve(1024+8+32)) // Add some for the expr. too
+    return;
+  str->qs_append(STRING_WITH_LEN("freturn "));
+  str->qs_append((uint) m_return_field_type);
+  str->qs_append(' ');
+  m_expr_item->print(str, QT_ORDINARY);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_hpush_jump implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
+{
+  *nextp= m_dest;
+
+  return thd->sp_runtime_ctx->push_handler(m_handler, get_ip() + 1);
+}
+
+
+void sp_instr_hpush_jump::print(String *str)
+{
+  /* hpush_jump dest fsize type */
+  if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 21))
+    return;
+
+  str->qs_append(STRING_WITH_LEN("hpush_jump "));
+  str->qs_append(m_dest);
+  str->qs_append(' ');
+  str->qs_append(m_frame);
+
+  switch (m_handler->type) {
+  case sp_handler::EXIT:
+    str->qs_append(STRING_WITH_LEN(" EXIT"));
+    break;
+  case sp_handler::CONTINUE:
+    str->qs_append(STRING_WITH_LEN(" CONTINUE"));
+    break;
+  default:
+    // The handler type must be either CONTINUE or EXIT.
+    DBUG_ASSERT(0);
+  }
+}
+
+
+uint sp_instr_hpush_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
+{
+  m_marked= true;
+
+  sp_instr *i= sp->get_instr(m_dest);
+
+  if (i)
+  {
+    m_dest= i->opt_shortcut_jump(sp, this);
+    m_optdest= sp->get_instr(m_dest);
+  }
+
+  sp->add_mark_lead(m_dest, leads);
+
+  /*
+    For continue handlers, all instructions in the scope of the handler
+    are possible leads. For example, the instruction after freturn might
+    be executed if the freturn triggers the condition handled by the
+    continue handler.
+
+    m_dest marks the start of the handler scope. It's added as a lead
+    above, so we start on m_dest+1 here.
+    m_opt_hpop is the hpop marking the end of the handler scope.
+  */
+  if (m_handler->type == sp_handler::CONTINUE)
+  {
+    for (uint scope_ip= m_dest+1; scope_ip <= m_opt_hpop; scope_ip++)
+      sp->add_mark_lead(scope_ip, leads);
+  }
+
+  return get_ip() + 1;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_hpop implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_hpop::execute(THD *thd, uint *nextp)
+{
+  thd->sp_runtime_ctx->pop_handlers(m_count);
+  *nextp= get_ip() + 1;
+  return false;
+}
+
+
+void sp_instr_hpop::print(String *str)
+{
+  /* hpop count */
+  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
+    return;
+  str->qs_append(STRING_WITH_LEN("hpop "));
+  str->qs_append(m_count);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_hreturn implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_hreturn::execute(THD *thd, uint *nextp)
+{
+  // NOTE: we must call sp_rcontext::exit_handler() even if m_dest is set.
+
+  uint continue_ip= thd->sp_runtime_ctx->exit_handler(thd->get_stmt_da());
+
+  *nextp= m_dest ? m_dest : continue_ip;
+
+  return false;
+}
+
+
+void sp_instr_hreturn::print(String *str)
+{
+  /* hreturn framesize dest */
+  if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 9))
+    return;
+  str->qs_append(STRING_WITH_LEN("hreturn "));
+  if (m_dest)
+  {
+    // NOTE: this is legacy: hreturn instruction for EXIT handler
+    // should print out 0 as frame index.
+    str->qs_append(STRING_WITH_LEN("0 "));
+    str->qs_append(m_dest);
+  }
+  else
+  {
+    str->qs_append(m_frame);
+  }
+}
+
+
+uint sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads)
+{
+  m_marked= true;
+
+  if (m_dest)
+  {
+    /*
+      This is an EXIT handler; next instruction step is in m_dest.
+     */
+    return m_dest;
+  }
+
+  /*
+    This is a CONTINUE handler; next instruction step will come from
+    the handler stack and not from opt_mark.
+   */
+  return UINT_MAX;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_cpush implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_cpush::execute(THD *thd, uint *nextp)
+{
+  *nextp= get_ip() + 1;
+
+  // sp_instr_cpush::execute() just registers the cursor in the runtime context.
+
+  return thd->sp_runtime_ctx->push_cursor(this);
+}
+
+
+bool sp_instr_cpush::exec_core(THD *thd, uint *nextp)
+{
+  sp_cursor *c= thd->sp_runtime_ctx->get_cursor(m_cursor_idx);
+
+  // sp_instr_cpush::exec_core() opens the cursor (it's called from
+  // sp_instr_copen::execute().
+
+  return c ? c->open(thd) : true;
+}
+
+
+void sp_instr_cpush::print(String *str)
+{
+  const LEX_STRING *cursor_name= m_parsing_ctx->find_cursor(m_cursor_idx);
+
+  uint rsrv= SP_INSTR_UINT_MAXLEN + 7 + m_cursor_query.length + 1;
+
+  if (cursor_name)
+    rsrv+= cursor_name->length;
+  if (str->reserve(rsrv))
+    return;
+  str->qs_append(STRING_WITH_LEN("cpush "));
+  if (cursor_name)
+  {
+    str->qs_append(cursor_name->str, cursor_name->length);
+    str->qs_append('@');
+  }
+  str->qs_append(m_cursor_idx);
+
+  str->qs_append(':');
+  str->qs_append(m_cursor_query.str, m_cursor_query.length);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_cpop implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_cpop::execute(THD *thd, uint *nextp)
+{
+  thd->sp_runtime_ctx->pop_cursors(m_count);
+  *nextp= get_ip() + 1;
+
+  return false;
+}
+
+
+void sp_instr_cpop::print(String *str)
+{
+  /* cpop count */
+  if (str->reserve(SP_INSTR_UINT_MAXLEN+5))
+    return;
+  str->qs_append(STRING_WITH_LEN("cpop "));
+  str->qs_append(m_count);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_copen implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_copen::execute(THD *thd, uint *nextp)
+{
+  *nextp= get_ip() + 1;
+
+  // Get the cursor pointer.
+
+  sp_cursor *c= thd->sp_runtime_ctx->get_cursor(m_cursor_idx);
+
+  if (!c)
+    return true;
+
+  // Retrieve sp_instr_cpush instance.
+
+  sp_instr_cpush *push_instr= c->get_push_instr();
+
+  // Switch Statement Arena to the sp_instr_cpush object. It contains the
+  // free_list of the query, so new items (if any) are stored in the right
+  // free_list, and we can cleanup after each open.
+
+  Query_arena *stmt_arena_saved= thd->stmt_arena;
+  thd->stmt_arena= push_instr;
+
+  // Switch to the cursor's lex and execute sp_instr_cpush::exec_core().
+  // sp_instr_cpush::exec_core() is *not* executed during
+  // sp_instr_cpush::execute(). sp_instr_cpush::exec_core() is intended to be
+  // executed on cursor opening.
+
+  bool rc= push_instr->validate_lex_and_execute_core(thd, nextp, false);
+
+  // Cleanup the query's items.
+
+  if (push_instr->free_list)
+    cleanup_items(push_instr->free_list);
+
+  // Restore Statement Arena.
+
+  thd->stmt_arena= stmt_arena_saved;
+
+  return rc;
+}
+
+
+void sp_instr_copen::print(String *str)
+{
+  const LEX_STRING *cursor_name= m_parsing_ctx->find_cursor(m_cursor_idx);
+
+  /* copen name@offset */
+  uint rsrv= SP_INSTR_UINT_MAXLEN+7;
+
+  if (cursor_name)
+    rsrv+= cursor_name->length;
+  if (str->reserve(rsrv))
+    return;
+  str->qs_append(STRING_WITH_LEN("copen "));
+  if (cursor_name)
+  {
+    str->qs_append(cursor_name->str, cursor_name->length);
+    str->qs_append('@');
+  }
+  str->qs_append(m_cursor_idx);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_cclose implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_cclose::execute(THD *thd, uint *nextp)
+{
+  *nextp= get_ip() + 1;
+
+  sp_cursor *c= thd->sp_runtime_ctx->get_cursor(m_cursor_idx);
+
+  return c ? c->close(thd) : true;
+}
+
+
+void sp_instr_cclose::print(String *str)
+{
+  const LEX_STRING *cursor_name= m_parsing_ctx->find_cursor(m_cursor_idx);
+
+  /* cclose name@offset */
+  uint rsrv= SP_INSTR_UINT_MAXLEN+8;
+
+  if (cursor_name)
+    rsrv+= cursor_name->length;
+  if (str->reserve(rsrv))
+    return;
+  str->qs_append(STRING_WITH_LEN("cclose "));
+  if (cursor_name)
+  {
+    str->qs_append(cursor_name->str, cursor_name->length);
+    str->qs_append('@');
+  }
+  str->qs_append(m_cursor_idx);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_cfetch implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_cfetch::execute(THD *thd, uint *nextp)
+{
+  *nextp= get_ip() + 1;
+
+  sp_cursor *c= thd->sp_runtime_ctx->get_cursor(m_cursor_idx);
+
+  return c ? c->fetch(thd, &m_varlist) : true;
+}
+
+
+void sp_instr_cfetch::print(String *str)
+{
+  List_iterator_fast<sp_variable> li(m_varlist);
+  sp_variable *pv;
+  const LEX_STRING *cursor_name= m_parsing_ctx->find_cursor(m_cursor_idx);
+
+  /* cfetch name@offset vars... */
+  uint rsrv= SP_INSTR_UINT_MAXLEN+8;
+
+  if (cursor_name)
+    rsrv+= cursor_name->length;
+  if (str->reserve(rsrv))
+    return;
+  str->qs_append(STRING_WITH_LEN("cfetch "));
+  if (cursor_name)
+  {
+    str->qs_append(cursor_name->str, cursor_name->length);
+    str->qs_append('@');
+  }
+  str->qs_append(m_cursor_idx);
+  while ((pv= li++))
+  {
+    if (str->reserve(pv->name.length+SP_INSTR_UINT_MAXLEN+2))
+      return;
+    str->qs_append(' ');
+    str->qs_append(pv->name.str, pv->name.length);
+    str->qs_append('@');
+    str->qs_append(pv->offset);
+  }
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_error implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+void sp_instr_error::print(String *str)
+{
+  /* error code */
+  if (str->reserve(SP_INSTR_UINT_MAXLEN+6))
+    return;
+  str->qs_append(STRING_WITH_LEN("error "));
+  str->qs_append(m_errcode);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// sp_instr_set_case_expr implementation.
+///////////////////////////////////////////////////////////////////////////
+
+
+bool sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
+{
+  *nextp= get_ip() + 1;
+
+  sp_rcontext *rctx= thd->sp_runtime_ctx;
+
+  if (rctx->set_case_expr(thd, m_case_expr_id, &m_expr_item) &&
+      !rctx->get_case_expr(m_case_expr_id))
+  {
+    // Failed to evaluate the value, the case expression is still not
+    // initialized. Set to NULL so we can continue.
+
+    Item *null_item= new Item_null();
+
+    if (!null_item || rctx->set_case_expr(thd, m_case_expr_id, &null_item))
+    {
+      // If this also failed, we have to abort.
+      my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
+
+void sp_instr_set_case_expr::print(String *str)
+{
+  /* set_case_expr (cont) id ... */
+  str->reserve(2*SP_INSTR_UINT_MAXLEN+18+32); // Add some extra for expr too
+  str->qs_append(STRING_WITH_LEN("set_case_expr ("));
+  str->qs_append(m_cont_dest);
+  str->qs_append(STRING_WITH_LEN(") "));
+  str->qs_append(m_case_expr_id);
+  str->qs_append(' ');
+  m_expr_item->print(str, QT_ORDINARY);
+}
+
+
+uint sp_instr_set_case_expr::opt_mark(sp_head *sp, List<sp_instr> *leads)
+{
+  m_marked= true;
+
+  sp_instr *i= sp->get_instr(m_cont_dest);
+
+  if (i)
+  {
+    m_cont_dest= i->opt_shortcut_jump(sp, this);
+    m_cont_optdest= sp->get_instr(m_cont_dest);
+  }
+
+  sp->add_mark_lead(m_cont_dest, leads);
+  return get_ip() + 1;
+}
+
+
+void sp_instr_set_case_expr::opt_move(uint dst, List<sp_branch_instr> *bp)
+{
+  if (m_cont_dest > get_ip())
+    bp->push_back(this);        // Forward
+  else if (m_cont_optdest)
+    m_cont_dest= m_cont_optdest->get_ip(); // Backward
+  m_ip= dst;
+}

=== added file 'sql/sp_instr.h'
--- a/sql/sp_instr.h	1970-01-01 00:00:00 +0000
+++ b/sql/sp_instr.h	2012-05-16 13:58:54 +0000
@@ -0,0 +1,1409 @@
+/* Copyright (c) 2012, 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
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#ifndef _SP_INSTR_H_
+#define _SP_INSTR_H_
+
+#include "my_global.h"    // NO_EMBEDDED_ACCESS_CHECKS
+#include "sp_pcontext.h"  // sp_pcontext
+#include "sql_class.h"    // THD
+#include "sp_head.h"      // sp_printable
+
+///////////////////////////////////////////////////////////////////////////
+// This file contains SP-instruction classes.
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  An interface for all SP-instructions with destinations that
+  need to be updated by the SP-optimizer.
+*/
+class sp_branch_instr
+{
+public:
+  /**
+    Update the destination; used by the SP-instruction-optimizer.
+
+    @param old_dest current (old) destination (instruction pointer).
+    @param new_dest new destination (instruction pointer).
+  */
+  virtual void set_destination(uint old_dest, uint new_dest) = 0;
+
+  /**
+    Update all instruction with the given label in the backpatch list to
+    the specified instruction pointer.
+
+    @param dest     destination instruction pointer.
+  */
+  virtual void backpatch(uint dest) = 0;
+
+  virtual ~sp_branch_instr()
+  { }
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  Base class for every SP-instruction. sp_instr defines interface and provides
+  base implementation.
+*/
+class sp_instr : public Query_arena,
+                 public Sql_alloc,
+                 public sp_printable
+{
+public:
+  sp_instr(uint ip, sp_pcontext *ctx)
+   :Query_arena(0, STMT_INITIALIZED_FOR_SP),
+    m_marked(false),
+    m_ip(ip),
+    m_parsing_ctx(ctx)
+  { }
+
+  virtual ~sp_instr()
+  { free_items(); }
+
+  /**
+    Execute this instruction
+
+    @param thd         Thread context
+    @param[out] nextp  index of the next instruction to execute. (For most
+                       instructions this will be the instruction following this
+                       one). Note that this parameter is undefined in case of
+                       errors, use get_cont_dest() to find the continuation
+                       instruction for CONTINUE error handlers.
+
+    @return Error status.
+  */
+  virtual bool execute(THD *thd, uint *nextp) = 0;
+
+  uint get_ip() const
+  { return m_ip; }
+
+  /**
+    Get the continuation destination (instruction pointer for the CONTINUE
+    HANDLER) of this instruction.
+    @return the continuation destination
+  */
+  virtual uint get_cont_dest() const
+  { return get_ip() + 1; }
+
+  sp_pcontext *get_parsing_ctx() const
+  { return m_parsing_ctx; }
+
+  ///////////////////////////////////////////////////////////////////////////
+  // The following operations are used solely for SP-code-optimizer.
+  ///////////////////////////////////////////////////////////////////////////
+
+  /**
+    Mark this instruction as reachable during optimization and return the
+    index to the next instruction. Jump instruction will add their
+    destination to the leads list.
+  */
+  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
+  {
+    m_marked= true;
+    return get_ip() + 1;
+  }
+
+  /**
+    Short-cut jumps to jumps during optimization. This is used by the
+    jump instructions' opt_mark() methods. 'start' is the starting point,
+    used to prevent the mark sweep from looping for ever. Return the
+    end destination.
+  */
+  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
+  { return get_ip(); }
+
+  /**
+    Inform the instruction that it has been moved during optimization.
+    Most instructions will simply update its index, but jump instructions
+    must also take care of their destination pointers. Forward jumps get
+    pushed to the backpatch list 'ibp'.
+  */
+  virtual void opt_move(uint dst, List<sp_branch_instr> *ibp)
+  { m_ip= dst; }
+
+  bool opt_is_marked() const
+  { return m_marked; }
+
+protected:
+  /// Show if this instruction is reachable within the SP
+  /// (used by SP-optimizer).
+  bool m_marked;
+
+  /// Instruction pointer.
+  uint m_ip;
+
+  /// Instruction parsing context.
+  sp_pcontext *m_parsing_ctx;
+
+private:
+  // Prevent use of copy constructor and assignment operator.
+  sp_instr(const sp_instr &);
+  void operator= (sp_instr &);
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_lex_instr is a class providing the interface and base implementation
+  for SP-instructions, whose execution is based on expression evaluation.
+
+  sp_lex_instr keeps LEX-object to be able to evaluate the expression.
+
+  sp_lex_instr also provides possibility to re-parse the original query
+  string if for some reason the LEX-object is not valid any longer.
+*/
+class sp_lex_instr : public sp_instr
+{
+public:
+  sp_lex_instr(uint ip, sp_pcontext *ctx, LEX *lex, bool is_lex_owner)
+   :sp_instr(ip, ctx),
+    m_lex(NULL),
+    m_is_lex_owner(false),
+    m_first_execution(true),
+    m_prelocking_tables(NULL),
+    m_lex_query_tables_own_last(NULL)
+  {
+    set_lex(lex, is_lex_owner);
+  }
+
+  virtual ~sp_lex_instr()
+  { free_lex(); }
+
+  /**
+    Make a few attempts to execute the instruction.
+
+    Basically, this operation does the following things:
+      - install Reprepare_observer to catch metadata changes (if any);
+      - calls reset_lex_and_exec_core() to execute the instruction;
+      - if the execution fails due to a change in metadata, re-parse the
+        instruction's SQL-statement and repeat execution.
+
+    @param      thd           Thread context.
+    @param[out] nextp         Next instruction pointer
+    @param      open_tables   Flag to specify if the function should check read
+                              access to tables in LEX's table list and open and
+                              lock them (used in instructions which need to
+                              calculate some expression and don't execute
+                              complete statement).
+
+    @return Error status.
+  */
+  bool validate_lex_and_execute_core(THD *thd, uint *nextp, bool open_tables);
+
+private:
+  /**
+    Prepare LEX and thread for execution of instruction, if requested open
+    and lock LEX's tables, execute instruction's core function, perform
+    cleanup afterwards.
+
+    @param thd           thread context
+    @param nextp[out]    next instruction pointer
+    @param open_tables   if TRUE then check read access to tables in LEX's table
+                         list and open and lock them (used in instructions which
+                         need to calculate some expression and don't execute
+                         complete statement).
+
+    @note
+      We are not saving/restoring some parts of THD which may need this because
+      we do this once for whole routine execution in sp_head::execute().
+
+    @return Error status.
+  */
+  bool reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables);
+
+  /**
+    (Re-)parse the query corresponding to this instruction and return a new
+    LEX-object.
+
+    @param thd  Thread context.
+    @param sp   The stored program.
+
+    @return new LEX-object or NULL in case of failure.
+  */
+  LEX *parse_expr(THD *thd, sp_head *sp);
+
+  /**
+     Set LEX-object.
+
+     Previously assigned LEX-object (if any) will be properly cleaned up
+     and destroyed.
+
+     @param lex          LEX-object to be used by this instance of sp_lex_instr.
+     @param is_lex_owner the flag specifying if this instance sp_lex_instr
+                         owns (and thus deletes when needed) passed LEX-object.
+  */
+  void set_lex(LEX *lex, bool is_lex_owner);
+
+  /**
+     Cleanup and destroy assigned LEX-object if needed.
+  */
+  void free_lex();
+
+public:
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp)
+  { return validate_lex_and_execute_core(thd, nextp, true); }
+
+protected:
+  /////////////////////////////////////////////////////////////////////////
+  // Interface (virtual) methods.
+  /////////////////////////////////////////////////////////////////////////
+
+  /**
+    Execute core function of instruction after all preparations
+    (e.g. setting of proper LEX, saving part of the thread context).
+
+    @param thd  Thread context.
+    @param nextp[out]    next instruction pointer
+
+    @return Error flag.
+  */
+  virtual bool exec_core(THD *thd, uint *nextp) = 0;
+
+  /**
+    @retval false if the object (i.e. LEX-object) is valid and exec_core() can be
+    just called.
+
+    @retval true if the object is not valid any longer, exec_core() can not be
+    called. The original query string should be re-parsed and a new LEX-object
+    should be used.
+  */
+  virtual bool is_invalid() const = 0;
+
+  /**
+    Invalidate the object.
+  */
+  virtual void invalidate() = 0;
+
+  /**
+    Return the query string, which can be passed to the parser. I.e. the
+    operation should return a valid SQL-statement query string.
+
+    @param[out] sql_query SQL-statement query string.
+  */
+  virtual void get_query(String *sql_query) const;
+
+  /**
+    @return the expression query string. This string can not be passed directly
+    to the parser as it is most likely not a valid SQL-statement.
+
+    @note as it can be seen in the get_query() implementation, get_expr_query()
+    might return EMPTY_STR. EMPTY_STR means that no query-expression is
+    available. That happens when class provides different implementation of
+    get_query(). Strictly speaking, this is a drawback of the current class
+    hierarchy.
+  */
+  virtual LEX_STRING get_expr_query() const
+  { return EMPTY_STR; }
+
+  /**
+    Callback function which is called after the statement query string is
+    successfully parsed, and the thread context has not been switched to the
+    outer context. The thread context contains new LEX-object corresponding to
+    the parsed query string.
+
+    @param thd  Thread context.
+
+    @return Error flag.
+  */
+  virtual bool on_after_expr_parsing(THD *thd)
+  { return false; }
+
+  /**
+    Destroy items in the free list before re-parsing the statement query
+    string (and thus, creating new items).
+
+    @param thd  Thread context.
+  */
+  virtual void cleanup_before_parsing(THD *thd);
+
+private:
+  /// LEX-object.
+  LEX *m_lex;
+
+  /**
+    Indicates whether this sp_lex_instr instance is responsible for
+    LEX-object deletion.
+  */
+  bool m_is_lex_owner;
+
+  /**
+    Indicates whether exec_core() has not been already called on the current
+    LEX-object.
+  */
+  bool m_first_execution;
+
+  /*****************************************************************************
+    Support for being able to execute this statement in two modes:
+    a) inside prelocked mode set by the calling procedure or its ancestor.
+    b) outside of prelocked mode, when this statement enters/leaves
+       prelocked mode itself.
+  *****************************************************************************/
+
+  /**
+    List of additional tables this statement needs to lock when it
+    enters/leaves prelocked mode on its own.
+  */
+  TABLE_LIST *m_prelocking_tables;
+
+  /**
+    The value m_lex->query_tables_own_last should be set to this when the
+    statement enters/leaves prelocked mode on its own.
+  */
+  TABLE_LIST **m_lex_query_tables_own_last;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_instr_stmt represents almost all conventional SQL-statements, which are
+  supported outside stored programs.
+
+  SET-statements, which deal with SP-variable or NEW/OLD trigger pseudo-rows are
+  not represented by this instruction.
+*/
+class sp_instr_stmt : public sp_lex_instr
+{
+public:
+  sp_instr_stmt(uint ip,
+                LEX *lex,
+                LEX_STRING query)
+   :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true),
+    m_query(query),
+    m_valid(true)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_lex_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool exec_core(THD *thd, uint *nextp);
+
+  virtual bool is_invalid() const
+  { return !m_valid; }
+
+  virtual void invalidate()
+  { m_valid= false; }
+
+  virtual void get_query(String *sql_query) const
+  { sql_query->append(m_query.str, m_query.length); }
+
+private:
+  /// Complete query of the SQL-statement.
+  LEX_STRING m_query;
+
+  /// Specify if the stored LEX-object is up-to-date.
+  bool m_valid;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_instr_set represents SET-statememnts, which deal with SP-variables.
+*/
+class sp_instr_set : public sp_lex_instr
+{
+public:
+  sp_instr_set(uint ip,
+               LEX *lex,
+	       uint offset,
+               Item *value_item,
+               LEX_STRING value_query,
+               bool is_lex_owner)
+   :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, is_lex_owner),
+    m_offset(offset),
+    m_value_item(value_item),
+    m_value_query(value_query)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_lex_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool exec_core(THD *thd, uint *nextp);
+
+  virtual bool is_invalid() const
+  { return m_value_item == NULL; }
+
+  virtual void invalidate()
+  { m_value_item= NULL; }
+
+  virtual bool on_after_expr_parsing(THD *thd)
+  {
+    DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
+
+    m_value_item= thd->lex->select_lex.item_list.head();
+
+    return false;
+  }
+
+  virtual LEX_STRING get_expr_query() const
+  { return m_value_query; }
+
+private:
+  /// Frame offset.
+  uint m_offset;
+
+  /// Value expression item of the SET-statement.
+  Item *m_value_item;
+
+  /// SQL-query corresponding to the value expression.
+  LEX_STRING m_value_query;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_instr_set_trigger_field represents SET-statements, which deal with NEW/OLD
+  trigger pseudo-rows.
+*/
+class sp_instr_set_trigger_field : public sp_lex_instr
+{
+public:
+  sp_instr_set_trigger_field(uint ip,
+                             LEX *lex,
+                             LEX_STRING trigger_field_name,
+                             Item_trigger_field *trigger_field,
+                             Item *value_item,
+                             LEX_STRING value_query)
+   :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true),
+    m_trigger_field_name(trigger_field_name),
+    m_trigger_field(trigger_field),
+    m_value_item(value_item),
+    m_value_query(value_query)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_lex_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool exec_core(THD *thd, uint *nextp);
+
+  virtual bool is_invalid() const
+  { return m_value_item == NULL; }
+
+  virtual void invalidate()
+  { m_value_item= NULL; }
+
+  virtual bool on_after_expr_parsing(THD *thd);
+
+  virtual void cleanup_before_parsing(THD *thd);
+
+  virtual LEX_STRING get_expr_query() const
+  { return m_value_query; }
+
+private:
+  /// Trigger field name ("field_name" of the "NEW.field_name").
+  LEX_STRING m_trigger_field_name;
+
+  /// Item corresponding to the NEW/OLD trigger field.
+  Item_trigger_field *m_trigger_field;
+
+  /// Value expression item of the SET-statement.
+  Item *m_value_item;
+
+  /// SQL-query corresponding to the value expression.
+  LEX_STRING m_value_query;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_instr_freturn represents RETURN statement in stored functions.
+*/
+class sp_instr_freturn : public sp_lex_instr
+{
+public:
+  sp_instr_freturn(uint ip,
+                   LEX *lex,
+		   Item *expr_item,
+                   LEX_STRING expr_query,
+                   enum enum_field_types return_field_type)
+   :sp_lex_instr(ip, lex->get_sp_current_parsing_ctx(), lex, true),
+    m_expr_item(expr_item),
+    m_expr_query(expr_query),
+    m_return_field_type(return_field_type)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
+  {
+    m_marked= true;
+    return UINT_MAX;
+  }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_lex_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool exec_core(THD *thd, uint *nextp);
+
+  virtual bool is_invalid() const
+  { return m_expr_item == NULL; }
+
+  virtual void invalidate()
+  {
+    // it's already deleted.
+    m_expr_item= NULL;
+  }
+
+  virtual bool on_after_expr_parsing(THD *thd)
+  {
+    DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
+
+    m_expr_item= thd->lex->select_lex.item_list.head();
+
+    return false;
+  }
+
+  virtual LEX_STRING get_expr_query() const
+  { return m_expr_query; }
+
+private:
+  /// RETURN-expression item.
+  Item *m_expr_item;
+
+  /// SQL-query corresponding to the RETURN-expression.
+  LEX_STRING m_expr_query;
+
+  /// RETURN-field type code.
+  enum enum_field_types m_return_field_type;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  This is base class for all kinds of jump instructions.
+
+  @note this is the only class, we directly construct instances of, that has
+  subclasses. We also redefine sp_instr_jump behavior in those subclasses.
+
+  @todo later we will consider introducing a new class, which will be the base
+  for sp_instr_jump, sp_instr_set_case_expr and sp_instr_jump_case_when.
+  Something like sp_regular_branch_instr (similar to sp_lex_branch_instr).
+*/
+class sp_instr_jump : public sp_instr,
+                      public sp_branch_instr
+{
+public:
+  sp_instr_jump(uint ip, sp_pcontext *ctx)
+   :sp_instr(ip, ctx),
+    m_dest(0),
+    m_optdest(NULL)
+  { }
+
+  sp_instr_jump(uint ip, sp_pcontext *ctx, uint dest)
+   :sp_instr(ip, ctx),
+    m_dest(dest),
+    m_optdest(NULL)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp)
+  {
+    *nextp= m_dest;
+    return false;
+  }
+
+  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
+
+  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start);
+
+  virtual void opt_move(uint dst, List<sp_branch_instr> *ibp);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_branch_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void set_destination(uint old_dest, uint new_dest)
+  {
+    if (m_dest == old_dest)
+      m_dest= new_dest;
+  }
+
+  virtual void backpatch(uint dest)
+  {
+    /* Calling backpatch twice is a logic flaw in jump resolution. */
+    DBUG_ASSERT(m_dest == 0);
+    m_dest= dest;
+  }
+
+protected:
+  /// Where we will go.
+  uint m_dest;
+
+  // The following attribute is used by SP-optimizer.
+  sp_instr *m_optdest;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_lex_branch_instr is a base class for SP-instructions, which might perform
+  conditional jump depending on the value of an SQL-expression.
+*/
+class sp_lex_branch_instr : public sp_lex_instr,
+                            public sp_branch_instr
+{
+protected:
+  sp_lex_branch_instr(uint ip, sp_pcontext *ctx, LEX *lex,
+                      Item *expr_item, LEX_STRING expr_query)
+   :sp_lex_instr(ip, ctx, lex, true),
+    m_dest(0),
+    m_cont_dest(0),
+    m_optdest(NULL),
+    m_cont_optdest(NULL),
+    m_expr_item(expr_item),
+    m_expr_query(expr_query)
+  { }
+
+  sp_lex_branch_instr(uint ip, sp_pcontext *ctx, LEX *lex,
+                      Item *expr_item, LEX_STRING expr_query,
+                      uint dest)
+   :sp_lex_instr(ip, ctx, lex, true),
+    m_dest(dest),
+    m_cont_dest(0),
+    m_optdest(NULL),
+    m_cont_optdest(NULL),
+    m_expr_item(expr_item),
+    m_expr_query(expr_query)
+  { }
+
+public:
+  void set_cont_dest(uint cont_dest)
+  { m_cont_dest= cont_dest; }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
+
+  virtual void opt_move(uint dst, List<sp_branch_instr> *ibp);
+
+  virtual uint get_cont_dest() const
+  { return m_cont_dest; }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_lex_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool is_invalid() const
+  { return m_expr_item == NULL; }
+
+  virtual void invalidate()
+  { m_expr_item= NULL; /* it's already deleted. */ }
+
+  virtual LEX_STRING get_expr_query() const
+  { return m_expr_query; }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_branch_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void set_destination(uint old_dest, uint new_dest)
+  {
+    if (m_dest == old_dest)
+      m_dest= new_dest;
+
+    if (m_cont_dest == old_dest)
+      m_cont_dest= new_dest;
+  }
+
+  virtual void backpatch(uint dest)
+  {
+    /* Calling backpatch twice is a logic flaw in jump resolution. */
+    DBUG_ASSERT(m_dest == 0);
+    m_dest= dest;
+  }
+
+protected:
+  /// Where we will go.
+  uint m_dest;
+
+  /// Where continue handlers will go.
+  uint m_cont_dest;
+
+  // The following attributes are used by SP-optimizer.
+  sp_instr *m_optdest;
+  sp_instr *m_cont_optdest;
+
+  /// Expression item.
+  Item *m_expr_item;
+
+  /// SQL-query corresponding to the expression.
+  LEX_STRING m_expr_query;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_instr_jump_if_not implements SP-instruction, which does the jump if its
+  SQL-expression is false.
+*/
+class sp_instr_jump_if_not : public sp_lex_branch_instr
+{
+public:
+  sp_instr_jump_if_not(uint ip,
+                       LEX *lex,
+                       Item *expr_item,
+                       LEX_STRING expr_query)
+   :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
+                        expr_item, expr_query)
+  { }
+
+  sp_instr_jump_if_not(uint ip,
+                       LEX *lex,
+                       Item *expr_item,
+                       LEX_STRING expr_query,
+                       uint dest)
+   :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
+                        expr_item, expr_query, dest)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_lex_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool exec_core(THD *thd, uint *nextp);
+
+  virtual bool on_after_expr_parsing(THD *thd)
+  {
+    DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
+
+    m_expr_item= thd->lex->select_lex.item_list.head();
+
+    return false;
+  }
+};
+
+///////////////////////////////////////////////////////////////////////////
+// Instructions used for the "simple CASE" implementation.
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_instr_set_case_expr is used in the "simple CASE" implementation to evaluate
+  and store the CASE-expression in the runtime context.
+*/
+class sp_instr_set_case_expr : public sp_lex_branch_instr
+{
+public:
+  sp_instr_set_case_expr(uint ip,
+                         LEX *lex,
+                         uint case_expr_id,
+                         Item *case_expr_item,
+                         LEX_STRING case_expr_query)
+   :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
+                        case_expr_item, case_expr_query),
+    m_case_expr_id(case_expr_id)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
+
+  virtual void opt_move(uint dst, List<sp_branch_instr> *ibp);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_branch_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  /*
+    NOTE: set_destination() and backpatch() are overriden here just because the
+    m_dest attribute is not used by this class, so there is no need to do
+    anything about it.
+
+    @todo These operations probably should be left as they are (i.e. do not
+    override them here). The m_dest attribute would be set and not used, but
+    that should not be a big deal.
+
+    @todo This also indicates deficiency of the current SP-istruction class
+    hierarchy.
+  */
+
+  virtual void set_destination(uint old_dest, uint new_dest)
+  {
+    if (m_cont_dest == old_dest)
+      m_cont_dest= new_dest;
+  }
+
+  virtual void backpatch(uint dest)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_lex_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool exec_core(THD *thd, uint *nextp);
+
+  virtual bool on_after_expr_parsing(THD *thd)
+  {
+    DBUG_ASSERT(thd->lex->select_lex.item_list.elements == 1);
+
+    m_expr_item= thd->lex->select_lex.item_list.head();
+
+    return false;
+  }
+
+private:
+  /// Identifier (index) of the CASE-expression in the runtime context.
+  uint m_case_expr_id;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_instr_jump_case_when instruction is used in the "simple CASE"
+  implementation. It's a jump instruction with the following condition:
+    (CASE-expression = WHEN-expression)
+  CASE-expression is retrieved from sp_rcontext;
+  WHEN-expression is kept by this instruction.
+*/
+class sp_instr_jump_case_when : public sp_lex_branch_instr
+{
+public:
+  sp_instr_jump_case_when(uint ip,
+                          LEX *lex,
+                          int case_expr_id,
+                          Item *when_expr_item,
+                          LEX_STRING when_expr_query)
+   :sp_lex_branch_instr(ip, lex->get_sp_current_parsing_ctx(), lex,
+                        when_expr_item, when_expr_query),
+    m_case_expr_id(case_expr_id)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_lex_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool exec_core(THD *thd, uint *nextp);
+
+  virtual void invalidate()
+  {
+    // Items should be already deleted in lex-keeper.
+    m_case_expr_item= NULL;
+    m_eq_item= NULL;
+    m_expr_item= NULL; // it's a WHEN-expression.
+  }
+
+  virtual bool on_after_expr_parsing(THD *thd)
+  { return build_expr_items(thd); }
+
+private:
+  /**
+    Build CASE-expression item tree:
+      Item_func_eq(case-expression, when-i-expression)
+
+    This function is used for the following form of CASE statement:
+      CASE case-expression
+        WHEN when-1-expression THEN ...
+        WHEN when-2-expression THEN ...
+        ...
+        WHEN when-n-expression THEN ...
+      END CASE
+
+    The thing is that after the parsing we have an item (item tree) for the
+    case-expression and for each when-expression. Here we build jump
+    conditions: expressions like (case-expression = when-i-expression).
+
+    @param thd  Thread context.
+
+    @return Error flag.
+  */
+  bool build_expr_items(THD *thd);
+
+private:
+  /// Identifier (index) of the CASE-expression in the runtime context.
+  int m_case_expr_id;
+
+  /// Item representing the CASE-expression.
+  Item_case_expr *m_case_expr_item;
+
+  /**
+    Item corresponding to the main item of the jump-condition-expression:
+    it's the equal function (=) in the (case-expression = when-i-expression)
+    expression.
+  */
+  Item *m_eq_item;
+};
+
+///////////////////////////////////////////////////////////////////////////
+// SQL-condition handler instructions.
+///////////////////////////////////////////////////////////////////////////
+
+class sp_instr_hpush_jump : public sp_instr_jump
+{
+public:
+  sp_instr_hpush_jump(uint ip,
+                      sp_pcontext *ctx,
+                      sp_handler *handler)
+   :sp_instr_jump(ip, ctx),
+    m_handler(handler),
+    m_opt_hpop(0),
+    m_frame(ctx->current_var_count())
+  {
+    DBUG_ASSERT(m_handler->condition_values.elements == 0);
+  }
+
+  virtual ~sp_instr_hpush_jump()
+  {
+    m_handler->condition_values.empty();
+    m_handler= NULL;
+  }
+
+  void add_condition(sp_condition_value *condition_value)
+  { m_handler->condition_values.push_back(condition_value); }
+
+  sp_handler *get_handler()
+  { return m_handler; }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp);
+
+  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
+
+  /** Override sp_instr_jump's shortcut; we stop here. */
+  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
+  { return get_ip(); }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_branch_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void backpatch(uint dest)
+  {
+    DBUG_ASSERT(!m_dest || !m_opt_hpop);
+    if (!m_dest)
+      m_dest= dest;
+    else
+      m_opt_hpop= dest;
+  }
+
+private:
+  /// Handler.
+  sp_handler *m_handler;
+
+  /// hpop marking end of handler scope.
+  uint m_opt_hpop;
+
+  // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in
+  // debug version only). It's used in print().
+  uint m_frame;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class sp_instr_hpop : public sp_instr
+{
+public:
+  sp_instr_hpop(uint ip, sp_pcontext *ctx, uint count)
+    : sp_instr(ip, ctx), m_count(count)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp);
+
+private:
+  /// How many handlers this instruction should pop.
+  uint m_count;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class sp_instr_hreturn : public sp_instr_jump
+{
+public:
+  sp_instr_hreturn(uint ip, sp_pcontext *ctx)
+   :sp_instr_jump(ip, ctx),
+    m_frame(ctx->current_var_count())
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp);
+
+  /** Override sp_instr_jump's shortcut; we stop here. */
+  virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
+  { return get_ip(); }
+
+  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
+
+private:
+  // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in
+  // debug version only). It's used in print().
+  uint m_frame;
+};
+
+///////////////////////////////////////////////////////////////////////////
+// Cursor implementation.
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_instr_cpush corresponds to DECLARE CURSOR, implements DECLARE CURSOR and
+  OPEN.
+
+  This is the most important instruction in cursor implementation. It is created
+  and added to sp_head when DECLARE CURSOR is being parsed. The arena of this
+  instruction contains LEX-object for the cursor's SELECT-statement.
+
+  This instruction is actually used to open the cursor.
+
+  execute() operation "implements" DECLARE CURSOR statement -- it merely pushes
+  a new cursor object into the stack in sp_rcontext object.
+
+  exec_core() operation implements OPEN statement. It is important to implement
+  OPEN statement in this instruction, because OPEN may lead to re-parsing of the
+  SELECT-statement. So, the original Arena and parsing context must be used.
+*/
+class sp_instr_cpush : public sp_lex_instr
+{
+public:
+  sp_instr_cpush(uint ip,
+                 sp_pcontext *ctx,
+                 LEX *cursor_lex,
+                 LEX_STRING cursor_query,
+                 int cursor_idx)
+   :sp_lex_instr(ip, ctx, cursor_lex, true),
+    m_cursor_query(cursor_query),
+    m_valid(true),
+    m_cursor_idx(cursor_idx)
+  {
+    // Cursor can't be stored in Query Cache, so we should prevent opening QC
+    // for try to write results which are absent.
+
+    cursor_lex->safe_to_cache_query= false;
+  }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // Query_arena implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  /**
+    This call is used to cleanup the instruction when a sensitive
+    cursor is closed. For now stored procedures always use materialized
+    cursors and the call is not used.
+  */
+  virtual void cleanup_stmt()
+  { /* no op */ }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_lex_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool exec_core(THD *thd, uint *nextp);
+
+  virtual bool is_invalid() const
+  { return !m_valid; }
+
+  virtual void invalidate()
+  { m_valid= false; }
+
+  virtual void get_query(String *sql_query) const
+  { sql_query->append(m_cursor_query.str, m_cursor_query.length); }
+
+private:
+  /// This attribute keeps the cursor SELECT statement.
+  LEX_STRING m_cursor_query;
+
+  /// Flag if the LEX-object of this instruction is valid or not.
+  /// The LEX-object is not valid when metadata have changed.
+  bool m_valid;
+
+  /// Used to identify the cursor in the sp_rcontext.
+  int m_cursor_idx;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_instr_cpop instruction is added at the end of BEGIN..END block.
+  It's used to remove declared cursors so that they are not visible any longer.
+*/
+class sp_instr_cpop : public sp_instr
+{
+public:
+  sp_instr_cpop(uint ip, sp_pcontext *ctx, uint count)
+   :sp_instr(ip, ctx),
+    m_count(count)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp);
+
+private:
+  uint m_count;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_instr_copen represents OPEN statement (opens the cursor).
+  However, the actual implementation is in sp_instr_cpush::exec_core().
+*/
+class sp_instr_copen : public sp_instr
+{
+public:
+  sp_instr_copen(uint ip, sp_pcontext *ctx, int cursor_idx)
+   :sp_instr(ip, ctx),
+    m_cursor_idx(cursor_idx)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp);
+
+private:
+  /// Used to identify the cursor in the sp_rcontext.
+  int m_cursor_idx;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  The instruction corresponds to the CLOSE statement.
+  It just forwards the close-call to the appropriate sp_cursor object in the
+  sp_rcontext.
+*/
+class sp_instr_cclose : public sp_instr
+{
+public:
+  sp_instr_cclose(uint ip, sp_pcontext *ctx, int cursor_idx)
+   :sp_instr(ip, ctx),
+    m_cursor_idx(cursor_idx)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp);
+
+private:
+  /// Used to identify the cursor in the sp_rcontext.
+  int m_cursor_idx;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  The instruction corresponds to the FETCH statement.
+  It just forwards the close-call to the appropriate sp_cursor object in the
+  sp_rcontext.
+*/
+class sp_instr_cfetch : public sp_instr
+{
+public:
+  sp_instr_cfetch(uint ip, sp_pcontext *ctx, int cursor_idx)
+   :sp_instr(ip, ctx),
+    m_cursor_idx(cursor_idx)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp);
+
+  void add_to_varlist(sp_variable *var)
+  { m_varlist.push_back(var); }
+
+private:
+  /// List of SP-variables to store fetched values.
+  List<sp_variable> m_varlist;
+
+  /// Used to identify the cursor in the sp_rcontext.
+  int m_cursor_idx;
+};
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+
+/**
+  sp_instr_error just throws an SQL-condition if the execution flow comes to it.
+  It's used in the CASE implementation to perform runtime-check that the
+  CASE-expression is handled by some WHEN/ELSE clause.
+*/
+class sp_instr_error : public sp_instr
+{
+public:
+  sp_instr_error(uint ip, sp_pcontext *ctx, int errcode)
+   :sp_instr(ip, ctx),
+    m_errcode(errcode)
+  { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_printable implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual void print(String *str);
+
+  /////////////////////////////////////////////////////////////////////////
+  // sp_instr implementation.
+  /////////////////////////////////////////////////////////////////////////
+
+  virtual bool execute(THD *thd, uint *nextp)
+  {
+    my_message(m_errcode, ER(m_errcode), MYF(0));
+    *nextp= get_ip() + 1;
+    return true;
+  }
+
+  virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
+  {
+    m_marked= true;
+    return UINT_MAX;
+  }
+
+private:
+  /// The error code, which should be raised by this instruction.
+  int m_errcode;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif // _SP_INSTR_H_

=== modified file 'sql/sp_rcontext.cc'
--- a/sql/sp_rcontext.cc	2012-05-16 11:03:43 +0000
+++ b/sql/sp_rcontext.cc	2012-05-16 13:58:54 +0000
@@ -21,6 +21,7 @@
 #include "sp_rcontext.h"
 #include "sp_pcontext.h"
 #include "sql_tmp_table.h"                     // create_virtual_tmp_table
+#include "sp_instr.h"
 
 
 ///////////////////////////////////////////////////////////////////////////

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	2012-05-16 14:19:34 +0000
+++ b/sql/sql_acl.cc	2012-05-16 17:45:57 +0000
@@ -9721,7 +9721,7 @@ acl_authenticate(THD *thd, uint com_chan
     my_ok(thd);
 
 #ifdef HAVE_PSI_THREAD_INTERFACE
-  PSI_THREAD_CALL(set_thread_user_host)
+  PSI_THREAD_CALL(set_thread_account)
     (thd->main_security_ctx.user, strlen(thd->main_security_ctx.user),
     thd->main_security_ctx.host_or_ip, strlen(thd->main_security_ctx.host_or_ip));
 #endif

=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h	2012-03-08 14:22:07 +0000
+++ b/sql/sql_base.h	2012-05-16 17:27:18 +0000
@@ -611,5 +611,7 @@ private:
   int m_unhandled_errors;
 };
 
+#include "pfs_table_provider.h"
+#include "mysql/psi/mysql_table.h"
 
 #endif /* SQL_BASE_INCLUDED */

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2012-05-16 14:19:34 +0000
+++ b/sql/sql_class.h	2012-05-16 17:45:57 +0000
@@ -37,9 +37,15 @@
 #include "opt_trace_context.h"    /* Opt_trace_context */
 #include "rpl_gtid.h"
 
+#include <pfs_stage_provider.h>
 #include <mysql/psi/mysql_stage.h>
+
+#include <pfs_statement_provider.h>
 #include <mysql/psi/mysql_statement.h>
+
+#include <pfs_idle_provider.h>
 #include <mysql/psi/mysql_idle.h>
+
 #include <mysql_com_server.h>
 
 /**

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2012-05-16 14:19:34 +0000
+++ b/sql/sql_table.cc	2012-05-16 17:45:57 +0000
@@ -54,7 +54,6 @@
 #include "transaction.h"
 #include "datadict.h"  // dd_frm_type()
 #include "sql_resolver.h"              // setup_order, fix_inner_refs
-#include <mysql/psi/mysql_table.h>
 
 #ifdef __WIN__
 #include <io.h>

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2012-05-16 12:38:01 +0000
+++ b/sql/sql_yacc.yy	2012-05-16 13:58:54 +0000
@@ -50,6 +50,7 @@
 #include "lex_symbol.h"
 #include "item_create.h"
 #include "sp_head.h"
+#include "sp_instr.h"
 #include "sp_pcontext.h"
 #include "sp_rcontext.h"
 #include "sp.h"

=== modified file 'storage/innobase/include/univ.i'
--- a/storage/innobase/include/univ.i	2012-05-09 16:47:39 +0000
+++ b/storage/innobase/include/univ.i	2012-05-16 17:27:18 +0000
@@ -127,21 +127,35 @@ Sun Studio */
 #include <inttypes.h>
 #endif /* !__WIN__ */
 
+#if !defined UNIV_HOTBACKUP
+# if defined HAVE_PSI_INTERFACE
+#  include "mysql/psi/psi.h"
+# endif
+
 /* Following defines are to enable performance schema
-instrumentation in each of four InnoDB modules if
-HAVE_PSI_INTERFACE is defined. */
-#if defined HAVE_PSI_INTERFACE && !defined UNIV_HOTBACKUP
-# define UNIV_PFS_MUTEX
-# define UNIV_PFS_RWLOCK
+instrumentation in each of four InnoDB modules if the
+corresponding HAVE_PSI_XXX_INTERFACE is defined. */
+# if defined HAVE_PSI_MUTEX_INTERFACE
+#  define UNIV_PFS_MUTEX
+# endif
+# if defined HAVE_PSI_RWLOCK_INTERFACE
+#  define UNIV_PFS_RWLOCK
+# endif
 /* For I/O instrumentation, performance schema rely
 on a native descriptor to identify the file, this
 descriptor could conflict with our OS level descriptor.
 Disable IO instrumentation on Windows until this is
 resolved */
 # ifndef __WIN__
-#  define UNIV_PFS_IO
+#  if defined HAVE_PSI_FILE_INTERFACE
+#   define UNIV_PFS_IO
+#   include "mysql/psi/mysql_file.h"
+#  endif
+# endif
+# if defined HAVE_PSI_THREAD_INTERFACE
+#  define UNIV_PFS_THREAD
+#  include "mysql/psi/mysql_thread.h"
 # endif
-# define UNIV_PFS_THREAD
 
 /* There are mutexes/rwlocks that we want to exclude from
 instrumentation even if their corresponding performance schema
@@ -152,7 +166,7 @@ be excluded from instrumentation. */
 
 # define PFS_IS_INSTRUMENTED(key)	((key) != PFS_NOT_INSTRUMENTED)
 
-#endif /* HAVE_PSI_INTERFACE */
+#endif /* ! UNIV_HOTBACKUP */
 
 #ifdef __WIN__
 # define YY_NO_UNISTD_H 1

=== modified file 'storage/perfschema/pfs.cc'
--- a/storage/perfschema/pfs.cc	2012-05-15 09:42:30 +0000
+++ b/storage/perfschema/pfs.cc	2012-05-16 17:27:18 +0000
@@ -386,14 +386,14 @@ static inline int mysql_mutex_lock(
   struct PSI_mutex_locker *locker= NULL;
 
   ............... (a)
-  locker= PSI_server->start_mutex_wait(&state, that->p_psi,
-                                       PSI_MUTEX_LOCK, locker, src_file, src_line);
+  locker= PSI_MUTEX_CALL(start_mutex_wait)(&state, that->p_psi, PSI_MUTEX_LOCK,
+                                           locker, src_file, src_line);
 
   ............... (b)
   result= pthread_mutex_lock(&that->m_mutex);
 
   ............... (c)
-  PSI_server->end_mutex_wait(locker, result);
+  PSI_MUTEX_CALL(end_mutex_wait)(locker, result);
 
   return result;
 }
@@ -413,6 +413,62 @@ static inline int mysql_mutex_lock(...)
   return result;
 }
 @endverbatim
+
+  When the performance schema instrumentation is compiled in,
+  and when the code compiled is internal to the server implementation,
+  PSI_MUTEX_CALL expands directly to functions calls in the performance schema,
+  to make (a) and (c) calls as efficient as possible.
+
+@verbatim
+static inline int mysql_mutex_lock(...)
+{
+  int result;
+  struct PSI_mutex_locker_state state;
+  struct PSI_mutex_locker *locker= NULL;
+
+  ............... (a)
+  locker= pfs_start_mutex_wait_v1(&state, that->p_psi, PSI_MUTEX_LOCK,
+                                  locker, src_file, src_line);
+
+  ............... (b)
+  result= pthread_mutex_lock(&that->m_mutex);
+
+  ............... (c)
+  pfs_end_mutex_wait_v1(locker, result);
+
+  return result;
+}
+@endverbatim
+
+  When the performance schema instrumentation is compiled in,
+  and when the code compiled is external to the server implementation
+  (typically, a dynamic plugin),
+  PSI_MUTEX_CALL expands to dynamic calls to the underlying implementation,
+  using the PSI_server entry point.
+  This makes (a) and (c) slower, as a function pointer is used instead of a static call,
+  but also independent of the implementation, for binary compatibility.
+
+@verbatim
+static inline int mysql_mutex_lock(...)
+{
+  int result;
+  struct PSI_mutex_locker_state state;
+  struct PSI_mutex_locker *locker= NULL;
+
+  ............... (a)
+  locker= PSI_server->start_mutex_wait(&state, that->p_psi, PSI_MUTEX_LOCK,
+                                       locker, src_file, src_line);
+
+  ............... (b)
+  result= pthread_mutex_lock(&that->m_mutex);
+
+  ............... (c)
+  PSI_server->end_mutex_wait(locker, result);
+
+  return result;
+}
+@endverbatim
+
 */
 
 /**
@@ -1263,7 +1319,8 @@ static int build_prefix(const LEX_STRING
   DBUG_ASSERT(category != NULL);                                      \
   DBUG_ASSERT(info != NULL);                                          \
   if (unlikely(build_prefix(&PREFIX, category,                        \
-                   formatted_name, &prefix_length)))                  \
+                   formatted_name, &prefix_length)) ||                \
+      ! pfs_initialized)                                              \
   {                                                                   \
     for (; count>0; count--, info++)                                  \
       *(info->m_key)= 0;                                              \
@@ -1300,9 +1357,9 @@ C_MODE_START
   Implementation of the mutex instrumentation interface.
   @sa PSI_v1::register_mutex.
 */
-static void register_mutex_v1(const char *category,
-                              PSI_mutex_info_v1 *info,
-                              int count)
+void pfs_register_mutex_v1(const char *category,
+                           PSI_mutex_info_v1 *info,
+                           int count)
 {
   REGISTER_BODY_V1(PSI_mutex_key,
                    mutex_instrument_prefix,
@@ -1313,9 +1370,9 @@ static void register_mutex_v1(const char
   Implementation of the rwlock instrumentation interface.
   @sa PSI_v1::register_rwlock.
 */
-static void register_rwlock_v1(const char *category,
-                               PSI_rwlock_info_v1 *info,
-                               int count)
+void pfs_register_rwlock_v1(const char *category,
+                            PSI_rwlock_info_v1 *info,
+                            int count)
 {
   REGISTER_BODY_V1(PSI_rwlock_key,
                    rwlock_instrument_prefix,
@@ -1326,9 +1383,9 @@ static void register_rwlock_v1(const cha
   Implementation of the cond instrumentation interface.
   @sa PSI_v1::register_cond.
 */
-static void register_cond_v1(const char *category,
-                             PSI_cond_info_v1 *info,
-                             int count)
+void pfs_register_cond_v1(const char *category,
+                          PSI_cond_info_v1 *info,
+                          int count)
 {
   REGISTER_BODY_V1(PSI_cond_key,
                    cond_instrument_prefix,
@@ -1339,9 +1396,9 @@ static void register_cond_v1(const char
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::register_thread.
 */
-static void register_thread_v1(const char *category,
-                               PSI_thread_info_v1 *info,
-                               int count)
+void pfs_register_thread_v1(const char *category,
+                            PSI_thread_info_v1 *info,
+                            int count)
 {
   REGISTER_BODY_V1(PSI_thread_key,
                    thread_instrument_prefix,
@@ -1352,18 +1409,18 @@ static void register_thread_v1(const cha
   Implementation of the file instrumentation interface.
   @sa PSI_v1::register_file.
 */
-static void register_file_v1(const char *category,
-                             PSI_file_info_v1 *info,
-                             int count)
+void pfs_register_file_v1(const char *category,
+                          PSI_file_info_v1 *info,
+                          int count)
 {
   REGISTER_BODY_V1(PSI_file_key,
                    file_instrument_prefix,
                    register_file_class)
 }
 
-static void register_stage_v1(const char *category,
-                              PSI_stage_info_v1 **info_array,
-                              int count)
+void pfs_register_stage_v1(const char *category,
+                           PSI_stage_info_v1 **info_array,
+                           int count)
 {
   char formatted_name[PFS_MAX_INFO_NAME_LENGTH];
   int prefix_length;
@@ -1374,7 +1431,8 @@ static void register_stage_v1(const char
   DBUG_ASSERT(category != NULL);
   DBUG_ASSERT(info_array != NULL);
   if (unlikely(build_prefix(&stage_instrument_prefix, category,
-               formatted_name, &prefix_length)))
+               formatted_name, &prefix_length)) ||
+      ! pfs_initialized)
   {
     for (; count>0; count--, info_array++)
       (*info_array)->m_key= 0;
@@ -1404,9 +1462,9 @@ static void register_stage_v1(const char
   return;
 }
 
-static void register_statement_v1(const char *category,
-                                  PSI_statement_info_v1 *info,
-                                  int count)
+void pfs_register_statement_v1(const char *category,
+                               PSI_statement_info_v1 *info,
+                               int count)
 {
   char formatted_name[PFS_MAX_INFO_NAME_LENGTH];
   int prefix_length;
@@ -1416,7 +1474,8 @@ static void register_statement_v1(const
   DBUG_ASSERT(category != NULL);
   DBUG_ASSERT(info != NULL);
   if (unlikely(build_prefix(&statement_instrument_prefix,
-                            category, formatted_name, &prefix_length)))
+                            category, formatted_name, &prefix_length)) ||
+      ! pfs_initialized)
   {
     for (; count>0; count--, info++)
       info->m_key= 0;
@@ -1443,9 +1502,9 @@ static void register_statement_v1(const
   return;
 }
 
-static void register_socket_v1(const char *category,
-                             PSI_socket_info_v1 *info,
-                             int count)
+void pfs_register_socket_v1(const char *category,
+                            PSI_socket_info_v1 *info,
+                            int count)
 {
   REGISTER_BODY_V1(PSI_socket_key,
                    socket_instrument_prefix,
@@ -1467,8 +1526,8 @@ static void register_socket_v1(const cha
   Implementation of the mutex instrumentation interface.
   @sa PSI_v1::init_mutex.
 */
-static PSI_mutex*
-init_mutex_v1(PSI_mutex_key key, const void *identity)
+PSI_mutex*
+pfs_init_mutex_v1(PSI_mutex_key key, const void *identity)
 {
   INIT_BODY_V1(mutex, key, identity);
 }
@@ -1477,7 +1536,7 @@ init_mutex_v1(PSI_mutex_key key, const v
   Implementation of the mutex instrumentation interface.
   @sa PSI_v1::destroy_mutex.
 */
-static void destroy_mutex_v1(PSI_mutex* mutex)
+void pfs_destroy_mutex_v1(PSI_mutex* mutex)
 {
   PFS_mutex *pfs= reinterpret_cast<PFS_mutex*> (mutex);
 
@@ -1490,8 +1549,8 @@ static void destroy_mutex_v1(PSI_mutex*
   Implementation of the rwlock instrumentation interface.
   @sa PSI_v1::init_rwlock.
 */
-static PSI_rwlock*
-init_rwlock_v1(PSI_rwlock_key key, const void *identity)
+PSI_rwlock*
+pfs_init_rwlock_v1(PSI_rwlock_key key, const void *identity)
 {
   INIT_BODY_V1(rwlock, key, identity);
 }
@@ -1500,7 +1559,7 @@ init_rwlock_v1(PSI_rwlock_key key, const
   Implementation of the rwlock instrumentation interface.
   @sa PSI_v1::destroy_rwlock.
 */
-static void destroy_rwlock_v1(PSI_rwlock* rwlock)
+void pfs_destroy_rwlock_v1(PSI_rwlock* rwlock)
 {
   PFS_rwlock *pfs= reinterpret_cast<PFS_rwlock*> (rwlock);
 
@@ -1513,8 +1572,8 @@ static void destroy_rwlock_v1(PSI_rwlock
   Implementation of the cond instrumentation interface.
   @sa PSI_v1::init_cond.
 */
-static PSI_cond*
-init_cond_v1(PSI_cond_key key, const void *identity)
+PSI_cond*
+pfs_init_cond_v1(PSI_cond_key key, const void *identity)
 {
   INIT_BODY_V1(cond, key, identity);
 }
@@ -1523,7 +1582,7 @@ init_cond_v1(PSI_cond_key key, const voi
   Implementation of the cond instrumentation interface.
   @sa PSI_v1::destroy_cond.
 */
-static void destroy_cond_v1(PSI_cond* cond)
+void pfs_destroy_cond_v1(PSI_cond* cond)
 {
   PFS_cond *pfs= reinterpret_cast<PFS_cond*> (cond);
 
@@ -1536,8 +1595,8 @@ static void destroy_cond_v1(PSI_cond* co
   Implementation of the table instrumentation interface.
   @sa PSI_v1::get_table_share.
 */
-static PSI_table_share*
-get_table_share_v1(my_bool temporary, TABLE_SHARE *share)
+PSI_table_share*
+pfs_get_table_share_v1(my_bool temporary, TABLE_SHARE *share)
 {
   /* Ignore temporary tables and views. */
   if (temporary || share->is_view)
@@ -1555,7 +1614,7 @@ get_table_share_v1(my_bool temporary, TA
   Implementation of the table instrumentation interface.
   @sa PSI_v1::release_table_share.
 */
-static void release_table_share_v1(PSI_table_share* share)
+void pfs_release_table_share_v1(PSI_table_share* share)
 {
   PFS_table_share* pfs= reinterpret_cast<PFS_table_share*> (share);
 
@@ -1569,10 +1628,10 @@ static void release_table_share_v1(PSI_t
   Implementation of the table instrumentation interface.
   @sa PSI_v1::drop_table_share.
 */
-static void
-drop_table_share_v1(my_bool temporary,
-                    const char *schema_name, int schema_name_length,
-                    const char *table_name, int table_name_length)
+void
+pfs_drop_table_share_v1(my_bool temporary,
+                        const char *schema_name, int schema_name_length,
+                        const char *table_name, int table_name_length)
 {
   /* Ignore temporary tables. */
   if (temporary)
@@ -1589,8 +1648,8 @@ drop_table_share_v1(my_bool temporary,
   Implementation of the table instrumentation interface.
   @sa PSI_v1::open_table.
 */
-static PSI_table*
-open_table_v1(PSI_table_share *share, const void *identity)
+PSI_table*
+pfs_open_table_v1(PSI_table_share *share, const void *identity)
 {
   PFS_table_share *pfs_table_share= reinterpret_cast<PFS_table_share*> (share);
 
@@ -1625,7 +1684,7 @@ open_table_v1(PSI_table_share *share, co
   Implementation of the table instrumentation interface.
   @sa PSI_v1::unbind_table.
 */
-static void unbind_table_v1(PSI_table *table)
+void pfs_unbind_table_v1(PSI_table *table)
 {
   PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
   if (likely(pfs != NULL))
@@ -1638,8 +1697,8 @@ static void unbind_table_v1(PSI_table *t
   Implementation of the table instrumentation interface.
   @sa PSI_v1::rebind_table.
 */
-static PSI_table *
-rebind_table_v1(PSI_table_share *share, const void *identity, PSI_table *table)
+PSI_table *
+pfs_rebind_table_v1(PSI_table_share *share, const void *identity, PSI_table *table)
 {
   PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
   if (likely(pfs != NULL))
@@ -1698,7 +1757,7 @@ rebind_table_v1(PSI_table_share *share,
   Implementation of the table instrumentation interface.
   @sa PSI_v1::close_table.
 */
-static void close_table_v1(PSI_table *table)
+void pfs_close_table_v1(PSI_table *table)
 {
   PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
   if (unlikely(pfs == NULL))
@@ -1707,13 +1766,13 @@ static void close_table_v1(PSI_table *ta
   destroy_table(pfs);
 }
 
-static PSI_socket*
-init_socket_v1(PSI_socket_key key, const my_socket *fd)
+PSI_socket*
+pfs_init_socket_v1(PSI_socket_key key, const my_socket *fd)
 {
   INIT_BODY_V1(socket, key, fd);
 }
 
-static void destroy_socket_v1(PSI_socket *socket)
+void pfs_destroy_socket_v1(PSI_socket *socket)
 {
   PFS_socket *pfs= reinterpret_cast<PFS_socket*> (socket);
 
@@ -1726,7 +1785,7 @@ static void destroy_socket_v1(PSI_socket
   Implementation of the file instrumentation interface.
   @sa PSI_v1::create_file.
 */
-static void create_file_v1(PSI_file_key key, const char *name, File file)
+void pfs_create_file_v1(PSI_file_key key, const char *name, File file)
 {
   if (! flag_global_instrumentation)
     return;
@@ -1833,9 +1892,9 @@ void* pfs_spawn_thread(void *arg)
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::spawn_thread.
 */
-static int spawn_thread_v1(PSI_thread_key key,
-                           pthread_t *thread, const pthread_attr_t *attr,
-                           void *(*start_routine)(void*), void *arg)
+int pfs_spawn_thread_v1(PSI_thread_key key,
+                        pthread_t *thread, const pthread_attr_t *attr,
+                        void *(*start_routine)(void*), void *arg)
 {
   PFS_spawn_thread_arg *psi_arg;
 
@@ -1861,8 +1920,8 @@ static int spawn_thread_v1(PSI_thread_ke
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::new_thread.
 */
-static PSI_thread*
-new_thread_v1(PSI_thread_key key, const void *identity, ulong thread_id)
+PSI_thread*
+pfs_new_thread_v1(PSI_thread_key key, const void *identity, ulong thread_id)
 {
   PFS_thread *pfs;
 
@@ -1879,7 +1938,7 @@ new_thread_v1(PSI_thread_key key, const
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::set_thread_id.
 */
-static void set_thread_id_v1(PSI_thread *thread, unsigned long id)
+void pfs_set_thread_id_v1(PSI_thread *thread, unsigned long id)
 {
   PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread);
   if (unlikely(pfs == NULL))
@@ -1891,8 +1950,8 @@ static void set_thread_id_v1(PSI_thread
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::get_thread_id.
 */
-static PSI_thread*
-get_thread_v1(void)
+PSI_thread*
+pfs_get_thread_v1(void)
 {
   PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
   return reinterpret_cast<PSI_thread*> (pfs);
@@ -1902,7 +1961,7 @@ get_thread_v1(void)
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::set_thread_user.
 */
-static void set_thread_user_v1(const char *user, int user_len)
+void pfs_set_thread_user_v1(const char *user, int user_len)
 {
   PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
 
@@ -1952,8 +2011,8 @@ static void set_thread_user_v1(const cha
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::set_thread_account.
 */
-static void set_thread_account_v1(const char *user, int user_len,
-                                    const char *host, int host_len)
+void pfs_set_thread_account_v1(const char *user, int user_len,
+                               const char *host, int host_len)
 {
   PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
 
@@ -2007,7 +2066,7 @@ static void set_thread_account_v1(const
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::set_thread_db.
 */
-static void set_thread_db_v1(const char* db, int db_len)
+void pfs_set_thread_db_v1(const char* db, int db_len)
 {
   PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
 
@@ -2029,7 +2088,7 @@ static void set_thread_db_v1(const char*
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::set_thread_command.
 */
-static void set_thread_command_v1(int command)
+void pfs_set_thread_command_v1(int command)
 {
   PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
 
@@ -2048,7 +2107,7 @@ static void set_thread_command_v1(int co
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::set_thread_start_time.
 */
-static void set_thread_start_time_v1(time_t start_time)
+void pfs_set_thread_start_time_v1(time_t start_time)
 {
   PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
 
@@ -2064,7 +2123,7 @@ static void set_thread_start_time_v1(tim
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::set_thread_state.
 */
-static void set_thread_state_v1(const char* state)
+void pfs_set_thread_state_v1(const char* state)
 {
   PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
 
@@ -2083,7 +2142,7 @@ static void set_thread_state_v1(const ch
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::set_thread_info.
 */
-static void set_thread_info_v1(const char* info, int info_len)
+void pfs_set_thread_info_v1(const char* info, int info_len)
 {
   PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
 
@@ -2100,7 +2159,7 @@ static void set_thread_info_v1(const cha
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::set_thread.
 */
-static void set_thread_v1(PSI_thread* thread)
+void pfs_set_thread_v1(PSI_thread* thread)
 {
   PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread);
   my_pthread_setspecific_ptr(THR_PFS, pfs);
@@ -2110,7 +2169,7 @@ static void set_thread_v1(PSI_thread* th
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::delete_current_thread.
 */
-static void delete_current_thread_v1(void)
+void pfs_delete_current_thread_v1(void)
 {
   PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
   if (thread != NULL)
@@ -2125,7 +2184,7 @@ static void delete_current_thread_v1(voi
   Implementation of the thread instrumentation interface.
   @sa PSI_v1::delete_thread.
 */
-static void delete_thread_v1(PSI_thread *thread)
+void pfs_delete_thread_v1(PSI_thread *thread)
 {
   PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread);
 
@@ -2140,10 +2199,10 @@ static void delete_thread_v1(PSI_thread
   Implementation of the mutex instrumentation interface.
   @sa PSI_v1::start_mutex_wait.
 */
-static PSI_mutex_locker*
-start_mutex_wait_v1(PSI_mutex_locker_state *state,
-                    PSI_mutex *mutex, PSI_mutex_operation op,
-                    const char *src_file, uint src_line)
+PSI_mutex_locker*
+pfs_start_mutex_wait_v1(PSI_mutex_locker_state *state,
+                        PSI_mutex *mutex, PSI_mutex_operation op,
+                        const char *src_file, uint src_line)
 {
   PFS_mutex *pfs_mutex= reinterpret_cast<PFS_mutex*> (mutex);
   DBUG_ASSERT((int) op >= 0);
@@ -2238,11 +2297,11 @@ start_mutex_wait_v1(PSI_mutex_locker_sta
   @sa PSI_v1::start_rwlock_rdwait
   @sa PSI_v1::start_rwlock_wrwait
 */
-static PSI_rwlock_locker*
-start_rwlock_wait_v1(PSI_rwlock_locker_state *state,
-                     PSI_rwlock *rwlock,
-                     PSI_rwlock_operation op,
-                     const char *src_file, uint src_line)
+PSI_rwlock_locker*
+pfs_start_rwlock_rdwait_v1(PSI_rwlock_locker_state *state,
+                           PSI_rwlock *rwlock,
+                           PSI_rwlock_operation op,
+                           const char *src_file, uint src_line)
 {
   PFS_rwlock *pfs_rwlock= reinterpret_cast<PFS_rwlock*> (rwlock);
   DBUG_ASSERT(static_cast<int> (op) >= 0);
@@ -2331,15 +2390,24 @@ start_rwlock_wait_v1(PSI_rwlock_locker_s
   return reinterpret_cast<PSI_rwlock_locker*> (state);
 }
 
+PSI_rwlock_locker*
+pfs_start_rwlock_wrwait_v1(PSI_rwlock_locker_state *state,
+                           PSI_rwlock *rwlock,
+                           PSI_rwlock_operation op,
+                           const char *src_file, uint src_line)
+{
+  return pfs_start_rwlock_rdwait_v1(state, rwlock, op, src_file, src_line);
+}
+
 /**
   Implementation of the cond instrumentation interface.
   @sa PSI_v1::start_cond_wait.
 */
-static PSI_cond_locker*
-start_cond_wait_v1(PSI_cond_locker_state *state,
-                   PSI_cond *cond, PSI_mutex *mutex,
-                   PSI_cond_operation op,
-                   const char *src_file, uint src_line)
+PSI_cond_locker*
+pfs_start_cond_wait_v1(PSI_cond_locker_state *state,
+                       PSI_cond *cond, PSI_mutex *mutex,
+                       PSI_cond_operation op,
+                       const char *src_file, uint src_line)
 {
   /*
     Note about the unused PSI_mutex *mutex parameter:
@@ -2487,12 +2555,12 @@ static inline PFS_TL_LOCK_TYPE external_
   Implementation of the table instrumentation interface.
   @sa PSI_v1::start_table_io_wait_v1
 */
-static PSI_table_locker*
-start_table_io_wait_v1(PSI_table_locker_state *state,
-                       PSI_table *table,
-                       PSI_table_io_operation op,
-                       uint index,
-                       const char *src_file, uint src_line)
+PSI_table_locker*
+pfs_start_table_io_wait_v1(PSI_table_locker_state *state,
+                           PSI_table *table,
+                           PSI_table_io_operation op,
+                           uint index,
+                           const char *src_file, uint src_line)
 {
   DBUG_ASSERT(static_cast<int> (op) >= 0);
   DBUG_ASSERT(static_cast<uint> (op) < array_elements(table_io_operation_map));
@@ -2592,12 +2660,12 @@ start_table_io_wait_v1(PSI_table_locker_
   Implementation of the table instrumentation interface.
   @sa PSI_v1::start_table_lock_wait.
 */
-static PSI_table_locker*
-start_table_lock_wait_v1(PSI_table_locker_state *state,
-                         PSI_table *table,
-                         PSI_table_lock_operation op,
-                         ulong op_flags,
-                         const char *src_file, uint src_line)
+PSI_table_locker*
+pfs_start_table_lock_wait_v1(PSI_table_locker_state *state,
+                             PSI_table *table,
+                             PSI_table_lock_operation op,
+                             ulong op_flags,
+                             const char *src_file, uint src_line)
 {
   DBUG_ASSERT(state != NULL);
   DBUG_ASSERT((op == PSI_TABLE_LOCK) || (op == PSI_TABLE_EXTERNAL_LOCK));
@@ -2720,11 +2788,11 @@ start_table_lock_wait_v1(PSI_table_locke
   Implementation of the file instrumentation interface.
   @sa PSI_v1::get_thread_file_name_locker.
 */
-static PSI_file_locker*
-get_thread_file_name_locker_v1(PSI_file_locker_state *state,
-                               PSI_file_key key,
-                               PSI_file_operation op,
-                               const char *name, const void *identity)
+PSI_file_locker*
+pfs_get_thread_file_name_locker_v1(PSI_file_locker_state *state,
+                                   PSI_file_key key,
+                                   PSI_file_operation op,
+                                   const char *name, const void *identity)
 {
   DBUG_ASSERT(static_cast<int> (op) >= 0);
   DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map));
@@ -2801,9 +2869,9 @@ get_thread_file_name_locker_v1(PSI_file_
   Implementation of the file instrumentation interface.
   @sa PSI_v1::get_thread_file_stream_locker.
 */
-static PSI_file_locker*
-get_thread_file_stream_locker_v1(PSI_file_locker_state *state,
-                                 PSI_file *file, PSI_file_operation op)
+PSI_file_locker*
+pfs_get_thread_file_stream_locker_v1(PSI_file_locker_state *state,
+                                     PSI_file *file, PSI_file_operation op)
 {
   PFS_file *pfs_file= reinterpret_cast<PFS_file*> (file);
   DBUG_ASSERT(static_cast<int> (op) >= 0);
@@ -2888,9 +2956,9 @@ get_thread_file_stream_locker_v1(PSI_fil
   Implementation of the file instrumentation interface.
   @sa PSI_v1::get_thread_file_descriptor_locker.
 */
-static PSI_file_locker*
-get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state,
-                                     File file, PSI_file_operation op)
+PSI_file_locker*
+pfs_get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state,
+                                         File file, PSI_file_operation op)
 {
   int index= static_cast<int> (file);
   DBUG_ASSERT(static_cast<int> (op) >= 0);
@@ -2988,12 +3056,12 @@ get_thread_file_descriptor_locker_v1(PSI
 
 /** Socket locker */
 
-static PSI_socket_locker*
-start_socket_wait_v1(PSI_socket_locker_state *state,
-                     PSI_socket *socket,
-                     PSI_socket_operation op,
-                     size_t count,
-                     const char *src_file, uint src_line)
+PSI_socket_locker*
+pfs_start_socket_wait_v1(PSI_socket_locker_state *state,
+                         PSI_socket *socket,
+                         PSI_socket_operation op,
+                         size_t count,
+                         const char *src_file, uint src_line)
 {
   DBUG_ASSERT(static_cast<int> (op) >= 0);
   DBUG_ASSERT(static_cast<uint> (op) < array_elements(socket_operation_map));
@@ -3116,7 +3184,7 @@ start_socket_wait_v1(PSI_socket_locker_s
   Implementation of the mutex instrumentation interface.
   @sa PSI_v1::unlock_mutex.
 */
-static void unlock_mutex_v1(PSI_mutex *mutex)
+void pfs_unlock_mutex_v1(PSI_mutex *mutex)
 {
   PFS_mutex *pfs_mutex= reinterpret_cast<PFS_mutex*> (mutex);
 
@@ -3160,7 +3228,7 @@ static void unlock_mutex_v1(PSI_mutex *m
   Implementation of the rwlock instrumentation interface.
   @sa PSI_v1::unlock_rwlock.
 */
-static void unlock_rwlock_v1(PSI_rwlock *rwlock)
+void pfs_unlock_rwlock_v1(PSI_rwlock *rwlock)
 {
   PFS_rwlock *pfs_rwlock= reinterpret_cast<PFS_rwlock*> (rwlock);
   DBUG_ASSERT(pfs_rwlock != NULL);
@@ -3247,7 +3315,7 @@ static void unlock_rwlock_v1(PSI_rwlock
   Implementation of the cond instrumentation interface.
   @sa PSI_v1::signal_cond.
 */
-static void signal_cond_v1(PSI_cond* cond)
+void pfs_signal_cond_v1(PSI_cond* cond)
 {
   PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond);
 
@@ -3260,7 +3328,7 @@ static void signal_cond_v1(PSI_cond* con
   Implementation of the cond instrumentation interface.
   @sa PSI_v1::broadcast_cond.
 */
-static void broadcast_cond_v1(PSI_cond* cond)
+void pfs_broadcast_cond_v1(PSI_cond* cond)
 {
   PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond);
 
@@ -3273,8 +3341,8 @@ static void broadcast_cond_v1(PSI_cond*
   Implementation of the idle instrumentation interface.
   @sa PSI_v1::start_idle_wait.
 */
-static PSI_idle_locker*
-start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_line)
+PSI_idle_locker*
+pfs_start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_line)
 {
   DBUG_ASSERT(state != NULL);
 
@@ -3357,7 +3425,7 @@ start_idle_wait_v1(PSI_idle_locker_state
   Implementation of the mutex instrumentation interface.
   @sa PSI_v1::end_idle_wait.
 */
-static void end_idle_wait_v1(PSI_idle_locker* locker)
+void pfs_end_idle_wait_v1(PSI_idle_locker* locker)
 {
   PSI_idle_locker_state *state= reinterpret_cast<PSI_idle_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
@@ -3409,7 +3477,7 @@ static void end_idle_wait_v1(PSI_idle_lo
   Implementation of the mutex instrumentation interface.
   @sa PSI_v1::end_mutex_wait.
 */
-static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc)
+void pfs_end_mutex_wait_v1(PSI_mutex_locker* locker, int rc)
 {
   PSI_mutex_locker_state *state= reinterpret_cast<PSI_mutex_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
@@ -3479,7 +3547,7 @@ static void end_mutex_wait_v1(PSI_mutex_
   Implementation of the rwlock instrumentation interface.
   @sa PSI_v1::end_rwlock_rdwait.
 */
-static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc)
+void pfs_end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc)
 {
   PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
@@ -3558,7 +3626,7 @@ static void end_rwlock_rdwait_v1(PSI_rwl
   Implementation of the rwlock instrumentation interface.
   @sa PSI_v1::end_rwlock_wrwait.
 */
-static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc)
+void pfs_end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc)
 {
   PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
@@ -3630,7 +3698,7 @@ static void end_rwlock_wrwait_v1(PSI_rwl
   Implementation of the cond instrumentation interface.
   @sa PSI_v1::end_cond_wait.
 */
-static void end_cond_wait_v1(PSI_cond_locker* locker, int rc)
+void pfs_end_cond_wait_v1(PSI_cond_locker* locker, int rc)
 {
   PSI_cond_locker_state *state= reinterpret_cast<PSI_cond_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
@@ -3694,7 +3762,7 @@ static void end_cond_wait_v1(PSI_cond_lo
   Implementation of the table instrumentation interface.
   @sa PSI_v1::end_table_io_wait.
 */
-static void end_table_io_wait_v1(PSI_table_locker* locker)
+void pfs_end_table_io_wait_v1(PSI_table_locker* locker)
 {
   PSI_table_locker_state *state= reinterpret_cast<PSI_table_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
@@ -3790,7 +3858,7 @@ static void end_table_io_wait_v1(PSI_tab
   Implementation of the table instrumentation interface.
   @sa PSI_v1::end_table_lock_wait.
 */
-static void end_table_lock_wait_v1(PSI_table_locker* locker)
+void pfs_end_table_lock_wait_v1(PSI_table_locker* locker)
 {
   PSI_table_locker_state *state= reinterpret_cast<PSI_table_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
@@ -3855,26 +3923,26 @@ static void end_table_lock_wait_v1(PSI_t
   table->m_has_lock_stats= true;
 }
 
-static void start_file_wait_v1(PSI_file_locker *locker,
-                               size_t count,
-                               const char *src_file,
-                               uint src_line);
+void pfs_start_file_wait_v1(PSI_file_locker *locker,
+                            size_t count,
+                            const char *src_file,
+                            uint src_line);
 
-static void end_file_wait_v1(PSI_file_locker *locker,
-                             size_t count);
+void pfs_end_file_wait_v1(PSI_file_locker *locker,
+                          size_t count);
 
 /**
   Implementation of the file instrumentation interface.
   @sa PSI_v1::start_file_open_wait.
 */
-static PSI_file* start_file_open_wait_v1(PSI_file_locker *locker,
-                                         const char *src_file,
-                                         uint src_line)
+PSI_file* pfs_start_file_open_wait_v1(PSI_file_locker *locker,
+                                      const char *src_file,
+                                      uint src_line)
 {
   PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
 
-  start_file_wait_v1(locker, 0, src_file, src_line);
+  pfs_start_file_wait_v1(locker, 0, src_file, src_line);
 
   return state->m_file;
 }
@@ -3883,23 +3951,23 @@ static PSI_file* start_file_open_wait_v1
   Implementation of the file instrumentation interface.
   @sa PSI_v1::end_file_open_wait.
 */
-static void end_file_open_wait_v1(PSI_file_locker *locker)
+void pfs_end_file_open_wait_v1(PSI_file_locker *locker)
 {
-  end_file_wait_v1(locker, 0);
+  pfs_end_file_wait_v1(locker, 0);
 }
 
 /**
   Implementation of the file instrumentation interface.
   @sa PSI_v1::end_file_open_wait_and_bind_to_descriptor.
 */
-static void end_file_open_wait_and_bind_to_descriptor_v1
+void pfs_end_file_open_wait_and_bind_to_descriptor_v1
   (PSI_file_locker *locker, File file)
 {
   int index= (int) file;
   PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
 
-  end_file_wait_v1(locker, 0);
+  pfs_end_file_wait_v1(locker, 0);
 
   PFS_file *pfs_file= reinterpret_cast<PFS_file*> (state->m_file);
   DBUG_ASSERT(pfs_file != NULL);
@@ -3921,10 +3989,10 @@ static void end_file_open_wait_and_bind_
   Implementation of the file instrumentation interface.
   @sa PSI_v1::start_file_wait.
 */
-static void start_file_wait_v1(PSI_file_locker *locker,
-                               size_t count,
-                               const char *src_file,
-                               uint src_line)
+void pfs_start_file_wait_v1(PSI_file_locker *locker,
+                            size_t count,
+                            const char *src_file,
+                            uint src_line)
 {
   ulonglong timer_start= 0;
   PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
@@ -3954,8 +4022,8 @@ static void start_file_wait_v1(PSI_file_
   Implementation of the file instrumentation interface.
   @sa PSI_v1::end_file_wait.
 */
-static void end_file_wait_v1(PSI_file_locker *locker,
-                             size_t byte_count)
+void pfs_end_file_wait_v1(PSI_file_locker *locker,
+                          size_t byte_count)
 {
   PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
@@ -4070,7 +4138,7 @@ static void end_file_wait_v1(PSI_file_lo
   }
 }
 
-static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line)
+void pfs_start_stage_v1(PSI_stage_key key, const char *src_file, int src_line)
 {
   ulonglong timer_value= 0;
 
@@ -4168,7 +4236,7 @@ static void start_stage_v1(PSI_stage_key
   }
 }
 
-static void end_stage_v1()
+void pfs_end_stage_v1()
 {
   ulonglong timer_value= 0;
 
@@ -4227,10 +4295,10 @@ static void end_stage_v1()
   }
 }
 
-static PSI_statement_locker*
-get_thread_statement_locker_v1(PSI_statement_locker_state *state,
-                               PSI_statement_key key,
-                               const void *charset)
+PSI_statement_locker*
+pfs_get_thread_statement_locker_v1(PSI_statement_locker_state *state,
+                                   PSI_statement_key key,
+                                   const void *charset)
 {
   DBUG_ASSERT(state != NULL);
   if (! flag_global_instrumentation)
@@ -4357,9 +4425,9 @@ get_thread_statement_locker_v1(PSI_state
   return reinterpret_cast<PSI_statement_locker*> (state);
 }
 
-static PSI_statement_locker*
-refine_statement_v1(PSI_statement_locker *locker,
-                    PSI_statement_key key)
+PSI_statement_locker*
+pfs_refine_statement_v1(PSI_statement_locker *locker,
+                        PSI_statement_key key)
 {
   PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
   if (state == NULL)
@@ -4402,9 +4470,9 @@ refine_statement_v1(PSI_statement_locker
   return reinterpret_cast<PSI_statement_locker*> (state);
 }
 
-static void start_statement_v1(PSI_statement_locker *locker,
-                               const char *db, uint db_len,
-                               const char *src_file, uint src_line)
+void pfs_start_statement_v1(PSI_statement_locker *locker,
+                            const char *db, uint db_len,
+                            const char *src_file, uint src_line)
 {
   PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
@@ -4434,8 +4502,8 @@ static void start_statement_v1(PSI_state
   }
 }
 
-static void set_statement_text_v1(PSI_statement_locker *locker,
-                                  const char *text, uint text_len)
+void pfs_set_statement_text_v1(PSI_statement_locker *locker,
+                               const char *text, uint text_len)
 {
   PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
@@ -4491,101 +4559,101 @@ static void set_statement_text_v1(PSI_st
   }                                                                     \
   return;
 
-static void set_statement_lock_time_v1(PSI_statement_locker *locker,
-                                       ulonglong count)
+void pfs_set_statement_lock_time_v1(PSI_statement_locker *locker,
+                                    ulonglong count)
 {
   SET_STATEMENT_ATTR_BODY(locker, m_lock_time, count);
 }
 
-static void set_statement_rows_sent_v1(PSI_statement_locker *locker,
-                                       ulonglong count)
+void pfs_set_statement_rows_sent_v1(PSI_statement_locker *locker,
+                                    ulonglong count)
 {
   SET_STATEMENT_ATTR_BODY(locker, m_rows_sent, count);
 }
 
-static void set_statement_rows_examined_v1(PSI_statement_locker *locker,
-                                           ulonglong count)
+void pfs_set_statement_rows_examined_v1(PSI_statement_locker *locker,
+                                        ulonglong count)
 {
   SET_STATEMENT_ATTR_BODY(locker, m_rows_examined, count);
 }
 
-static void inc_statement_created_tmp_disk_tables_v1(PSI_statement_locker *locker,
-                                                    ulong count)
+void pfs_inc_statement_created_tmp_disk_tables_v1(PSI_statement_locker *locker,
+                                                  ulong count)
 {
   INC_STATEMENT_ATTR_BODY(locker, m_created_tmp_disk_tables, count);
 }
 
-static void inc_statement_created_tmp_tables_v1(PSI_statement_locker *locker,
-                                                ulong count)
+void pfs_inc_statement_created_tmp_tables_v1(PSI_statement_locker *locker,
+                                             ulong count)
 {
   INC_STATEMENT_ATTR_BODY(locker, m_created_tmp_tables, count);
 }
 
-static void inc_statement_select_full_join_v1(PSI_statement_locker *locker,
-                                              ulong count)
+void pfs_inc_statement_select_full_join_v1(PSI_statement_locker *locker,
+                                           ulong count)
 {
   INC_STATEMENT_ATTR_BODY(locker, m_select_full_join, count);
 }
 
-static void inc_statement_select_full_range_join_v1(PSI_statement_locker *locker,
-                                                    ulong count)
+void pfs_inc_statement_select_full_range_join_v1(PSI_statement_locker *locker,
+                                                 ulong count)
 {
   INC_STATEMENT_ATTR_BODY(locker, m_select_full_range_join, count);
 }
 
-static void inc_statement_select_range_v1(PSI_statement_locker *locker,
-                                          ulong count)
+void pfs_inc_statement_select_range_v1(PSI_statement_locker *locker,
+                                       ulong count)
 {
   INC_STATEMENT_ATTR_BODY(locker, m_select_range, count);
 }
 
-static void inc_statement_select_range_check_v1(PSI_statement_locker *locker,
-                                                ulong count)
+void pfs_inc_statement_select_range_check_v1(PSI_statement_locker *locker,
+                                             ulong count)
 {
   INC_STATEMENT_ATTR_BODY(locker, m_select_range_check, count);
 }
 
-static void inc_statement_select_scan_v1(PSI_statement_locker *locker,
-                                         ulong count)
+void pfs_inc_statement_select_scan_v1(PSI_statement_locker *locker,
+                                      ulong count)
 {
   INC_STATEMENT_ATTR_BODY(locker, m_select_scan, count);
 }
 
-static void inc_statement_sort_merge_passes_v1(PSI_statement_locker *locker,
-                                               ulong count)
+void pfs_inc_statement_sort_merge_passes_v1(PSI_statement_locker *locker,
+                                            ulong count)
 {
   INC_STATEMENT_ATTR_BODY(locker, m_sort_merge_passes, count);
 }
 
-static void inc_statement_sort_range_v1(PSI_statement_locker *locker,
-                                        ulong count)
+void pfs_inc_statement_sort_range_v1(PSI_statement_locker *locker,
+                                     ulong count)
 {
   INC_STATEMENT_ATTR_BODY(locker, m_sort_range, count);
 }
 
-static void inc_statement_sort_rows_v1(PSI_statement_locker *locker,
-                                       ulong count)
+void pfs_inc_statement_sort_rows_v1(PSI_statement_locker *locker,
+                                    ulong count)
 {
   INC_STATEMENT_ATTR_BODY(locker, m_sort_rows, count);
 }
 
-static void inc_statement_sort_scan_v1(PSI_statement_locker *locker,
-                                       ulong count)
+void pfs_inc_statement_sort_scan_v1(PSI_statement_locker *locker,
+                                    ulong count)
 {
   INC_STATEMENT_ATTR_BODY(locker, m_sort_scan, count);
 }
 
-static void set_statement_no_index_used_v1(PSI_statement_locker *locker)
+void pfs_set_statement_no_index_used_v1(PSI_statement_locker *locker)
 {
   SET_STATEMENT_ATTR_BODY(locker, m_no_index_used, 1);
 }
 
-static void set_statement_no_good_index_used_v1(PSI_statement_locker *locker)
+void pfs_set_statement_no_good_index_used_v1(PSI_statement_locker *locker)
 {
   SET_STATEMENT_ATTR_BODY(locker, m_no_good_index_used, 1);
 }
 
-static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da)
+void pfs_end_statement_v1(PSI_statement_locker *locker, void *stmt_da)
 {
   PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker);
   Diagnostics_area *da= reinterpret_cast<Diagnostics_area*> (stmt_da);
@@ -4799,7 +4867,7 @@ static void end_statement_v1(PSI_stateme
   Implementation of the socket instrumentation interface.
   @sa PSI_v1::end_socket_wait.
 */
-static void end_socket_wait_v1(PSI_socket_locker *locker, size_t byte_count)
+void pfs_end_socket_wait_v1(PSI_socket_locker *locker, size_t byte_count)
 {
   PSI_socket_locker_state *state= reinterpret_cast<PSI_socket_locker_state*> (locker);
   DBUG_ASSERT(state != NULL);
@@ -4880,7 +4948,7 @@ static void end_socket_wait_v1(PSI_socke
   }
 }
 
-static void set_socket_state_v1(PSI_socket *socket, PSI_socket_state state)
+void pfs_set_socket_state_v1(PSI_socket *socket, PSI_socket_state state)
 {
   DBUG_ASSERT((state == PSI_SOCKET_STATE_IDLE) || (state == PSI_SOCKET_STATE_ACTIVE));
   PFS_socket *pfs= reinterpret_cast<PFS_socket*>(socket);
@@ -4893,10 +4961,10 @@ static void set_socket_state_v1(PSI_sock
 /**
   Set socket descriptor and address info.
 */
-static void set_socket_info_v1(PSI_socket *socket,
-                               const my_socket *fd,
-                               const struct sockaddr *addr,
-                               socklen_t addr_len)
+void pfs_set_socket_info_v1(PSI_socket *socket,
+                            const my_socket *fd,
+                            const struct sockaddr *addr,
+                            socklen_t addr_len)
 {
   PFS_socket *pfs= reinterpret_cast<PFS_socket*>(socket);
   DBUG_ASSERT(pfs != NULL);
@@ -4922,7 +4990,7 @@ static void set_socket_info_v1(PSI_socke
   Implementation of the socket instrumentation interface.
   @sa PSI_v1::set_socket_info.
 */
-static void set_socket_thread_owner_v1(PSI_socket *socket)
+void pfs_set_socket_thread_owner_v1(PSI_socket *socket)
 {
   PFS_socket *pfs_socket= reinterpret_cast<PFS_socket*>(socket);
   DBUG_ASSERT(pfs_socket != NULL);
@@ -4935,98 +5003,98 @@ static void set_socket_thread_owner_v1(P
 */
 PSI_v1 PFS_v1=
 {
-  register_mutex_v1,
-  register_rwlock_v1,
-  register_cond_v1,
-  register_thread_v1,
-  register_file_v1,
-  register_stage_v1,
-  register_statement_v1,
-  register_socket_v1,
-  init_mutex_v1,
-  destroy_mutex_v1,
-  init_rwlock_v1,
-  destroy_rwlock_v1,
-  init_cond_v1,
-  destroy_cond_v1,
-  init_socket_v1,
-  destroy_socket_v1,
-  get_table_share_v1,
-  release_table_share_v1,
-  drop_table_share_v1,
-  open_table_v1,
-  unbind_table_v1,
-  rebind_table_v1,
-  close_table_v1,
-  create_file_v1,
-  spawn_thread_v1,
-  new_thread_v1,
-  set_thread_id_v1,
-  get_thread_v1,
-  set_thread_user_v1,
-  set_thread_account_v1,
-  set_thread_db_v1,
-  set_thread_command_v1,
-  set_thread_start_time_v1,
-  set_thread_state_v1,
-  set_thread_info_v1,
-  set_thread_v1,
-  delete_current_thread_v1,
-  delete_thread_v1,
-  get_thread_file_name_locker_v1,
-  get_thread_file_stream_locker_v1,
-  get_thread_file_descriptor_locker_v1,
-  unlock_mutex_v1,
-  unlock_rwlock_v1,
-  signal_cond_v1,
-  broadcast_cond_v1,
-  start_idle_wait_v1,
-  end_idle_wait_v1,
-  start_mutex_wait_v1,
-  end_mutex_wait_v1,
-  start_rwlock_wait_v1, /* read */
-  end_rwlock_rdwait_v1,
-  start_rwlock_wait_v1, /* write */
-  end_rwlock_wrwait_v1,
-  start_cond_wait_v1,
-  end_cond_wait_v1,
-  start_table_io_wait_v1,
-  end_table_io_wait_v1,
-  start_table_lock_wait_v1,
-  end_table_lock_wait_v1,
-  start_file_open_wait_v1,
-  end_file_open_wait_v1,
-  end_file_open_wait_and_bind_to_descriptor_v1,
-  start_file_wait_v1,
-  end_file_wait_v1,
-  start_stage_v1,
-  end_stage_v1,
-  get_thread_statement_locker_v1,
-  refine_statement_v1,
-  start_statement_v1,
-  set_statement_text_v1,
-  set_statement_lock_time_v1,
-  set_statement_rows_sent_v1,
-  set_statement_rows_examined_v1,
-  inc_statement_created_tmp_disk_tables_v1,
-  inc_statement_created_tmp_tables_v1,
-  inc_statement_select_full_join_v1,
-  inc_statement_select_full_range_join_v1,
-  inc_statement_select_range_v1,
-  inc_statement_select_range_check_v1,
-  inc_statement_select_scan_v1,
-  inc_statement_sort_merge_passes_v1,
-  inc_statement_sort_range_v1,
-  inc_statement_sort_rows_v1,
-  inc_statement_sort_scan_v1,
-  set_statement_no_index_used_v1,
-  set_statement_no_good_index_used_v1,
-  end_statement_v1,
-  start_socket_wait_v1,
-  end_socket_wait_v1,
-  set_socket_state_v1,
-  set_socket_info_v1,
-  set_socket_thread_owner_v1,
+  pfs_register_mutex_v1,
+  pfs_register_rwlock_v1,
+  pfs_register_cond_v1,
+  pfs_register_thread_v1,
+  pfs_register_file_v1,
+  pfs_register_stage_v1,
+  pfs_register_statement_v1,
+  pfs_register_socket_v1,
+  pfs_init_mutex_v1,
+  pfs_destroy_mutex_v1,
+  pfs_init_rwlock_v1,
+  pfs_destroy_rwlock_v1,
+  pfs_init_cond_v1,
+  pfs_destroy_cond_v1,
+  pfs_init_socket_v1,
+  pfs_destroy_socket_v1,
+  pfs_get_table_share_v1,
+  pfs_release_table_share_v1,
+  pfs_drop_table_share_v1,
+  pfs_open_table_v1,
+  pfs_unbind_table_v1,
+  pfs_rebind_table_v1,
+  pfs_close_table_v1,
+  pfs_create_file_v1,
+  pfs_spawn_thread_v1,
+  pfs_new_thread_v1,
+  pfs_set_thread_id_v1,
+  pfs_get_thread_v1,
+  pfs_set_thread_user_v1,
+  pfs_set_thread_account_v1,
+  pfs_set_thread_db_v1,
+  pfs_set_thread_command_v1,
+  pfs_set_thread_start_time_v1,
+  pfs_set_thread_state_v1,
+  pfs_set_thread_info_v1,
+  pfs_set_thread_v1,
+  pfs_delete_current_thread_v1,
+  pfs_delete_thread_v1,
+  pfs_get_thread_file_name_locker_v1,
+  pfs_get_thread_file_stream_locker_v1,
+  pfs_get_thread_file_descriptor_locker_v1,
+  pfs_unlock_mutex_v1,
+  pfs_unlock_rwlock_v1,
+  pfs_signal_cond_v1,
+  pfs_broadcast_cond_v1,
+  pfs_start_idle_wait_v1,
+  pfs_end_idle_wait_v1,
+  pfs_start_mutex_wait_v1,
+  pfs_end_mutex_wait_v1,
+  pfs_start_rwlock_rdwait_v1,
+  pfs_end_rwlock_rdwait_v1,
+  pfs_start_rwlock_wrwait_v1,
+  pfs_end_rwlock_wrwait_v1,
+  pfs_start_cond_wait_v1,
+  pfs_end_cond_wait_v1,
+  pfs_start_table_io_wait_v1,
+  pfs_end_table_io_wait_v1,
+  pfs_start_table_lock_wait_v1,
+  pfs_end_table_lock_wait_v1,
+  pfs_start_file_open_wait_v1,
+  pfs_end_file_open_wait_v1,
+  pfs_end_file_open_wait_and_bind_to_descriptor_v1,
+  pfs_start_file_wait_v1,
+  pfs_end_file_wait_v1,
+  pfs_start_stage_v1,
+  pfs_end_stage_v1,
+  pfs_get_thread_statement_locker_v1,
+  pfs_refine_statement_v1,
+  pfs_start_statement_v1,
+  pfs_set_statement_text_v1,
+  pfs_set_statement_lock_time_v1,
+  pfs_set_statement_rows_sent_v1,
+  pfs_set_statement_rows_examined_v1,
+  pfs_inc_statement_created_tmp_disk_tables_v1,
+  pfs_inc_statement_created_tmp_tables_v1,
+  pfs_inc_statement_select_full_join_v1,
+  pfs_inc_statement_select_full_range_join_v1,
+  pfs_inc_statement_select_range_v1,
+  pfs_inc_statement_select_range_check_v1,
+  pfs_inc_statement_select_scan_v1,
+  pfs_inc_statement_sort_merge_passes_v1,
+  pfs_inc_statement_sort_range_v1,
+  pfs_inc_statement_sort_rows_v1,
+  pfs_inc_statement_sort_scan_v1,
+  pfs_set_statement_no_index_used_v1,
+  pfs_set_statement_no_good_index_used_v1,
+  pfs_end_statement_v1,
+  pfs_start_socket_wait_v1,
+  pfs_end_socket_wait_v1,
+  pfs_set_socket_state_v1,
+  pfs_set_socket_info_v1,
+  pfs_set_socket_thread_owner_v1,
   pfs_digest_start_v1,
   pfs_digest_add_token_v1
 };

=== modified file 'storage/perfschema/pfs_digest.h'
--- a/storage/perfschema/pfs_digest.h	2012-05-15 09:42:30 +0000
+++ b/storage/perfschema/pfs_digest.h	2012-05-16 17:27:18 +0000
@@ -80,13 +80,6 @@ void reset_esms_by_digest();
 /* Exposing the data directly, for iterators. */
 extern PFS_statements_digest_stat *statements_digest_stat_array;
 
-/* Instrumentation callbacks for pfs.cc */
-
-struct PSI_digest_locker *pfs_digest_start_v1(PSI_statement_locker *locker);
-PSI_digest_locker *pfs_digest_add_token_v1(PSI_digest_locker *locker,
-                                           uint token,
-                                           OPAQUE_LEX_YYSTYPE *yylval);
-
 static inline void digest_reset(PSI_digest_storage *digest)
 {
   digest->m_full= false;

=== modified file 'storage/perfschema/pfs_events_stages.cc'
--- a/storage/perfschema/pfs_events_stages.cc	2011-11-18 16:49:29 +0000
+++ b/storage/perfschema/pfs_events_stages.cc	2012-05-16 17:27:18 +0000
@@ -30,20 +30,20 @@
 #include "pfs_atomic.h"
 #include "m_string.h"
 
-ulong events_stages_history_long_size= 0;
+PFS_ALIGNED ulong events_stages_history_long_size= 0;
 /** Consumer flag for table EVENTS_STAGES_CURRENT. */
-bool flag_events_stages_current= false;
+PFS_ALIGNED bool flag_events_stages_current= false;
 /** Consumer flag for table EVENTS_STAGES_HISTORY. */
-bool flag_events_stages_history= false;
+PFS_ALIGNED bool flag_events_stages_history= false;
 /** Consumer flag for table EVENTS_STAGES_HISTORY_LONG. */
-bool flag_events_stages_history_long= false;
+PFS_ALIGNED bool flag_events_stages_history_long= false;
 
 /** True if EVENTS_STAGES_HISTORY_LONG circular buffer is full. */
-bool events_stages_history_long_full= false;
+PFS_ALIGNED bool events_stages_history_long_full= false;
 /** Index in EVENTS_STAGES_HISTORY_LONG circular buffer. */
-volatile uint32 events_stages_history_long_index= 0;
+PFS_ALIGNED volatile uint32 events_stages_history_long_index= 0;
 /** EVENTS_STAGES_HISTORY_LONG circular buffer. */
-PFS_events_stages *events_stages_history_long_array= NULL;
+PFS_ALIGNED PFS_events_stages *events_stages_history_long_array= NULL;
 
 /**
   Initialize table EVENTS_STAGES_HISTORY_LONG.

=== modified file 'storage/perfschema/pfs_events_statements.cc'
--- a/storage/perfschema/pfs_events_statements.cc	2011-11-18 16:49:29 +0000
+++ b/storage/perfschema/pfs_events_statements.cc	2012-05-16 17:27:18 +0000
@@ -30,20 +30,20 @@
 #include "pfs_atomic.h"
 #include "m_string.h"
 
-ulong events_statements_history_long_size= 0;
+PFS_ALIGNED ulong events_statements_history_long_size= 0;
 /** Consumer flag for table EVENTS_STATEMENTS_CURRENT. */
-bool flag_events_statements_current= false;
+PFS_ALIGNED bool flag_events_statements_current= false;
 /** Consumer flag for table EVENTS_STATEMENTS_HISTORY. */
-bool flag_events_statements_history= false;
+PFS_ALIGNED bool flag_events_statements_history= false;
 /** Consumer flag for table EVENTS_STATEMENTS_HISTORY_LONG. */
-bool flag_events_statements_history_long= false;
+PFS_ALIGNED bool flag_events_statements_history_long= false;
 
 /** True if EVENTS_STATEMENTS_HISTORY_LONG circular buffer is full. */
-bool events_statements_history_long_full= false;
+PFS_ALIGNED bool events_statements_history_long_full= false;
 /** Index in EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
-volatile uint32 events_statements_history_long_index= 0;
+PFS_ALIGNED volatile uint32 events_statements_history_long_index= 0;
 /** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
-PFS_events_statements *events_statements_history_long_array= NULL;
+PFS_ALIGNED PFS_events_statements *events_statements_history_long_array= NULL;
 
 /**
   Initialize table EVENTS_STATEMENTS_HISTORY_LONG.

=== modified file 'storage/perfschema/pfs_events_waits.cc'
--- a/storage/perfschema/pfs_events_waits.cc	2012-05-15 09:42:30 +0000
+++ b/storage/perfschema/pfs_events_waits.cc	2012-05-16 17:27:18 +0000
@@ -30,24 +30,24 @@
 #include "pfs_atomic.h"
 #include "m_string.h"
 
-ulong events_waits_history_long_size= 0;
+PFS_ALIGNED ulong events_waits_history_long_size= 0;
 /** Consumer flag for table EVENTS_WAITS_CURRENT. */
-bool flag_events_waits_current= false;
+PFS_ALIGNED bool flag_events_waits_current= false;
 /** Consumer flag for table EVENTS_WAITS_HISTORY. */
-bool flag_events_waits_history= false;
+PFS_ALIGNED bool flag_events_waits_history= false;
 /** Consumer flag for table EVENTS_WAITS_HISTORY_LONG. */
-bool flag_events_waits_history_long= false;
+PFS_ALIGNED bool flag_events_waits_history_long= false;
 /** Consumer flag for the global instrumentation. */
-bool flag_global_instrumentation= false;
+PFS_ALIGNED bool flag_global_instrumentation= false;
 /** Consumer flag for the per thread instrumentation. */
-bool flag_thread_instrumentation= false;
+PFS_ALIGNED bool flag_thread_instrumentation= false;
 
 /** True if EVENTS_WAITS_HISTORY_LONG circular buffer is full. */
-bool events_waits_history_long_full= false;
+PFS_ALIGNED bool events_waits_history_long_full= false;
 /** Index in EVENTS_WAITS_HISTORY_LONG circular buffer. */
-volatile uint32 events_waits_history_long_index= 0;
+PFS_ALIGNED volatile uint32 events_waits_history_long_index= 0;
 /** EVENTS_WAITS_HISTORY_LONG circular buffer. */
-PFS_events_waits *events_waits_history_long_array= NULL;
+PFS_ALIGNED PFS_events_waits *events_waits_history_long_array= NULL;
 
 /**
   Initialize table EVENTS_WAITS_HISTORY_LONG.

=== modified file 'storage/perfschema/pfs_instr.cc'
--- a/storage/perfschema/pfs_instr.cc	2012-05-15 09:42:30 +0000
+++ b/storage/perfschema/pfs_instr.cc	2012-05-16 17:27:18 +0000
@@ -37,47 +37,47 @@
 */
 
 /** Size of the mutex instances array. @sa mutex_array */
-ulong mutex_max;
+ulong mutex_max= 0;
 /** Number of mutexes instance lost. @sa mutex_array */
-ulong mutex_lost;
+ulong mutex_lost= 0;
 /** Size of the rwlock instances array. @sa rwlock_array */
-ulong rwlock_max;
+ulong rwlock_max= 0;
 /** Number or rwlock instances lost. @sa rwlock_array */
-ulong rwlock_lost;
+ulong rwlock_lost= 0;
 /** Size of the conditions instances array. @sa cond_array */
-ulong cond_max;
+ulong cond_max= 0;
 /** Number of conditions instances lost. @sa cond_array */
-ulong cond_lost;
+ulong cond_lost= 0;
 /** Size of the thread instances array. @sa thread_array */
-ulong thread_max;
+ulong thread_max= 0;
 /** Number or thread instances lost. @sa thread_array */
-ulong thread_lost;
+ulong thread_lost= 0;
 /** Size of the file instances array. @sa file_array */
-ulong file_max;
+ulong file_max= 0;
 /** Number of file instances lost. @sa file_array */
-ulong file_lost;
+ulong file_lost= 0;
 /**
   Size of the file handle array. @sa file_handle_array.
   Signed value, for easier comparisons with a file descriptor number.
 */
-long file_handle_max;
+long file_handle_max= 0;
 /** Number of file handle lost. @sa file_handle_array */
-ulong file_handle_lost;
+ulong file_handle_lost= 0;
 /** Size of the table instances array. @sa table_array */
-ulong table_max;
+ulong table_max= 0;
 /** Number of table instances lost. @sa table_array */
-ulong table_lost;
+ulong table_lost= 0;
 /** Size of the socket instances array. @sa socket_array */
-ulong socket_max;
+ulong socket_max= 0;
 /** Number of socket instances lost. @sa socket_array */
-ulong socket_lost;
+ulong socket_lost= 0;
 /** Number of EVENTS_WAITS_HISTORY records per thread. */
-ulong events_waits_history_per_thread;
+ulong events_waits_history_per_thread= 0;
 /** Number of EVENTS_STAGES_HISTORY records per thread. */
-ulong events_stages_history_per_thread;
+ulong events_stages_history_per_thread= 0;
 /** Number of EVENTS_STATEMENTS_HISTORY records per thread. */
-ulong events_statements_history_per_thread;
-uint statement_stack_max;
+ulong events_statements_history_per_thread= 0;
+uint statement_stack_max= 0;
 /** Number of locker lost. @sa LOCKER_STACK_SIZE. */
 ulong locker_lost= 0;
 /** Number of statement lost. @sa STATEMENT_STACK_SIZE. */
@@ -146,9 +146,9 @@ PFS_statement_stat *global_instr_class_s
 
 static volatile uint32 thread_internal_id_counter= 0;
 
-static uint thread_instr_class_waits_sizing;
-static uint thread_instr_class_stages_sizing;
-static uint thread_instr_class_statements_sizing;
+static uint thread_instr_class_waits_sizing= 0;
+static uint thread_instr_class_stages_sizing= 0;
+static uint thread_instr_class_statements_sizing= 0;
 static PFS_single_stat *thread_instr_class_waits_array= NULL;
 static PFS_stage_stat *thread_instr_class_stages_array= NULL;
 static PFS_statement_stat *thread_instr_class_statements_array= NULL;

=== modified file 'storage/perfschema/pfs_server.cc'
--- a/storage/perfschema/pfs_server.cc	2012-05-15 09:42:30 +0000
+++ b/storage/perfschema/pfs_server.cc	2012-05-16 17:27:18 +0000
@@ -49,8 +49,7 @@ C_MODE_END
 static void cleanup_performance_schema(void);
 void cleanup_instrument_config(void);
 
-struct PSI_bootstrap*
-initialize_performance_schema(const PFS_global_param *param)
+void pre_initialize_performance_schema()
 {
   pfs_initialized= false;
 
@@ -58,6 +57,18 @@ initialize_performance_schema(const PFS_
   global_table_io_stat.reset();
   global_table_lock_stat.reset();
 
+  init_timers();
+  PFS_atomic::init();
+
+  if (pthread_key_create(&THR_PFS, destroy_pfs_thread))
+    return;
+
+  THR_PFS_initialized= true;
+}
+
+struct PSI_bootstrap*
+initialize_performance_schema(const PFS_global_param *param)
+{
   if (! param->m_enabled)
   {
     /*
@@ -67,17 +78,9 @@ initialize_performance_schema(const PFS_
     return NULL;
   }
 
-  init_timers();
-  PFS_atomic::init();
-
   init_event_name_sizing(param);
   register_global_classes();
 
-  if (pthread_key_create(&THR_PFS, destroy_pfs_thread))
-    return NULL;
-
-  THR_PFS_initialized= true;
-
   if (init_sync_class(param->m_mutex_class_sizing,
                       param->m_rwlock_class_sizing,
                       param->m_cond_class_sizing) ||

=== modified file 'storage/perfschema/pfs_server.h'
--- a/storage/perfschema/pfs_server.h	2011-12-19 19:08:09 +0000
+++ b/storage/perfschema/pfs_server.h	2012-05-16 17:27:18 +0000
@@ -249,6 +249,14 @@ struct PFS_global_param
 extern PFS_global_param pfs_param;
 
 /**
+  Null initialization.
+  Disable all instrumentation, size all internal buffers to 0.
+  This pre initialization step is needed to ensure that events can be collected
+  and discarded, until such time @c initialize_performance_schema() is called.
+*/
+void pre_initialize_performance_schema();
+
+/**
   Initialize the performance schema.
   @param param Size parameters to use.
   @return A boostrap handle, or NULL.

=== modified file 'storage/perfschema/unittest/CMakeLists.txt'
--- a/storage/perfschema/unittest/CMakeLists.txt	2011-10-27 23:08:08 +0000
+++ b/storage/perfschema/unittest/CMakeLists.txt	2012-05-16 17:27:18 +0000
@@ -24,9 +24,11 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/
 
 ADD_DEFINITIONS(-DMYSQL_SERVER)
 
+ADD_CONVENIENCE_LIBRARY(pfs_server_stubs pfs_server_stubs.cc)
+
 MACRO (PFS_ADD_TEST name)
   ADD_EXECUTABLE(${name}-t ${name}-t.cc)
-  TARGET_LINK_LIBRARIES(${name}-t mytap perfschema mysys)
+  TARGET_LINK_LIBRARIES(${name}-t mytap perfschema mysys pfs_server_stubs)
   ADD_TEST(${name} ${name}-t)
 ENDMACRO()
 
@@ -45,7 +47,7 @@ FOREACH(testname ${tests})
 ENDFOREACH()
 
 ADD_EXECUTABLE(pfs_benchmark-t pfs_benchmark-t.cc pfs_benchmark_helper.cc)
-TARGET_LINK_LIBRARIES(pfs_benchmark-t mytap perfschema mysys)
+TARGET_LINK_LIBRARIES(pfs_benchmark-t mytap perfschema mysys pfs_server_stubs)
 ADD_TEST(pfs_benchmark pfs_benchmark-t)
 
 

=== modified file 'storage/perfschema/unittest/pfs-t.cc'
--- a/storage/perfschema/unittest/pfs-t.cc	2012-05-15 17:18:00 +0000
+++ b/storage/perfschema/unittest/pfs-t.cc	2012-05-16 17:27:18 +0000
@@ -26,7 +26,6 @@
 
 #include "stub_print_error.h"
 #include "stub_pfs_defaults.h"
-#include "stub_server_misc.h"
 
 /* test helpers, to simulate the setup */
 

=== modified file 'storage/perfschema/unittest/pfs_account-oom-t.cc'
--- a/storage/perfschema/unittest/pfs_account-oom-t.cc	2011-07-29 09:10:56 +0000
+++ b/storage/perfschema/unittest/pfs_account-oom-t.cc	2012-05-16 17:27:18 +0000
@@ -22,7 +22,6 @@
 #include <tap.h>
 
 #include "stub_pfs_global.h"
-#include "stub_server_misc.h"
 
 #include <string.h> /* memset */
 

=== modified file 'storage/perfschema/unittest/pfs_benchmark-t.cc'
--- a/storage/perfschema/unittest/pfs_benchmark-t.cc	2012-05-14 14:05:47 +0000
+++ b/storage/perfschema/unittest/pfs_benchmark-t.cc	2012-05-16 17:27:18 +0000
@@ -34,12 +34,16 @@
 #include "pfs_instr_class.h"
 #include "pfs_instr.h"
 #include "mysql/psi/psi.h"
+
+/* Make static calls */
+#include "pfs_thread_provider.h"
+#include "pfs_table_provider.h"
 #include "mysql/psi/mysql_thread.h"
 #include "mysql/psi/mysql_table.h"
+
 #include "my_sys.h"
 #include "tap.h"
 
-#include "stub_server_misc.h"
 #include "pfs_benchmark_helper.h"
 
 /* TABLE_SHARE */

=== modified file 'storage/perfschema/unittest/pfs_host-oom-t.cc'
--- a/storage/perfschema/unittest/pfs_host-oom-t.cc	2011-07-29 09:10:56 +0000
+++ b/storage/perfschema/unittest/pfs_host-oom-t.cc	2012-05-16 17:27:18 +0000
@@ -22,7 +22,6 @@
 #include <tap.h>
 
 #include "stub_pfs_global.h"
-#include "stub_server_misc.h"
 
 #include <string.h> /* memset */
 

=== modified file 'storage/perfschema/unittest/pfs_instr-oom-t.cc'
--- a/storage/perfschema/unittest/pfs_instr-oom-t.cc	2011-08-11 03:11:58 +0000
+++ b/storage/perfschema/unittest/pfs_instr-oom-t.cc	2012-05-16 17:27:18 +0000
@@ -22,7 +22,6 @@
 #include <tap.h>
 
 #include "stub_pfs_global.h"
-#include "stub_server_misc.h"
 
 #include <string.h> /* memset */
 

=== modified file 'storage/perfschema/unittest/pfs_instr-t.cc'
--- a/storage/perfschema/unittest/pfs_instr-t.cc	2011-08-11 03:11:58 +0000
+++ b/storage/perfschema/unittest/pfs_instr-t.cc	2012-05-16 17:27:18 +0000
@@ -23,8 +23,6 @@
 
 #include <memory.h>
 
-#include "stub_server_misc.h"
-
 void test_no_instruments()
 {
   int rc;

=== modified file 'storage/perfschema/unittest/pfs_instr_class-oom-t.cc'
--- a/storage/perfschema/unittest/pfs_instr_class-oom-t.cc	2011-08-11 03:11:58 +0000
+++ b/storage/perfschema/unittest/pfs_instr_class-oom-t.cc	2012-05-16 17:27:18 +0000
@@ -20,7 +20,6 @@
 #include <tap.h>
 
 #include "stub_pfs_global.h"
-#include "stub_server_misc.h"
 
 void test_oom()
 {

=== modified file 'storage/perfschema/unittest/pfs_instr_class-t.cc'
--- a/storage/perfschema/unittest/pfs_instr_class-t.cc	2011-07-08 21:31:33 +0000
+++ b/storage/perfschema/unittest/pfs_instr_class-t.cc	2012-05-16 17:27:18 +0000
@@ -21,7 +21,6 @@
 #include <pfs_global.h>
 #include <tap.h>
 
-#include "stub_server_misc.h"
 
 void test_no_registration()
 {

=== added file 'storage/perfschema/unittest/pfs_server_stubs.cc'
--- a/storage/perfschema/unittest/pfs_server_stubs.cc	1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/unittest/pfs_server_stubs.cc	2012-05-16 17:27:18 +0000
@@ -0,0 +1,31 @@
+/* Copyright (c) 2010, 2012, 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
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  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 */
+
+/*
+  Minimal code to be able to link a unit test.
+*/
+
+#include "my_global.h"
+#include "m_ctype.h"
+
+volatile bool ready_to_exit= false;
+
+uint lower_case_table_names= 0;
+CHARSET_INFO *files_charset_info= NULL;
+
+extern "C" void compute_md5_hash(char *, const char *, int)
+{
+}
+

=== modified file 'storage/perfschema/unittest/pfs_user-oom-t.cc'
--- a/storage/perfschema/unittest/pfs_user-oom-t.cc	2011-07-29 09:10:56 +0000
+++ b/storage/perfschema/unittest/pfs_user-oom-t.cc	2012-05-16 17:27:18 +0000
@@ -22,7 +22,6 @@
 #include <tap.h>
 
 #include "stub_pfs_global.h"
-#include "stub_server_misc.h"
 
 #include <string.h> /* memset */
 

=== removed file 'storage/perfschema/unittest/stub_server_misc.h'
--- a/storage/perfschema/unittest/stub_server_misc.h	2012-02-20 20:56:20 +0000
+++ b/storage/perfschema/unittest/stub_server_misc.h	1970-01-01 00:00:00 +0000
@@ -1,28 +0,0 @@
-/* Copyright (c) 2010, 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
-  the Free Software Foundation; version 2 of the License.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  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 */
-
-/*
-  Minimal code to be able to link a unit test.
-*/
-
-volatile bool ready_to_exit= false;
-
-uint lower_case_table_names= 0;
-CHARSET_INFO *files_charset_info= NULL;
-
-extern "C" void compute_md5_hash(char *, const char *, int)
-{
-}
-

=== modified file 'unittest/gunit/CMakeLists.txt'
--- a/unittest/gunit/CMakeLists.txt	2012-05-07 12:05:48 +0000
+++ b/unittest/gunit/CMakeLists.txt	2012-05-16 17:27:18 +0000
@@ -208,6 +208,9 @@ MESSAGE(STATUS "GTEST_LIBRARIES:${GTEST_
 # Add some defines.
 ADD_DEFINITIONS(-DMYSQL_SERVER)
 
+# Compile unit tests without the performance schema instrumentation
+ADD_DEFINITIONS(-DDISABLE_ALL_PSI)
+
 # libgtest.dylib may have been moved after it was built.
 # We can use otool(1) and install_name_tool(1) to patch the executables.
 # If it moves after linking, use DYLD_LIBRARY_PATH env.var.
@@ -271,6 +274,9 @@ SET(SERVER_TESTS
 FOREACH(test ${TESTS})
   ADD_EXECUTABLE(${test}-t ${test}-t.cc)
   TARGET_LINK_LIBRARIES(${test}-t gunit_small sqlgunitlib strings dbug regex)
+  IF(WITH_PERFSCHEMA_STORAGE_ENGINE)
+    TARGET_LINK_LIBRARIES(${test}-t perfschema pfs_server_stubs)
+  ENDIF()
   IF(APPLE AND GTEST_DYLIB_LOCATION)
     ADD_CUSTOM_COMMAND(TARGET ${test}-t POST_BUILD
       COMMAND install_name_tool -change

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk-pfs-tuning branch (marc.alff:3517) Marc Alff16 May