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
|
||||
|
||||
/* MariaDB plugin interface version */
|
||||
#define MARIA_PLUGIN_INTERFACE_VERSION 0x010e
|
||||
#define MARIA_PLUGIN_INTERFACE_VERSION 0x010f
|
||||
|
||||
/*
|
||||
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_json.h>
|
||||
/*#include <mysql/service_wsrep.h>*/
|
||||
#include <mysql/service_sql.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -44,3 +44,4 @@
|
|||
#define VERSION_wsrep 0x0500
|
||||
#define VERSION_json 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);
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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})
|
||||
|
|
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_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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -14,71 +14,113 @@
|
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
|
||||
|
||||
|
||||
#define PLUGIN_VERSION 0x100
|
||||
#define PLUGIN_STR_VERSION "1.0.0"
|
||||
|
||||
#define _my_thread_var loc_thread_var
|
||||
#define PLUGIN_VERSION 0x20000
|
||||
#define PLUGIN_STR_VERSION "2.0"
|
||||
|
||||
#include <my_config.h>
|
||||
#include <assert.h>
|
||||
#include <my_global.h>
|
||||
#include <my_base.h>
|
||||
#include <typelib.h>
|
||||
//#include <mysql_com.h> /* for enum enum_server_command */
|
||||
#include <mysql/plugin.h>
|
||||
#include <mysql/plugin_audit.h>
|
||||
//#include <string.h>
|
||||
#include <mysql.h>
|
||||
|
||||
|
||||
LEX_STRING * thd_query_string (MYSQL_THD thd);
|
||||
unsigned long long thd_query_id(const MYSQL_THD thd);
|
||||
size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen);
|
||||
const char *thd_user_name(MYSQL_THD thd);
|
||||
const char *thd_client_host(MYSQL_THD thd);
|
||||
const char *thd_client_ip(MYSQL_THD thd);
|
||||
LEX_CSTRING *thd_current_db(MYSQL_THD thd);
|
||||
int thd_current_status(MYSQL_THD thd);
|
||||
enum enum_server_command thd_current_command(MYSQL_THD thd);
|
||||
|
||||
int maria_compare_hostname(const char *wild_host, long wild_ip, long ip_mask,
|
||||
const char *host, const char *ip);
|
||||
void maria_update_hostname(const char **wild_host, long *wild_ip, long *ip_mask,
|
||||
const char *host);
|
||||
|
||||
/* Status variables for SHOW STATUS */
|
||||
static long test_passed= 0;
|
||||
static char *sql_text_local, *sql_text_global;
|
||||
static char qwe_res[1024]= "";
|
||||
|
||||
static struct st_mysql_show_var test_sql_status[]=
|
||||
{
|
||||
{"test_sql_service_passed", (char *)&test_passed, SHOW_LONG},
|
||||
{"test_sql_query_result", qwe_res, SHOW_CHAR},
|
||||
{0,0,0}
|
||||
};
|
||||
|
||||
static my_bool do_test= TRUE;
|
||||
static void run_test(MYSQL_THD thd, struct st_mysql_sys_var *var,
|
||||
void *var_ptr, const void *save);
|
||||
static MYSQL_SYSVAR_BOOL(run_test, do_test, PLUGIN_VAR_OPCMDARG,
|
||||
"Perform the test now.", NULL, run_test, FALSE);
|
||||
static int run_test(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
|
||||
struct st_mysql_value *value);
|
||||
static int run_sql_local(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
|
||||
struct st_mysql_value *value);
|
||||
static int run_sql_global(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
|
||||
struct st_mysql_value *value);
|
||||
|
||||
static void noop_update(MYSQL_THD thd, struct st_mysql_sys_var *var,
|
||||
void *var_ptr, const void *save);
|
||||
|
||||
static MYSQL_SYSVAR_BOOL(run_test, do_test,
|
||||
PLUGIN_VAR_OPCMDARG,
|
||||
"Perform the test now.",
|
||||
run_test, NULL, FALSE);
|
||||
|
||||
static MYSQL_SYSVAR_STR(execute_sql_local, sql_text_local,
|
||||
PLUGIN_VAR_OPCMDARG,
|
||||
"Create the new local connection, execute SQL statement with it.",
|
||||
run_sql_local, noop_update, FALSE);
|
||||
|
||||
static MYSQL_SYSVAR_STR(execute_sql_global, sql_text_global,
|
||||
PLUGIN_VAR_OPCMDARG,
|
||||
"Execute SQL statement using the global connection.",
|
||||
run_sql_global, noop_update, FALSE);
|
||||
|
||||
static struct st_mysql_sys_var* test_sql_vars[]=
|
||||
{
|
||||
MYSQL_SYSVAR(run_test),
|
||||
MYSQL_SYSVAR(execute_sql_local),
|
||||
MYSQL_SYSVAR(execute_sql_global),
|
||||
NULL
|
||||
};
|
||||
|
||||
static MYSQL *global_mysql;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1526,6 +1526,16 @@ static void end_ssl();
|
|||
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
extern Atomic_counter<uint32_t> local_connection_thread_count;
|
||||
|
||||
uint THD_count::connection_thd_count()
|
||||
{
|
||||
return value() -
|
||||
binlog_dump_thread_count -
|
||||
local_connection_thread_count;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
** Code to end mysqld
|
||||
****************************************************************************/
|
||||
|
@ -1757,7 +1767,7 @@ static void close_connections(void)
|
|||
*/
|
||||
DBUG_PRINT("info", ("THD_count: %u", THD_count::value()));
|
||||
|
||||
for (int i= 0; (THD_count::value() - binlog_dump_thread_count) && i < 1000; i++)
|
||||
for (int i= 0; (THD_count::connection_thd_count()) && i < 1000; i++)
|
||||
my_sleep(20000);
|
||||
|
||||
if (global_system_variables.log_warnings)
|
||||
|
@ -1772,12 +1782,12 @@ static void close_connections(void)
|
|||
/* All threads has now been aborted */
|
||||
DBUG_PRINT("quit", ("Waiting for threads to die (count=%u)", THD_count::value()));
|
||||
|
||||
while (THD_count::value() - binlog_dump_thread_count)
|
||||
while (THD_count::connection_thd_count())
|
||||
my_sleep(1000);
|
||||
|
||||
/* Kill phase 2 */
|
||||
server_threads.iterate(kill_thread_phase_2);
|
||||
for (uint64 i= 0; THD_count::value(); i++)
|
||||
for (uint64 i= 0; THD_count::connection_thd_count(); i++)
|
||||
{
|
||||
/*
|
||||
This time the warnings are emitted within the loop to provide a
|
||||
|
@ -5056,6 +5066,7 @@ static int init_server_components()
|
|||
|
||||
init_global_table_stats();
|
||||
init_global_index_stats();
|
||||
init_update_queries();
|
||||
|
||||
/* Allow storage engine to give real error messages */
|
||||
if (unlikely(ha_init_errors()))
|
||||
|
@ -5063,6 +5074,9 @@ static int init_server_components()
|
|||
|
||||
tc_log= 0; // ha_initialize_handlerton() needs that
|
||||
|
||||
if (ddl_log_initialize())
|
||||
unireg_abort(1);
|
||||
|
||||
if (plugin_init(&remaining_argc, remaining_argv,
|
||||
(opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
|
||||
(opt_abort ? PLUGIN_INIT_SKIP_INITIALIZATION : 0)))
|
||||
|
@ -5304,9 +5318,6 @@ static int init_server_components()
|
|||
}
|
||||
#endif
|
||||
|
||||
if (ddl_log_initialize())
|
||||
unireg_abort(1);
|
||||
|
||||
tc_log= get_tc_log_implementation();
|
||||
|
||||
if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
|
||||
|
@ -5387,7 +5398,6 @@ static int init_server_components()
|
|||
ft_init_stopwords();
|
||||
|
||||
init_max_user_conn();
|
||||
init_update_queries();
|
||||
init_global_user_stats();
|
||||
init_global_client_stats();
|
||||
if (!opt_bootstrap)
|
||||
|
|
|
@ -1131,6 +1131,7 @@ struct THD_count
|
|||
{
|
||||
static Atomic_counter<uint32_t> count;
|
||||
static uint value() { return static_cast<uint>(count); }
|
||||
static uint connection_thd_count();
|
||||
THD_count() { count++; }
|
||||
~THD_count() { count--; }
|
||||
};
|
||||
|
@ -3918,6 +3919,11 @@ public:
|
|||
user_time= t;
|
||||
set_time();
|
||||
}
|
||||
inline void force_set_time(my_time_t t, ulong sec_part)
|
||||
{
|
||||
start_time= system_time.sec= t;
|
||||
start_time_sec_part= system_time.sec_part= sec_part;
|
||||
}
|
||||
/*
|
||||
this is only used by replication and BINLOG command.
|
||||
usecs > TIME_MAX_SECOND_PART means "was not in binlog"
|
||||
|
@ -3929,15 +3935,9 @@ public:
|
|||
else
|
||||
{
|
||||
if (sec_part <= TIME_MAX_SECOND_PART)
|
||||
{
|
||||
start_time= system_time.sec= t;
|
||||
start_time_sec_part= system_time.sec_part= sec_part;
|
||||
}
|
||||
force_set_time(t, sec_part);
|
||||
else if (t != system_time.sec)
|
||||
{
|
||||
start_time= system_time.sec= t;
|
||||
start_time_sec_part= system_time.sec_part= 0;
|
||||
}
|
||||
force_set_time(t, 0);
|
||||
else
|
||||
{
|
||||
start_time= t;
|
||||
|
|
|
@ -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 },
|
||||
};
|
||||
|
|
|
@ -133,6 +133,7 @@ static const uint PARAMETER_FLAG_UNSIGNED= 128U << 8;
|
|||
#include "wsrep_trans_observer.h"
|
||||
#endif /* WITH_WSREP */
|
||||
#include "xa.h" // xa_recover_get_fields
|
||||
#include "sql_audit.h" // mysql_audit_release
|
||||
|
||||
/**
|
||||
A result class used to send cursor rows using the binary protocol.
|
||||
|
@ -4049,19 +4050,22 @@ Execute_sql_statement(LEX_STRING sql_text)
|
|||
executions without having to cleanup/reset THD in between.
|
||||
*/
|
||||
|
||||
bool
|
||||
Execute_sql_statement::execute_server_code(THD *thd)
|
||||
static bool execute_server_code(THD *thd,
|
||||
const char *sql_text, size_t sql_len)
|
||||
{
|
||||
PSI_statement_locker *parent_locker;
|
||||
bool error;
|
||||
query_id_t save_query_id= thd->query_id;
|
||||
query_id_t next_id= next_query_id();
|
||||
|
||||
if (alloc_query(thd, m_sql_text.str, m_sql_text.length))
|
||||
if (alloc_query(thd, sql_text, sql_len))
|
||||
return TRUE;
|
||||
|
||||
Parser_state parser_state;
|
||||
if (parser_state.init(thd, thd->query(), thd->query_length()))
|
||||
return TRUE;
|
||||
|
||||
thd->query_id= next_id;
|
||||
parser_state.m_lip.multi_statements= FALSE;
|
||||
lex_start(thd);
|
||||
|
||||
|
@ -4079,17 +4083,23 @@ Execute_sql_statement::execute_server_code(THD *thd)
|
|||
|
||||
/* report error issued during command execution */
|
||||
if (likely(error == 0) && thd->spcont == NULL)
|
||||
general_log_write(thd, COM_STMT_EXECUTE,
|
||||
general_log_write(thd, COM_QUERY,
|
||||
thd->query(), thd->query_length());
|
||||
|
||||
end:
|
||||
thd->lex->restore_set_statement_var();
|
||||
thd->query_id= save_query_id;
|
||||
delete_explain_query(thd->lex);
|
||||
lex_end(thd->lex);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
bool Execute_sql_statement::execute_server_code(THD *thd)
|
||||
{
|
||||
return ::execute_server_code(thd, m_sql_text.str, m_sql_text.length);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Prepared_statement
|
||||
****************************************************************************/
|
||||
|
@ -4850,7 +4860,10 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
|
|||
Statement stmt_backup;
|
||||
bool error;
|
||||
Query_arena *save_stmt_arena= thd->stmt_arena;
|
||||
my_time_t save_query_start= thd->query_start();
|
||||
ulong save_query_sec= thd->start_time_sec_part;
|
||||
Item_change_list save_change_list;
|
||||
|
||||
thd->Item_change_list::move_elements_to(&save_change_list);
|
||||
|
||||
state= STMT_CONVENTIONAL_EXECUTION;
|
||||
|
@ -4858,6 +4871,7 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
|
|||
if (!(lex= new (mem_root) st_lex_local))
|
||||
return TRUE;
|
||||
|
||||
thd->set_time();
|
||||
thd->set_n_backup_statement(this, &stmt_backup);
|
||||
thd->set_n_backup_active_arena(this, &stmt_backup);
|
||||
thd->stmt_arena= this;
|
||||
|
@ -4871,6 +4885,7 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
|
|||
thd->stmt_arena= save_stmt_arena;
|
||||
|
||||
save_change_list.move_elements_to(thd);
|
||||
thd->force_set_time(save_query_start, save_query_sec);
|
||||
|
||||
/* Items and memory will freed in destructor */
|
||||
|
||||
|
@ -5582,14 +5597,6 @@ Ed_connection::store_result_set()
|
|||
return ed_result_set;
|
||||
}
|
||||
|
||||
/*
|
||||
MENT-56
|
||||
Protocol_local and service_sql for plugins to enable 'local' SQL query execution.
|
||||
*/
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
// This part is mostly copied from libmysqld/lib_sql.cc
|
||||
// TODO: get rid of code duplications
|
||||
|
||||
#include <mysql.h>
|
||||
#include "../libmysqld/embedded_priv.h"
|
||||
|
@ -5605,11 +5612,13 @@ public:
|
|||
char **next_field;
|
||||
MYSQL_FIELD *next_mysql_field;
|
||||
MEM_ROOT *alloc;
|
||||
THD *new_thd;
|
||||
|
||||
Protocol_local(THD *thd_arg, ulong prealloc= 0) :
|
||||
Protocol_local(THD *thd_arg, THD *new_thd_arg, ulong prealloc) :
|
||||
Protocol_text(thd_arg, prealloc),
|
||||
cur_data(0), first_data(0), data_tail(&first_data), alloc(0)
|
||||
{}
|
||||
cur_data(0), first_data(0), data_tail(&first_data), alloc(0),
|
||||
new_thd(new_thd_arg)
|
||||
{}
|
||||
|
||||
protected:
|
||||
bool net_store_data(const uchar *from, size_t length);
|
||||
|
@ -5681,6 +5690,20 @@ MYSQL_DATA *Protocol_local::alloc_new_dataset()
|
|||
}
|
||||
|
||||
|
||||
void Protocol_local::clear_data_list()
|
||||
{
|
||||
while (first_data)
|
||||
{
|
||||
MYSQL_DATA *data= first_data;
|
||||
first_data= data->embedded_info->next;
|
||||
free_rows(data);
|
||||
}
|
||||
data_tail= &first_data;
|
||||
free_rows(cur_data);
|
||||
cur_data= 0;
|
||||
}
|
||||
|
||||
|
||||
static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length,
|
||||
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
|
||||
{
|
||||
|
@ -5974,7 +5997,6 @@ bool Protocol_local::send_result_set_metadata(List<Item> *list, uint flags)
|
|||
{
|
||||
List_iterator_fast<Item> it(*list);
|
||||
Item *item;
|
||||
// Protocol_local prot(thd);
|
||||
DBUG_ENTER("send_result_set_metadata");
|
||||
|
||||
// if (!thd->mysql) // bootstrap file handling
|
||||
|
@ -5985,7 +6007,7 @@ bool Protocol_local::send_result_set_metadata(List<Item> *list, uint flags)
|
|||
|
||||
for (uint pos= 0 ; (item= it++); pos++)
|
||||
{
|
||||
if (/*prot.*/store_item_metadata(thd, item, pos))
|
||||
if (store_item_metadata(thd, item, pos))
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -5999,6 +6021,7 @@ bool Protocol_local::send_result_set_metadata(List<Item> *list, uint flags)
|
|||
DBUG_RETURN(1); /* purecov: inspected */
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
list_fields_send_default(THD *thd, Protocol_local *p, Field *fld, uint pos)
|
||||
{
|
||||
|
@ -6086,19 +6109,6 @@ bool Protocol_local::store_null()
|
|||
#include <sql_common.h>
|
||||
#include <errmsg.h>
|
||||
|
||||
struct local_results
|
||||
{
|
||||
struct st_mysql_data *cur_data;
|
||||
struct st_mysql_data *first_data;
|
||||
struct st_mysql_data **data_tail;
|
||||
void clear_data_list();
|
||||
struct st_mysql_data *alloc_new_dataset();
|
||||
char **next_field;
|
||||
MYSQL_FIELD *next_mysql_field;
|
||||
MEM_ROOT *alloc;
|
||||
};
|
||||
|
||||
|
||||
static void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data)
|
||||
{
|
||||
NET *net= &mysql->net;
|
||||
|
@ -6113,11 +6123,11 @@ static void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data)
|
|||
|
||||
static my_bool loc_read_query_result(MYSQL *mysql)
|
||||
{
|
||||
local_results *thd= (local_results *) mysql->thd;
|
||||
Protocol_local *p= (Protocol_local *) mysql->thd;
|
||||
|
||||
MYSQL_DATA *res= thd->first_data;
|
||||
DBUG_ASSERT(!thd->cur_data);
|
||||
thd->first_data= res->embedded_info->next;
|
||||
MYSQL_DATA *res= p->first_data;
|
||||
DBUG_ASSERT(!p->cur_data);
|
||||
p->first_data= res->embedded_info->next;
|
||||
if (res->embedded_info->last_errno &&
|
||||
!res->embedded_info->fields_list)
|
||||
{
|
||||
|
@ -6145,7 +6155,7 @@ static my_bool loc_read_query_result(MYSQL *mysql)
|
|||
if (res->embedded_info->fields_list)
|
||||
{
|
||||
mysql->status=MYSQL_STATUS_GET_RESULT;
|
||||
thd->cur_data= res;
|
||||
p->cur_data= res;
|
||||
}
|
||||
else
|
||||
my_free(res);
|
||||
|
@ -6154,23 +6164,193 @@ static my_bool loc_read_query_result(MYSQL *mysql)
|
|||
}
|
||||
|
||||
|
||||
static my_bool
|
||||
loc_advanced_command(MYSQL *mysql, enum enum_server_command command,
|
||||
const uchar *header, ulong header_length,
|
||||
const uchar *arg, ulong arg_length, my_bool skip_check,
|
||||
MYSQL_STMT *stmt)
|
||||
{
|
||||
my_bool result= 1;
|
||||
Protocol_local *p= (Protocol_local *) mysql->thd;
|
||||
NET *net= &mysql->net;
|
||||
|
||||
if (p->thd && p->thd->killed != NOT_KILLED)
|
||||
{
|
||||
if (p->thd->killed < KILL_CONNECTION)
|
||||
p->thd->killed= NOT_KILLED;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
p->clear_data_list();
|
||||
/* Check that we are calling the client functions in right order */
|
||||
if (mysql->status != MYSQL_STATUS_READY)
|
||||
{
|
||||
set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Clear result variables */
|
||||
p->thd->clear_error(1);
|
||||
mysql->affected_rows= ~(my_ulonglong) 0;
|
||||
mysql->field_count= 0;
|
||||
net_clear_error(net);
|
||||
|
||||
/*
|
||||
We have to call free_old_query before we start to fill mysql->fields
|
||||
for new query. In the case of embedded server we collect field data
|
||||
during query execution (not during data retrieval as it is in remote
|
||||
client). So we have to call free_old_query here
|
||||
*/
|
||||
free_old_query(mysql);
|
||||
|
||||
if (header)
|
||||
{
|
||||
arg= header;
|
||||
arg_length= header_length;
|
||||
}
|
||||
|
||||
if (p->new_thd)
|
||||
{
|
||||
THD *thd_orig= current_thd;
|
||||
set_current_thd(p->thd);
|
||||
p->thd->thread_stack= (char*) &result;
|
||||
p->thd->set_time();
|
||||
result= execute_server_code(p->thd, (const char *)arg, arg_length);
|
||||
p->thd->cleanup_after_query();
|
||||
mysql_audit_release(p->thd);
|
||||
p->end_statement();
|
||||
set_current_thd(thd_orig);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ed_connection con(p->thd);
|
||||
MYSQL_LEX_STRING sql_text;
|
||||
DBUG_ASSERT(current_thd == p->thd);
|
||||
sql_text.str= (char *) arg;
|
||||
sql_text.length= arg_length;
|
||||
result= con.execute_direct(p, sql_text);
|
||||
}
|
||||
if (skip_check)
|
||||
result= 0;
|
||||
p->cur_data= 0;
|
||||
|
||||
end:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
reads dataset from the next query result
|
||||
|
||||
SYNOPSIS
|
||||
loc_read_rows()
|
||||
mysql connection handle
|
||||
other parameters are not used
|
||||
|
||||
NOTES
|
||||
It just gets next MYSQL_DATA from the result's queue
|
||||
|
||||
RETURN
|
||||
pointer to MYSQL_DATA with the coming recordset
|
||||
*/
|
||||
|
||||
static MYSQL_DATA *
|
||||
loc_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields __attribute__((unused)),
|
||||
unsigned int fields __attribute__((unused)))
|
||||
{
|
||||
MYSQL_DATA *result= ((Protocol_local *)mysql->thd)->cur_data;
|
||||
((Protocol_local *)mysql->thd)->cur_data= 0;
|
||||
if (result->embedded_info->last_errno)
|
||||
{
|
||||
embedded_get_error(mysql, result);
|
||||
return NULL;
|
||||
}
|
||||
*result->embedded_info->prev_ptr= NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
Get column lengths of the current row
|
||||
If one uses mysql_use_result, res->lengths contains the length information,
|
||||
else the lengths are calculated from the offset between pointers.
|
||||
**************************************************************************/
|
||||
|
||||
static void loc_fetch_lengths(ulong *to, MYSQL_ROW column,
|
||||
unsigned int field_count)
|
||||
{
|
||||
MYSQL_ROW end;
|
||||
|
||||
for (end=column + field_count; column != end ; column++,to++)
|
||||
*to= *column ? *(uint *)((*column) - sizeof(uint)) : 0;
|
||||
}
|
||||
|
||||
|
||||
static void loc_flush_use_result(MYSQL *mysql, my_bool)
|
||||
{
|
||||
Protocol_local *p= (Protocol_local *) mysql->thd;
|
||||
if (p->cur_data)
|
||||
{
|
||||
free_rows(p->cur_data);
|
||||
p->cur_data= 0;
|
||||
}
|
||||
else if (p->first_data)
|
||||
{
|
||||
MYSQL_DATA *data= p->first_data;
|
||||
p->first_data= data->embedded_info->next;
|
||||
free_rows(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void loc_on_close_free(MYSQL *mysql)
|
||||
{
|
||||
Protocol_local *p= (Protocol_local *) mysql->thd;
|
||||
THD *thd= p->new_thd;
|
||||
delete p;
|
||||
if (thd)
|
||||
{
|
||||
delete thd;
|
||||
local_connection_thread_count--;
|
||||
}
|
||||
my_free(mysql->info_buffer);
|
||||
mysql->info_buffer= 0;
|
||||
}
|
||||
|
||||
|
||||
static MYSQL_METHODS local_methods=
|
||||
{
|
||||
loc_read_query_result, /* read_query_result */
|
||||
NULL/*loc_advanced_command*/, /* advanced_command */
|
||||
NULL/*loc_read_rows*/, /* read_rows */
|
||||
NULL/*loc_use_result*/, /* use_result */
|
||||
NULL/*loc_fetch_lengths*/, /* fetch_lengths */
|
||||
NULL/*loc_flush_use_result*/, /* flush_use_result */
|
||||
NULL/*loc_read_change_user_result*/ /* read_change_user_result */
|
||||
loc_advanced_command, /* advanced_command */
|
||||
loc_read_rows, /* read_rows */
|
||||
mysql_store_result, /* use_result */
|
||||
loc_fetch_lengths, /* fetch_lengths */
|
||||
loc_flush_use_result, /* flush_use_result */
|
||||
NULL, /* read_change_user_result */
|
||||
loc_on_close_free /* on_close_free */
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
,NULL, /* list_fields */
|
||||
NULL, /* read_prepare_result */
|
||||
NULL, /* stmt_execute */
|
||||
NULL, /* read_binary_rows */
|
||||
NULL, /* unbuffered_fetch */
|
||||
NULL, /* read_statistics */
|
||||
NULL, /* next_result */
|
||||
NULL /* read_rows_from_cursor */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
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<uint32_t> 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 (; ptr<end; ptr++)
|
||||
// {
|
||||
// MYSQL_RES *res;
|
||||
// if (mysql_query(mysql,*ptr))
|
||||
// goto error;
|
||||
// if (mysql->fields)
|
||||
// {
|
||||
// if (!(res= (*mysql->methods->use_result)(mysql)))
|
||||
// goto error;
|
||||
// mysql_free_result(res);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
DBUG_PRINT("exit",("Mysql handler: %p", mysql));
|
||||
DBUG_RETURN(mysql);
|
||||
|
||||
//error:
|
||||
DBUG_PRINT("error",("message: %u (%s)",
|
||||
mysql->net.last_errno,
|
||||
mysql->net.last_error));
|
||||
if (!thd_orig || thd_orig->lock)
|
||||
{
|
||||
/* Free alloced memory */
|
||||
my_bool free_me=mysql->free_me;
|
||||
free_old_query(mysql);
|
||||
mysql->free_me=0;
|
||||
mysql_close(mysql);
|
||||
mysql->free_me=free_me;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
/*
|
||||
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*/
|
||||
|
|
|
@ -351,4 +351,6 @@ private:
|
|||
size_t m_column_count; /* TODO: change to point to metadata */
|
||||
};
|
||||
|
||||
extern Atomic_counter<uint32_t> local_connection_thread_count;
|
||||
|
||||
#endif // SQL_PREPARE_H
|
||||
|
|
|
@ -14,9 +14,9 @@ along with this program; if not, write to the Free Software
|
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 - 1301 USA*/
|
||||
|
||||
#include <mysql_version.h>
|
||||
#include <mysql/plugin.h>
|
||||
|
||||
#include <my_global.h>
|
||||
#include <mysql/plugin.h>
|
||||
#include <sql_class.h>
|
||||
#include <sql_i_s.h>
|
||||
#include <mysql/plugin.h>
|
||||
|
|
Loading…
Reference in a new issue