diff options
author | Alexey Botchkov <holyfoot@askmonty.org> | 2021-09-06 22:34:35 +0400 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2021-10-19 17:35:06 +0200 |
commit | 0a0dfd63d9a0ae5adb139159e0aeca93c5c2d5c9 (patch) | |
tree | 66209a932d5575a6c3021ab1d215c16e9a3bead7 | |
parent | 401ff6994d842a4072b7b155e5a958e178e6497a (diff) | |
download | mariadb-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.
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> |