擴充 MySQL 9.0  /  ...  /  編寫稽核外掛程式

4.4.8 編寫稽核外掛程式

本節說明如何使用 MySQL 原始碼發行版的 plugin/audit_null 目錄中的範例外掛程式,來編寫伺服器端稽核外掛程式。該目錄中的 audit_null.caudit_null_variables.h 原始檔實作了一個名為 NULL_AUDIT 的稽核外掛程式。

注意

使用稽核外掛程式 API 的其他外掛程式範例為查詢重寫外掛程式 (請參閱 重寫器查詢重寫外掛程式) 和版本權杖外掛程式 (請參閱 版本權杖)。

在伺服器中,可外掛式稽核介面實作於 MySQL 原始碼發行版的 sql 目錄中的 sql_audit.hsql_audit.cc 檔案中。此外,當發生可稽核事件時,伺服器中的多個位置會呼叫稽核介面,以便在必要時通知已註冊的稽核外掛程式有關該事件。若要查看此類呼叫的發生位置,請在伺服器原始檔中搜尋名稱格式為 mysql_audit_xxx() 的函數的調用。伺服器作業 (例如下列作業) 會發生稽核通知:

  • 用戶端連線和中斷連線事件

  • 將訊息寫入一般查詢記錄檔 (如果已啟用記錄檔)

  • 將訊息寫入錯誤記錄檔

  • 將查詢結果傳送至用戶端

若要編寫稽核外掛程式,請在外掛程式原始檔中包含下列標頭檔。根據外掛程式的功能和需求,可能還需要其他 MySQL 或一般標頭檔。

#include <mysql/plugin_audit.h>

plugin_audit.h 包含 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 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;

第一個成員 MYSQL_AUDIT_PLUGIN 可將此外掛程式識別為稽核外掛程式。

audit_null_descriptor 會指向稍後描述的特定類型外掛程式描述符。

name 成員 (NULL_AUDIT) 表示在諸如 INSTALL PLUGINUNINSTALL PLUGIN 之類的陳述式中用來參考外掛程式的名稱。這也是 INFORMATION_SCHEMA.PLUGINSSHOW PLUGINS 顯示的名稱。

audit_null_plugin_init 初始化函數會在載入外掛程式時執行外掛程式初始化。audit_null_plugin_deinit 函數會在卸載外掛程式時執行清除。

一般外掛程式描述符也會參考 simple_statussystem_variables,這些結構會公開數個狀態和系統變數。啟用外掛程式時,可以使用 SHOW 陳述式 (SHOW STATUSSHOW VARIABLES) 或適當的效能結構描述資料表來檢查這些變數。

simple_status 結構會宣告數個名稱格式為 Audit_null_xxx 的狀態變數。NULL_AUDIT 會針對其接收的每個通知遞增 Audit_null_called 狀態變數。其他狀態變數會更具體,且 NULL_AUDIT 只會針對特定事件的通知遞增這些變數。

system_variables 是一個系統變數元素陣列,每個元素都使用 MYSQL_THDVAR_xxx 巨集來定義。這些系統變數的名稱格式為 null_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_maskMYSQL_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 元素的數量對應於事件類別的數量,每個事件類別都會列在 plugin_audit.h 中定義的 mysql_event_class_t 列舉中。

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 符號 (這是所有子類別位元遮罩的聯集)。例如,對於 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 外掛程式所做),外掛程式會在對應的 class_mask 元素中指定 MYSQL_AUDIT_CONNECTION_ALL(在此情況下為 class_mask[1])。若要僅訂閱某些子類別,外掛程式會將 class_mask 元素設定為感興趣子類別的聯集。例如,若要僅訂閱連線和變更使用者子類別,外掛程式會將 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_class 的值解譯 event 引數。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_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 會計算所有事件,而其他變數會計算特定事件子類別的執行個體。例如,前面的 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_record 值為 NULL。若要再次記錄事件,必須重新啟動外掛程式。

若要檢查稽核 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。例如,如果事件被指定為預期會影響資料表 t1,但實際上影響了 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 值中,於事件字串的 command 部分指定 ABORT_RET,可以中止指定事件上的稽核 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";

要在發生 MYSQL_AUDIT_QUERY_STATUS_END 事件時中止 INSERT 語句的執行,請像這樣設定 null_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_check 設定為 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              |
+--------------------------------+

從稽核 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;