Skip to content

Commit 0ccdf8b

Browse files
author
Alexey Botchkov
committed
MDEV-19275 Provide SQL service to plugins.
test_sql_service plugin added and employed in test_sql_service.test.
1 parent 82bc007 commit 0ccdf8b

File tree

10 files changed

+630
-3
lines changed

10 files changed

+630
-3
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
install plugin test_sql_service soname 'test_sql_service';
2+
set global test_sql_service_run_test= 1;
3+
show status like 'test_sql_service%';
4+
Variable_name Value
5+
Test_sql_service_passed 0
6+
uninstall plugin test_sql_service;
7+
Warnings:
8+
Warning 1620 Plugin is busy and will be uninstalled on shutdown
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
--thread_handling='one-thread-per-connection'
2+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
--source include/not_embedded.inc
3+
4+
if (!$TEST_SQL_SERVICE_SO) {
5+
skip No TEST_SQL_SERVICE plugin;
6+
}
7+
8+
# An unfortunate wait for check-testcase.test to complete disconnect.
9+
let count_sessions= 1;
10+
source include/wait_until_count_sessions.inc;
11+
12+
install plugin test_sql_service soname 'test_sql_service';
13+
14+
set global test_sql_service_run_test= 1;
15+
show status like 'test_sql_service%';
16+
17+
uninstall plugin test_sql_service;
18+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright (C) 2013 Alexey Botchkov and SkySQL Ab
2+
#
3+
# This program is free software; you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation; version 2 of the License.
6+
#
7+
# This program is distributed in the hope that it will be useful,
8+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
# GNU General Public License for more details.
11+
#
12+
# You should have received a copy of the GNU General Public License
13+
# along with this program; if not, write to the Free Software
14+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
15+
16+
SET(SOURCES test_sql_service.c)
17+
18+
MYSQL_ADD_PLUGIN(test_sql_service ${SOURCES} MODULE_ONLY RECOMPILE_FOR_EMBEDDED)

plugin/test_sql_service/COPYING

Lines changed: 339 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/* Copyright (C) 2019, Alexey Botchkov and MariaDB Corporation
2+
3+
This program is free software; you can redistribute it and/or modify
4+
it under the terms of the GNU General Public License as published by
5+
the Free Software Foundation; version 2 of the License.
6+
7+
This program is distributed in the hope that it will be useful,
8+
but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
GNU General Public License for more details.
11+
12+
You should have received a copy of the GNU General Public License
13+
along with this program; if not, write to the Free Software
14+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
15+
16+
17+
#define PLUGIN_VERSION 0x100
18+
#define PLUGIN_STR_VERSION "1.0.0"
19+
20+
#define _my_thread_var loc_thread_var
21+
22+
#include <my_config.h>
23+
#include <assert.h>
24+
#include <my_global.h>
25+
#include <my_base.h>
26+
#include <typelib.h>
27+
//#include <mysql_com.h> /* for enum enum_server_command */
28+
#include <mysql/plugin.h>
29+
#include <mysql/plugin_audit.h>
30+
//#include <string.h>
31+
32+
33+
LEX_STRING * thd_query_string (MYSQL_THD thd);
34+
unsigned long long thd_query_id(const MYSQL_THD thd);
35+
size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen);
36+
const char *thd_user_name(MYSQL_THD thd);
37+
const char *thd_client_host(MYSQL_THD thd);
38+
const char *thd_client_ip(MYSQL_THD thd);
39+
LEX_CSTRING *thd_current_db(MYSQL_THD thd);
40+
int thd_current_status(MYSQL_THD thd);
41+
enum enum_server_command thd_current_command(MYSQL_THD thd);
42+
43+
int maria_compare_hostname(const char *wild_host, long wild_ip, long ip_mask,
44+
const char *host, const char *ip);
45+
void maria_update_hostname(const char **wild_host, long *wild_ip, long *ip_mask,
46+
const char *host);
47+
48+
/* Status variables for SHOW STATUS */
49+
static long test_passed= 0;
50+
static struct st_mysql_show_var test_sql_status[]=
51+
{
52+
{"test_sql_service_passed", (char *)&test_passed, SHOW_LONG},
53+
{0,0,0}
54+
};
55+
56+
static my_bool do_test= TRUE;
57+
static void run_test(MYSQL_THD thd, struct st_mysql_sys_var *var,
58+
void *var_ptr, const void *save);
59+
static MYSQL_SYSVAR_BOOL(run_test, do_test, PLUGIN_VAR_OPCMDARG,
60+
"Perform the test now.", NULL, run_test, FALSE);
61+
static struct st_mysql_sys_var* test_sql_vars[]=
62+
{
63+
MYSQL_SYSVAR(run_test),
64+
NULL
65+
};
66+
67+
68+
extern int execute_sql_command(const char *command,
69+
char *hosts, char *names, char *filters);
70+
71+
72+
73+
static int do_tests()
74+
{
75+
char plugins[1024];
76+
char names[1024];
77+
char dl[2048];
78+
int result;
79+
80+
result= execute_sql_command("select 'plugin', name, dl from mysql.plugin",
81+
plugins, names, dl);
82+
83+
return result;
84+
}
85+
86+
87+
void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev)
88+
{
89+
}
90+
91+
92+
static void run_test(MYSQL_THD thd __attribute__((unused)),
93+
struct st_mysql_sys_var *var __attribute__((unused)),
94+
void *var_ptr __attribute__((unused)),
95+
const void *save __attribute__((unused)))
96+
{
97+
test_passed= do_tests();
98+
}
99+
100+
101+
static int init_done= 0;
102+
103+
static int test_sql_service_plugin_init(void *p __attribute__((unused)))
104+
{
105+
init_done= 1;
106+
return 0;
107+
}
108+
109+
110+
static int test_sql_service_plugin_deinit(void *p __attribute__((unused)))
111+
{
112+
if (!init_done)
113+
return 0;
114+
115+
return 0;
116+
}
117+
118+
119+
static struct st_mysql_audit maria_descriptor =
120+
{
121+
MYSQL_AUDIT_INTERFACE_VERSION,
122+
NULL,
123+
auditing,
124+
{ MYSQL_AUDIT_GENERAL_CLASSMASK |
125+
MYSQL_AUDIT_TABLE_CLASSMASK |
126+
MYSQL_AUDIT_CONNECTION_CLASSMASK }
127+
};
128+
maria_declare_plugin(test_sql_service)
129+
{
130+
MYSQL_AUDIT_PLUGIN,
131+
&maria_descriptor,
132+
"TEST_SQL_SERVICE",
133+
"Alexey Botchkov (MariaDB Corporation)",
134+
"Test SQL service",
135+
PLUGIN_LICENSE_GPL,
136+
test_sql_service_plugin_init,
137+
test_sql_service_plugin_deinit,
138+
PLUGIN_VERSION,
139+
test_sql_status,
140+
test_sql_vars,
141+
PLUGIN_STR_VERSION,
142+
MariaDB_PLUGIN_MATURITY_STABLE
143+
}
144+
maria_declare_plugin_end;
145+

sql/log.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1355,7 +1355,7 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, size_t query_length,
13551355
my_hrtime_t current_time= { hrtime_from_time(thd->start_time) +
13561356
thd->start_time_sec_part + query_utime };
13571357

1358-
if (!query)
1358+
if (!query || thd->get_command() == COM_STMT_PREPARE)
13591359
{
13601360
is_command= TRUE;
13611361
query= command_name[thd->get_command()].str;

sql/sp_head.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
12111211
Query_arena execute_arena(&execute_mem_root, STMT_INITIALIZED_FOR_SP),
12121212
backup_arena;
12131213
query_id_t old_query_id;
1214+
CSET_STRING old_query;
12141215
TABLE *old_derived_tables;
12151216
TABLE *old_rec_tables;
12161217
LEX *old_lex;
@@ -1291,6 +1292,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
12911292
be able properly do close_thread_tables() in instructions.
12921293
*/
12931294
old_query_id= thd->query_id;
1295+
old_query= thd->query_string;
12941296
old_derived_tables= thd->derived_tables;
12951297
thd->derived_tables= 0;
12961298
old_rec_tables= thd->rec_tables;
@@ -1567,6 +1569,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
15671569
old_change_list.move_elements_to(thd);
15681570
thd->lex= old_lex;
15691571
thd->set_query_id(old_query_id);
1572+
thd->set_query_inner(old_query);
15701573
DBUG_ASSERT(!thd->derived_tables);
15711574
thd->derived_tables= old_derived_tables;
15721575
thd->rec_tables= old_rec_tables;

sql/sql_acl.cc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14679,3 +14679,40 @@ maria_declare_plugin(mysql_password)
1467914679
MariaDB_PLUGIN_MATURITY_STABLE /* Maturity */
1468014680
}
1468114681
maria_declare_plugin_end;
14682+
14683+
14684+
/*
14685+
Exporting functions that allow plugins to do server-style
14686+
host/user matching. Used in server_audit2 plugin.
14687+
*/
14688+
extern "C" int maria_compare_hostname(
14689+
const char *wild_host, long wild_ip, long ip_mask,
14690+
const char *host, const char *ip)
14691+
{
14692+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
14693+
acl_host_and_ip h;
14694+
h.hostname= (char *) wild_host;
14695+
h.ip= wild_ip;
14696+
h.ip_mask= ip_mask;
14697+
14698+
return compare_hostname(&h, host, ip);
14699+
#else
14700+
return 0;
14701+
#endif
14702+
}
14703+
14704+
14705+
extern "C" void maria_update_hostname(
14706+
const char **wild_host, long *wild_ip, long *ip_mask,
14707+
const char *host)
14708+
{
14709+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
14710+
acl_host_and_ip h;
14711+
update_hostname(&h, host);
14712+
*wild_host= h.hostname;
14713+
*wild_ip= h.ip;
14714+
*ip_mask= h.ip_mask;
14715+
#endif
14716+
}
14717+
14718+

sql/sql_prepare.cc

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2618,6 +2618,15 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length)
26182618

26192619
if (stmt->prepare(packet, packet_length))
26202620
{
2621+
/*
2622+
Prepare failed and stmt will be freed.
2623+
Now we have to save the query_string in the so the
2624+
audit plugin later gets the meaningful notification.
2625+
*/
2626+
if (alloc_query(thd, stmt->query_string.str(), stmt->query_string.length()))
2627+
{
2628+
thd->set_query(0, 0);
2629+
}
26212630
/* Statement map deletes statement on erase */
26222631
thd->stmt_map.erase(stmt);
26232632
thd->clear_last_stmt();
@@ -2752,6 +2761,7 @@ bool Lex_prepared_stmt::get_dynamic_sql_string(THD *thd,
27522761
void mysql_sql_stmt_prepare(THD *thd)
27532762
{
27542763
LEX *lex= thd->lex;
2764+
CSET_STRING orig_query= thd->query_string;
27552765
const LEX_CSTRING *name= &lex->prepared_stmt.name();
27562766
Prepared_statement *stmt;
27572767
LEX_CSTRING query;
@@ -2822,7 +2832,16 @@ void mysql_sql_stmt_prepare(THD *thd)
28222832
thd->m_statement_psi,
28232833
stmt->name.str, stmt->name.length);
28242834

2825-
if (stmt->prepare(query.str, (uint) query.length))
2835+
bool res= stmt->prepare(query.str, (uint) query.length);
2836+
/*
2837+
stmt->prepare() sets thd->query_string with the prepared
2838+
query, so the audit plugin gets adequate notification with the
2839+
mysqld_stmt_* set of functions.
2840+
But here we should restore the original query so it's mentioned in
2841+
logs properly.
2842+
*/
2843+
thd->set_query(orig_query);
2844+
if (res)
28262845
{
28272846
/* Statement map deletes the statement on erase */
28282847
thd->stmt_map.erase(stmt);
@@ -2841,6 +2860,7 @@ void mysql_sql_stmt_prepare(THD *thd)
28412860
void mysql_sql_stmt_execute_immediate(THD *thd)
28422861
{
28432862
LEX *lex= thd->lex;
2863+
CSET_STRING orig_query= thd->query_string;
28442864
Prepared_statement *stmt;
28452865
LEX_CSTRING query;
28462866
DBUG_ENTER("mysql_sql_stmt_execute_immediate");
@@ -2889,6 +2909,14 @@ void mysql_sql_stmt_execute_immediate(THD *thd)
28892909
thd->free_items();
28902910
thd->free_list= free_list_backup;
28912911

2912+
/*
2913+
stmt->execute_immediately() sets thd->query_string with the executed
2914+
query, so the audit plugin gets adequate notification with the
2915+
mysqld_stmt_* set of functions.
2916+
But here we should restore the original query so it's mentioned in
2917+
logs properly.
2918+
*/
2919+
thd->set_query_inner(orig_query);
28922920
stmt->lex->restore_set_statement_var();
28932921
delete stmt;
28942922
DBUG_VOID_RETURN;
@@ -3205,6 +3233,13 @@ static void mysql_stmt_execute_common(THD *thd,
32053233
if (!(stmt= find_prepared_statement(thd, stmt_id)))
32063234
{
32073235
char llbuf[22];
3236+
/*
3237+
Did not find the statement with the provided stmt_id.
3238+
Set thd->query_string with the stmt_id so the
3239+
audit plugin gets the meaningful notification.
3240+
*/
3241+
if (alloc_query(thd, llbuf, strlen(llbuf)))
3242+
thd->set_query(0, 0);
32083243
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), static_cast<int>(sizeof(llbuf)),
32093244
llstr(stmt_id, llbuf), "mysqld_stmt_execute");
32103245
DBUG_VOID_RETURN;
@@ -3969,6 +4004,19 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
39694004
DBUG_RETURN(TRUE);
39704005
}
39714006

4007+
/*
4008+
We'd like to have thd->query to be set to the actual query
4009+
after the function ends.
4010+
This value will be sent to audit plugins later.
4011+
As the statement is created, the query will be stored
4012+
in statement's arena. Normally the statement lives longer than
4013+
the end of this query, so we can just set thd->query_string to
4014+
be the stmt->query_string.
4015+
Though errors can result in statement to be freed. These cases
4016+
should be handled appropriately.
4017+
*/
4018+
stmt_backup.query_string= thd->query_string;
4019+
39724020
old_stmt_arena= thd->stmt_arena;
39734021
thd->stmt_arena= this;
39744022

@@ -4504,6 +4552,15 @@ Prepared_statement::reprepare()
45044552
*/
45054553
thd->get_stmt_da()->clear_warning_info(thd->query_id);
45064554
}
4555+
else
4556+
{
4557+
/*
4558+
Prepare failed and the 'copy' will be freed.
4559+
Now we have to restore the query_string in the so the
4560+
audit plugin later gets the meaningful notification.
4561+
*/
4562+
thd->set_query(query(), query_length());
4563+
}
45074564
return error;
45084565
}
45094566

@@ -5127,7 +5184,7 @@ class Protocol_local : public Protocol_text
51275184

51285185
Protocol_local(THD *thd_arg, ulong prealloc= 0) :
51295186
Protocol_text(thd_arg, prealloc),
5130-
cur_data(0), first_data(0), data_tail(&first_data)
5187+
cur_data(0), first_data(0), data_tail(&first_data), alloc(0)
51315188
{}
51325189

51335190
protected:

0 commit comments

Comments
 (0)