扩展 MySQL 8.0  / 第 4 章 MySQL 插件 API  / 4.4 编写插件  /  4.4.8 编写审计插件

4.4.8 编写审计插件

本节介绍如何使用 plugin/audit_nullMySQL 源代码分发目录中的示例插件编写服务器端审计插件。该目录中的audit_null.caudit_null_variables.h源文件实现了一个名为 NULL_AUDIT.

笔记

MySQL 5.7 中进行了更改以将查询重写插件重新实现为审计插件,并且审计插件 API 本身与 MySQL 5.6 相比进行了广泛的修改。要针对旧 API 编写审计插件,请参阅 扩展MySQL 5.6中的编写审计插件

笔记

使用审计插件 API 的插件的其他示例是查询重写插件(请参阅 重写器查询重写插件)和版本令牌插件(请参阅 版本令牌)。

在服务器内部,可插入审计接口在MySQL 源代码分发目录中sql_audit.hsql_audit.cc文件中 实现。sql此外,当可审计事件发生时,服务器中的几个地方会调用审计接口,以便在必要时通知已注册的审计插件有关该事件的信息。要查看此类调用发生的位置,请搜索服务器源文件以查找名称为 . 服务器操作会出现审核通知,例如: mysql_audit_xxx()

  • 客户端连接和断开连接事件

  • 将消息写入一般查询日志(如果启用了日志)

  • 将消息写入错误日志

  • 向客户端发送查询结果

要编写审计插件,请在插件源文件中包含以下头文件。根据插件功能和要求,可能还需要其他 MySQL 或通用头文件。

#include <mysql/plugin_audit.h>

plugin_audit.hincludes plugin.h,因此您无需明确包含后一个文件。plugin.h定义MYSQL_AUDIT_PLUGIN服务器插件类型和声明插件所需的数据结构。 plugin_audit.h定义特定于审计插件的数据结构。

审计插件通用描述符

与任何 MySQL 服务器插件一样,审计插件具有通用插件描述符(请参阅 第 4.4.2.1 节,“服务器插件库和插件描述符”)和特定于类型的插件描述符。在 audit_null.c中, 的一般描述符audit_null如下所示:

mysql_declare_plugin(audit_null)
{
  MYSQL_AUDIT_PLUGIN,         /* type                            */
  &audit_null_descriptor,     /* descriptor                      */
  "NULL_AUDIT",               /* name                            */
  "Oracle Corp",              /* 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;

第一个成员 ,MYSQL_AUDIT_PLUGIN将此插件标识为审计插件。

audit_null_descriptor指向特定于类型的插件描述符,稍后描述。

name成员 ( ) 表示在or NULL_AUDIT等​​语句中用于引用插件的 名称。这也是 或 显示的名称。 INSTALL PLUGINUNINSTALL PLUGININFORMATION_SCHEMA.PLUGINSSHOW PLUGINS

初始化函数在audit_null_plugin_init加载插件时执行插件初始化。该audit_null_plugin_deinit 函数在卸载插件时执行清理。

通用插件描述符还引用 simple_statussystem_variables公开多个状态和系统变量的结构。SHOW启用插件后,可以使用语句 ( SHOW STATUS, SHOW VARIABLES) 或适当的性能模式表 检查这些变量 。

simple_status结构声明了几个状态变量,名称为 . 为收到的每个通知递增 状态变量。其他状态变量更具体,并且 仅针对特定事件的通知递增它们。 Audit_null_xxxNULL_AUDITAudit_null_calledNULL_AUDIT

system_variables是系统变量元素的数组,每个元素都使用 宏定义。这些系统变量的名称为 . 这些变量可用于在运行时与插件通信。 MYSQL_THDVAR_xxxnull_audit_xxx

审计插件类型特定的描述符

通用插件描述符中的audit_null_descriptor值指向特定类型的插件描述符。对于审计插件,此描述符具有以下结构(在 中定义 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];
};

审计插件的特定类型描述符具有以下成员:

  • interface_version:按照惯例,特定于类型的插件描述符以给定插件类型的接口版本开头。服务器interface_version在加载插件时检查插件是否与其兼容。对于审计插件, interface_version成员的值为 MYSQL_AUDIT_INTERFACE_VERSION (在 中定义plugin_audit.h)。

  • release_thd:服务器调用的一个函数,用于通知插件它正在与其线程上下文分离。NULL如果没有这样的功能, 应该 是这样。

  • event_notify:服务器调用的函数,用于通知插件发生了可审计事件。这个功能不应该是 NULL;这没有意义,因为不会进行审计。

  • class_mask: MYSQL_AUDIT_CLASS_MASK_SIZE元素数组。每个元素为给定的事件类指定一个位掩码,以指示插件需要通知的子类。(这就是插件 订阅感兴趣事件的方式。)元素应该为 0 以忽略相应事件类的所有事件。

服务器同时使用event_notifyrelease_thd函数。它们在特定线程的上下文中被调用,并且线程可能执行产生多个事件通知的活动。服务器第一次调用 event_notify线程时,它会创建插件到线程的绑定。此绑定存在时无法卸载插件。当线程不再有事件发生时,服务器通过调用release_thd函数,然后销毁绑定。例如,当客户端发出一条语句时,处理该语句的线程可能会通知审计插件有关语句生成的结果集以及正在记录的语句。在这些通知发生后,服务器在让线程休眠之前释放插件,直到客户端发出另一个语句。

这种设计使插件能够在第一次调用函数时为给定线程分配所需的资源,并在 event_notify函数中释放它们release_thd

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 ...

这比在通知函数中反复分配和释放内存更有效。

对于NULL_AUDIT审计插件,特定类型的插件描述符如下所示:

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 }
};

服务器调用audit_null_notify()以将审计事件信息传递给插件。该插件没有任何release_thd功能。

class_mask成员是一个数组,指示插件订阅了哪些事件类。如图所示,数组内容订阅所有可用事件类的所有子类。要忽略给定事件类的所有通知,请将相应的class_mask元素指定为 0。

元素的数量class_mask对应于事件类的数量,每个事件类都列在mysql_event_class_t 定义的枚举中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;

对于任何给定的事件类, plugin_audit.h为各个事件子类定义位掩码符号,以及作为 xxx_ALL所有子类位掩码的联合的符号。例如,for MYSQL_AUDIT_CONNECTION_CLASS(涵盖连接和断开事件的类) plugin_audit.h定义了这些符号:

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)

要订阅连接事件类的所有子类(如NULL_AUDIT插件所做的那样),插件MYSQL_AUDIT_CONNECTION_ALL在相应的class_mask元素中指定(class_mask[1]在本例中)。为了只订阅一些子类,插件将 class_mask元素设置为感兴趣的子类的并集。例如,只订阅 connect 和 change-user 子类,插件设置 class_mask[1]为这个值:

MYSQL_AUDIT_CONNECTION_CONNECT | MYSQL_AUDIT_CONNECTION_CHANGE_USER

审计插件通知功能

审计插件的大部分工作发生在通知函数中(event_notify 类型特定插件描述符的成员)。服务器为每个可审计事件调用此函数。审计插件通知函数有这个原型:

int (*event_notify)(MYSQL_THD, mysql_event_class_t, const void *);

函数原型的第二个和第三个参数 event_notify表示事件类和指向事件结构的通用指针。(不同类中的事件具有不同的结构。通知函数可以使用事件类值来确定应用哪个事件结构。)该函数处理事件并返回一个状态,指示服务器是继续处理事件还是终止事件。

对于NULL_AUDIT,通知功能是audit_null_notify()。此函数递增全局事件计数器(插件将其公开为Audit_null_called 状态值的值),然后检查事件类以确定如何处理事件结构:

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;
    ...
  }
  ...
}

通知函数 event根据 的值解释参数 event_class。参数是指向事件记录的event 通用指针,其结构因事件类而异。(该 plugin_audit.h文件包含定义每个事件类内容的结构。)对于每个类,audit_null_notify()将事件转换为适当的特定于类的结构,然后检查其子类以确定要递增哪个子类计数器。例如,连接事件类中处理事件的代码如下所示:

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;
  }
}
笔记

一般事件类 ( MYSQL_AUDIT_GENERAL_CLASS) 已弃用,将在未来的 MySQL 版本中删除。为了减少插件开销,最好只订阅感兴趣的更具体的事件类。

对于某些事件类,NULL_AUDIT 插件除了递增计数器外还执行其他处理。在任何情况下,当通知函数完成事件处理时,它应该返回一个状态,指示服务器是继续处理事件还是终止事件。

审计插件错误处理

审计插件通知函数可以通过两种方式报告当前事件的状态值:

  • 使用通知函数返回值。在这种情况下,如果服务器应继续处理事件,则函数返回零;如果服务器应终止事件,则函数返回非零。

  • 在从通知函数返回之前调用该my_message()函数来设置错误状态。在这种情况下,通知函数返回值被忽略,服务器中止事件并终止事件处理并出错。参数指示要报告的 my_message()错误及其消息。例如:

    my_message(ER_AUDIT_API_ABORT, "This is my error message.", MYF(0));

    有些事件无法中止。不考虑非零返回值, my_message()错误调用必须遵循is_error()检查。例如:

    if (!thd->get_stmt_da()->is_error())
    {
      my_message(ER_AUDIT_API_ABORT, "This is my error message.", MYF(0));
    }

这些事件不能中止:

  • MYSQL_AUDIT_CONNECTION_DISCONNECT: 服务器无法阻止客户端断开连接。

  • MYSQL_AUDIT_COMMAND_END:此事件提供已完成执行的命令的状态,因此没有终止它的目的。

如果审计插件为不可终止的事件返回非零状态,服务器将忽略该状态并继续处理该事件。如果审计插件使用my_message() 函数来终止不可终止的事件,也是如此。

审核插件使用

要编译和安装插件库文件,请使用 第 4.4.3 节“编译和安装插件库”中的说明。要使库文件可用,请将其安装在插件目录(由 plugin_dir系统变量命名的目录)中。对于NULL_AUDIT插件,它是在您从源代码构建 MySQL 时编译和安装的。它也包含在二进制发行版中。构建过程会生成一个名称为 adt_null.so.so后缀可能因平台而异)的共享对象库。

要在运行时注册插件,请使用此语句,.so根据需要调整平台的后缀:

INSTALL PLUGIN NULL_AUDIT SONAME 'adt_null.so';

有关插件加载的其他信息,请参阅 安装和卸载插件

要验证插件安装,请检查 INFORMATION_SCHEMA.PLUGINS 表或使用SHOW PLUGINS 语句。请参阅 获取服务器插件信息

安装NULL_AUDIT审计插件时,它会公开状态变量,指示已调用插件的事件:

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_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计算所有事件,其他变量计算特定事件子类的实例。例如,前面的 SHOW STATUS语句使服务器向客户端发送结果,并在启用该日志的情况下将消息写入常规查询日志。因此,重复发出该语句的客户端会导致 Audit_null_calledAudit_null_general_resultAudit_null_general_log每次递增。

状态变量值是全局的,并在所有会话中聚合。个别会话没有计数器。

NULL_AUDIT公开了几个系统变量,可以在运行时与插件进行通信:

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                       |       |
+---------------------------------------------------+-------+

系统变量具有以下NULL_AUDIT含义:

  • null_audit_abort_message:事件中止时使用的自定义错误消息。

  • null_audit_abort_value:事件中止时使用的自定义错误代码。

  • null_audit_event_order_check:在事件匹配之前,预期的事件顺序。事件匹配后,匹配结果。

  • null_audit_event_order_check_consume_ignore_count:事件匹配不应消耗匹配事件的次数。

  • null_audit_event_order_check_exact: 事件匹配是否必须精确。null_audit_event_order_check禁用此变量可以跳过事件顺序匹配期间未列出的 事件。在指定的事件中,它们仍必须按照给定的顺序匹配。

  • null_audit_event_order_started: 供内部使用。

  • null_audit_event_record:事件记录发生后记录的事件。

  • null_audit_event_record_def: 记录事件时要匹配的开始和结束事件的名称,以分号分隔。必须在记录事件的每个语句之前设置该值。

为了演示这些系统变量的使用,假设db1.t1存在一个表,创建如下:

CREATE DATABASE db1;
CREATE TABLE db1.t1 (a VARCHAR(255));

出于测试创建目的,可以记录通过插件的事件。null_audit_event_record_def要开始记录,请在变量中指定开始和结束事件 。例如:

SET @@null_audit_event_record_def =
  'MYSQL_AUDIT_COMMAND_START;MYSQL_AUDIT_COMMAND_END';

在匹配那些开始和结束事件的语句发生后,null_audit_event_record 系统变量包含生成的事件序列。例如,在记录SELECT 1语句的事件之后, null_audit_event_record是一个字符串,其值由一组事件字符串组成:

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";

记录INSERT INTO db1.t1 VALUES ('some data')语句的事件后, null_audit_event_record具有以下值:

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";

每个事件字符串都有这种格式,用分号分隔字符串部分:

event_name;event_data;command

事件字符串包含以下部分:

  • event_name:事件名称(以 开头的符号 MYSQL_AUDIT_)。

  • event_data:空,或者,如后所述,与事件关联的数据。

  • command:空,或者,如后所述,当事件匹配时执行的命令。

笔记

该插件的一个限制NULL_AUDIT是事件记录仅适用于单个会话。在给定会话中记录事件后,后续会话中的事件记录将产生 null_audit_event_recordNULL. 要再次记录事件,需要重新启动插件。

要检查审计 API 调用的顺序,请将 null_audit_event_order_check变量设置为特定操作的预期事件顺序,列出一个或多个事件字符串,每个事件字符串内部包含两个分号,并用额外的分号分隔相邻的事件字符串:

event_name;event_data;command [;event_name;event_data;command] ...

例如:

SET @@null_audit_event_order_check =
  'MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE;;;'
  'MYSQL_AUDIT_GENERAL_LOG;;;'
  'MYSQL_AUDIT_CONNECTION_CONNECT;;';

为了更好的可读性,该语句利用了将相邻字符串连接成单个字符串的 SQL 语法。

null_audit_event_order_check变量设置为事件字符串列表后,下一个匹配操作会将变量值替换为指示操作结果的值:

  • 如果成功匹配预期的事件顺序,则结果 null_audit_event_order_check值为 EVENT-ORDER-OK

  • 如果该null_audit_event_order_check 值指定中止匹配的事件(如后所述),则结果 null_audit_event_order_check值为 EVENT-ORDER-ABORT

  • 如果预期的事件顺序因意外数据而失败,则结果 null_audit_event_order_check值为 EVENT-ORDER-INVALID-DATA。例如,如果一个事件被指定为预期影响 tablet1但实际上影响了 ,就会发生这种情况t2

当您分配给 null_audit_event_order_check要匹配的事件列表时,一些事件应该用event_data事件字符串的非空部分指定。下表显示了 event_data这些事件的格式。如果事件采用多个数据值,则必须按照显示的顺序指定它们。或者,可以指定一个event_data<IGNORE>来忽略事件数据内容;在这种情况下,事件是否有数据并不重要。

适用事件 事件数据格式

MYSQL_AUDIT_COMMAND_START

MYSQL_AUDIT_COMMAND_END

command_id="id_value"

MYSQL_AUDIT_GLOBAL_VARIABLE_GET

MYSQL_AUDIT_GLOBAL_VARIABLE_SET

name="var_value" value="var_value"

MYSQL_AUDIT_QUERY_NESTED_START

MYSQL_AUDIT_QUERY_NESTED_STATUS_END

MYSQL_AUDIT_QUERY_START

MYSQL_AUDIT_QUERY_STATUS_END

sql_command_id="id_value"

MYSQL_AUDIT_TABLE_ACCESS_DELETE

MYSQL_AUDIT_TABLE_ACCESS_INSERT

MYSQL_AUDIT_TABLE_ACCESS_READ

MYSQL_AUDIT_TABLE_ACCESS_UPDATE

db="db_name" table="table_name"

在该null_audit_event_order_check 值中,ABORT_RETcommand事件字符串部分指定可以中止对指定事件的审计 API 调用。(假设该事件是一个可以中止的事件。那些不能中止的事件之前已经描述过。)例如,如前所示,这是插入到的事件的预期顺序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";

要在事件发生时 中止INSERT语句执行 , 请这样设置(请记住在相邻的事件字符串之间添加分号分隔符): MYSQL_AUDIT_QUERY_STATUS_ENDnull_audit_event_order_check

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';

command没有必要列出预期在包含值 的事件字符串之后发生的事件 ABORT_RET

审计插件匹配前面的序列后,它会中止事件处理并向客户端发送错误消息。它还设置 null_audit_event_order_checkEVENT-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              |
+--------------------------------+

从审计 API 通知例程返回一个非零值是中止事件执行的标准方法。也可以通过将 null_audit_abort_value变量设置为通知例程应返回的值来指定自定义错误代码:

SET @@null_audit_abort_value = 123;

中止序列会生成带有自定义错误代码的标准消息。假设您像这样设置审计日志系统变量,以中止对SELECT 1语句发生的事件的匹配:

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';

SELECT 1然后在包含自定义错误代码的错误消息中 执行结果:

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              |
+--------------------------------+

事件也可以通过设置 null_audit_abort_message变量指定的自定义消息中止。假设您像这样设置审计日志系统变量:

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';

然后中止序列会导致以下错误消息:

mysql> SELECT 1;
ERROR 3164 (HY000): Custom error text.
mysql> SELECT @@null_audit_event_order_check;
+--------------------------------+
| @@null_audit_event_order_check |
+--------------------------------+
| EVENT-ORDER-ABORT              |
+--------------------------------+

要在测试后禁用NULL_AUDIT插件,请使用以下语句卸载它:

UNINSTALL PLUGIN NULL_AUDIT;