summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2021-09-06 22:34:35 +0400
committerOleksandr Byelkin <sanja@mariadb.com>2021-10-19 17:35:06 +0200
commit0a0dfd63d9a0ae5adb139159e0aeca93c5c2d5c9 (patch)
tree66209a932d5575a6c3021ab1d215c16e9a3bead7
parent401ff6994d842a4072b7b155e5a958e178e6497a (diff)
downloadmariadb-git-0a0dfd63d9a0ae5adb139159e0aeca93c5c2d5c9.tar.gz
MDEV-19275 Provide SQL service to plugins.
SQL service added. It provides the limited set of client library functions to be used by plugin.
-rw-r--r--include/mysql/plugin.h2
-rw-r--r--include/mysql/service_sql.h99
-rw-r--r--include/mysql/services.h1
-rw-r--r--include/service_versions.h1
-rw-r--r--include/sql_common.h2
-rw-r--r--libmysqld/lib_sql.cc21
-rw-r--r--libservices/CMakeLists.txt1
-rw-r--r--libservices/sql_service.c19
-rw-r--r--mysql-test/main/handlersocket.result2
-rw-r--r--mysql-test/main/plugin.result6
-rw-r--r--mysql-test/suite/plugins/r/auth_ed25519.result2
-rw-r--r--mysql-test/suite/plugins/r/cracklib_password_check.result2
-rw-r--r--mysql-test/suite/plugins/r/show_all_plugins.result4
-rw-r--r--mysql-test/suite/plugins/r/simple_password_check.result2
-rw-r--r--mysql-test/suite/plugins/r/test_sql_service.result47
-rw-r--r--mysql-test/suite/plugins/t/test_sql_service.test33
-rw-r--r--plugin/test_sql_service/CMakeLists.txt3
-rw-r--r--plugin/test_sql_service/test_sql_service.c210
-rw-r--r--sql-common/client.c17
-rw-r--r--sql/mysqld.cc24
-rw-r--r--sql/sql_class.h16
-rw-r--r--sql/sql_plugin_services.ic19
-rw-r--r--sql/sql_prepare.cc411
-rw-r--r--sql/sql_prepare.h2
-rw-r--r--sql/thread_pool_info.cc2
25 files changed, 698 insertions, 250 deletions
diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h
index d3301a36e82..6bb8e5233cf 100644
--- a/include/mysql/plugin.h
+++ b/include/mysql/plugin.h
@@ -77,7 +77,7 @@ typedef struct st_mysql_xid MYSQL_XID;
#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0104
/* MariaDB plugin interface version */
-#define MARIA_PLUGIN_INTERFACE_VERSION 0x010e
+#define MARIA_PLUGIN_INTERFACE_VERSION 0x010f
/*
The allowable types of plugins
diff --git a/include/mysql/service_sql.h b/include/mysql/service_sql.h
new file mode 100644
index 00000000000..22770883be2
--- /dev/null
+++ b/include/mysql/service_sql.h
@@ -0,0 +1,99 @@
+/* Copyright (C) 2021 MariaDB Corporation
+
+ 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+#if defined(MYSQL_SERVER) && !defined MYSQL_SERVICE_SQL
+#define MYSQL_SERVICE_SQL
+
+#include <mysql.h>
+
+/**
+ @file
+ SQL service
+
+ Interface for plugins to execute SQL queries on the local server.
+
+ Functions of the service are the 'server-limited' client library:
+ mysql_init
+ mysql_real_connect_local
+ mysql_real_connect
+ mysql_errno
+ mysql_error
+ mysql_real_query
+ mysql_affected_rows
+ mysql_num_rows
+ mysql_store_result
+ mysql_free_result
+ mysql_fetch_row
+ mysql_close
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct sql_service_st {
+ MYSQL *(STDCALL *mysql_init)(MYSQL *mysql);
+ MYSQL *(*mysql_real_connect_local)(MYSQL *mysql,
+ const char *host, const char *user, const char *db,
+ unsigned long clientflag);
+ MYSQL *(STDCALL *mysql_real_connect)(MYSQL *mysql, const char *host,
+ const char *user, const char *passwd, const char *db, unsigned int port,
+ const char *unix_socket, unsigned long clientflag);
+ unsigned int(STDCALL *mysql_errno)(MYSQL *mysql);
+ const char *(STDCALL *mysql_error)(MYSQL *mysql);
+ int (STDCALL *mysql_real_query)(MYSQL *mysql, const char *q,
+ unsigned long length);
+ my_ulonglong (STDCALL *mysql_affected_rows)(MYSQL *mysql);
+ my_ulonglong (STDCALL *mysql_num_rows)(MYSQL_RES *res);
+ MYSQL_RES *(STDCALL *mysql_store_result)(MYSQL *mysql);
+ void (STDCALL *mysql_free_result)(MYSQL_RES *result);
+ MYSQL_ROW (STDCALL *mysql_fetch_row)(MYSQL_RES *result);
+ void (STDCALL *mysql_close)(MYSQL *sock);
+} *sql_service;
+
+#ifdef MYSQL_DYNAMIC_PLUGIN
+
+#define mysql_init sql_service->mysql_init
+#define mysql_real_connect_local sql_service->mysql_real_connect_local
+#define mysql_real_connect sql_service->mysql_real_connect
+#define mysql_errno(M) sql_service->mysql_errno(M)
+#define mysql_error(M) sql_service->mysql_error(M)
+#define mysql_real_query sql_service->mysql_real_query
+#define mysql_affected_rows sql_service->mysql_affected_rows
+#define mysql_num_rows sql_service->mysql_num_rows
+#define mysql_store_result sql_service->mysql_store_result
+#define mysql_free_result sql_service->mysql_free_result
+#define mysql_fetch_row sql_service->mysql_fetch_row
+#define mysql_close sql_service->mysql_close
+
+#else
+
+MYSQL *mysql_real_connect_local(MYSQL *mysql,
+ const char *host, const char *user, const char *db,
+ unsigned long clientflag);
+
+/* The rest of the function declarations mest be taken from the mysql.h */
+
+#endif /*MYSQL_DYNAMIC_PLUGIN*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*MYSQL_SERVICE_SQL */
+
+
diff --git a/include/mysql/services.h b/include/mysql/services.h
index 2c3a0ae421b..94f7bb3b2da 100644
--- a/include/mysql/services.h
+++ b/include/mysql/services.h
@@ -41,6 +41,7 @@ extern "C" {
#include <mysql/service_thd_wait.h>
#include <mysql/service_json.h>
/*#include <mysql/service_wsrep.h>*/
+#include <mysql/service_sql.h>
#ifdef __cplusplus
}
diff --git a/include/service_versions.h b/include/service_versions.h
index 34e4952c94c..f0580dc2efc 100644
--- a/include/service_versions.h
+++ b/include/service_versions.h
@@ -44,3 +44,4 @@
#define VERSION_wsrep 0x0500
#define VERSION_json 0x0100
#define VERSION_thd_mdl 0x0100
+#define VERSION_sql_service 0x0100
diff --git a/include/sql_common.h b/include/sql_common.h
index 9fc983616a0..ad5ab7e19af 100644
--- a/include/sql_common.h
+++ b/include/sql_common.h
@@ -61,13 +61,13 @@ typedef struct st_mysql_methods
MYSQL_ROW column, unsigned int field_count);
void (*flush_use_result)(MYSQL *mysql, my_bool flush_all_results);
int (*read_change_user_result)(MYSQL *mysql);
+ void (*on_close_free)(MYSQL *mysql);
#if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
MYSQL_FIELD * (*list_fields)(MYSQL *mysql);
my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt);
int (*stmt_execute)(MYSQL_STMT *stmt);
int (*read_binary_rows)(MYSQL_STMT *stmt);
int (*unbuffered_fetch)(MYSQL *mysql, char **row);
- void (*free_embedded_thd)(MYSQL *mysql);
const char *(*read_statistics)(MYSQL *mysql);
my_bool (*next_result)(MYSQL *mysql);
int (*read_rows_from_cursor)(MYSQL_STMT *stmt);
diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
index a8f554326cd..db4e7e6cfa9 100644
--- a/libmysqld/lib_sql.cc
+++ b/libmysqld/lib_sql.cc
@@ -43,7 +43,7 @@ C_MODE_START
extern unsigned int mysql_server_last_errno;
extern char mysql_server_last_error[MYSQL_ERRMSG_SIZE];
static my_bool emb_read_query_result(MYSQL *mysql);
-static void emb_free_embedded_thd(MYSQL *mysql);
+static void free_embedded_thd(MYSQL *mysql);
static bool embedded_print_errors= 0;
extern "C" void unireg_clear(int exit_code)
@@ -121,7 +121,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
thd->killed= NOT_KILLED;
else
{
- emb_free_embedded_thd(mysql);
+ free_embedded_thd(mysql);
thd= 0;
}
}
@@ -430,7 +430,7 @@ int emb_unbuffered_fetch(MYSQL *mysql, char **row)
return 0;
}
-static void emb_free_embedded_thd(MYSQL *mysql)
+static void free_embedded_thd(MYSQL *mysql)
{
THD *thd= (THD*)mysql->thd;
server_threads.erase(thd);
@@ -453,12 +453,23 @@ static MYSQL_RES * emb_store_result(MYSQL *mysql)
return mysql_store_result(mysql);
}
-int emb_read_change_user_result(MYSQL *mysql)
+static int emb_read_change_user_result(MYSQL *mysql)
{
mysql->net.read_pos= (uchar*)""; // fake an OK packet
return mysql_errno(mysql) ? (int)packet_error : 1 /* length of the OK packet */;
}
+static void emb_on_close_free(MYSQL *mysql)
+{
+ my_free(mysql->info_buffer);
+ mysql->info_buffer= 0;
+ if (mysql->thd)
+ {
+ free_embedded_thd(mysql);
+ mysql->thd= 0;
+ }
+}
+
MYSQL_METHODS embedded_methods=
{
emb_read_query_result,
@@ -468,12 +479,12 @@ MYSQL_METHODS embedded_methods=
emb_fetch_lengths,
emb_flush_use_result,
emb_read_change_user_result,
+ emb_on_close_free,
emb_list_fields,
emb_read_prepare_result,
emb_stmt_execute,
emb_read_binary_rows,
emb_unbuffered_fetch,
- emb_free_embedded_thd,
emb_read_statistics,
emb_read_query_result,
emb_read_rows_from_cursor
diff --git a/libservices/CMakeLists.txt b/libservices/CMakeLists.txt
index 274c8ce6dac..6b47bb53fdb 100644
--- a/libservices/CMakeLists.txt
+++ b/libservices/CMakeLists.txt
@@ -38,6 +38,7 @@ SET(MYSQLSERVICES_SOURCES
thd_wait_service.c
wsrep_service.c
json_service.c
+ sql_service.c
)
ADD_CONVENIENCE_LIBRARY(mysqlservices ${MYSQLSERVICES_SOURCES})
diff --git a/libservices/sql_service.c b/libservices/sql_service.c
new file mode 100644
index 00000000000..5c0102bfadf
--- /dev/null
+++ b/libservices/sql_service.c
@@ -0,0 +1,19 @@
+
+/* Copyright (c) 2018, Monty Program Ab
+
+ 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 <service_versions.h>
+SERVICE_VERSION sql_service= (void*)VERSION_sql_service;
diff --git a/mysql-test/main/handlersocket.result b/mysql-test/main/handlersocket.result
index 8ef9b289cd0..38027afc414 100644
--- a/mysql-test/main/handlersocket.result
+++ b/mysql-test/main/handlersocket.result
@@ -5,7 +5,7 @@ plugin_version 1.0
plugin_status ACTIVE
plugin_type DAEMON
plugin_library handlersocket.so
-plugin_library_version 1.14
+plugin_library_version 1.15
plugin_author higuchi dot akira at dena dot jp
plugin_description Direct access into InnoDB
plugin_license BSD
diff --git a/mysql-test/main/plugin.result b/mysql-test/main/plugin.result
index f7571740f31..2b8d1e68bc9 100644
--- a/mysql-test/main/plugin.result
+++ b/mysql-test/main/plugin.result
@@ -12,7 +12,7 @@ PLUGIN_STATUS ACTIVE
PLUGIN_TYPE STORAGE ENGINE
PLUGIN_TYPE_VERSION #
PLUGIN_LIBRARY ha_example.so
-PLUGIN_LIBRARY_VERSION 1.14
+PLUGIN_LIBRARY_VERSION 1.15
PLUGIN_AUTHOR Brian Aker, MySQL AB
PLUGIN_DESCRIPTION Example storage engine
PLUGIN_LICENSE GPL
@@ -25,7 +25,7 @@ PLUGIN_STATUS ACTIVE
PLUGIN_TYPE DAEMON
PLUGIN_TYPE_VERSION #
PLUGIN_LIBRARY ha_example.so
-PLUGIN_LIBRARY_VERSION 1.14
+PLUGIN_LIBRARY_VERSION 1.15
PLUGIN_AUTHOR Sergei Golubchik
PLUGIN_DESCRIPTION Unusable Daemon
PLUGIN_LICENSE GPL
@@ -64,7 +64,7 @@ PLUGIN_STATUS DELETED
PLUGIN_TYPE STORAGE ENGINE
PLUGIN_TYPE_VERSION #
PLUGIN_LIBRARY ha_example.so
-PLUGIN_LIBRARY_VERSION 1.14
+PLUGIN_LIBRARY_VERSION 1.15
PLUGIN_AUTHOR Brian Aker, MySQL AB
PLUGIN_DESCRIPTION Example storage engine
PLUGIN_LICENSE GPL
diff --git a/mysql-test/suite/plugins/r/auth_ed25519.result b/mysql-test/suite/plugins/r/auth_ed25519.result
index 6769d867167..f5d1ce2497d 100644
--- a/mysql-test/suite/plugins/r/auth_ed25519.result
+++ b/mysql-test/suite/plugins/r/auth_ed25519.result
@@ -27,7 +27,7 @@ PLUGIN_STATUS ACTIVE
PLUGIN_TYPE AUTHENTICATION
PLUGIN_TYPE_VERSION 2.2
PLUGIN_LIBRARY auth_ed25519.so
-PLUGIN_LIBRARY_VERSION 1.14
+PLUGIN_LIBRARY_VERSION 1.15
PLUGIN_AUTHOR Sergei Golubchik
PLUGIN_DESCRIPTION Elliptic curve ED25519 based authentication
PLUGIN_LICENSE GPL
diff --git a/mysql-test/suite/plugins/r/cracklib_password_check.result b/mysql-test/suite/plugins/r/cracklib_password_check.result
index 1194e6eef5a..7ab4231b967 100644
--- a/mysql-test/suite/plugins/r/cracklib_password_check.result
+++ b/mysql-test/suite/plugins/r/cracklib_password_check.result
@@ -6,7 +6,7 @@ PLUGIN_STATUS ACTIVE
PLUGIN_TYPE PASSWORD VALIDATION
PLUGIN_TYPE_VERSION 1.0
PLUGIN_LIBRARY cracklib_password_check.so
-PLUGIN_LIBRARY_VERSION 1.14
+PLUGIN_LIBRARY_VERSION 1.15
PLUGIN_AUTHOR Sergei Golubchik
PLUGIN_DESCRIPTION Password validation via CrackLib
PLUGIN_LICENSE GPL
diff --git a/mysql-test/suite/plugins/r/show_all_plugins.result b/mysql-test/suite/plugins/r/show_all_plugins.result
index 3bdaf39d0d0..ebd5b6cc198 100644
--- a/mysql-test/suite/plugins/r/show_all_plugins.result
+++ b/mysql-test/suite/plugins/r/show_all_plugins.result
@@ -4,8 +4,8 @@ Variable_name Value
Opened_plugin_libraries 0
select * from information_schema.all_plugins where plugin_library='ha_example.so';
PLUGIN_NAME PLUGIN_VERSION PLUGIN_STATUS PLUGIN_TYPE PLUGIN_TYPE_VERSION PLUGIN_LIBRARY PLUGIN_LIBRARY_VERSION PLUGIN_AUTHOR PLUGIN_DESCRIPTION PLUGIN_LICENSE LOAD_OPTION PLUGIN_MATURITY PLUGIN_AUTH_VERSION
-EXAMPLE 0.1 NOT INSTALLED STORAGE ENGINE MYSQL_VERSION_ID ha_example.so 1.14 Brian Aker, MySQL AB Example storage engine GPL OFF Experimental 0.1
-UNUSABLE 3.14 NOT INSTALLED DAEMON MYSQL_VERSION_ID ha_example.so 1.14 Sergei Golubchik Unusable Daemon GPL OFF Experimental 3.14.15.926
+EXAMPLE 0.1 NOT INSTALLED STORAGE ENGINE MYSQL_VERSION_ID ha_example.so 1.15 Brian Aker, MySQL AB Example storage engine GPL OFF Experimental 0.1
+UNUSABLE 3.14 NOT INSTALLED DAEMON MYSQL_VERSION_ID ha_example.so 1.15 Sergei Golubchik Unusable Daemon GPL OFF Experimental 3.14.15.926
show status like '%libraries%';
Variable_name Value
Opened_plugin_libraries 1
diff --git a/mysql-test/suite/plugins/r/simple_password_check.result b/mysql-test/suite/plugins/r/simple_password_check.result
index f8f56bc8b15..2853fff3d5f 100644
--- a/mysql-test/suite/plugins/r/simple_password_check.result
+++ b/mysql-test/suite/plugins/r/simple_password_check.result
@@ -6,7 +6,7 @@ PLUGIN_STATUS ACTIVE
PLUGIN_TYPE PASSWORD VALIDATION
PLUGIN_TYPE_VERSION 1.0
PLUGIN_LIBRARY simple_password_check.so
-PLUGIN_LIBRARY_VERSION 1.14
+PLUGIN_LIBRARY_VERSION 1.15
PLUGIN_AUTHOR Sergei Golubchik
PLUGIN_DESCRIPTION Simple password strength checks
PLUGIN_LICENSE GPL
diff --git a/mysql-test/suite/plugins/r/test_sql_service.result b/mysql-test/suite/plugins/r/test_sql_service.result
index af414d6c6e7..494b1131c59 100644
--- a/mysql-test/suite/plugins/r/test_sql_service.result
+++ b/mysql-test/suite/plugins/r/test_sql_service.result
@@ -1,8 +1,51 @@
install plugin test_sql_service soname 'test_sql_service';
+show status like 'test_sql_service_passed';
+Variable_name Value
+Test_sql_service_passed 1
set global test_sql_service_run_test= 1;
-show status like 'test_sql_service%';
+show status like 'test_sql_service_passed';
+Variable_name Value
+Test_sql_service_passed 1
+set global test_sql_service_execute_sql_local= 'create table test.t1(id int)';
+show status like 'test_sql_query_result';
+Variable_name Value
+Test_sql_query_result Query affected 0 rows.
+set global test_sql_service_execute_sql_local= 'insert into test.t1 values (1), (2)';
+show status like 'test_sql_query_result';
+Variable_name Value
+Test_sql_query_result Query affected 2 rows.
+set global test_sql_service_execute_sql_local= 'select * from test.t1';
+show status like 'test_sql_query_result';
+Variable_name Value
+Test_sql_query_result Query returned 2 rows.
+set global test_sql_service_execute_sql_local= 'drop table test.t1';
+show status like 'test_sql_query_result';
+Variable_name Value
+Test_sql_query_result Query affected 0 rows.
+set global test_sql_service_execute_sql_local= 'drop table test.t1';
+show status like 'test_sql_query_result';
+Variable_name Value
+Test_sql_query_result Error 1051 returned. Unknown table 'test.t1'
+set global test_sql_service_execute_sql_global= 'create table test.t1(id int)';
+show status like 'test_sql_query_result';
+Variable_name Value
+Test_sql_query_result Query affected 0 rows.
+set global test_sql_service_execute_sql_global= 'insert into test.t1 values (1), (2)';
+show status like 'test_sql_query_result';
+Variable_name Value
+Test_sql_query_result Query affected 2 rows.
+set global test_sql_service_execute_sql_global= 'select * from test.t1';
+show status like 'test_sql_query_result';
+Variable_name Value
+Test_sql_query_result Query returned 2 rows.
+set global test_sql_service_execute_sql_global= 'drop table test.t1';
+show status like 'test_sql_query_result';
+Variable_name Value
+Test_sql_query_result Query affected 0 rows.
+set global test_sql_service_execute_sql_global= 'drop table test.t1';
+show status like 'test_sql_query_result';
Variable_name Value
-Test_sql_service_passed 0
+Test_sql_query_result Error 1051 returned. Unknown table 'test.t1'
uninstall plugin test_sql_service;
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown
diff --git a/mysql-test/suite/plugins/t/test_sql_service.test b/mysql-test/suite/plugins/t/test_sql_service.test
index 9b9e29c6913..bb3dfb15bf7 100644
--- a/mysql-test/suite/plugins/t/test_sql_service.test
+++ b/mysql-test/suite/plugins/t/test_sql_service.test
@@ -9,9 +9,40 @@ let count_sessions= 1;
source include/wait_until_count_sessions.inc;
install plugin test_sql_service soname 'test_sql_service';
+show status like 'test_sql_service_passed';
set global test_sql_service_run_test= 1;
-show status like 'test_sql_service%';
+show status like 'test_sql_service_passed';
+
+set global test_sql_service_execute_sql_local= 'create table test.t1(id int)';
+show status like 'test_sql_query_result';
+
+set global test_sql_service_execute_sql_local= 'insert into test.t1 values (1), (2)';
+show status like 'test_sql_query_result';
+
+set global test_sql_service_execute_sql_local= 'select * from test.t1';
+show status like 'test_sql_query_result';
+
+set global test_sql_service_execute_sql_local= 'drop table test.t1';
+show status like 'test_sql_query_result';
+
+set global test_sql_service_execute_sql_local= 'drop table test.t1';
+show status like 'test_sql_query_result';
+
+set global test_sql_service_execute_sql_global= 'create table test.t1(id int)';
+show status like 'test_sql_query_result';
+
+set global test_sql_service_execute_sql_global= 'insert into test.t1 values (1), (2)';
+show status like 'test_sql_query_result';
+
+set global test_sql_service_execute_sql_global= 'select * from test.t1';
+show status like 'test_sql_query_result';
+
+set global test_sql_service_execute_sql_global= 'drop table test.t1';
+show status like 'test_sql_query_result';
+
+set global test_sql_service_execute_sql_global= 'drop table test.t1';
+show status like 'test_sql_query_result';
uninstall plugin test_sql_service;
diff --git a/plugin/test_sql_service/CMakeLists.txt b/plugin/test_sql_service/CMakeLists.txt
index aa9ecfe685e..7c61a1c3c7a 100644
--- a/plugin/test_sql_service/CMakeLists.txt
+++ b/plugin/test_sql_service/CMakeLists.txt
@@ -15,4 +15,5 @@
SET(SOURCES test_sql_service.c)
-MYSQL_ADD_PLUGIN(test_sql_service ${SOURCES} MODULE_ONLY RECOMPILE_FOR_EMBEDDED)
+ADD_DEFINITIONS(-DMYSQL_SERVER)
+MYSQL_ADD_PLUGIN(test_sql_service ${SOURCES} MODULE_ONLY)
diff --git a/plugin/test_sql_service/test_sql_service.c b/plugin/test_sql_service/test_sql_service.c
index 062f10fce58..e1155a98c40 100644
--- a/plugin/test_sql_service/test_sql_service.c
+++ b/plugin/test_sql_service/test_sql_service.c
@@ -14,71 +14,113 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
-#define PLUGIN_VERSION 0x100
-#define PLUGIN_STR_VERSION "1.0.0"
-
-#define _my_thread_var loc_thread_var
+#define PLUGIN_VERSION 0x20000
+#define PLUGIN_STR_VERSION "2.0"
#include <my_config.h>
-#include <assert.h>
#include <my_global.h>
#include <my_base.h>
-#include <typelib.h>
-//#include <mysql_com.h> /* for enum enum_server_command */
-#include <mysql/plugin.h>
#include <mysql/plugin_audit.h>
-//#include <string.h>
-
+#include <mysql.h>
-LEX_STRING * thd_query_string (MYSQL_THD thd);
-unsigned long long thd_query_id(const MYSQL_THD thd);
-size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen);
-const char *thd_user_name(MYSQL_THD thd);
-const char *thd_client_host(MYSQL_THD thd);
-const char *thd_client_ip(MYSQL_THD thd);
-LEX_CSTRING *thd_current_db(MYSQL_THD thd);
-int thd_current_status(MYSQL_THD thd);
-enum enum_server_command thd_current_command(MYSQL_THD thd);
-
-int maria_compare_hostname(const char *wild_host, long wild_ip, long ip_mask,
- const char *host, const char *ip);
-void maria_update_hostname(const char **wild_host, long *wild_ip, long *ip_mask,
- const char *host);
/* Status variables for SHOW STATUS */
static long test_passed= 0;
+static char *sql_text_local, *sql_text_global;
+static char qwe_res[1024]= "";
+
static struct st_mysql_show_var test_sql_status[]=
{
{"test_sql_service_passed", (char *)&test_passed, SHOW_LONG},
+ {"test_sql_query_result", qwe_res, SHOW_CHAR},
{0,0,0}
};
static my_bool do_test= TRUE;
-static void run_test(MYSQL_THD thd, struct st_mysql_sys_var *var,
- void *var_ptr, const void *save);
-static MYSQL_SYSVAR_BOOL(run_test, do_test, PLUGIN_VAR_OPCMDARG,
- "Perform the test now.", NULL, run_test, FALSE);
+static int run_test(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
+ struct st_mysql_value *value);
+static int run_sql_local(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
+ struct st_mysql_value *value);
+static int run_sql_global(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
+ struct st_mysql_value *value);
+
+static void noop_update(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+
+static MYSQL_SYSVAR_BOOL(run_test, do_test,
+ PLUGIN_VAR_OPCMDARG,
+ "Perform the test now.",
+ run_test, NULL, FALSE);
+
+static MYSQL_SYSVAR_STR(execute_sql_local, sql_text_local,
+ PLUGIN_VAR_OPCMDARG,
+ "Create the new local connection, execute SQL statement with it.",
+ run_sql_local, noop_update, FALSE);
+
+static MYSQL_SYSVAR_STR(execute_sql_global, sql_text_global,
+ PLUGIN_VAR_OPCMDARG,
+ "Execute SQL statement using the global connection.",
+ run_sql_global, noop_update, FALSE);
+
static struct st_mysql_sys_var* test_sql_vars[]=
{
MYSQL_SYSVAR(run_test),
+ MYSQL_SYSVAR(execute_sql_local),
+ MYSQL_SYSVAR(execute_sql_global),
NULL
};
+static MYSQL *global_mysql;
+
+
+static int run_queries(MYSQL *mysql)
+{
+ MYSQL_RES *res;
+
+ if (mysql_real_query(mysql,
+ STRING_WITH_LEN("CREATE TABLE test.ts_table"
+ " ( hash varbinary(512),"
+ " time timestamp default current_time,"
+ " primary key (hash), index tm (time) )")))
+ return 1;
+
+ if (mysql_real_query(mysql,
+ STRING_WITH_LEN("INSERT INTO test.ts_table VALUES('1234567890', NULL)")))
+ return 1;
-extern int execute_sql_command(const char *command,
- char *hosts, char *names, char *filters);
+ if (mysql_real_query(mysql, STRING_WITH_LEN("select * from test.ts_table")))
+ return 1;
+ if (!(res= mysql_store_result(mysql)))
+ return 1;
+
+ mysql_free_result(res);
+
+ if (mysql_real_query(mysql, STRING_WITH_LEN("DROP TABLE test.ts_table")))
+ return 1;
+
+ return 0;
+}
static int do_tests()
{
- char plugins[1024];
- char names[1024];
- char dl[2048];
- int result;
+ MYSQL *mysql;
+ int result= 1;
+
+ mysql= mysql_init(NULL);
+ if (mysql_real_connect_local(mysql, NULL, NULL, NULL, 0) == NULL)
+ return 1;
+
+ if (run_queries(mysql))
+ goto exit;
- result= execute_sql_command("select 'plugin', name, dl from mysql.plugin",
- plugins, names, dl);
+ if (run_queries(global_mysql))
+ goto exit;
+
+ result= 0;
+exit:
+ mysql_close(mysql);
return result;
}
@@ -89,12 +131,87 @@ void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev)
}
-static void run_test(MYSQL_THD thd __attribute__((unused)),
- struct st_mysql_sys_var *var __attribute__((unused)),
- void *var_ptr __attribute__((unused)),
- const void *save __attribute__((unused)))
+static int run_test(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
+ struct st_mysql_value *value)
+{
+ return (test_passed= (do_tests() == 0)) == 0;
+}
+
+
+static int run_sql(MYSQL *mysql, void *save, struct st_mysql_value *value)
+{
+ const char *str;
+ int len= 0;
+ MYSQL_RES *res;
+
+ str= value->val_str(value, NULL, &len);
+
+ if (mysql_real_query(mysql, str, len))
+ {
+ if (mysql_error(mysql)[0])
+ {
+ my_snprintf(qwe_res, sizeof(qwe_res), "Error %d returned. %s",
+ mysql_errno(mysql), mysql_error(mysql));
+ return 0;
+ }
+
+ return 1;
+ }
+
+ if ((res= mysql_store_result(mysql)))
+ {
+ my_snprintf(qwe_res, sizeof(qwe_res), "Query returned %lld rows.",
+ mysql_num_rows(res));
+ mysql_free_result(res);
+ }
+ else
+ {
+ if (mysql_error(mysql)[0])
+ {
+ my_snprintf(qwe_res, sizeof(qwe_res), "Error %d returned. %s",
+ mysql_errno(mysql), mysql_error(mysql));
+ }
+ else
+ my_snprintf(qwe_res, sizeof(qwe_res), "Query affected %lld rows.",
+ mysql_affected_rows(mysql));
+ }
+
+ return 0;
+}
+
+
+static void noop_update(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
{
- test_passed= do_tests();
+ sql_text_local= sql_text_global= qwe_res;
+}
+
+static int run_sql_local(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
+ struct st_mysql_value *value)
+{
+ MYSQL *mysql;
+ int result= 1;
+
+ mysql= mysql_init(NULL);
+ if (mysql_real_connect_local(mysql, NULL, NULL, NULL, 0) == NULL)
+ return 1;
+
+ if (run_sql(mysql, save, value))
+ goto exit;
+
+ result= 0;
+
+exit:
+ mysql_close(mysql);
+
+ return result;
+}
+
+
+static int run_sql_global(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
+ struct st_mysql_value *value)
+{
+ return run_sql(global_mysql, save, value);
}
@@ -102,7 +219,16 @@ static int init_done= 0;
static int test_sql_service_plugin_init(void *p __attribute__((unused)))
{
+ global_mysql= mysql_init(NULL);
+
+ if (!global_mysql ||
+ mysql_real_connect_local(global_mysql, NULL, NULL, NULL, 0) == NULL)
+ return 1;
+
init_done= 1;
+
+ test_passed= (do_tests() == 0);
+
return 0;
}
@@ -112,6 +238,8 @@ static int test_sql_service_plugin_deinit(void *p __attribute__((unused)))
if (!init_done)
return 0;
+ mysql_close(global_mysql);
+
return 0;
}
diff --git a/sql-common/client.c b/sql-common/client.c
index a551258aa34..3bb000db937 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -1712,14 +1712,14 @@ static MYSQL_METHODS client_methods=
cli_use_result, /* use_result */
cli_fetch_lengths, /* fetch_lengths */
cli_flush_use_result, /* flush_use_result */
- cli_read_change_user_result /* read_change_user_result */
+ cli_read_change_user_result, /* read_change_user_result */
+ NULL /* on_close_free */
#ifndef MYSQL_SERVER
,cli_list_fields, /* list_fields */
cli_read_prepare_result, /* read_prepare_result */
cli_stmt_execute, /* stmt_execute */
cli_read_binary_rows, /* read_binary_rows */
cli_unbuffered_fetch, /* unbuffered_fetch */
- NULL, /* free_embedded_thd */
cli_read_statistics, /* read_statistics */
cli_read_query_result, /* next_result */
cli_read_binary_rows /* read_rows_from_cursor */
@@ -3319,10 +3319,8 @@ static void mysql_close_free(MYSQL *mysql)
my_free(mysql->user);
my_free(mysql->passwd);
my_free(mysql->db);
-#if defined(EMBEDDED_LIBRARY) || MYSQL_VERSION_ID >= 50100
- my_free(mysql->info_buffer);
- mysql->info_buffer= 0;
-#endif
+ if (mysql->methods && mysql->methods->on_close_free)
+ (*mysql->methods->on_close_free)(mysql);
/* Clear pointers for better safety */
mysql->host_info= mysql->user= mysql->passwd= mysql->db= 0;
}
@@ -3441,13 +3439,6 @@ void STDCALL mysql_close(MYSQL *mysql)
mysql_close_free_options(mysql);
mysql_close_free(mysql);
mysql_detach_stmt_list(&mysql->stmts, "mysql_close");
-#ifndef MYSQL_SERVER
- if (mysql->thd)
- {
- (*mysql->methods->free_embedded_thd)(mysql);
- mysql->thd= 0;
- }
-#endif
if (mysql->free_me)
my_free(mysql);
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index fcd5528d4bc..7952d38b4c5 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1526,6 +1526,16 @@ static void end_ssl();
#ifndef EMBEDDED_LIBRARY
+extern Atomic_counter<uint32_t> local_connection_thread_count;
+
+uint THD_count::connection_thd_count()
+{
+ return value() -
+ binlog_dump_thread_count -
+ local_connection_thread_count;
+}
+
+
/****************************************************************************
** Code to end mysqld
****************************************************************************/
@@ -1757,7 +1767,7 @@ static void close_connections(void)
*/
DBUG_PRINT("info", ("THD_count: %u", THD_count::value()));
- for (int i= 0; (THD_count::value() - binlog_dump_thread_count) && i < 1000; i++)
+ for (int i= 0; (THD_count::connection_thd_count()) && i < 1000; i++)
my_sleep(20000);
if (global_system_variables.log_warnings)
@@ -1772,12 +1782,12 @@ static void close_connections(void)
/* All threads has now been aborted */
DBUG_PRINT("quit", ("Waiting for threads to die (count=%u)", THD_count::value()));
- while (THD_count::value() - binlog_dump_thread_count)
+ while (THD_count::connection_thd_count())
my_sleep(1000);
/* Kill phase 2 */
server_threads.iterate(kill_thread_phase_2);
- for (uint64 i= 0; THD_count::value(); i++)
+ for (uint64 i= 0; THD_count::connection_thd_count(); i++)
{
/*
This time the warnings are emitted within the loop to provide a
@@ -5056,6 +5066,7 @@ static int init_server_components()
init_global_table_stats();
init_global_index_stats();
+ init_update_queries();
/* Allow storage engine to give real error messages */
if (unlikely(ha_init_errors()))
@@ -5063,6 +5074,9 @@ static int init_server_components()
tc_log= 0; // ha_initialize_handlerton() needs that
+ if (ddl_log_initialize())
+ unireg_abort(1);
+
if (plugin_init(&remaining_argc, remaining_argv,
(opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
(opt_abort ? PLUGIN_INIT_SKIP_INITIALIZATION : 0)))
@@ -5304,9 +5318,6 @@ static int init_server_components()
}
#endif
- if (ddl_log_initialize())
- unireg_abort(1);
-
tc_log= get_tc_log_implementation();
if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
@@ -5387,7 +5398,6 @@ static int init_server_components()
ft_init_stopwords();
init_max_user_conn();
- init_update_queries();
init_global_user_stats();
init_global_client_stats();
if (!opt_bootstrap)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index e569fcd32d6..964626be3d4 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1131,6 +1131,7 @@ struct THD_count
{
static Atomic_counter<uint32_t> count;
static uint value() { return static_cast<uint>(count); }
+ static uint connection_thd_count();
THD_count() { count++; }
~THD_count() { count--; }
};
@@ -3918,6 +3919,11 @@ public:
user_time= t;
set_time();
}
+ inline void force_set_time(my_time_t t, ulong sec_part)
+ {
+ start_time= system_time.sec= t;
+ start_time_sec_part= system_time.sec_part= sec_part;
+ }
/*
this is only used by replication and BINLOG command.
usecs > TIME_MAX_SECOND_PART means "was not in binlog"
@@ -3929,15 +3935,9 @@ public:
else
{
if (sec_part <= TIME_MAX_SECOND_PART)
- {
- start_time= system_time.sec= t;
- start_time_sec_part= system_time.sec_part= sec_part;
- }
+ force_set_time(t, sec_part);
else if (t != system_time.sec)
- {
- start_time= system_time.sec= t;
- start_time_sec_part= system_time.sec_part= 0;
- }
+ force_set_time(t, 0);
else
{
start_time= t;
diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic
index 8f2296160e6..b9da8831cdd 100644
--- a/sql/sql_plugin_services.ic
+++ b/sql/sql_plugin_services.ic
@@ -230,6 +230,22 @@ static struct thd_mdl_service_st thd_mdl_handler=
thd_mdl_context
};
+struct sql_service_st sql_service_handler=
+{
+ mysql_init,
+ mysql_real_connect_local,
+ mysql_real_connect,
+ mysql_errno,
+ mysql_error,
+ mysql_real_query,
+ mysql_affected_rows,
+ mysql_num_rows,
+ mysql_store_result,
+ mysql_free_result,
+ mysql_fetch_row,
+ mysql_close,
+};
+
static struct st_service_ref list_of_services[]=
{
{ "base64_service", VERSION_base64, &base64_handler },
@@ -254,5 +270,6 @@ static struct st_service_ref list_of_services[]=
{ "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
{ "wsrep_service", VERSION_wsrep, &wsrep_handler },
{ "json_service", VERSION_json, &json_handler },
- { "thd_mdl_service", VERSION_thd_mdl, &thd_mdl_handler }
+ { "thd_mdl_service", VERSION_thd_mdl, &thd_mdl_handler },
+ { "sql_service", VERSION_sql_service, &sql_service_handler },
};
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index f9f008602ed..19ae176ddcb 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -133,6 +133,7 @@ static const uint PARAMETER_FLAG_UNSIGNED= 128U << 8;
#include "wsrep_trans_observer.h"
#endif /* WITH_WSREP */
#include "xa.h" // xa_recover_get_fields
+#include "sql_audit.h" // mysql_audit_release
/**
A result class used to send cursor rows using the binary protocol.
@@ -4049,19 +4050,22 @@ Execute_sql_statement(LEX_STRING sql_text)
executions without having to cleanup/reset THD in between.
*/
-bool
-Execute_sql_statement::execute_server_code(THD *thd)
+static bool execute_server_code(THD *thd,
+ const char *sql_text, size_t sql_len)
{
PSI_statement_locker *parent_locker;
bool error;
+ query_id_t save_query_id= thd->query_id;
+ query_id_t next_id= next_query_id();
- if (alloc_query(thd, m_sql_text.str, m_sql_text.length))
+ if (alloc_query(thd, sql_text, sql_len))
return TRUE;
Parser_state parser_state;
if (parser_state.init(thd, thd->query(), thd->query_length()))
return TRUE;
+ thd->query_id= next_id;
parser_state.m_lip.multi_statements= FALSE;
lex_start(thd);
@@ -4079,17 +4083,23 @@ Execute_sql_statement::execute_server_code(THD *thd)
/* report error issued during command execution */
if (likely(error == 0) && thd->spcont == NULL)
- general_log_write(thd, COM_STMT_EXECUTE,
+ general_log_write(thd, COM_QUERY,
thd->query(), thd->query_length());
end:
thd->lex->restore_set_statement_var();
+ thd->query_id= save_query_id;
delete_explain_query(thd->lex);
lex_end(thd->lex);
return error;
}
+bool Execute_sql_statement::execute_server_code(THD *thd)
+{
+ return ::execute_server_code(thd, m_sql_text.str, m_sql_text.length);
+}
+
/***************************************************************************
Prepared_statement
****************************************************************************/
@@ -4850,7 +4860,10 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
Statement stmt_backup;
bool error;
Query_arena *save_stmt_arena= thd->stmt_arena;
+ my_time_t save_query_start= thd->query_start();
+ ulong save_query_sec= thd->start_time_sec_part;
Item_change_list save_change_list;
+
thd->Item_change_list::move_elements_to(&save_change_list);
state= STMT_CONVENTIONAL_EXECUTION;
@@ -4858,6 +4871,7 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
if (!(lex= new (mem_root) st_lex_local))
return TRUE;
+ thd->set_time();
thd->set_n_backup_statement(this, &stmt_backup);
thd->set_n_backup_active_arena(this, &stmt_backup);
thd->stmt_arena= this;
@@ -4871,6 +4885,7 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
thd->stmt_arena= save_stmt_arena;
save_change_list.move_elements_to(thd);
+ thd->force_set_time(save_query_start, save_query_sec);
/* Items and memory will freed in destructor */
@@ -5582,14 +5597,6 @@ Ed_connection::store_result_set()
return ed_result_set;
}
-/*
- MENT-56
- Protocol_local and service_sql for plugins to enable 'local' SQL query execution.
-*/
-
-#ifndef EMBEDDED_LIBRARY
-// This part is mostly copied from libmysqld/lib_sql.cc
-// TODO: get rid of code duplications
#include <mysql.h>
#include "../libmysqld/embedded_priv.h"
@@ -5605,11 +5612,13 @@ public:
char **next_field;
MYSQL_FIELD *next_mysql_field;
MEM_ROOT *alloc;
+ THD *new_thd;
- Protocol_local(THD *thd_arg, ulong prealloc= 0) :
+ Protocol_local(THD *thd_arg, THD *new_thd_arg, ulong prealloc) :
Protocol_text(thd_arg, prealloc),
- cur_data(0), first_data(0), data_tail(&first_data), alloc(0)
- {}
+ cur_data(0), first_data(0), data_tail(&first_data), alloc(0),
+ new_thd(new_thd_arg)
+ {}
protected:
bool net_store_data(const uchar *from, size_t length);
@@ -5681,6 +5690,20 @@ MYSQL_DATA *Protocol_local::alloc_new_dataset()
}
+void Protocol_local::clear_data_list()
+{
+ while (first_data)
+ {
+ MYSQL_DATA *data= first_data;
+ first_data= data->embedded_info->next;
+ free_rows(data);
+ }
+ data_tail= &first_data;
+ free_rows(cur_data);
+ cur_data= 0;
+}
+
+
static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
@@ -5974,7 +5997,6 @@ bool Protocol_local::send_result_set_metadata(List<Item> *list, uint flags)
{
List_iterator_fast<Item> it(*list);
Item *item;
-// Protocol_local prot(thd);
DBUG_ENTER("send_result_set_metadata");
// if (!thd->mysql) // bootstrap file handling
@@ -5985,7 +6007,7 @@ bool Protocol_local::send_result_set_metadata(List<Item> *list, uint flags)
for (uint pos= 0 ; (item= it++); pos++)
{
- if (/*prot.*/store_item_metadata(thd, item, pos))
+ if (store_item_metadata(thd, item, pos))
goto err;
}
@@ -5999,6 +6021,7 @@ bool Protocol_local::send_result_set_metadata(List<Item> *list, uint flags)
DBUG_RETURN(1); /* purecov: inspected */
}
+
static void
list_fields_send_default(THD *thd, Protocol_local *p, Field *fld, uint pos)
{
@@ -6086,19 +6109,6 @@ bool Protocol_local::store_null()
#include <sql_common.h>
#include <errmsg.h>
-struct local_results
-{
- struct st_mysql_data *cur_data;
- struct st_mysql_data *first_data;
- struct st_mysql_data **data_tail;
- void clear_data_list();
- struct st_mysql_data *alloc_new_dataset();
- char **next_field;
- MYSQL_FIELD *next_mysql_field;
- MEM_ROOT *alloc;
-};
-
-
static void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data)
{
NET *net= &mysql->net;
@@ -6113,11 +6123,11 @@ static void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data)
static my_bool loc_read_query_result(MYSQL *mysql)
{
- local_results *thd= (local_results *) mysql->thd;
+ Protocol_local *p= (Protocol_local *) mysql->thd;
- MYSQL_DATA *res= thd->first_data;
- DBUG_ASSERT(!thd->cur_data);
- thd->first_data= res->embedded_info->next;
+ MYSQL_DATA *res= p->first_data;
+ DBUG_ASSERT(!p->cur_data);
+ p->first_data= res->embedded_info->next;
if (res->embedded_info->last_errno &&
!res->embedded_info->fields_list)
{
@@ -6145,7 +6155,7 @@ static my_bool loc_read_query_result(MYSQL *mysql)
if (res->embedded_info->fields_list)
{
mysql->status=MYSQL_STATUS_GET_RESULT;
- thd->cur_data= res;
+ p->cur_data= res;
}
else
my_free(res);
@@ -6154,23 +6164,193 @@ static my_bool loc_read_query_result(MYSQL *mysql)
}
+static my_bool
+loc_advanced_command(MYSQL *mysql, enum enum_server_command command,
+ const uchar *header, ulong header_length,
+ const uchar *arg, ulong arg_length, my_bool skip_check,
+ MYSQL_STMT *stmt)
+{
+ my_bool result= 1;
+ Protocol_local *p= (Protocol_local *) mysql->thd;
+ NET *net= &mysql->net;
+
+ if (p->thd && p->thd->killed != NOT_KILLED)
+ {
+ if (p->thd->killed < KILL_CONNECTION)
+ p->thd->killed= NOT_KILLED;
+ else
+ return 1;
+ }
+
+ p->clear_data_list();
+ /* Check that we are calling the client functions in right order */
+ if (mysql->status != MYSQL_STATUS_READY)
+ {
+ set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
+ goto end;
+ }
+
+ /* Clear result variables */
+ p->thd->clear_error(1);
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ mysql->field_count= 0;
+ net_clear_error(net);
+
+ /*
+ We have to call free_old_query before we start to fill mysql->fields
+ for new query. In the case of embedded server we collect field data
+ during query execution (not during data retrieval as it is in remote
+ client). So we have to call free_old_query here
+ */
+ free_old_query(mysql);
+
+ if (header)
+ {
+ arg= header;
+ arg_length= header_length;
+ }
+
+ if (p->new_thd)
+ {
+ THD *thd_orig= current_thd;
+ set_current_thd(p->thd);
+ p->thd->thread_stack= (char*) &result;
+ p->thd->set_time();
+ result= execute_server_code(p->thd, (const char *)arg, arg_length);
+ p->thd->cleanup_after_query();
+ mysql_audit_release(p->thd);
+ p->end_statement();
+ set_current_thd(thd_orig);
+ }
+ else
+ {
+ Ed_connection con(p->thd);
+ MYSQL_LEX_STRING sql_text;
+ DBUG_ASSERT(current_thd == p->thd);
+ sql_text.str= (char *) arg;
+ sql_text.length= arg_length;
+ result= con.execute_direct(p, sql_text);
+ }
+ if (skip_check)
+ result= 0;
+ p->cur_data= 0;
+
+end:
+ return result;
+}
+
+
+/*
+ reads dataset from the next query result
+
+ SYNOPSIS
+ loc_read_rows()
+ mysql connection handle
+ other parameters are not used
+
+ NOTES
+ It just gets next MYSQL_DATA from the result's queue
+
+ RETURN
+ pointer to MYSQL_DATA with the coming recordset
+*/
+
+static MYSQL_DATA *
+loc_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields __attribute__((unused)),
+ unsigned int fields __attribute__((unused)))
+{
+ MYSQL_DATA *result= ((Protocol_local *)mysql->thd)->cur_data;
+ ((Protocol_local *)mysql->thd)->cur_data= 0;
+ if (result->embedded_info->last_errno)
+ {
+ embedded_get_error(mysql, result);
+ return NULL;
+ }
+ *result->embedded_info->prev_ptr= NULL;
+ return result;
+}
+
+
+/**************************************************************************
+ Get column lengths of the current row
+ If one uses mysql_use_result, res->lengths contains the length information,
+ else the lengths are calculated from the offset between pointers.
+**************************************************************************/
+
+static void loc_fetch_lengths(ulong *to, MYSQL_ROW column,
+ unsigned int field_count)
+{
+ MYSQL_ROW end;
+
+ for (end=column + field_count; column != end ; column++,to++)
+ *to= *column ? *(uint *)((*column) - sizeof(uint)) : 0;
+}
+
+
+static void loc_flush_use_result(MYSQL *mysql, my_bool)
+{
+ Protocol_local *p= (Protocol_local *) mysql->thd;
+ if (p->cur_data)
+ {
+ free_rows(p->cur_data);
+ p->cur_data= 0;
+ }
+ else if (p->first_data)
+ {
+ MYSQL_DATA *data= p->first_data;
+ p->first_data= data->embedded_info->next;
+ free_rows(data);
+ }
+}
+
+
+static void loc_on_close_free(MYSQL *mysql)
+{
+ Protocol_local *p= (Protocol_local *) mysql->thd;
+ THD *thd= p->new_thd;
+ delete p;
+ if (thd)
+ {
+ delete thd;
+ local_connection_thread_count--;
+ }
+ my_free(mysql->info_buffer);
+ mysql->info_buffer= 0;
+}
+
+
static MYSQL_METHODS local_methods=
{
loc_read_query_result, /* read_query_result */
- NULL/*loc_advanced_command*/, /* advanced_command */
- NULL/*loc_read_rows*/, /* read_rows */
- NULL/*loc_use_result*/, /* use_result */
- NULL/*loc_fetch_lengths*/, /* fetch_lengths */
- NULL/*loc_flush_use_result*/, /* flush_use_result */
- NULL/*loc_read_change_user_result*/ /* read_change_user_result */
+ loc_advanced_command, /* advanced_command */
+ loc_read_rows, /* read_rows */
+ mysql_store_result, /* use_result */
+ loc_fetch_lengths, /* fetch_lengths */
+ loc_flush_use_result, /* flush_use_result */
+ NULL, /* read_change_user_result */
+ loc_on_close_free /* on_close_free */
+#ifdef EMBEDDED_LIBRARY
+ ,NULL, /* list_fields */
+ NULL, /* read_prepare_result */
+ NULL, /* stmt_execute */
+ NULL, /* read_binary_rows */
+ NULL, /* unbuffered_fetch */
+ NULL, /* read_statistics */
+ NULL, /* next_result */
+ NULL /* read_rows_from_cursor */
+#endif
};
+Atomic_counter<uint32_t> local_connection_thread_count;
+
extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql,
- const char *host, const char *user, const char *passwd, const char *db)
+ const char *host, const char *user, const char *db,
+ unsigned long clientflag)
{
- //char name_buff[USERNAME_LENGTH];
-
+ THD *thd_orig= current_thd;
+ THD *new_thd;
+ Protocol_local *p;
DBUG_ENTER("mysql_real_connect_local");
/* Test whether we're already connected */
@@ -6191,137 +6371,50 @@ extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql,
if (!user || !user[0])
user=mysql->options.user;
- mysql->user= my_strdup(PSI_INSTRUMENT_ME, user, MYF(0));
-
+ mysql->user= NULL;
mysql->info_buffer= (char *) my_malloc(PSI_INSTRUMENT_ME,
MYSQL_ERRMSG_SIZE, MYF(0));
- //mysql->thd= create_embedded_thd(client_flag);
-
- //init_embedded_mysql(mysql, client_flag);
-
- //if (mysql_init_character_set(mysql))
- // goto error;
-
- //if (check_embedded_connection(mysql, db))
- // goto error;
-
- mysql->server_status= SERVER_STATUS_AUTOCOMMIT;
-
- //if (mysql->options.init_commands)
- //{
- // DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
- // char **ptr= (char**)init_commands->buffer;
- // char **end= ptr + init_commands->elements;
-//
- // for (; ptr<end; ptr++)
- // {
- // MYSQL_RES *res;
- // if (mysql_query(mysql,*ptr))
- // goto error;
- // if (mysql->fields)
- // {
- // if (!(res= (*mysql->methods->use_result)(mysql)))
- // goto error;
- // mysql_free_result(res);
- // }
- // }
- //}
-
- DBUG_PRINT("exit",("Mysql handler: %p", mysql));
- DBUG_RETURN(mysql);
-
-//error:
- DBUG_PRINT("error",("message: %u (%s)",
- mysql->net.last_errno,
- mysql->net.last_error));
+ if (!thd_orig || thd_orig->lock)
{
- /* Free alloced memory */
- my_bool free_me=mysql->free_me;
- free_old_query(mysql);
- mysql->free_me=0;
- mysql_close(mysql);
- mysql->free_me=free_me;
- }
- DBUG_RETURN(0);
-}
-
-
-extern "C" int execute_sql_command(const char *command,
- char *hosts, char *names, char *filters)
-{
- MYSQL_LEX_STRING sql_text;
- THD *thd= current_thd;
- THD *new_thd= 0;
- int result;
- my_bool qc_save= 0;
- Reprepare_observer *save_reprepare_observer= nullptr;
+ /*
+ When we start with the empty current_thd (that happens when plugins
+ are loaded during the server start) or when some tables are locked
+ with the current_thd already (that happens when INSTALL PLUGIN
+ calls the plugin_init or with queries), we create the new THD for
+ the local connection. So queries with this MYSQL will be run with
+ it rather than the current THD.
+ */
- if (!thd)
- {
new_thd= new THD(0);
- new_thd->thread_stack= (char*) &sql_text;
+ local_connection_thread_count++;
+ new_thd->thread_stack= (char*) &thd_orig;
new_thd->store_globals();
new_thd->security_ctx->skip_grants();
new_thd->query_cache_is_applicable= 0;
new_thd->variables.wsrep_on= 0;
+ /*
+ TOSO: decide if we should turn the auditing off
+ for such threads.
+ We can do it like this:
+ new_thd->audit_class_mask[0]= ~0;
+ */
bzero((char*) &new_thd->net, sizeof(new_thd->net));
- thd= new_thd;
+ set_current_thd(thd_orig);
+ thd_orig= new_thd;
}
else
- {
- if (thd->lock)
- /* Doesn't work if the thread opened/locked tables already. */
- return 2;
+ new_thd= NULL;
- qc_save= thd->query_cache_is_applicable;
- thd->query_cache_is_applicable= 0;
- save_reprepare_observer= thd->m_reprepare_observer;
- thd->m_reprepare_observer= nullptr;
- }
- sql_text.str= (char *) command;
- sql_text.length= strlen(command);
- {
- Protocol_local p(thd);
- Ed_connection con(thd);
- result= con.execute_direct(&p, sql_text);
- if (!result && p.first_data)
- {
- int nr= (int) p.first_data->rows;
- MYSQL_ROWS *rows= p.first_data->data;
+ p= new Protocol_local(thd_orig, new_thd, 0);
+ if (new_thd)
+ new_thd->protocol= p;
- while (nr--)
- {
- strcpy(hosts, rows->data[0]);
- hosts+= strlen(hosts) + 1;
- strcpy(names, rows->data[1]);
- names+= strlen(names) + 1;
- if (filters)
- {
- strcpy(filters, rows->data[2]);
- filters+= strlen(filters) + 1;
- }
- rows= rows->next;
- }
- }
- if (p.first_data)
- {
- if (p.alloc)
- free_root(p.alloc, MYF(0));
- my_free(p.first_data);
- }
- }
+ mysql->thd= p;
+ mysql->server_status= SERVER_STATUS_AUTOCOMMIT;
- if (new_thd)
- delete new_thd;
- else
- {
- thd->query_cache_is_applicable= qc_save;
- thd->m_reprepare_observer= save_reprepare_observer;
- }
- *hosts= 0;
- return result;
+ DBUG_PRINT("exit",("Mysql handler: %p", mysql));
+ DBUG_RETURN(mysql);
}
-#endif /*!EMBEDDED_LIBRARY*/
diff --git a/sql/sql_prepare.h b/sql/sql_prepare.h
index 166be95eb89..d4a03c433b2 100644
--- a/sql/sql_prepare.h
+++ b/sql/sql_prepare.h
@@ -351,4 +351,6 @@ private:
size_t m_column_count; /* TODO: change to point to metadata */
};
+extern Atomic_counter<uint32_t> local_connection_thread_count;
+
#endif // SQL_PREPARE_H
diff --git a/sql/thread_pool_info.cc b/sql/thread_pool_info.cc
index 90ac6871784..e3ffd160a11 100644
--- a/sql/thread_pool_info.cc
+++ b/sql/thread_pool_info.cc
@@ -14,9 +14,9 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 - 1301 USA*/
#include <mysql_version.h>
-#include <mysql/plugin.h>
#include <my_global.h>
+#include <mysql/plugin.h>
#include <sql_class.h>
#include <sql_i_s.h>
#include <mysql/plugin.h>