• 【database】审计/记录mysql、postgres、sqlserver、oracle数据库的ddl事件和语句


    一、mysql

    很遗憾,mysql不支持database级别的trigger。无法使用触发器记录ddl。
    如果需要获取dll记录可以使用debezium/cdc在mysql的binlog中解析。

    二、postgres

    创建trigger

    能记录:

    • create table
    • drop table
    • alter table add/drop/rename/修改类型

    不能记录

    • truncate

    参考文章

    -- 参考文章:https://blog.csdn.net/weixin_42212488/article/details/127873487
    -- 官方文档:https://www.postgresql.org/docs/13/functions-event-triggers.html#PG-EVENT-TRIGGER-TABLE-REWRITE-FUNCTIONS
    drop table ddl_log;
    create table ddl_log(
          id serial8,
          "user" text,
          txid bigint,
          schema_name text,
          ddl_type text,
          object varchar,
          ddl_query text,
          query_time timestamp
      );
     
    
    truncate audit_ddl;
    select * from audit_ddl;
    
    drop function ddl_listen_common();
    create or replace function ddl_listen_common()
    returns event_trigger
    language plpgsql
    as
    $$
      declare
          query text;
          command record;
      begin
          query := current_query();
          if exists(select * from pg_event_trigger_ddl_commands()) then
              for command in select * from pg_event_trigger_ddl_commands()
              loop
              insert into audit_ddl("user", txid, schema_name, ddl_type, object, ddl_query, query_time)
              VALUES (current_user,txid_current(),command.schema_name,command.command_tag,command.object_identity,query, statement_timestamp());
              end loop ;
          end if;
      end;
    $$
    security definer;
    
    drop event trigger trg_ddl_listen_common;
    create event trigger trg_ddl_listen_common on ddl_command_end execute procedure ddl_listen_common();
    
    drop function ddl_listen_drop;
    create or replace function ddl_listen_drop()
    returns event_trigger
    language plpgsql
    as
    $$
    declare
      query text;
      command record;
    begin
      query := current_query();
      if exists(select * from pg_event_trigger_dropped_objects()) is not null then
          for command in select * from pg_event_trigger_dropped_objects()
          loop
          insert into audit_ddl("user", txid, schema_name, ddl_type, object, ddl_query, query_time)
          VALUES (current_user,txid_current(),command.schema_name,'DROP '||command.object_type,command.object_identity,query, statement_timestamp());
          end loop;
      end if;
    end;
    $$
    security definer;
    
    drop event trigger trg_ddl_listen_drop;
    create event trigger trg_ddl_listen_drop on sql_drop  execute procedure ddl_listen_drop();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    测试

    drop table if exists ischema.schema_evo;
    create table ischema.schema_evo(
    id bigint primary key
    ,name varchar(30)
    ,address varchar(30)
    );
    
    insert into ischema.schema_evo values(1,'zhangsna','beijing');
    
    alter table ischema.schema_evo add "gender" varchar(10);
    insert into ischema.schema_evo values(2,'lisi','male','shanghai');
    alter table ischema.schema_evo rename column "name" to name_abbr;
    insert into ischema.schema_evo values(3,'lvzhou','male','shanghai');
    alter table ischema.schema_evo alter column "name_abbr" type varchar(50);
    insert into ischema.schema_evo values(4,'wangwu','female','chongqing');
    alter table ischema.schema_evo drop column address;
    insert into ischema.schema_evo values(5,'zhaoliu','male');
    -- 不支持truncate记录。
    truncate ischema.schema_evo;
    
    select * from ischema.schema_evo where 1=1 order by id desc limit 10;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    三、sqlserver

    创建trigger

    能记录

    • create table
    • drop table
    • alter table add/drop/修改类型 column

    不能记录

    • alter table rename column
    • truncate

    参考文章

    
    -- 参考文章:https://blog.csdn.net/qq_40205468/article/details/88845215
    
    drop table ischema.audit_ddl;
    truncate ischema.audit_ddl;
    select * from ischema.audit_ddl;
    
    drop trigger trg_ddl_listen ON DATABASE;
    -- 以下均为触发器内容,一次执行即可。
    CREATE TRIGGER trg_ddl_listen
        ON DATABASE
        FOR CREATE_TABLE, DROP_TABLE, ALTER_TABLE
    AS
    /* 本触发器只针对触发器的增删改,进行记录触发器的相关信息 */
    IF OBJECT_ID(N'ischema.audit_ddl', N'U') is NULL
    begin
    CREATE TABLE ischema.audit_ddl
        (
          rowid INT IDENTITY ,
          EventType VARCHAR(20) ,
          PostTime DATETIME ,
          SPID INT ,
          ServerName VARCHAR(255) ,
          LoginName VARCHAR(255) ,
          DatabaseName VARCHAR(255) ,
    	  UserName VARCHAR(255),
          SchemaName VARCHAR(20) ,
          ObjectName VARCHAR(255) ,
          ObjectType VARCHAR(20) ,
          CommandText NVARCHAR(MAX) ,
          remark NVARCHAR(MAX) ,
          commandtext_check INT
        );
    end
    
    DECLARE
    @EeventType VARCHAR(20),
    		@PostTime DATETIME,
    		@SPID INT,
    		@ServerName VARCHAR(255),
    		@LoginName VARCHAR(255),
    		@DatabaseName VARCHAR(255),
    		@UserName VARCHAR(255),
    		@SchemaName VARCHAR(255),
    		@ObjectName VARCHAR(255),
    		@ObjectType VARCHAR(20),
    		@CommandText NVARCHAR(MAX),
    		@Remarks NVARCHAR(MAX),
    		@Commandtest_check INT
     
    SET @EeventType=EVENTDATA().value('(/EVENT_INSTANCE/EventType)[1]','VARCHAR(20)')
    SET @PostTime=EVENTDATA().value('(/EVENT_INSTANCE/PostTime)[1]','DATETIME')
    SET @SPID=EVENTDATA().value('(/EVENT_INSTANCE/SPID)[1]','INT')
    SET @ServerName=EVENTDATA().value('(/EVENT_INSTANCE/ServerName)[1]','VARCHAR(255)')
    SET @LoginName=EVENTDATA().value('(/EVENT_INSTANCE/LoginName)[1]','VARCHAR(255)')
    SET @DatabaseName=EVENTDATA().value('(/EVENT_INSTANCE/LoginName)[1]','VARCHAR(255)')
    SET @UserName=EVENTDATA().value('(EVENT_INSTANCE/UserName)[1]','VARCHAR(255)')
    SET @SchemaName=EVENTDATA().value('(EVENT_INSTANCE/SchemaName)[1]','VARCHAR(255)')
    SET @ObjectName=EVENTDATA().value('(EVENT_INSTANCE/ObjectName)[1]','VARCHAR(255)')
    SET @ObjectType=EVENTDATA().value('(EVENT_INSTANCE/ObjectType)[1]','VARCHAR(255)')
    SET @CommandText=EVENTDATA().value('(EVENT_INSTANCE/TSQLCommand/CommandText)[1]','NVARCHAR(MAX)')
     
    INSERT  INTO ischema.audit_ddl
            ( EventType ,
              PostTime ,
              SPID ,
              ServerName ,
              LoginName ,
              DatabaseName ,
              UserName ,
              SchemaName ,
              ObjectName ,
              ObjectType ,
              CommandText ,
              remark ,
              commandtext_check
            )
    SELECT @EeventType,
           @PostTime,
           @SPID,
           @ServerName,
           @LoginName,
           @DatabaseName,
           @UserName,
           @SchemaName,
           @ObjectName,
           @ObjectType,
           @CommandText,
           '',
           0;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    测试

    
    drop table ischema.schema_evo;
    create table ischema.schema_evo(
    id bigint primary key
    ,name varchar(30)
    ,address varchar(30)
    );
    -- 启动表的CDC跟踪。
    EXEC sys.sp_cdc_enable_table @source_schema = 'ischema', @source_name = 'schema_evo', @role_name = NULL, @supports_net_changes = 0;
    
    insert into ischema.schema_evo values(1,'test','xinjiang');
    
    alter table ischema.schema_evo add gender varchar(10);
    insert into ischema.schema_evo values(2,'test','beijing','female');
    
    alter table ischema.schema_evo alter column "name" varchar(50);
    insert into ischema.schema_evo values(3,'test','hangzhou','male');
    
    -- 已经启用cdc的表无法修改列名称:Cannot alter column 'name' because it is 'REPLICATED'.
    exec sp_rename 'ischema.schema_evo.name','name_abbr';
    
    alter table ischema.schema_evo drop column address;
    insert into ischema.schema_evo values(4,'test','female');
    
    -- 已经启用cdc的表无法truncate:Cannot truncate table 'ischema.schema_evo' because it is published for replication or enabled for Change Data Capture.
    TRUNCATE table ischema.schema_evo;
    
    select * from ischema.schema_evo;
    
    -- 获取ddl, 可以通过 "ddl_command"列 获取到具体的ddl命令。
    -- 参考:https://learn.microsoft.com/zh-cn/sql/relational-databases/system-stored-procedures/sys-sp-cdc-get-ddl-history-transact-sql?view=sql-server-ver16&redirectedfrom=MSDN
    EXEC sys.sp_cdc_get_ddl_history  @capture_instance = 'ischema_schema_evo';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    四、oracle

    创建trigger

    参考文章

    能记录

    • create table
    • drop table
    • alter table add/drop/rename/修改类型 column
    • truncate

    不能记录

    
    -- 参考文章:https://blog.csdn.net/u014257861/article/details/80182067
    -- DBA账号授权。
    grant administer DATABASE TRIGGER to cdcuser;
    SELECT * FROM USER_SYS_PRIVS;  -- 要有:ADMINISTER DATABASE TRIGGER 权限 
    
    DROP TABLE audit_ddl;
    create table audit_ddl (
    opertime timestamp PRIMARY KEY,
    ip varchar2(20),
    hostname varchar2(30),
    operation varchar2(30),
    object_type varchar2(30),
    object_name varchar2(30),
    sql_stmt clob,
    db_schema varchar2(30)
    );
    
    
    TRUNCATE TABLE audit_ddl;
    SELECT * FROM audit_ddl;
    
    DROP TRIGGER trg_ddl_listen;
    
    create or replace trigger trg_ddl_listen
      after ddl on database
    DECLARE
      PRAGMA AUTONOMOUS_TRANSACTION;
      n        NUMBER;
      stmt     clob := NULL;
      sql_text ora_name_list_t;
    BEGIN
      n := ora_sql_txt(sql_text);
      FOR i IN 1 .. n LOOP
        stmt := stmt || sql_text(i);
      END LOOP;
      INSERT INTO audit_ddl
        (opertime, ip, hostname, operation, object_type, object_name, sql_stmt,db_schema)
      VALUES
        (systimestamp,
         sys_context('userenv', 'ip_address'),
         sys_context('userenv', 'HOST'),
         ora_sysevent,
         ora_dict_obj_type,
         ora_dict_obj_name,
         stmt,
         user
       );
      COMMIT;
    END;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    测试

    drop table DBO.SCHEMA_EVO;
    create table DBO.SCHEMA_EVO(
    id numeric(10,0) primary key
    ,name varchar(30)
    ,address varchar(30)
    );
    INSERT INTO DBO.SCHEMA_EVO VALUES(1,'TEST','BEIJING');
    
    ALTER TABLE DBO.SCHEMA_EVO ADD gender varchar(10);
    INSERT INTO DBO.SCHEMA_EVO VALUES(2,'TEST','SHANGHAI','FEMALE');
    ALTER TABLE DBO.SCHEMA_EVO MODIFY name varchar(50) default 'abbr';
    INSERT INTO DBO.SCHEMA_EVO VALUES(3,'TEST','SHANGHAI','MALE');
    ALTER TABLE DBO.SCHEMA_EVO RENAME COLUMN name TO name_abbr;
    INSERT INTO DBO.SCHEMA_EVO VALUES(4,'TEST','SUZHOU','FEMALE');
    ALTER TABLE DBO.SCHEMA_EVO DROP COLUMN address;
    INSERT INTO DBO.SCHEMA_EVO VALUES(5,'TEST','FEMALE');
    -- 支持记录TRUNCATE操作.
    TRUNCATE TABLE DBO.SCHEMA_EVO;
    
    SELECT * FROM DBO.SCHEMA_EVO;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图
    Vue组件中的生命周期函数执行流程
    性能测试包含哪些内容?
    mybatis foeahe 批量插入 删除 修改
    Spring Security认证架构介绍
    ETCD快速入门-03 常用命令
    Fragment碎片的切换
    Linux:线程互斥与同步 | 生产者消费者模型 | 线程伪唤醒、唤醒丢失 | 死锁
    Linux 学习(CentOS 7)
    js中运算规则
  • 原文地址:https://blog.csdn.net/lisacumt/article/details/134289755