This section describes how to write a server-side audit
plugin, using the example plugin found in the
plugin/audit_null
directory of MySQL source
distributions. The audit_null.c
and
audit_null_variables.h
source files in
that directory implement an audit plugin named
NULL_AUDIT
.
Other examples of plugins that use the audit plugin API are the query rewrite plugin (see The Rewriter Query Rewrite Plugin) and the Version Tokens plugin (see Version Tokens).
Within the server, the pluggable audit interface is
implemented in the sql_audit.h
and
sql_audit.cc
files in the
sql
directory of MySQL source
distributions. Additionally, several places in the server call
the audit interface when an auditable event occurs, so that
registered audit plugins can be notified about the event if
necessary. To see where such calls occur, search the server
source files for invocations of functions with names of the
form
mysql_audit_
.
Audit notification occurs for server operations such as these:
xxx
()
Client connect and disconnect events
Writing a message to the general query log (if the log is enabled)
Writing a message to the error log
Sending a query result to a client
To write an audit plugin, include the following header file in the plugin source file. Other MySQL or general header files might also be needed, depending on the plugin capabilities and requirements.
#include <mysql/plugin_audit.h>
plugin_audit.h
includes
plugin.h
, so you need not include the
latter file explicitly. plugin.h
defines
the MYSQL_AUDIT_PLUGIN
server plugin type
and the data structures needed to declare the plugin.
plugin_audit.h
defines data structures
specific to audit plugins.
An audit plugin, like any MySQL server plugin, has a general
plugin descriptor (see
Section 4.4.2.1, “Server Plugin Library and Plugin Descriptors”) and a
type-specific plugin descriptor. In
audit_null.c
, the general descriptor
for audit_null
looks like this:
mysql_declare_plugin(audit_null)
{
MYSQL_AUDIT_PLUGIN, /* type */
&audit_null_descriptor, /* descriptor */
"NULL_AUDIT", /* name */
"Oracle Corporation", /* author */
"Simple NULL Audit", /* description */
PLUGIN_LICENSE_GPL,
audit_null_plugin_init, /* init function (when loaded) */
audit_null_plugin_deinit, /* deinit function (when unloaded) */
0x0003, /* version */
simple_status, /* status variables */
system_variables, /* system variables */
NULL,
0,
}
mysql_declare_plugin_end;
The first member, MYSQL_AUDIT_PLUGIN
,
identifies this plugin as an audit plugin.
audit_null_descriptor
points to the
type-specific plugin descriptor, described later.
The name
member
(NULL_AUDIT
) indicates the name to use
for references to the plugin in statements such as
INSTALL PLUGIN
or
UNINSTALL PLUGIN
. This is
also the name displayed by
INFORMATION_SCHEMA.PLUGINS
or
SHOW PLUGINS
.
The audit_null_plugin_init
initialization
function performs plugin initialization when the plugin is
loaded. The audit_null_plugin_deinit
function performs cleanup when the plugin is unloaded.
The general plugin descriptor also refers to
simple_status
and
system_variables
, structures that expose
several status and system variables. When the plugin is
enabled, these variables can be inspected using
SHOW
statements
(SHOW STATUS
,
SHOW VARIABLES
) or the
appropriate Performance Schema tables.
The simple_status
structure declares
several status variables with names of the form
Audit_null_
.
xxx
NULL_AUDIT
increments the
Audit_null_called
status variable for
every notification that it receives. The other status
variables are more specific and
NULL_AUDIT
increments them only for
notifications of specific events.
system_variables
is an array of system
variable elements, each of which is defined using a
MYSQL_THDVAR_
macro. These system variables have names of the form
xxx
null_audit_
.
These variables can be used to communicate with the plugin
at runtime.
xxx
The audit_null_descriptor
value in the
general plugin descriptor points to the type-specific plugin
descriptor. For audit plugins, this descriptor has the
following structure (defined in
plugin_audit.h
):
struct st_mysql_audit
{
int interface_version;
void (*release_thd)(MYSQL_THD);
int (*event_notify)(MYSQL_THD, mysql_event_class_t, const void *);
unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
};
The type-specific descriptor for audit plugins has these members:
interface_version
: By convention, type-specific plugin descriptors begin with the interface version for the given plugin type. The server checksinterface_version
when it loads the plugin to see whether the plugin is compatible with it. For audit plugins, the value of theinterface_version
member isMYSQL_AUDIT_INTERFACE_VERSION
(defined inplugin_audit.h
).release_thd
: A function that the server calls to inform the plugin that it is being dissociated from its thread context. This should beNULL
if there is no such function.event_notify
: A function that the server calls to notify the plugin that an auditable event has occurred. This function should not beNULL
; that would not make sense because no auditing would occur.class_mask
: An array ofMYSQL_AUDIT_CLASS_MASK_SIZE
elements. Each element specifies a bitmask for a given event class to indicate the subclasses for which the plugin wants notification. (This is how the plugin “subscribes” to events of interest.) An element should be 0 to ignore all events for the corresponding event class.
The server uses the event_notify
and
release_thd
functions together. They are
called within the context of a specific thread, and a thread
might perform an activity that produces several event
notifications. The first time the server calls
event_notify
for a thread, it creates a
binding of the plugin to the thread. The plugin cannot be
uninstalled while this binding exists. When no more events
for the thread will occur, the server informs the plugin of
this by calling the release_thd
function,
and then destroys the binding. For example, when a client
issues a statement, the thread processing the statement
might notify audit plugins about the result set produced by
the statement and about the statement being logged. After
these notifications occur, the server releases the plugin
before putting the thread to sleep until the client issues
another statement.
This design enables the plugin to allocate resources needed
for a given thread in the first call to the
event_notify
function and release them in
the release_thd
function:
event_notify function:
if memory is needed to service the thread
allocate memory
... rest of notification processing ...
release_thd function:
if memory was allocated
release memory
... rest of release processing ...
That is more efficient than allocating and releasing memory repeatedly in the notification function.
For the NULL_AUDIT
audit plugin, the
type-specific plugin descriptor looks like this:
static struct st_mysql_audit audit_null_descriptor=
{
MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */
NULL, /* release_thd function */
audit_null_notify, /* notify function */
{ (unsigned long) MYSQL_AUDIT_GENERAL_ALL,
(unsigned long) MYSQL_AUDIT_CONNECTION_ALL,
(unsigned long) MYSQL_AUDIT_PARSE_ALL,
(unsigned long) MYSQL_AUDIT_AUTHORIZATION_ALL,
(unsigned long) MYSQL_AUDIT_TABLE_ACCESS_ALL,
(unsigned long) MYSQL_AUDIT_GLOBAL_VARIABLE_ALL,
(unsigned long) MYSQL_AUDIT_SERVER_STARTUP_ALL,
(unsigned long) MYSQL_AUDIT_SERVER_SHUTDOWN_ALL,
(unsigned long) MYSQL_AUDIT_COMMAND_ALL,
(unsigned long) MYSQL_AUDIT_QUERY_ALL,
(unsigned long) MYSQL_AUDIT_STORED_PROGRAM_ALL }
};
The server calls audit_null_notify()
to
pass audit event information to the plugin. The plugin has
no release_thd
function.
The class_mask
member is an array that
indicates which event classes the plugin subscribes to. As
shown, the array contents subscribe to all subclasses of all
event classes that are available. To ignore all
notifications for a given event class, specify the
corresponding class_mask
element as 0.
The number of class_mask
elements
corresponds to the number of event classes, each of which is
listed in the mysql_event_class_t
enumeration defined in plugin_audit.h
:
typedef enum
{
MYSQL_AUDIT_GENERAL_CLASS = 0,
MYSQL_AUDIT_CONNECTION_CLASS = 1,
MYSQL_AUDIT_PARSE_CLASS = 2,
MYSQL_AUDIT_AUTHORIZATION_CLASS = 3,
MYSQL_AUDIT_TABLE_ACCESS_CLASS = 4,
MYSQL_AUDIT_GLOBAL_VARIABLE_CLASS = 5,
MYSQL_AUDIT_SERVER_STARTUP_CLASS = 6,
MYSQL_AUDIT_SERVER_SHUTDOWN_CLASS = 7,
MYSQL_AUDIT_COMMAND_CLASS = 8,
MYSQL_AUDIT_QUERY_CLASS = 9,
MYSQL_AUDIT_STORED_PROGRAM_CLASS = 10,
/* This item must be last in the list. */
MYSQL_AUDIT_CLASS_MASK_SIZE
} mysql_event_class_t;
For any given event class,
plugin_audit.h
defines bitmask symbols
for individual event subclasses, as well as an
symbol
that is the union of the all subclass bitmasks. For example,
for xxx
_ALLMYSQL_AUDIT_CONNECTION_CLASS
(the
class that covers connect and disconnect events),
plugin_audit.h
defines these symbols:
typedef enum
{
/** occurs after authentication phase is completed. */
MYSQL_AUDIT_CONNECTION_CONNECT = 1 << 0,
/** occurs after connection is terminated. */
MYSQL_AUDIT_CONNECTION_DISCONNECT = 1 << 1,
/** occurs after COM_CHANGE_USER RPC is completed. */
MYSQL_AUDIT_CONNECTION_CHANGE_USER = 1 << 2,
/** occurs before authentication. */
MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE = 1 << 3
} mysql_event_connection_subclass_t;
#define MYSQL_AUDIT_CONNECTION_ALL (MYSQL_AUDIT_CONNECTION_CONNECT | \
MYSQL_AUDIT_CONNECTION_DISCONNECT | \
MYSQL_AUDIT_CONNECTION_CHANGE_USER | \
MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE)
To subscribe to all subclasses of the connection event class
(as the NULL_AUDIT
plugin does), a plugin
specifies MYSQL_AUDIT_CONNECTION_ALL
in
the corresponding class_mask
element
(class_mask[1]
in this case). To
subscribe to only some subclasses, the plugin sets the
class_mask
element to the union of the
subclasses of interest. For example, to subscribe only to
the connect and change-user subclasses, the plugin sets
class_mask[1]
to this value:
MYSQL_AUDIT_CONNECTION_CONNECT | MYSQL_AUDIT_CONNECTION_CHANGE_USER
Most of the work for an audit plugin occurs in the
notification function (the event_notify
member of the type-specific plugin descriptor). The server
calls this function for each auditable event. Audit plugin
notification functions have this prototype:
int (*event_notify)(MYSQL_THD, mysql_event_class_t, const void *);
The second and third parameters of the
event_notify
function prototype represent
the event class and a generic pointer to an event structure.
(Events in different classes have different structures. The
notification function can use the event class value to
determine which event structure applies.) The function
processes the event and returns a status indicating whether
the server should continue processing the event or terminate
it.
For NULL_AUDIT
, the notification function
is audit_null_notify()
. This function
increments a global event counter (which the plugin exposes
as the value of the Audit_null_called
status value), and then examines the event class to
determine how to process the event structure:
static int audit_null_notify(MYSQL_THD thd __attribute__((unused)),
mysql_event_class_t event_class,
const void *event)
{
...
number_of_calls++;
if (event_class == MYSQL_AUDIT_GENERAL_CLASS)
{
const struct mysql_event_general *event_general=
(const struct mysql_event_general *)event;
...
}
else if (event_class == MYSQL_AUDIT_CONNECTION_CLASS)
{
const struct mysql_event_connection *event_connection=
(const struct mysql_event_connection *) event;
...
}
else if (event_class == MYSQL_AUDIT_PARSE_CLASS)
{
const struct mysql_event_parse *event_parse =
(const struct mysql_event_parse *)event;
...
}
...
}
The notification function interprets the
event
argument according to the value of
event_class
. The event
argument is a generic pointer to the event record, the
structure of which differs per event class. (The
plugin_audit.h
file contains the
structures that define the contents of each event class.)
For each class, audit_null_notify()
casts
the event to the appropriate class-specific structure and
then checks its subclass to determine which subclass counter
to increment. For example, the code to handle events in the
connection-event class looks like this:
else if (event_class == MYSQL_AUDIT_CONNECTION_CLASS)
{
const struct mysql_event_connection *event_connection=
(const struct mysql_event_connection *) event;
switch (event_connection->event_subclass)
{
case MYSQL_AUDIT_CONNECTION_CONNECT:
number_of_calls_connection_connect++;
break;
case MYSQL_AUDIT_CONNECTION_DISCONNECT:
number_of_calls_connection_disconnect++;
break;
case MYSQL_AUDIT_CONNECTION_CHANGE_USER:
number_of_calls_connection_change_user++;
break;
case MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE:
number_of_calls_connection_pre_authenticate++;
break;
default:
break;
}
}
The general event class
(MYSQL_AUDIT_GENERAL_CLASS
) is
deprecated and will be removed in a future MySQL release.
To reduce plugin overhead, it is preferable to subscribe
only to the more specific event classes of interest.
For some event classes, the NULL_AUDIT
plugin performs other processing in addition to incrementing
a counter. In any case, when the notification function
finishes processing the event, it should return a status
indicating whether the server should continue processing the
event or terminate it.
Audit plugin notification functions can report a status value for the current event two ways:
Use the notification function return value. In this case, the function returns zero if the server should continue processing the event, or nonzero if the server should terminate the event.
-
Call the
my_message()
function to set the error state before returning from the notification function. In this case, the notification function return value is ignored and the server aborts the event and terminates event processing with an error. Themy_message()
arguments indicate which error to report, and its message. For example:my_message(ER_AUDIT_API_ABORT, "This is my error message.", MYF(0));
Some events cannot be aborted. A nonzero return value is not taken into consideration and the
my_message()
error call must follow anis_error()
check. For example:if (!thd->get_stmt_da()->is_error()) { my_message(ER_AUDIT_API_ABORT, "This is my error message.", MYF(0)); }
These events cannot be aborted:
MYSQL_AUDIT_CONNECTION_DISCONNECT
: The server cannot prevent a client from disconnecting.MYSQL_AUDIT_COMMAND_END
: This event provides the status of a command that has finished executing, so there is no purpose to terminating it.
If an audit plugin returns nonzero status for a
nonterminable event, the server ignores the status and
continues processing the event. This is also true if an
audit plugin uses the my_message()
function to terminate a nonterminable event.
To compile and install a plugin library file, use the
instructions in
Section 4.4.3, “Compiling and Installing Plugin Libraries”. To make the
library file available for use, install it in the plugin
directory (the directory named by the
plugin_dir
system
variable). For the NULL_AUDIT
plugin, it
is compiled and installed when you build MySQL from source.
It is also included in binary distributions. The build
process produces a shared object library with a name of
adt_null.so
(the
.so
suffix might differ depending on
your platform).
To register the plugin at runtime, use this statement,
adjusting the .so
suffix for your
platform as necessary:
INSTALL PLUGIN NULL_AUDIT SONAME 'adt_null.so';
For additional information about plugin loading, see Installing and Uninstalling Plugins.
To verify plugin installation, examine the
INFORMATION_SCHEMA.PLUGINS
table or use the SHOW PLUGINS
statement. See
Obtaining Server Plugin Information.
While the NULL_AUDIT
audit plugin is
installed, it exposes status variables that indicate the
events for which the plugin has been called:
mysql> SHOW STATUS LIKE 'Audit_null%';
+----------------------------------------+--------+
| Variable_name | Value |
+----------------------------------------+--------+
| Audit_null_authorization_column | 0 |
| Audit_null_authorization_db | 0 |
| Audit_null_authorization_procedure | 0 |
| Audit_null_authorization_proxy | 0 |
| Audit_null_authorization_table | 0 |
| Audit_null_authorization_user | 0 |
| Audit_null_called | 185547 |
| Audit_null_command_end | 20999 |
| Audit_null_command_start | 21001 |
| Audit_null_connection_change_user | 0 |
| Audit_null_connection_connect | 5823 |
| Audit_null_connection_disconnect | 5818 |
| Audit_null_connection_pre_authenticate | 5823 |
| Audit_null_general_error | 1 |
| Audit_null_general_log | 26559 |
| Audit_null_general_result | 19922 |
| Audit_null_general_status | 21000 |
| Audit_null_global_variable_get | 0 |
| Audit_null_global_variable_set | 0 |
| Audit_null_message_internal | 0 |
| Audit_null_message_user | 0 |
| Audit_null_parse_postparse | 14648 |
| Audit_null_parse_preparse | 14648 |
| Audit_null_query_nested_start | 6 |
| Audit_null_query_nested_status_end | 6 |
| Audit_null_query_start | 14648 |
| Audit_null_query_status_end | 14647 |
| Audit_null_server_shutdown | 0 |
| Audit_null_server_startup | 1 |
| Audit_null_table_access_delete | 104 |
| Audit_null_table_access_insert | 2839 |
| Audit_null_table_access_read | 97842 |
| Audit_null_table_access_update | 278 |
+----------------------------------------+--------+
Audit_null_called
counts all events, and
the other variables count instances of specific event
subclasses. For example, the preceding
SHOW STATUS
statement causes
the server to send a result to the client and to write a
message to the general query log if that log is enabled.
Thus, a client that issues the statement repeatedly causes
Audit_null_called
,
Audit_null_general_result
, and
Audit_null_general_log
to be incremented
each time. Notifications occur whether or not that log is
enabled.
The status variables values are global and aggregated across all sessions. There are no counters for individual sessions.
NULL_AUDIT
exposes several system
variables that enable communication with the plugin at
runtime:
mysql> SHOW VARIABLES LIKE 'null_audit%';
+---------------------------------------------------+-------+
| Variable_name | Value |
+---------------------------------------------------+-------+
| null_audit_abort_message | |
| null_audit_abort_value | 1 |
| null_audit_event_order_check | |
| null_audit_event_order_check_consume_ignore_count | 0 |
| null_audit_event_order_check_exact | 1 |
| null_audit_event_order_started | 0 |
| null_audit_event_record | |
| null_audit_event_record_def | |
+---------------------------------------------------+-------+
The NULL_AUDIT
system variables have
these meanings:
null_audit_abort_message
: The custom error message to use when an event is aborted.null_audit_abort_value
: The custom error code to use when an event is aborted.null_audit_event_order_check
: Prior to event matching, the expected event order. After event matching, the matching outcome.null_audit_event_order_check_consume_ignore_count
: Number of times event matching should not consume matched events.null_audit_event_order_check_exact
: Whether event matching must be exact. Disabling this variable enables skipping events not listed innull_audit_event_order_check
during event-order matching. Of the events specified, they must still match in the order given.null_audit_event_order_started
: For internal use.null_audit_event_record
: The recorded events after event recording takes place.null_audit_event_record_def
: The names of the start and end events to match when recording events, separated by a semicolon. The value must be set before each statement for which events are recorded.
To demonstrate use of those system variables, suppose that a
table db1.t1
exists, created as follows:
CREATE DATABASE db1;
CREATE TABLE db1.t1 (a VARCHAR(255));
For test-creation purposes, it is possible to record events
that pass through the plugin. To start recording, specify
the start and end events in the
null_audit_event_record_def
variable. For
example:
SET @@null_audit_event_record_def =
'MYSQL_AUDIT_COMMAND_START;MYSQL_AUDIT_COMMAND_END';
After a statement occurs that matches those start and end
events, the null_audit_event_record
system variable contains the resulting event sequence. For
example, after recording the events for a SELECT
1
statement,
null_audit_event_record
is a string that
has a value consisting of a set of event strings:
MYSQL_AUDIT_COMMAND_START;command_id="3";
MYSQL_AUDIT_PARSE_PREPARSE;;
MYSQL_AUDIT_PARSE_POSTPARSE;;
MYSQL_AUDIT_GENERAL_LOG;;
MYSQL_AUDIT_QUERY_START;sql_command_id="0";
MYSQL_AUDIT_QUERY_STATUS_END;sql_command_id="0";
MYSQL_AUDIT_GENERAL_RESULT;;
MYSQL_AUDIT_GENERAL_STATUS;;
MYSQL_AUDIT_COMMAND_END;command_id="3";
After recording the events for an INSERT INTO
db1.t1 VALUES ('some data')
statement,
null_audit_event_record
has this value:
MYSQL_AUDIT_COMMAND_START;command_id="3";
MYSQL_AUDIT_PARSE_PREPARSE;;
MYSQL_AUDIT_PARSE_POSTPARSE;;
MYSQL_AUDIT_GENERAL_LOG;;
MYSQL_AUDIT_QUERY_START;sql_command_id="5";
MYSQL_AUDIT_TABLE_ACCESS_INSERT;db="db1" table="t1";
MYSQL_AUDIT_QUERY_STATUS_END;sql_command_id="5";
MYSQL_AUDIT_GENERAL_RESULT;;
MYSQL_AUDIT_GENERAL_STATUS;;
MYSQL_AUDIT_COMMAND_END;command_id="3";
Each event string has this format, with semicolons separating the string parts:
event_name;event_data;command
Event strings have these parts:
event_name
: The event name (a symbol that begins withMYSQL_AUDIT_
).event_data
: Empty, or, as described later, data associated with the event.command
: Empty, or, as described later, a command to execute when the event is matched.
A limitation of the NULL_AUDIT
plugin
is that event recording works for a single session only.
Once you record events in a given session, event recording
in subsequent sessions yields a
null_audit_event_record
value of
NULL
. To record events again, it is
necessary to restart the plugin.
To check the order of audit API calls, set the
null_audit_event_order_check
variable to
the expected event order for a particular operation, listing
one or more event strings, each containing two semicolons
internally, with additional semicolons separating adjacent
event strings:
event_name;event_data;command [;event_name;event_data;command] ...
For example:
SET @@null_audit_event_order_check =
'MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE;;;'
'MYSQL_AUDIT_GENERAL_LOG;;;'
'MYSQL_AUDIT_CONNECTION_CONNECT;;';
For better readability, the statement takes advantage of the SQL syntax that concatenates adjacent strings into a single string.
After you set the
null_audit_event_order_check
variable to
a list of event strings, the next matching operation
replaces the variable value with a value that indicates the
operation outcome:
If the expected event order was matched successfully, the resulting
null_audit_event_order_check
value isEVENT-ORDER-OK
.If the
null_audit_event_order_check
value specified aborting a matched event (as described later), the resultingnull_audit_event_order_check
value isEVENT-ORDER-ABORT
.If the expected event order failed with unexpected data, the resulting
null_audit_event_order_check
value isEVENT-ORDER-INVALID-DATA
. This occurs, for example, if an event was specified as expected to affect tablet1
but actually affectedt2
.
When you assign to
null_audit_event_order_check
the list of
events to be matched, some events should be specified with a
nonempty event_data
part of the
event string. The following table shows the
event_data
format for these
events. If an event takes multiple data values, they must be
specified in the order shown. Alternatively, it is possible
to specify an event_data
value as
<IGNORE>
to ignore event data
content; in this case, it does not matter whether or not an
event haas data.
Applicable Events | Event Data Format |
---|---|
|
command_id=" |
|
name=" |
|
sql_command_id=" |
|
db=" |
In the null_audit_event_order_check
value, specifying ABORT_RET
in the
command
part of an event string
makes it possible to abort the audit API call on the
specified event. (Assuming that the event is one that can be
aborted. Those that cannot were described previously.) For
example, as shown previously, this is the expected order of
events for an insert into t1
:
MYSQL_AUDIT_COMMAND_START;command_id="3";
MYSQL_AUDIT_PARSE_PREPARSE;;
MYSQL_AUDIT_PARSE_POSTPARSE;;
MYSQL_AUDIT_GENERAL_LOG;;
MYSQL_AUDIT_QUERY_START;sql_command_id="5";
MYSQL_AUDIT_TABLE_ACCESS_INSERT;db="db1" table="t1";
MYSQL_AUDIT_QUERY_STATUS_END;sql_command_id="5";
MYSQL_AUDIT_GENERAL_RESULT;;
MYSQL_AUDIT_GENERAL_STATUS;;
MYSQL_AUDIT_COMMAND_END;command_id="3";
To abort INSERT
statement
execution when the
MYSQL_AUDIT_QUERY_STATUS_END
event
occurs, set null_audit_event_order_check
like this (remember to add semicolon separators between
adjacent event strings):
SET @@null_audit_event_order_check =
'MYSQL_AUDIT_COMMAND_START;command_id="3";;'
'MYSQL_AUDIT_PARSE_PREPARSE;;;'
'MYSQL_AUDIT_PARSE_POSTPARSE;;;'
'MYSQL_AUDIT_GENERAL_LOG;;;'
'MYSQL_AUDIT_QUERY_START;sql_command_id="5";;'
'MYSQL_AUDIT_TABLE_ACCESS_INSERT;db="db1" table="t1";;'
'MYSQL_AUDIT_QUERY_STATUS_END;sql_command_id="5";ABORT_RET';
It is not necesary to list events that are expected to occur
after the event string that contains a
command
value of
ABORT_RET
.
After the audit plugin matches the preceding sequence, it
aborts event processing and sends an error message to the
client. It also sets
null_audit_event_order_check
to
EVENT-ORDER-ABORT
:
mysql> INSERT INTO db1.t1 VALUES ('some data');
ERROR 3164 (HY000): Aborted by Audit API ('MYSQL_AUDIT_QUERY_STATUS_END';1).
mysql> SELECT @@null_audit_event_order_check;
+--------------------------------+
| @@null_audit_event_order_check |
+--------------------------------+
| EVENT-ORDER-ABORT |
+--------------------------------+
Returning a nonzero value from the audit API notification
routine is the standard way to abort event execution. It is
also possible to specify a custom error code by setting the
null_audit_abort_value
variable to the
value that the notification routine should return:
SET @@null_audit_abort_value = 123;
Aborting a sequence results in a standard message with the
custom error code. Suppose that you set audit log system
variables like this, to abort on a match for the events that
occur for a SELECT 1
statement:
SET @@null_audit_abort_value = 123;
SET @@null_audit_event_order_check =
'MYSQL_AUDIT_COMMAND_START;command_id="3";;'
'MYSQL_AUDIT_PARSE_PREPARSE;;;'
'MYSQL_AUDIT_PARSE_POSTPARSE;;;'
'MYSQL_AUDIT_GENERAL_LOG;;;'
'MYSQL_AUDIT_QUERY_START;sql_command_id="0";ABORT_RET';
Then execution of SELECT 1
results in
this error message that includes the custom error code:
mysql> SELECT 1;
ERROR 3164 (HY000): Aborted by Audit API ('MYSQL_AUDIT_QUERY_START';123).
mysql> SELECT @@null_audit_event_order_check;
+--------------------------------+
| @@null_audit_event_order_check |
+--------------------------------+
| EVENT-ORDER-ABORT |
+--------------------------------+
An event can be also aborted with a custom message,
specified by setting the
null_audit_abort_message
variable.
Suppose that you set audit log system variables like this:
SET @@null_audit_abort_message = 'Custom error text.';
SET @@null_audit_event_order_check =
'MYSQL_AUDIT_COMMAND_START;command_id="3";;'
'MYSQL_AUDIT_PARSE_PREPARSE;;;'
'MYSQL_AUDIT_PARSE_POSTPARSE;;;'
'MYSQL_AUDIT_GENERAL_LOG;;;'
'MYSQL_AUDIT_QUERY_START;sql_command_id="0";ABORT_RET';
Then aborting a sequence results in the following error message:
mysql> SELECT 1;
ERROR 3164 (HY000): Custom error text.
mysql> SELECT @@null_audit_event_order_check;
+--------------------------------+
| @@null_audit_event_order_check |
+--------------------------------+
| EVENT-ORDER-ABORT |
+--------------------------------+
To disable the NULL_AUDIT
plugin after
testing it, use this statement to unload it:
UNINSTALL PLUGIN NULL_AUDIT;