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 Alff | 16 May |