Commit 1fa196a5 authored by Alexey Botchkov's avatar Alexey Botchkov

MDEV-27595 Backport SQL service, introduced by MDEV-19275.

   The SQL SERVICE backported into the 10.4.
parent f0fe2356
......@@ -331,7 +331,7 @@ typedef struct st_mysql_res {
} MYSQL_RES;
#if !defined(MYSQL_SERVER) && !defined(MYSQL_CLIENT)
#if !defined(MYSQL_SERVICE_SQL) && !defined(MYSQL_CLIENT)
#define MYSQL_CLIENT
#endif
......@@ -363,7 +363,7 @@ typedef struct st_mysql_parameters
*/
#define MYSQL_WAIT_TIMEOUT 8
#if !defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY)
#if !defined(MYSQL_SERVICE_SQL)
#define max_allowed_packet (*mysql_get_parameters()->p_max_allowed_packet)
#define net_buffer_length (*mysql_get_parameters()->p_net_buffer_length)
#endif
......
......@@ -419,6 +419,24 @@ int json_escape_string(const char *str,const char *str_end,
char *json, char *json_end);
int json_unescape_json(const char *json_str, const char *json_end,
char *res, char *res_end);
extern struct sql_service_st {
MYSQL *(STDCALL *mysql_init_func)(MYSQL *mysql);
MYSQL *(*mysql_real_connect_local_func)(MYSQL *mysql);
MYSQL *(STDCALL *mysql_real_connect_func)(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_func)(MYSQL *mysql);
const char *(STDCALL *mysql_error_func)(MYSQL *mysql);
int (STDCALL *mysql_real_query_func)(MYSQL *mysql, const char *q,
unsigned long length);
my_ulonglong (STDCALL *mysql_affected_rows_func)(MYSQL *mysql);
my_ulonglong (STDCALL *mysql_num_rows_func)(MYSQL_RES *res);
MYSQL_RES *(STDCALL *mysql_store_result_func)(MYSQL *mysql);
void (STDCALL *mysql_free_result_func)(MYSQL_RES *result);
MYSQL_ROW (STDCALL *mysql_fetch_row_func)(MYSQL_RES *result);
void (STDCALL *mysql_close_func)(MYSQL *mysql);
} *sql_service;
MYSQL *mysql_real_connect_local(MYSQL *mysql);
struct st_mysql_xid {
long formatID;
long gtrid_length;
......
......@@ -419,6 +419,24 @@ int json_escape_string(const char *str,const char *str_end,
char *json, char *json_end);
int json_unescape_json(const char *json_str, const char *json_end,
char *res, char *res_end);
extern struct sql_service_st {
MYSQL *(STDCALL *mysql_init_func)(MYSQL *mysql);
MYSQL *(*mysql_real_connect_local_func)(MYSQL *mysql);
MYSQL *(STDCALL *mysql_real_connect_func)(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_func)(MYSQL *mysql);
const char *(STDCALL *mysql_error_func)(MYSQL *mysql);
int (STDCALL *mysql_real_query_func)(MYSQL *mysql, const char *q,
unsigned long length);
my_ulonglong (STDCALL *mysql_affected_rows_func)(MYSQL *mysql);
my_ulonglong (STDCALL *mysql_num_rows_func)(MYSQL_RES *res);
MYSQL_RES *(STDCALL *mysql_store_result_func)(MYSQL *mysql);
void (STDCALL *mysql_free_result_func)(MYSQL_RES *result);
MYSQL_ROW (STDCALL *mysql_fetch_row_func)(MYSQL_RES *result);
void (STDCALL *mysql_close_func)(MYSQL *mysql);
} *sql_service;
MYSQL *mysql_real_connect_local(MYSQL *mysql);
struct st_mysql_xid {
long formatID;
long gtrid_length;
......
......@@ -419,6 +419,24 @@ int json_escape_string(const char *str,const char *str_end,
char *json, char *json_end);
int json_unescape_json(const char *json_str, const char *json_end,
char *res, char *res_end);
extern struct sql_service_st {
MYSQL *(STDCALL *mysql_init_func)(MYSQL *mysql);
MYSQL *(*mysql_real_connect_local_func)(MYSQL *mysql);
MYSQL *(STDCALL *mysql_real_connect_func)(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_func)(MYSQL *mysql);
const char *(STDCALL *mysql_error_func)(MYSQL *mysql);
int (STDCALL *mysql_real_query_func)(MYSQL *mysql, const char *q,
unsigned long length);
my_ulonglong (STDCALL *mysql_affected_rows_func)(MYSQL *mysql);
my_ulonglong (STDCALL *mysql_num_rows_func)(MYSQL_RES *res);
MYSQL_RES *(STDCALL *mysql_store_result_func)(MYSQL *mysql);
void (STDCALL *mysql_free_result_func)(MYSQL_RES *result);
MYSQL_ROW (STDCALL *mysql_fetch_row_func)(MYSQL_RES *result);
void (STDCALL *mysql_close_func)(MYSQL *mysql);
} *sql_service;
MYSQL *mysql_real_connect_local(MYSQL *mysql);
struct st_mysql_xid {
long formatID;
long gtrid_length;
......
......@@ -419,6 +419,24 @@ int json_escape_string(const char *str,const char *str_end,
char *json, char *json_end);
int json_unescape_json(const char *json_str, const char *json_end,
char *res, char *res_end);
extern struct sql_service_st {
MYSQL *(STDCALL *mysql_init_func)(MYSQL *mysql);
MYSQL *(*mysql_real_connect_local_func)(MYSQL *mysql);
MYSQL *(STDCALL *mysql_real_connect_func)(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_func)(MYSQL *mysql);
const char *(STDCALL *mysql_error_func)(MYSQL *mysql);
int (STDCALL *mysql_real_query_func)(MYSQL *mysql, const char *q,
unsigned long length);
my_ulonglong (STDCALL *mysql_affected_rows_func)(MYSQL *mysql);
my_ulonglong (STDCALL *mysql_num_rows_func)(MYSQL_RES *res);
MYSQL_RES *(STDCALL *mysql_store_result_func)(MYSQL *mysql);
void (STDCALL *mysql_free_result_func)(MYSQL_RES *result);
MYSQL_ROW (STDCALL *mysql_fetch_row_func)(MYSQL_RES *result);
void (STDCALL *mysql_close_func)(MYSQL *mysql);
} *sql_service;
MYSQL *mysql_real_connect_local(MYSQL *mysql);
struct st_mysql_xid {
long formatID;
long gtrid_length;
......
......@@ -419,6 +419,24 @@ int json_escape_string(const char *str,const char *str_end,
char *json, char *json_end);
int json_unescape_json(const char *json_str, const char *json_end,
char *res, char *res_end);
extern struct sql_service_st {
MYSQL *(STDCALL *mysql_init_func)(MYSQL *mysql);
MYSQL *(*mysql_real_connect_local_func)(MYSQL *mysql);
MYSQL *(STDCALL *mysql_real_connect_func)(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_func)(MYSQL *mysql);
const char *(STDCALL *mysql_error_func)(MYSQL *mysql);
int (STDCALL *mysql_real_query_func)(MYSQL *mysql, const char *q,
unsigned long length);
my_ulonglong (STDCALL *mysql_affected_rows_func)(MYSQL *mysql);
my_ulonglong (STDCALL *mysql_num_rows_func)(MYSQL_RES *res);
MYSQL_RES *(STDCALL *mysql_store_result_func)(MYSQL *mysql);
void (STDCALL *mysql_free_result_func)(MYSQL_RES *result);
MYSQL_ROW (STDCALL *mysql_fetch_row_func)(MYSQL_RES *result);
void (STDCALL *mysql_close_func)(MYSQL *mysql);
} *sql_service;
MYSQL *mysql_real_connect_local(MYSQL *mysql);
struct st_mysql_xid {
long formatID;
long gtrid_length;
......
/* 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 */
#ifndef MYSQL_SERVICE_SQL
#define MYSQL_SERVICE_SQL
#ifndef MYSQL_ABI_CHECK
#include <mysql.h>
#endif
/**
@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_func)(MYSQL *mysql);
MYSQL *(*mysql_real_connect_local_func)(MYSQL *mysql);
MYSQL *(STDCALL *mysql_real_connect_func)(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_func)(MYSQL *mysql);
const char *(STDCALL *mysql_error_func)(MYSQL *mysql);
int (STDCALL *mysql_real_query_func)(MYSQL *mysql, const char *q,
unsigned long length);
my_ulonglong (STDCALL *mysql_affected_rows_func)(MYSQL *mysql);
my_ulonglong (STDCALL *mysql_num_rows_func)(MYSQL_RES *res);
MYSQL_RES *(STDCALL *mysql_store_result_func)(MYSQL *mysql);
void (STDCALL *mysql_free_result_func)(MYSQL_RES *result);
MYSQL_ROW (STDCALL *mysql_fetch_row_func)(MYSQL_RES *result);
void (STDCALL *mysql_close_func)(MYSQL *mysql);
} *sql_service;
#ifdef MYSQL_DYNAMIC_PLUGIN
#define mysql_init(M) sql_service->mysql_init_func(M)
#define mysql_real_connect_local(M) sql_service->mysql_real_connect_local_func(M)
#define mysql_real_connect(M,H,U,PW,D,P,S,F) sql_service->mysql_real_connect_func(M,H,U,PW,D,P,S,F)
#define mysql_errno(M) sql_service->mysql_errno_func(M)
#define mysql_error(M) sql_service->mysql_error_func(M)
#define mysql_real_query sql_service->mysql_real_query_func
#define mysql_affected_rows(M) sql_service->mysql_affected_rows_func(M)
#define mysql_num_rows(R) sql_service->mysql_num_rows_func(R)
#define mysql_store_result(M) sql_service->mysql_store_result_func(M)
#define mysql_free_result(R) sql_service->mysql_free_result_func(R)
#define mysql_fetch_row(R) sql_service->mysql_fetch_row_func(R)
#define mysql_close(M) sql_service->mysql_close_func(M)
#else
/*
Establishes the connection to the 'local' server that started the plugin.
Like the mysql_real_connect() does for the remote server.
The established connection has no user/host associated to it,
neither it has the current db, so the queries should have
database/table name specified.
*/
MYSQL *mysql_real_connect_local(MYSQL *mysql);
/* 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
}
......
......@@ -43,3 +43,4 @@
#define VERSION_thd_wait 0x0100
#define VERSION_wsrep 0x0400
#define VERSION_json 0x0100
#define VERSION_sql_service 0x0100
......@@ -65,13 +65,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;
}
}
......@@ -431,7 +431,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);
......@@ -454,12 +454,25 @@ 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,
......@@ -469,12 +482,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
......
......@@ -1064,11 +1064,6 @@ unsigned int STDCALL mysql_field_count(MYSQL *mysql)
return mysql->field_count;
}
my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
{
return mysql->affected_rows;
}
my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
{
return mysql->insert_id;
......
......@@ -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})
......
/* 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;
install plugin test_sql_service soname 'test_sql_service';
show status like 'test_sql_service_passed';
Variable_name Value
Test_sql_service_passed 1
set global test_sql_service_run_test= 1;
show status like 'test_sql_service_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'
create table t1 (id int, time timestamp);
insert into t1 values (1, NULL), (2, NULL), (3, NULL), (4, NULL), (5, NULL);
set global test_sql_service_execute_sql_global= 'select * FROM test.t1 WHERE time < DATE_SUB(NOW(), interval 5 minute)';
show status like 'test_sql_query_result';
Variable_name Value
Test_sql_query_result Query returned 0 rows.
set global test_sql_service_execute_sql_global= 'select * FROM test.t1 WHERE time <= NOW()';
show status like 'test_sql_query_result';
Variable_name Value
Test_sql_query_result Query returned 5 rows.
set global test_sql_service_execute_sql_local= 'select * FROM test.t1 WHERE time < DATE_SUB(NOW(), interval 5 minute)';
show status like 'test_sql_query_result';
Variable_name Value
Test_sql_query_result Query returned 0 rows.
set global test_sql_service_execute_sql_local= 'select * FROM test.t1 WHERE time <= NOW()';
show status like 'test_sql_query_result';
Variable_name Value
Test_sql_query_result Query returned 5 rows.
drop table t1;
uninstall plugin test_sql_service;
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown
--source include/not_embedded.inc
if (!$TEST_SQL_SERVICE_SO) {
skip No TEST_SQL_SERVICE plugin;
}
# An unfortunate wait for check-testcase.test to complete disconnect.
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_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';
create table t1 (id int, time timestamp);
insert into t1 values (1, NULL), (2, NULL), (3, NULL), (4, NULL), (5, NULL);
set global test_sql_service_execute_sql_global= 'select * FROM test.t1 WHERE time < DATE_SUB(NOW(), interval 5 minute)';
show status like 'test_sql_query_result';
set global test_sql_service_execute_sql_global= 'select * FROM test.t1 WHERE time <= NOW()';
show status like 'test_sql_query_result';
set global test_sql_service_execute_sql_local= 'select * FROM test.t1 WHERE time < DATE_SUB(NOW(), interval 5 minute)';
show status like 'test_sql_query_result';
set global test_sql_service_execute_sql_local= 'select * FROM test.t1 WHERE time <= NOW()';
show status like 'test_sql_query_result';
drop table t1;
uninstall plugin test_sql_service;
......@@ -1145,7 +1145,6 @@ static void setup_connection_simple(struct connection_info *ci)
#define MAX_HOSTNAME 61
#define USERNAME_LENGTH 384
static void setup_connection_connect(struct connection_info *cn,
const struct mysql_event_connection *event)
......
# Copyright (C) 2013 Alexey Botchkov and SkySQL 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 Street, Fifth Floor, Boston, MA 02110-1335 USA
SET(SOURCES test_sql_service.c)
MYSQL_ADD_PLUGIN(test_sql_service ${SOURCES} MODULE_ONLY)
This diff is collapsed.
/* Copyright (C) 2019, Alexey Botchkov and 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 02110-1335 USA */
#define PLUGIN_VERSION 0x200
#include <mysql/plugin_audit.h>
#define STRING_WITH_LEN(X) (X), ((size_t) (sizeof(X) - 1))
/* 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= 1;
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, 0);
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, 0);
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, 0);
static struct st_mysql_sys_var* test_sql_vars[]=
{
MYSQL_SYSVAR(run_test),
MYSQL_SYSVAR(execute_sql_local),
MYSQL_SYSVAR(execute_sql_global),
NULL
};
static MYSQL *global_mysql;
static int run_queries(MYSQL *mysql)
{
MYSQL_RES *res;
if (mysql_real_query(mysql,
STRING_WITH_LEN("CREATE TABLE test.ts_table"
" ( hash varbinary(512),"
" time timestamp default current_time,"
" primary key (hash), index tm (time) )")))
return 1;
if (mysql_real_query(mysql,
STRING_WITH_LEN("INSERT INTO test.ts_table VALUES('1234567890', NULL)")))
return 1;
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()
{
MYSQL *mysql;
int result= 1;
mysql= mysql_init(NULL);
if (mysql_real_connect_local(mysql) == NULL)
return 1;
if (run_queries(mysql))
goto exit;
if (run_queries(global_mysql))
goto exit;
result= 0;
exit:
mysql_close(mysql);
return result;
}
void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev)
{
}
static int run_test(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
struct st_mysql_value *value)
{
return (test_passed= (do_tests() == 0)) == 0;
}
static int run_sql(MYSQL *mysql, void *save, struct st_mysql_value *value)
{
const char *str;
int len= 0;
MYSQL_RES *res;
str= value->val_str(value, NULL, &len);
if (mysql_real_query(mysql, str, len))
{
if (mysql_error(mysql)[0])
{
my_snprintf(qwe_res, sizeof(qwe_res), "Error %d returned. %s",
mysql_errno(mysql), mysql_error(mysql));
return 0;
}
return 1;
}
if ((res= mysql_store_result(mysql)))
{
my_snprintf(qwe_res, sizeof(qwe_res), "Query returned %lld rows.",
mysql_num_rows(res));
mysql_free_result(res);
}
else
{
if (mysql_error(mysql)[0])
{
my_snprintf(qwe_res, sizeof(qwe_res), "Error %d returned. %s",
mysql_errno(mysql), mysql_error(mysql));
}
else
my_snprintf(qwe_res, sizeof(qwe_res), "Query affected %lld rows.",
mysql_affected_rows(mysql));
}
return 0;
}
static void noop_update(MYSQL_THD thd, struct st_mysql_sys_var *var,
void *var_ptr, const void *save)
{
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)
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);
}
static int init_done= 0;
static int test_sql_service_plugin_init(void *p)
{
(void) p;
global_mysql= mysql_init(NULL);
if (!global_mysql ||
mysql_real_connect_local(global_mysql) == NULL)
return 1;
init_done= 1;
test_passed= (do_tests() == 0);
return 0;
}
static int test_sql_service_plugin_deinit(void *p)
{
(void) p;
if (!init_done)
return 0;
mysql_close(global_mysql);
return 0;
}
static struct st_mysql_audit maria_descriptor =
{
MYSQL_AUDIT_INTERFACE_VERSION,
NULL,
auditing,
{ MYSQL_AUDIT_GENERAL_CLASSMASK |
MYSQL_AUDIT_TABLE_CLASSMASK |
MYSQL_AUDIT_CONNECTION_CLASSMASK }
};
maria_declare_plugin(test_sql_service)
{
MYSQL_AUDIT_PLUGIN,
&maria_descriptor,
"TEST_SQL_SERVICE",
"Alexey Botchkov (MariaDB Corporation)",
"Test SQL service",
PLUGIN_LICENSE_GPL,
test_sql_service_plugin_init,
test_sql_service_plugin_deinit,
PLUGIN_VERSION,
test_sql_status,
test_sql_vars,
NULL,
MariaDB_PLUGIN_MATURITY_STABLE
}
maria_declare_plugin_end;
......@@ -1670,14 +1670,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 */
......@@ -3351,10 +3351,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;
}
......@@ -3473,13 +3471,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);
}
......@@ -4301,3 +4292,9 @@ int STDCALL mysql_cancel(MYSQL *mysql)
return vio_shutdown(mysql->net.vio, SHUT_RDWR);
return -1;
}
my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
{
return mysql->affected_rows;
}
......@@ -1508,6 +1508,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
****************************************************************************/
......@@ -1780,10 +1790,8 @@ 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 -
n_threads_awaiting_ack) &&
i < 1000;
i++)
for (int i= 0; THD_count::connection_thd_count() - n_threads_awaiting_ack
&& i < 1000; i++)
my_sleep(20000);
if (global_system_variables.log_warnings)
......@@ -1801,13 +1809,12 @@ static void close_connections(void)
THD_count::value() - binlog_dump_thread_count -
n_threads_awaiting_ack));
while (THD_count::value() - binlog_dump_thread_count -
n_threads_awaiting_ack)
while (THD_count::connection_thd_count() - n_threads_awaiting_ack)
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
......@@ -2570,7 +2577,7 @@ void close_connection(THD *thd, uint sql_errno)
if (sql_errno)
{
net_send_error(thd, sql_errno, ER_DEFAULT(sql_errno), NULL);
thd->protocol->net_send_error(thd, sql_errno, ER_DEFAULT(sql_errno), NULL);
thd->print_aborted_warning(lvl, ER_DEFAULT(sql_errno));
}
else if (!thd->main_security_ctx.user)
......@@ -5225,6 +5232,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()))
......@@ -5470,7 +5478,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)
......
......@@ -33,11 +33,6 @@
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
/* Declared non-static only because of the embedded library. */
bool net_send_error_packet(THD *, uint, const char *, const char *);
/* Declared non-static only because of the embedded library. */
bool net_send_ok(THD *, uint, uint, ulonglong, ulonglong, const char *,
bool, bool);
/* Declared non-static only because of the embedded library. */
bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count);
#ifndef EMBEDDED_LIBRARY
static bool write_eof_packet(THD *, NET *, uint, uint);
......@@ -147,7 +142,7 @@ bool Protocol_binary::net_store_data_cs(const uchar *from, size_t length,
@retval TRUE An error occurred and the message wasn't sent properly
*/
bool net_send_error(THD *thd, uint sql_errno, const char *err,
bool Protocol::net_send_error(THD *thd, uint sql_errno, const char *err,
const char* sqlstate)
{
bool error;
......@@ -209,7 +204,7 @@ bool net_send_error(THD *thd, uint sql_errno, const char *err,
#ifndef EMBEDDED_LIBRARY
bool
net_send_ok(THD *thd,
Protocol::net_send_ok(THD *thd,
uint server_status, uint statement_warn_count,
ulonglong affected_rows, ulonglong id, const char *message,
bool is_eof,
......@@ -321,7 +316,7 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */
*/
bool
net_send_eof(THD *thd, uint server_status, uint statement_warn_count)
Protocol::net_send_eof(THD *thd, uint server_status, uint statement_warn_count)
{
NET *net= &thd->net;
bool error= FALSE;
......@@ -412,7 +407,7 @@ static bool write_eof_packet(THD *thd, NET *net,
@retval TRUE An error occurred and the messages wasn't sent properly
*/
bool net_send_error_packet(THD *thd, uint sql_errno, const char *err,
bool Protocol::net_send_error_packet(THD *thd, uint sql_errno, const char *err,
const char* sqlstate)
{
......
......@@ -49,14 +49,13 @@ class Protocol
}
#endif
uint field_count;
#ifndef EMBEDDED_LIBRARY
bool net_store_data(const uchar *from, size_t length);
bool net_store_data_cs(const uchar *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
#else
virtual bool net_store_data(const uchar *from, size_t length);
virtual bool net_store_data_cs(const uchar *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
virtual bool net_send_ok(THD *, uint, uint, ulonglong, ulonglong, const char *,
bool, bool);
virtual bool net_send_error_packet(THD *, uint, const char *, const char *);
#ifdef EMBEDDED_LIBRARY
char **next_field;
MYSQL_FIELD *next_mysql_field;
MEM_ROOT *alloc;
......@@ -156,6 +155,9 @@ class Protocol
};
virtual enum enum_protocol_type type()= 0;
virtual bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count);
bool net_send_error(THD *thd, uint sql_errno, const char *err,
const char* sqlstate);
void end_statement();
friend int send_answer_1(Protocol *protocol, String *s1, String *s2,
......@@ -289,8 +291,6 @@ class Protocol_discard : public Protocol_text
void send_warning(THD *thd, uint sql_errno, const char *err=0);
bool net_send_error(THD *thd, uint sql_errno, const char *err,
const char* sqlstate);
void net_send_progress_packet(THD *thd);
uchar *net_store_data(uchar *to,const uchar *from, size_t length);
uchar *net_store_data(uchar *to,int32 from);
......
......@@ -1035,6 +1035,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--; }
};
......@@ -3622,6 +3623,11 @@ class THD: public THD_count, /* this must be first */
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"
......@@ -3633,15 +3639,9 @@ class THD: public THD_count, /* this must be first */
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;
......
......@@ -1477,7 +1477,7 @@ void CONNECT::close_with_error(uint sql_errno,
if (thd)
{
if (sql_errno)
net_send_error(thd, sql_errno, message, NULL);
thd->protocol->net_send_error(thd, sql_errno, message, NULL);
close_connection(thd, close_error);
delete thd;
set_current_thd(0);
......
......@@ -222,6 +222,22 @@ struct json_service_st json_handler=
json_unescape_json
};
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 },
......@@ -245,5 +261,6 @@ static struct st_service_ref list_of_services[]=
{ "thd_timezone_service", VERSION_thd_timezone, &thd_timezone_handler },
{ "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
{ "wsrep_service", VERSION_wsrep, &wsrep_handler },
{ "json_service", VERSION_json, &json_handler }
{ "json_service", VERSION_json, &json_handler },
{ "sql_service", VERSION_sql_service, &sql_service_handler },
};
This diff is collapsed.
......@@ -202,7 +202,7 @@ class Ed_connection
@retval TRUE error, use get_last_error()
to see the error number.
*/
bool execute_direct(LEX_STRING sql_text);
bool execute_direct(Protocol *p, LEX_STRING sql_text);
/**
Same as the previous, but takes an instance of Server_runnable
......@@ -215,7 +215,7 @@ class Ed_connection
return a result set
@retval TRUE failure
*/
bool execute_direct(Server_runnable *server_runnable);
bool execute_direct(Protocol *p, Server_runnable *server_runnable);
/**
Get the number of affected (deleted, updated)
......@@ -311,7 +311,6 @@ class Ed_connection
THD *m_thd;
Ed_result_set *m_rsets;
Ed_result_set *m_current_rset;
friend class Protocol_local;
private:
void free_old_result();
void add_result_set(Ed_result_set *ed_result_set);
......@@ -354,4 +353,6 @@ class Ed_row: public Sql_alloc
size_t m_column_count; /* TODO: change to point to metadata */
};
extern Atomic_counter<uint32_t> local_connection_thread_count;
#endif // SQL_PREPARE_H
......@@ -98,7 +98,7 @@
#pragma implementation // gcc: Class implementation
#endif
#include <my_config.h>
#include <my_global.h>
#include <mysql/plugin.h>
#include "ha_example.h"
#include "sql_class.h"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment