mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
MDEV-19275 Provide SQL service to plugins.
SQL service added. It provides the limited set of client library functions to be used by plugin.
This commit is contained in:
parent
401ff6994d
commit
0a0dfd63d9
25 changed files with 701 additions and 253 deletions
|
@ -77,7 +77,7 @@ typedef struct st_mysql_xid MYSQL_XID;
|
||||||
#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0104
|
#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0104
|
||||||
|
|
||||||
/* MariaDB plugin interface version */
|
/* MariaDB plugin interface version */
|
||||||
#define MARIA_PLUGIN_INTERFACE_VERSION 0x010e
|
#define MARIA_PLUGIN_INTERFACE_VERSION 0x010f
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The allowable types of plugins
|
The allowable types of plugins
|
||||||
|
|
99
include/mysql/service_sql.h
Normal file
99
include/mysql/service_sql.h
Normal file
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ extern "C" {
|
||||||
#include <mysql/service_thd_wait.h>
|
#include <mysql/service_thd_wait.h>
|
||||||
#include <mysql/service_json.h>
|
#include <mysql/service_json.h>
|
||||||
/*#include <mysql/service_wsrep.h>*/
|
/*#include <mysql/service_wsrep.h>*/
|
||||||
|
#include <mysql/service_sql.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,3 +44,4 @@
|
||||||
#define VERSION_wsrep 0x0500
|
#define VERSION_wsrep 0x0500
|
||||||
#define VERSION_json 0x0100
|
#define VERSION_json 0x0100
|
||||||
#define VERSION_thd_mdl 0x0100
|
#define VERSION_thd_mdl 0x0100
|
||||||
|
#define VERSION_sql_service 0x0100
|
||||||
|
|
|
@ -61,13 +61,13 @@ typedef struct st_mysql_methods
|
||||||
MYSQL_ROW column, unsigned int field_count);
|
MYSQL_ROW column, unsigned int field_count);
|
||||||
void (*flush_use_result)(MYSQL *mysql, my_bool flush_all_results);
|
void (*flush_use_result)(MYSQL *mysql, my_bool flush_all_results);
|
||||||
int (*read_change_user_result)(MYSQL *mysql);
|
int (*read_change_user_result)(MYSQL *mysql);
|
||||||
|
void (*on_close_free)(MYSQL *mysql);
|
||||||
#if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
|
#if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
|
||||||
MYSQL_FIELD * (*list_fields)(MYSQL *mysql);
|
MYSQL_FIELD * (*list_fields)(MYSQL *mysql);
|
||||||
my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt);
|
my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt);
|
||||||
int (*stmt_execute)(MYSQL_STMT *stmt);
|
int (*stmt_execute)(MYSQL_STMT *stmt);
|
||||||
int (*read_binary_rows)(MYSQL_STMT *stmt);
|
int (*read_binary_rows)(MYSQL_STMT *stmt);
|
||||||
int (*unbuffered_fetch)(MYSQL *mysql, char **row);
|
int (*unbuffered_fetch)(MYSQL *mysql, char **row);
|
||||||
void (*free_embedded_thd)(MYSQL *mysql);
|
|
||||||
const char *(*read_statistics)(MYSQL *mysql);
|
const char *(*read_statistics)(MYSQL *mysql);
|
||||||
my_bool (*next_result)(MYSQL *mysql);
|
my_bool (*next_result)(MYSQL *mysql);
|
||||||
int (*read_rows_from_cursor)(MYSQL_STMT *stmt);
|
int (*read_rows_from_cursor)(MYSQL_STMT *stmt);
|
||||||
|
|
|
@ -43,7 +43,7 @@ C_MODE_START
|
||||||
extern unsigned int mysql_server_last_errno;
|
extern unsigned int mysql_server_last_errno;
|
||||||
extern char mysql_server_last_error[MYSQL_ERRMSG_SIZE];
|
extern char mysql_server_last_error[MYSQL_ERRMSG_SIZE];
|
||||||
static my_bool emb_read_query_result(MYSQL *mysql);
|
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;
|
static bool embedded_print_errors= 0;
|
||||||
|
|
||||||
extern "C" void unireg_clear(int exit_code)
|
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;
|
thd->killed= NOT_KILLED;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
emb_free_embedded_thd(mysql);
|
free_embedded_thd(mysql);
|
||||||
thd= 0;
|
thd= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -430,7 +430,7 @@ int emb_unbuffered_fetch(MYSQL *mysql, char **row)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emb_free_embedded_thd(MYSQL *mysql)
|
static void free_embedded_thd(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
THD *thd= (THD*)mysql->thd;
|
THD *thd= (THD*)mysql->thd;
|
||||||
server_threads.erase(thd);
|
server_threads.erase(thd);
|
||||||
|
@ -453,12 +453,23 @@ static MYSQL_RES * emb_store_result(MYSQL *mysql)
|
||||||
return mysql_store_result(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
|
mysql->net.read_pos= (uchar*)""; // fake an OK packet
|
||||||
return mysql_errno(mysql) ? (int)packet_error : 1 /* length of the 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=
|
MYSQL_METHODS embedded_methods=
|
||||||
{
|
{
|
||||||
emb_read_query_result,
|
emb_read_query_result,
|
||||||
|
@ -468,12 +479,12 @@ MYSQL_METHODS embedded_methods=
|
||||||
emb_fetch_lengths,
|
emb_fetch_lengths,
|
||||||
emb_flush_use_result,
|
emb_flush_use_result,
|
||||||
emb_read_change_user_result,
|
emb_read_change_user_result,
|
||||||
|
emb_on_close_free,
|
||||||
emb_list_fields,
|
emb_list_fields,
|
||||||
emb_read_prepare_result,
|
emb_read_prepare_result,
|
||||||
emb_stmt_execute,
|
emb_stmt_execute,
|
||||||
emb_read_binary_rows,
|
emb_read_binary_rows,
|
||||||
emb_unbuffered_fetch,
|
emb_unbuffered_fetch,
|
||||||
emb_free_embedded_thd,
|
|
||||||
emb_read_statistics,
|
emb_read_statistics,
|
||||||
emb_read_query_result,
|
emb_read_query_result,
|
||||||
emb_read_rows_from_cursor
|
emb_read_rows_from_cursor
|
||||||
|
|
|
@ -38,6 +38,7 @@ SET(MYSQLSERVICES_SOURCES
|
||||||
thd_wait_service.c
|
thd_wait_service.c
|
||||||
wsrep_service.c
|
wsrep_service.c
|
||||||
json_service.c
|
json_service.c
|
||||||
|
sql_service.c
|
||||||
)
|
)
|
||||||
|
|
||||||
ADD_CONVENIENCE_LIBRARY(mysqlservices ${MYSQLSERVICES_SOURCES})
|
ADD_CONVENIENCE_LIBRARY(mysqlservices ${MYSQLSERVICES_SOURCES})
|
||||||
|
|
19
libservices/sql_service.c
Normal file
19
libservices/sql_service.c
Normal file
|
@ -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;
|
|
@ -5,7 +5,7 @@ plugin_version 1.0
|
||||||
plugin_status ACTIVE
|
plugin_status ACTIVE
|
||||||
plugin_type DAEMON
|
plugin_type DAEMON
|
||||||
plugin_library handlersocket.so
|
plugin_library handlersocket.so
|
||||||
plugin_library_version 1.14
|
plugin_library_version 1.15
|
||||||
plugin_author higuchi dot akira at dena dot jp
|
plugin_author higuchi dot akira at dena dot jp
|
||||||
plugin_description Direct access into InnoDB
|
plugin_description Direct access into InnoDB
|
||||||
plugin_license BSD
|
plugin_license BSD
|
||||||
|
|
|
@ -12,7 +12,7 @@ PLUGIN_STATUS ACTIVE
|
||||||
PLUGIN_TYPE STORAGE ENGINE
|
PLUGIN_TYPE STORAGE ENGINE
|
||||||
PLUGIN_TYPE_VERSION #
|
PLUGIN_TYPE_VERSION #
|
||||||
PLUGIN_LIBRARY ha_example.so
|
PLUGIN_LIBRARY ha_example.so
|
||||||
PLUGIN_LIBRARY_VERSION 1.14
|
PLUGIN_LIBRARY_VERSION 1.15
|
||||||
PLUGIN_AUTHOR Brian Aker, MySQL AB
|
PLUGIN_AUTHOR Brian Aker, MySQL AB
|
||||||
PLUGIN_DESCRIPTION Example storage engine
|
PLUGIN_DESCRIPTION Example storage engine
|
||||||
PLUGIN_LICENSE GPL
|
PLUGIN_LICENSE GPL
|
||||||
|
@ -25,7 +25,7 @@ PLUGIN_STATUS ACTIVE
|
||||||
PLUGIN_TYPE DAEMON
|
PLUGIN_TYPE DAEMON
|
||||||
PLUGIN_TYPE_VERSION #
|
PLUGIN_TYPE_VERSION #
|
||||||
PLUGIN_LIBRARY ha_example.so
|
PLUGIN_LIBRARY ha_example.so
|
||||||
PLUGIN_LIBRARY_VERSION 1.14
|
PLUGIN_LIBRARY_VERSION 1.15
|
||||||
PLUGIN_AUTHOR Sergei Golubchik
|
PLUGIN_AUTHOR Sergei Golubchik
|
||||||
PLUGIN_DESCRIPTION Unusable Daemon
|
PLUGIN_DESCRIPTION Unusable Daemon
|
||||||
PLUGIN_LICENSE GPL
|
PLUGIN_LICENSE GPL
|
||||||
|
@ -64,7 +64,7 @@ PLUGIN_STATUS DELETED
|
||||||
PLUGIN_TYPE STORAGE ENGINE
|
PLUGIN_TYPE STORAGE ENGINE
|
||||||
PLUGIN_TYPE_VERSION #
|
PLUGIN_TYPE_VERSION #
|
||||||
PLUGIN_LIBRARY ha_example.so
|
PLUGIN_LIBRARY ha_example.so
|
||||||
PLUGIN_LIBRARY_VERSION 1.14
|
PLUGIN_LIBRARY_VERSION 1.15
|
||||||
PLUGIN_AUTHOR Brian Aker, MySQL AB
|
PLUGIN_AUTHOR Brian Aker, MySQL AB
|
||||||
PLUGIN_DESCRIPTION Example storage engine
|
PLUGIN_DESCRIPTION Example storage engine
|
||||||
PLUGIN_LICENSE GPL
|
PLUGIN_LICENSE GPL
|
||||||
|
|
|
@ -27,7 +27,7 @@ PLUGIN_STATUS ACTIVE
|
||||||
PLUGIN_TYPE AUTHENTICATION
|
PLUGIN_TYPE AUTHENTICATION
|
||||||
PLUGIN_TYPE_VERSION 2.2
|
PLUGIN_TYPE_VERSION 2.2
|
||||||
PLUGIN_LIBRARY auth_ed25519.so
|
PLUGIN_LIBRARY auth_ed25519.so
|
||||||
PLUGIN_LIBRARY_VERSION 1.14
|
PLUGIN_LIBRARY_VERSION 1.15
|
||||||
PLUGIN_AUTHOR Sergei Golubchik
|
PLUGIN_AUTHOR Sergei Golubchik
|
||||||
PLUGIN_DESCRIPTION Elliptic curve ED25519 based authentication
|
PLUGIN_DESCRIPTION Elliptic curve ED25519 based authentication
|
||||||
PLUGIN_LICENSE GPL
|
PLUGIN_LICENSE GPL
|
||||||
|
|
|
@ -6,7 +6,7 @@ PLUGIN_STATUS ACTIVE
|
||||||
PLUGIN_TYPE PASSWORD VALIDATION
|
PLUGIN_TYPE PASSWORD VALIDATION
|
||||||
PLUGIN_TYPE_VERSION 1.0
|
PLUGIN_TYPE_VERSION 1.0
|
||||||
PLUGIN_LIBRARY cracklib_password_check.so
|
PLUGIN_LIBRARY cracklib_password_check.so
|
||||||
PLUGIN_LIBRARY_VERSION 1.14
|
PLUGIN_LIBRARY_VERSION 1.15
|
||||||
PLUGIN_AUTHOR Sergei Golubchik
|
PLUGIN_AUTHOR Sergei Golubchik
|
||||||
PLUGIN_DESCRIPTION Password validation via CrackLib
|
PLUGIN_DESCRIPTION Password validation via CrackLib
|
||||||
PLUGIN_LICENSE GPL
|
PLUGIN_LICENSE GPL
|
||||||
|
|
|
@ -4,8 +4,8 @@ Variable_name Value
|
||||||
Opened_plugin_libraries 0
|
Opened_plugin_libraries 0
|
||||||
select * from information_schema.all_plugins where plugin_library='ha_example.so';
|
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
|
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
|
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.14 Sergei Golubchik Unusable Daemon GPL OFF Experimental 3.14.15.926
|
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%';
|
show status like '%libraries%';
|
||||||
Variable_name Value
|
Variable_name Value
|
||||||
Opened_plugin_libraries 1
|
Opened_plugin_libraries 1
|
||||||
|
|
|
@ -6,7 +6,7 @@ PLUGIN_STATUS ACTIVE
|
||||||
PLUGIN_TYPE PASSWORD VALIDATION
|
PLUGIN_TYPE PASSWORD VALIDATION
|
||||||
PLUGIN_TYPE_VERSION 1.0
|
PLUGIN_TYPE_VERSION 1.0
|
||||||
PLUGIN_LIBRARY simple_password_check.so
|
PLUGIN_LIBRARY simple_password_check.so
|
||||||
PLUGIN_LIBRARY_VERSION 1.14
|
PLUGIN_LIBRARY_VERSION 1.15
|
||||||
PLUGIN_AUTHOR Sergei Golubchik
|
PLUGIN_AUTHOR Sergei Golubchik
|
||||||
PLUGIN_DESCRIPTION Simple password strength checks
|
PLUGIN_DESCRIPTION Simple password strength checks
|
||||||
PLUGIN_LICENSE GPL
|
PLUGIN_LICENSE GPL
|
||||||
|
|
|
@ -1,8 +1,51 @@
|
||||||
install plugin test_sql_service soname 'test_sql_service';
|
install plugin test_sql_service soname 'test_sql_service';
|
||||||
set global test_sql_service_run_test= 1;
|
show status like 'test_sql_service_passed';
|
||||||
show status like 'test_sql_service%';
|
|
||||||
Variable_name Value
|
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;
|
uninstall plugin test_sql_service;
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1620 Plugin is busy and will be uninstalled on shutdown
|
Warning 1620 Plugin is busy and will be uninstalled on shutdown
|
||||||
|
|
|
@ -9,9 +9,40 @@ let count_sessions= 1;
|
||||||
source include/wait_until_count_sessions.inc;
|
source include/wait_until_count_sessions.inc;
|
||||||
|
|
||||||
install plugin test_sql_service soname 'test_sql_service';
|
install plugin test_sql_service soname 'test_sql_service';
|
||||||
|
show status like 'test_sql_service_passed';
|
||||||
|
|
||||||
set global test_sql_service_run_test= 1;
|
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;
|
uninstall plugin test_sql_service;
|
||||||
|
|
||||||
|
|
|
@ -15,4 +15,5 @@
|
||||||
|
|
||||||
SET(SOURCES test_sql_service.c)
|
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)
|
||||||
|
|
|
@ -14,71 +14,113 @@
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
|
||||||
|
|
||||||
|
|
||||||
#define PLUGIN_VERSION 0x100
|
#define PLUGIN_VERSION 0x20000
|
||||||
#define PLUGIN_STR_VERSION "1.0.0"
|
#define PLUGIN_STR_VERSION "2.0"
|
||||||
|
|
||||||
#define _my_thread_var loc_thread_var
|
|
||||||
|
|
||||||
#include <my_config.h>
|
#include <my_config.h>
|
||||||
#include <assert.h>
|
|
||||||
#include <my_global.h>
|
#include <my_global.h>
|
||||||
#include <my_base.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 <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 */
|
/* Status variables for SHOW STATUS */
|
||||||
static long test_passed= 0;
|
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[]=
|
static struct st_mysql_show_var test_sql_status[]=
|
||||||
{
|
{
|
||||||
{"test_sql_service_passed", (char *)&test_passed, SHOW_LONG},
|
{"test_sql_service_passed", (char *)&test_passed, SHOW_LONG},
|
||||||
|
{"test_sql_query_result", qwe_res, SHOW_CHAR},
|
||||||
{0,0,0}
|
{0,0,0}
|
||||||
};
|
};
|
||||||
|
|
||||||
static my_bool do_test= TRUE;
|
static my_bool do_test= TRUE;
|
||||||
static void run_test(MYSQL_THD thd, struct st_mysql_sys_var *var,
|
static int run_test(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
|
||||||
void *var_ptr, const void *save);
|
struct st_mysql_value *value);
|
||||||
static MYSQL_SYSVAR_BOOL(run_test, do_test, PLUGIN_VAR_OPCMDARG,
|
static int run_sql_local(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
|
||||||
"Perform the test now.", NULL, run_test, FALSE);
|
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[]=
|
static struct st_mysql_sys_var* test_sql_vars[]=
|
||||||
{
|
{
|
||||||
MYSQL_SYSVAR(run_test),
|
MYSQL_SYSVAR(run_test),
|
||||||
|
MYSQL_SYSVAR(execute_sql_local),
|
||||||
|
MYSQL_SYSVAR(execute_sql_global),
|
||||||
NULL
|
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()
|
static int do_tests()
|
||||||
{
|
{
|
||||||
char plugins[1024];
|
MYSQL *mysql;
|
||||||
char names[1024];
|
int result= 1;
|
||||||
char dl[2048];
|
|
||||||
int result;
|
|
||||||
|
|
||||||
result= execute_sql_command("select 'plugin', name, dl from mysql.plugin",
|
mysql= mysql_init(NULL);
|
||||||
plugins, names, dl);
|
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;
|
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)),
|
static int run_test(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
|
||||||
struct st_mysql_sys_var *var __attribute__((unused)),
|
struct st_mysql_value *value)
|
||||||
void *var_ptr __attribute__((unused)),
|
|
||||||
const void *save __attribute__((unused)))
|
|
||||||
{
|
{
|
||||||
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)))
|
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;
|
init_done= 1;
|
||||||
|
|
||||||
|
test_passed= (do_tests() == 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +238,8 @@ static int test_sql_service_plugin_deinit(void *p __attribute__((unused)))
|
||||||
if (!init_done)
|
if (!init_done)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
mysql_close(global_mysql);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1712,14 +1712,14 @@ static MYSQL_METHODS client_methods=
|
||||||
cli_use_result, /* use_result */
|
cli_use_result, /* use_result */
|
||||||
cli_fetch_lengths, /* fetch_lengths */
|
cli_fetch_lengths, /* fetch_lengths */
|
||||||
cli_flush_use_result, /* flush_use_result */
|
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
|
#ifndef MYSQL_SERVER
|
||||||
,cli_list_fields, /* list_fields */
|
,cli_list_fields, /* list_fields */
|
||||||
cli_read_prepare_result, /* read_prepare_result */
|
cli_read_prepare_result, /* read_prepare_result */
|
||||||
cli_stmt_execute, /* stmt_execute */
|
cli_stmt_execute, /* stmt_execute */
|
||||||
cli_read_binary_rows, /* read_binary_rows */
|
cli_read_binary_rows, /* read_binary_rows */
|
||||||
cli_unbuffered_fetch, /* unbuffered_fetch */
|
cli_unbuffered_fetch, /* unbuffered_fetch */
|
||||||
NULL, /* free_embedded_thd */
|
|
||||||
cli_read_statistics, /* read_statistics */
|
cli_read_statistics, /* read_statistics */
|
||||||
cli_read_query_result, /* next_result */
|
cli_read_query_result, /* next_result */
|
||||||
cli_read_binary_rows /* read_rows_from_cursor */
|
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->user);
|
||||||
my_free(mysql->passwd);
|
my_free(mysql->passwd);
|
||||||
my_free(mysql->db);
|
my_free(mysql->db);
|
||||||
#if defined(EMBEDDED_LIBRARY) || MYSQL_VERSION_ID >= 50100
|
if (mysql->methods && mysql->methods->on_close_free)
|
||||||
my_free(mysql->info_buffer);
|
(*mysql->methods->on_close_free)(mysql);
|
||||||
mysql->info_buffer= 0;
|
|
||||||
#endif
|
|
||||||
/* Clear pointers for better safety */
|
/* Clear pointers for better safety */
|
||||||
mysql->host_info= mysql->user= mysql->passwd= mysql->db= 0;
|
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_options(mysql);
|
||||||
mysql_close_free(mysql);
|
mysql_close_free(mysql);
|
||||||
mysql_detach_stmt_list(&mysql->stmts, "mysql_close");
|
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)
|
if (mysql->free_me)
|
||||||
my_free(mysql);
|
my_free(mysql);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1526,6 +1526,16 @@ static void end_ssl();
|
||||||
|
|
||||||
|
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#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
|
** Code to end mysqld
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -1757,7 +1767,7 @@ static void close_connections(void)
|
||||||
*/
|
*/
|
||||||
DBUG_PRINT("info", ("THD_count: %u", THD_count::value()));
|
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);
|
my_sleep(20000);
|
||||||
|
|
||||||
if (global_system_variables.log_warnings)
|
if (global_system_variables.log_warnings)
|
||||||
|
@ -1772,12 +1782,12 @@ static void close_connections(void)
|
||||||
/* All threads has now been aborted */
|
/* All threads has now been aborted */
|
||||||
DBUG_PRINT("quit", ("Waiting for threads to die (count=%u)", THD_count::value()));
|
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);
|
my_sleep(1000);
|
||||||
|
|
||||||
/* Kill phase 2 */
|
/* Kill phase 2 */
|
||||||
server_threads.iterate(kill_thread_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
|
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_table_stats();
|
||||||
init_global_index_stats();
|
init_global_index_stats();
|
||||||
|
init_update_queries();
|
||||||
|
|
||||||
/* Allow storage engine to give real error messages */
|
/* Allow storage engine to give real error messages */
|
||||||
if (unlikely(ha_init_errors()))
|
if (unlikely(ha_init_errors()))
|
||||||
|
@ -5063,6 +5074,9 @@ static int init_server_components()
|
||||||
|
|
||||||
tc_log= 0; // ha_initialize_handlerton() needs that
|
tc_log= 0; // ha_initialize_handlerton() needs that
|
||||||
|
|
||||||
|
if (ddl_log_initialize())
|
||||||
|
unireg_abort(1);
|
||||||
|
|
||||||
if (plugin_init(&remaining_argc, remaining_argv,
|
if (plugin_init(&remaining_argc, remaining_argv,
|
||||||
(opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
|
(opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
|
||||||
(opt_abort ? PLUGIN_INIT_SKIP_INITIALIZATION : 0)))
|
(opt_abort ? PLUGIN_INIT_SKIP_INITIALIZATION : 0)))
|
||||||
|
@ -5304,9 +5318,6 @@ static int init_server_components()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ddl_log_initialize())
|
|
||||||
unireg_abort(1);
|
|
||||||
|
|
||||||
tc_log= get_tc_log_implementation();
|
tc_log= get_tc_log_implementation();
|
||||||
|
|
||||||
if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
|
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();
|
ft_init_stopwords();
|
||||||
|
|
||||||
init_max_user_conn();
|
init_max_user_conn();
|
||||||
init_update_queries();
|
|
||||||
init_global_user_stats();
|
init_global_user_stats();
|
||||||
init_global_client_stats();
|
init_global_client_stats();
|
||||||
if (!opt_bootstrap)
|
if (!opt_bootstrap)
|
||||||
|
|
|
@ -1131,6 +1131,7 @@ struct THD_count
|
||||||
{
|
{
|
||||||
static Atomic_counter<uint32_t> count;
|
static Atomic_counter<uint32_t> count;
|
||||||
static uint value() { return static_cast<uint>(count); }
|
static uint value() { return static_cast<uint>(count); }
|
||||||
|
static uint connection_thd_count();
|
||||||
THD_count() { count++; }
|
THD_count() { count++; }
|
||||||
~THD_count() { count--; }
|
~THD_count() { count--; }
|
||||||
};
|
};
|
||||||
|
@ -3918,6 +3919,11 @@ public:
|
||||||
user_time= t;
|
user_time= t;
|
||||||
set_time();
|
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.
|
this is only used by replication and BINLOG command.
|
||||||
usecs > TIME_MAX_SECOND_PART means "was not in binlog"
|
usecs > TIME_MAX_SECOND_PART means "was not in binlog"
|
||||||
|
@ -3929,15 +3935,9 @@ public:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (sec_part <= TIME_MAX_SECOND_PART)
|
if (sec_part <= TIME_MAX_SECOND_PART)
|
||||||
{
|
force_set_time(t, sec_part);
|
||||||
start_time= system_time.sec= t;
|
|
||||||
start_time_sec_part= system_time.sec_part= sec_part;
|
|
||||||
}
|
|
||||||
else if (t != system_time.sec)
|
else if (t != system_time.sec)
|
||||||
{
|
force_set_time(t, 0);
|
||||||
start_time= system_time.sec= t;
|
|
||||||
start_time_sec_part= system_time.sec_part= 0;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
start_time= t;
|
start_time= t;
|
||||||
|
|
|
@ -230,6 +230,22 @@ static struct thd_mdl_service_st thd_mdl_handler=
|
||||||
thd_mdl_context
|
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[]=
|
static struct st_service_ref list_of_services[]=
|
||||||
{
|
{
|
||||||
{ "base64_service", VERSION_base64, &base64_handler },
|
{ "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 },
|
{ "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
|
||||||
{ "wsrep_service", VERSION_wsrep, &wsrep_handler },
|
{ "wsrep_service", VERSION_wsrep, &wsrep_handler },
|
||||||
{ "json_service", VERSION_json, &json_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 },
|
||||||
};
|
};
|
||||||
|
|
|
@ -133,6 +133,7 @@ static const uint PARAMETER_FLAG_UNSIGNED= 128U << 8;
|
||||||
#include "wsrep_trans_observer.h"
|
#include "wsrep_trans_observer.h"
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
#include "xa.h" // xa_recover_get_fields
|
#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.
|
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.
|
executions without having to cleanup/reset THD in between.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
static bool execute_server_code(THD *thd,
|
||||||
Execute_sql_statement::execute_server_code(THD *thd)
|
const char *sql_text, size_t sql_len)
|
||||||
{
|
{
|
||||||
PSI_statement_locker *parent_locker;
|
PSI_statement_locker *parent_locker;
|
||||||
bool error;
|
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;
|
return TRUE;
|
||||||
|
|
||||||
Parser_state parser_state;
|
Parser_state parser_state;
|
||||||
if (parser_state.init(thd, thd->query(), thd->query_length()))
|
if (parser_state.init(thd, thd->query(), thd->query_length()))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
thd->query_id= next_id;
|
||||||
parser_state.m_lip.multi_statements= FALSE;
|
parser_state.m_lip.multi_statements= FALSE;
|
||||||
lex_start(thd);
|
lex_start(thd);
|
||||||
|
|
||||||
|
@ -4079,17 +4083,23 @@ Execute_sql_statement::execute_server_code(THD *thd)
|
||||||
|
|
||||||
/* report error issued during command execution */
|
/* report error issued during command execution */
|
||||||
if (likely(error == 0) && thd->spcont == NULL)
|
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());
|
thd->query(), thd->query_length());
|
||||||
|
|
||||||
end:
|
end:
|
||||||
thd->lex->restore_set_statement_var();
|
thd->lex->restore_set_statement_var();
|
||||||
|
thd->query_id= save_query_id;
|
||||||
delete_explain_query(thd->lex);
|
delete_explain_query(thd->lex);
|
||||||
lex_end(thd->lex);
|
lex_end(thd->lex);
|
||||||
|
|
||||||
return error;
|
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
|
Prepared_statement
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -4850,7 +4860,10 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
|
||||||
Statement stmt_backup;
|
Statement stmt_backup;
|
||||||
bool error;
|
bool error;
|
||||||
Query_arena *save_stmt_arena= thd->stmt_arena;
|
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;
|
Item_change_list save_change_list;
|
||||||
|
|
||||||
thd->Item_change_list::move_elements_to(&save_change_list);
|
thd->Item_change_list::move_elements_to(&save_change_list);
|
||||||
|
|
||||||
state= STMT_CONVENTIONAL_EXECUTION;
|
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))
|
if (!(lex= new (mem_root) st_lex_local))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
thd->set_time();
|
||||||
thd->set_n_backup_statement(this, &stmt_backup);
|
thd->set_n_backup_statement(this, &stmt_backup);
|
||||||
thd->set_n_backup_active_arena(this, &stmt_backup);
|
thd->set_n_backup_active_arena(this, &stmt_backup);
|
||||||
thd->stmt_arena= this;
|
thd->stmt_arena= this;
|
||||||
|
@ -4871,6 +4885,7 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
|
||||||
thd->stmt_arena= save_stmt_arena;
|
thd->stmt_arena= save_stmt_arena;
|
||||||
|
|
||||||
save_change_list.move_elements_to(thd);
|
save_change_list.move_elements_to(thd);
|
||||||
|
thd->force_set_time(save_query_start, save_query_sec);
|
||||||
|
|
||||||
/* Items and memory will freed in destructor */
|
/* Items and memory will freed in destructor */
|
||||||
|
|
||||||
|
@ -5582,14 +5597,6 @@ Ed_connection::store_result_set()
|
||||||
return ed_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 <mysql.h>
|
||||||
#include "../libmysqld/embedded_priv.h"
|
#include "../libmysqld/embedded_priv.h"
|
||||||
|
@ -5605,11 +5612,13 @@ public:
|
||||||
char **next_field;
|
char **next_field;
|
||||||
MYSQL_FIELD *next_mysql_field;
|
MYSQL_FIELD *next_mysql_field;
|
||||||
MEM_ROOT *alloc;
|
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),
|
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:
|
protected:
|
||||||
bool net_store_data(const uchar *from, size_t length);
|
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,
|
static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length,
|
||||||
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
|
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);
|
List_iterator_fast<Item> it(*list);
|
||||||
Item *item;
|
Item *item;
|
||||||
// Protocol_local prot(thd);
|
|
||||||
DBUG_ENTER("send_result_set_metadata");
|
DBUG_ENTER("send_result_set_metadata");
|
||||||
|
|
||||||
// if (!thd->mysql) // bootstrap file handling
|
// 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++)
|
for (uint pos= 0 ; (item= it++); pos++)
|
||||||
{
|
{
|
||||||
if (/*prot.*/store_item_metadata(thd, item, pos))
|
if (store_item_metadata(thd, item, pos))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5999,6 +6021,7 @@ bool Protocol_local::send_result_set_metadata(List<Item> *list, uint flags)
|
||||||
DBUG_RETURN(1); /* purecov: inspected */
|
DBUG_RETURN(1); /* purecov: inspected */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
list_fields_send_default(THD *thd, Protocol_local *p, Field *fld, uint pos)
|
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 <sql_common.h>
|
||||||
#include <errmsg.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)
|
static void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data)
|
||||||
{
|
{
|
||||||
NET *net= &mysql->net;
|
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)
|
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;
|
MYSQL_DATA *res= p->first_data;
|
||||||
DBUG_ASSERT(!thd->cur_data);
|
DBUG_ASSERT(!p->cur_data);
|
||||||
thd->first_data= res->embedded_info->next;
|
p->first_data= res->embedded_info->next;
|
||||||
if (res->embedded_info->last_errno &&
|
if (res->embedded_info->last_errno &&
|
||||||
!res->embedded_info->fields_list)
|
!res->embedded_info->fields_list)
|
||||||
{
|
{
|
||||||
|
@ -6145,7 +6155,7 @@ static my_bool loc_read_query_result(MYSQL *mysql)
|
||||||
if (res->embedded_info->fields_list)
|
if (res->embedded_info->fields_list)
|
||||||
{
|
{
|
||||||
mysql->status=MYSQL_STATUS_GET_RESULT;
|
mysql->status=MYSQL_STATUS_GET_RESULT;
|
||||||
thd->cur_data= res;
|
p->cur_data= res;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
my_free(res);
|
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=
|
static MYSQL_METHODS local_methods=
|
||||||
{
|
{
|
||||||
loc_read_query_result, /* read_query_result */
|
loc_read_query_result, /* read_query_result */
|
||||||
NULL/*loc_advanced_command*/, /* advanced_command */
|
loc_advanced_command, /* advanced_command */
|
||||||
NULL/*loc_read_rows*/, /* read_rows */
|
loc_read_rows, /* read_rows */
|
||||||
NULL/*loc_use_result*/, /* use_result */
|
mysql_store_result, /* use_result */
|
||||||
NULL/*loc_fetch_lengths*/, /* fetch_lengths */
|
loc_fetch_lengths, /* fetch_lengths */
|
||||||
NULL/*loc_flush_use_result*/, /* flush_use_result */
|
loc_flush_use_result, /* flush_use_result */
|
||||||
NULL/*loc_read_change_user_result*/ /* read_change_user_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,
|
Atomic_counter<uint32_t> local_connection_thread_count;
|
||||||
const char *host, const char *user, const char *passwd, const char *db)
|
|
||||||
{
|
|
||||||
//char name_buff[USERNAME_LENGTH];
|
|
||||||
|
|
||||||
|
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");
|
DBUG_ENTER("mysql_real_connect_local");
|
||||||
|
|
||||||
/* Test whether we're already connected */
|
/* Test whether we're already connected */
|
||||||
|
@ -6191,137 +6371,50 @@ extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql,
|
||||||
if (!user || !user[0])
|
if (!user || !user[0])
|
||||||
user=mysql->options.user;
|
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->info_buffer= (char *) my_malloc(PSI_INSTRUMENT_ME,
|
||||||
MYSQL_ERRMSG_SIZE, MYF(0));
|
MYSQL_ERRMSG_SIZE, MYF(0));
|
||||||
//mysql->thd= create_embedded_thd(client_flag);
|
if (!thd_orig || thd_orig->lock)
|
||||||
|
|
||||||
//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));
|
|
||||||
{
|
{
|
||||||
/* Free alloced memory */
|
/*
|
||||||
my_bool free_me=mysql->free_me;
|
When we start with the empty current_thd (that happens when plugins
|
||||||
free_old_query(mysql);
|
are loaded during the server start) or when some tables are locked
|
||||||
mysql->free_me=0;
|
with the current_thd already (that happens when INSTALL PLUGIN
|
||||||
mysql_close(mysql);
|
calls the plugin_init or with queries), we create the new THD for
|
||||||
mysql->free_me=free_me;
|
the local connection. So queries with this MYSQL will be run with
|
||||||
}
|
it rather than the current THD.
|
||||||
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;
|
|
||||||
|
|
||||||
if (!thd)
|
|
||||||
{
|
|
||||||
new_thd= new THD(0);
|
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->store_globals();
|
||||||
new_thd->security_ctx->skip_grants();
|
new_thd->security_ctx->skip_grants();
|
||||||
new_thd->query_cache_is_applicable= 0;
|
new_thd->query_cache_is_applicable= 0;
|
||||||
new_thd->variables.wsrep_on= 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));
|
bzero((char*) &new_thd->net, sizeof(new_thd->net));
|
||||||
thd= new_thd;
|
set_current_thd(thd_orig);
|
||||||
|
thd_orig= new_thd;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
new_thd= NULL;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
p= new Protocol_local(thd_orig, new_thd, 0);
|
||||||
if (new_thd)
|
if (new_thd)
|
||||||
delete new_thd;
|
new_thd->protocol= p;
|
||||||
else
|
|
||||||
{
|
|
||||||
thd->query_cache_is_applicable= qc_save;
|
|
||||||
thd->m_reprepare_observer= save_reprepare_observer;
|
|
||||||
}
|
|
||||||
|
|
||||||
*hosts= 0;
|
mysql->thd= p;
|
||||||
return result;
|
mysql->server_status= SERVER_STATUS_AUTOCOMMIT;
|
||||||
|
|
||||||
|
|
||||||
|
DBUG_PRINT("exit",("Mysql handler: %p", mysql));
|
||||||
|
DBUG_RETURN(mysql);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /*!EMBEDDED_LIBRARY*/
|
|
||||||
|
|
|
@ -351,4 +351,6 @@ private:
|
||||||
size_t m_column_count; /* TODO: change to point to metadata */
|
size_t m_column_count; /* TODO: change to point to metadata */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern Atomic_counter<uint32_t> local_connection_thread_count;
|
||||||
|
|
||||||
#endif // SQL_PREPARE_H
|
#endif // SQL_PREPARE_H
|
||||||
|
|
|
@ -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*/
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 - 1301 USA*/
|
||||||
|
|
||||||
#include <mysql_version.h>
|
#include <mysql_version.h>
|
||||||
#include <mysql/plugin.h>
|
|
||||||
|
|
||||||
#include <my_global.h>
|
#include <my_global.h>
|
||||||
|
#include <mysql/plugin.h>
|
||||||
#include <sql_class.h>
|
#include <sql_class.h>
|
||||||
#include <sql_i_s.h>
|
#include <sql_i_s.h>
|
||||||
#include <mysql/plugin.h>
|
#include <mysql/plugin.h>
|
||||||
|
|
Loading…
Reference in a new issue