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 + +/** + @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 #include /*#include */ +#include #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_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'; -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 0 +Test_sql_service_passed 1 +set global test_sql_service_run_test= 1; +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_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 -#include #include #include -#include -//#include /* for enum enum_server_command */ -#include #include -//#include +#include -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; -extern int execute_sql_command(const char *command, - char *hosts, char *names, char *filters); +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; + + 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; - result= execute_sql_command("select 'plugin', name, dl from mysql.plugin", - plugins, names, dl); + mysql= mysql_init(NULL); + if (mysql_real_connect_local(mysql, NULL, NULL, NULL, 0) == NULL) + return 1; + + if (run_queries(mysql)) + goto exit; + + 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) { - test_passed= do_tests(); + 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) +{ + 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 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 count; static uint value() { return static_cast(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 #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 *list, uint flags) { List_iterator_fast 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 *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 *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 #include -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 }; -extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql, - const char *host, const char *user, const char *passwd, const char *db) -{ - //char name_buff[USERNAME_LENGTH]; +Atomic_counter local_connection_thread_count; +extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql, + const char *host, const char *user, const char *db, + unsigned long clientflag) +{ + 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 (; ptrfields) - // { - // 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); -} + /* + 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. + */ - -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; - - 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; - - 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; - - 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); - } - } + new_thd= NULL; + p= new Protocol_local(thd_orig, new_thd, 0); if (new_thd) - delete new_thd; - else - { - thd->query_cache_is_applicable= qc_save; - thd->m_reprepare_observer= save_reprepare_observer; - } + new_thd->protocol= p; - *hosts= 0; - return result; + mysql->thd= p; + mysql->server_status= SERVER_STATUS_AUTOCOMMIT; + + + 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 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 -#include #include +#include #include #include #include