Postgresql学习笔记之——逻辑结构管理之触发器

触发器是一种由事件自动触发执行的特殊的存储过程,这些事件可以是对一个表进行的INSERT、UPDATE、DELETE等。

触发器经常用于加强数的完整性约束和业务规则上的约束等。

一、触发器的创建

创建语法:

CREATE [ CONSTRAINT ] TRIGGER name { BEFORE | AFTER | INSTEAD OF } { event [ OR ... ] }
    ON table_name
    [ FROM referenced_table_name ]
    [ NOT DEFERRABLE | [ DEFERRABLE ] [ INITIALLY IMMEDIATE | INITIALLY DEFERRED ] ]
    [ REFERENCING { { OLD | NEW } TABLE [ AS ] transition_relation_name } [ ... ] ]
    [ FOR [ EACH ] { ROW | STATEMENT } ]
    [ WHEN ( condition ) ]
    EXECUTE { FUNCTION | PROCEDURE } function_name ( arguments )

触发事件包括以下几种:
    INSERT-插入
    UPDATE [ OF column_name [, ... ] ]-更新
    DELETE-删除
    TRUNCATE-清除

PS:
不同于Oracle的触发器将触发后的操作定义在触发器本身的语法中,Postgresql的触发器是在触发后执行指定的函数(function)或者存储过程(procedure),触发的操作就是执行函数或存储过程。

创建触发器的步骤:
先为触发器创建一个执行函数,此函数返回的类型为触发器类型,然后即可创建相应的触发器。

例如:

create table student(
student_no int primary key,
student_name varchar(90),
age int,
sex boolean
);

create table score(
student_no int,
chinese_score int,
math_score int,
test_date date
);

如果在删除学生表中的一条记录时,对应这个学生的成绩表中的记录也会被删除,先创建触发器的触发函数:

create or replace function student_delete_trigger()
returns trigger as $$
begin
delete from score where student_no=OLD.student_no;
return old;
end;
$$ language plpgsql;

然后依据创建的触发函数创建对应的触发器:

create trigger delete_student_trigger
after delete on student
for each row execute procedure student_delete_trigger();

插入测试数据:

insert into student values(1,'张三',15);
insert into student values(2,'赵四',13);
insert into student values(3,'王二',16);
insert into student values(4,'李六',14);
insert into student values(5,'周康',18);
insert into student values(6,'丽丽',12);

insert into score values(1,88,79, date '2020-05-08');
insert into score values(1,80,91, date '2020-11-13');
insert into score values(2,81,88, date '2020-05-08');
insert into score values(2,90,90, date '2020-11-13');
insert into score values(3,89,82, date '2020-05-08');
insert into score values(3,91,78, date '2020-11-13');
insert into score values(4,90,77, date '2020-05-08');
insert into score values(4,87,79, date '2020-11-13');
insert into score values(5,82,92, date '2020-05-08');
insert into score values(5,84,95, date '2020-11-13');
insert into score values(6,79,94, date '2020-05-08');
insert into score values(6,86,86, date '2020-11-13');

数据如下:

postgres=# select * from student;
 student_no | student_name | age | sex 
------------+--------------+-----+-----
          1 | 张三         |  15 | 
          2 | 赵四         |  13 | 
          3 | 王二         |  16 | 
          4 | 李六         |  14 | 
          5 | 周康         |  18 | 
          6 | 丽丽         |  12 | 
(6 rows)

postgres=# select * from score;
 student_no | chinese_score | math_score | test_date  
------------+---------------+------------+------------
          1 |            88 |         79 | 2020-05-08
          1 |            80 |         91 | 2020-11-13
          2 |            81 |         88 | 2020-05-08
          2 |            90 |         90 | 2020-11-13
          3 |            89 |         82 | 2020-05-08
          3 |            91 |         78 | 2020-11-13
          4 |            90 |         77 | 2020-05-08
          4 |            87 |         79 | 2020-11-13
          5 |            82 |         92 | 2020-05-08
          5 |            84 |         95 | 2020-11-13
          6 |            79 |         94 | 2020-05-08
          6 |            86 |         86 | 2020-11-13
(12 rows)

现在删除学号为3的学生“王二”:

postgres=# delete from student where student_no=3;
DELETE 1
postgres=# select * from student;
 student_no | student_name | age | sex 
------------+--------------+-----+-----
          1 | 张三         |  15 | 
          2 | 赵四         |  13 | 
          4 | 李六         |  14 | 
          5 | 周康         |  18 | 
          6 | 丽丽         |  12 | 
(5 rows)

postgres=# select * from score;
 student_no | chinese_score | math_score | test_date  
------------+---------------+------------+------------
          1 |            88 |         79 | 2020-05-08
          1 |            80 |         91 | 2020-11-13
          2 |            81 |         88 | 2020-05-08
          2 |            90 |         90 | 2020-11-13
          4 |            90 |         77 | 2020-05-08
          4 |            87 |         79 | 2020-11-13
          5 |            82 |         92 | 2020-05-08
          5 |            84 |         95 | 2020-11-13
          6 |            79 |         94 | 2020-05-08
          6 |            86 |         86 | 2020-11-13
(10 rows)

以上测试看出,在删除学生“王二”后,对应score表中的记录也被删除。

二、语句级触发器和行级触发器
1.语句级触发器

语句级触发器时指执行每个SQL语句时,只执行一次,行级触发器则是指每行记录都会执行一次,一个修改0行的操作仍热会导致合适的语句级触发器被执行,

示例

假设对表student的更新情况加上记录日志:

# 创建记录student表更新的日志表log_student
create table log_student(
update_time timestamp,  --操作的时间
db_user varchar(60),  --操作数据库用户名
opr_type varchar(12)  --操作类型:insert、delete、update
);

创建记录log的触发器函数,如下:

create function log_student_trigger()
returns trigger as $$
begin
insert into log_student values(now(),user,TG_OP);
return null;
end;
$$ language plpgsql;

PS:创建语句中的 “TG_OP” 是触发器函数中的特殊变量,代表DML操作类型。

然后在表student上创建一个语句级触发器:

create trigger log_student_trigger
after insert or delete or update on student
for statement execute procedure log_student_trigger();

现在插入表student中两条记录(原先插入的可以先进行删除,是测试数据更清晰明了):

postgres=# insert into student values(7,'孙七',20),(8,'吴用',19);
INSERT 0 2
postgres=# select * from log_student;
        update_time         | db_user  | opr_type 
----------------------------+----------+----------
 2020-03-11 14:30:22.714301 | postgres | INSERT
(1 row)

postgres=# select * from student;
 student_no | student_name | age | sex 
------------+--------------+-----+-----
          7 | 孙七         |  20 | 
          8 | 吴用         |  19 | 
(7 rows)

从上面可以看出,虽然是插入了两条记录,但是由于执行语句只有一条,所以在日志表log_student中只记录了一次操作。
现在将log_student中记录删除,然后更新表student中的记录:

postgres=# delete from log_student ;
DELETE 1
postgres=# update student set age=16;
UPDATE 2
postgres=# select * from log_student ;
        update_time         | db_user  | opr_type 
----------------------------+----------+----------
 2020-03-11 14:35:19.804496 | postgres | UPDATE
(1 row)

从上面看到,虽然一条update语句更新了两行记录,但是在log_student中只记录了一行记录,说明了语句级触发器是按照语句进行触发的,不管这条语句实际操作了多少行记录。

但是语句级触发器更新0行时,也就是更新条件没有记录,但实际也会触发语句级触发器进行一次操作:

postgres=# delete from log_student ;
DELETE 1
postgres=# update student set age=20 where age=10;
UPDATE 0
postgres=# select * from log_student ;
        update_time         | db_user  | opr_type 
----------------------------+----------+----------
 2020-03-11 14:38:16.104763 | postgres | UPDATE
(1 row)

2.行级触发器

删除student的语句级触发器,清空log_student中的操作日记记录:

postgres=# drop trigger log_student_trigger on student;
DROP TRIGGER
postgres=# delete from log_student ;
DELETE 1
postgres=# delete from student;
DELETE 2

在student表上创建行级触发器:

create trigger log_student_trigger2
after insert or delete or update on student
for row execute procedure log_student_trigger();

然后使用一条SQL语句插入两条记录,如下:

postgres=# insert into student values(1,'李四',20),(2,'张三',19);
INSERT 0 2
postgres=# select * from log_student ;
        update_time         | db_user  | opr_type 
----------------------------+----------+----------
 2020-03-11 14:43:37.901749 | postgres | INSERT
 2020-03-11 14:43:37.901749 | postgres | INSERT
(2 rows)

postgres=# select * from student;
 student_no | student_name | age | sex 
------------+--------------+-----+-----
          1 | 李四         |  20 | 
          2 | 张三         |  19 | 
(2 rows)

从上面看出一条SQL语句插入两条记录后在log_student表中也会记录两条日志记录。
尝试执行一次更新操作:

postgres=# delete from log_student ;
DELETE 2
postgres=# update student set age=16;
UPDATE 2
postgres=# select * from log_student ;
        update_time         | db_user  | opr_type 
----------------------------+----------+----------
 2020-03-11 14:45:42.426286 | postgres | UPDATE
 2020-03-11 14:45:42.426286 | postgres | UPDATE
(2 rows)

更新操作同样会在log_student表中记录两条日志记录。
但是与语句级触发器不同,行级触发器如果更新操作没有修改任何行,则不会触发行级触发器,例如:

postgres=# delete from log_student ;
DELETE 2
postgres=# update student set age=20 where age=10;
UPDATE 0
postgres=# select * from log_student ;
 update_time | db_user | opr_type 
-------------+---------+----------
(0 rows)

三、before触发器和after触发器

一般,语句级别的 “before” 触发器是在语句开始做任何事情之前就被触发了的,而语句级别的 “after” 触发器是在语句结束时才触发的,行级别的 “before” 触发器在对特定行进行操作前触发,而行级别的 “after” 触发器是在语句结束时才触发的,但是它会在任何语句级别的 “after” 触发器被触发之前触发。

before 触发器可以直接修改 “NEW” 值以改变实际的更新值,例如:

# 触发器依赖函数
create function student_user_new_name_trigger()
returns trigger as $$
begin
	NEW.student_name = NEW.student_name||NEW.student_no;
	return NEW;
end;
$$ language plpgsql;

# 触发器
create trigger user_name_student_trigger
before insert or update  on student
for each row execute procedure student_user_new_name_trigger();

这个函数的作用就是在插入表student或者更新时,在插入值的 “student_name” 名称后加上 “student_no”,作为新的 student_name 插入表student的列中。
例如:

postgres=# select * from student;
 student_no | student_name | age | sex 
------------+--------------+-----+-----
          1 | 李四         |  16 | 
          2 | 张三         |  16 | 
(2 rows)

postgres=# insert into student values(3,'王二',19);
INSERT 0 1
postgres=# select * from student;
 student_no | student_name | age | sex 
------------+--------------+-----+-----
          1 | 李四         |  16 | 
          2 | 张三         |  16 | 
          3 | 王二3        |  19 | 
(3 rows)

相对的,如果创建的触发器时 AFTER,则修改NEW时没有用的。

四、删除触发器

语法:

DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]

语法说明:

1.IF EXISTS:如果指定的触发器不存在,返回一个notice,不会抛出错误。

2.CASCADE:级联删除依赖此触发器的对象。

3.RESTRICT:默认值,如果依赖的对象不存在,那么拒绝删除。

例如:

DROP TRIGGER user_name_student_trigger ON student;

PS: 删除触发器时,触发器的函数不会删除;删除表的时候,表上的触发器会删除。

五、触发器的行为

触发器函数有返回值。
语句级触发器应该总是返回NULL,即必须显式地在触发器函数中协商 “RETURN NULL” ,如果没有写,将导致出错,例如:

# 创建触发器函数,并且没有返回null
create or replace function log_student_triger()
returns trigger as $$
begin
	insert into log_student values(now(),user,TG_OP);
end;
$$ language plpgsql;

#  创建语句级触发器
create trigger log_student_trigger
after insert or delete or update on student
for statement execute procedure log_student_triger();

对表插入测试数据时就会出现如下错误:

postgres=# insert into student values(4,'zhang',20);
ERROR:  control reached end of trigger procedure without RETURN
CONTEXT:  PL/pgSQL function log_student_triger()

对于 before 和 instead of 这类行级触发器来说,如果返回的是 NULL,则表示忽略对当前行的操作。如果是返回非 NULL 的行,对于 insert 和 update 操作来说,返回的行将成为被插入的行或者更新的行。

对于 after 这类行级触发器来说,其返回值会被忽略。

如果同一事物上有多个触发器,则将按触发器名字的顺序来触发。如果是 before 和 instead of 行级触发器,每个触发器返回的行(可能已被更改)将成为下一个触发器的输入。如果 before 和 instead of 行级触发器返回的内容为空,那么该行上的其他行级触发器也不会被触发。

六、触发器函数中特殊变量

当把一个 PL/pgsql函数当作触发器函数调用的时候,系统会在顶层的声明段里自动创建几个特殊变量,比如之前看到的 “OLD”、“NEW”、“TG_OP”变量等。

特殊变量主要有以下几种:

1.NEW:
该变量为 insert/update 操作触发的行级触发器中存储的新的数据行,数据类型是 “RECORD” ,在语句级别的触发器里此变量没有分配,delete 操作触发的行级触发器中此变量也没有分配。

2.OLD:
该变量为 update/delete 操作触发的行级触发器中存储的旧数据行,数据类型为 “RECORD”,在语句级别的触发器里此变量没有分配,insert 操作触发的行级触发器中此变量也没有分配。

3.TG_NAME:
数据类型为 name,该变量包含实际触发的触发器名称。

4.TG_WHEN:
内容为 “BEFORE” 或 “AFTER” 的字符串用于指定是BEFORE触发还是AFTER触发。

5.TG_LEVEL:
内容为 “ROW” 或 “STATEMENT” 的字符串用于指定是语句级触发器还是行级触发器。

6.TG_OP:
内容为 “INSERT”、“UPDATE”、“DELETE”、“TRUNCATE”之一的字符串,用于指定DML语句的类型。

7.TG_RELID:
触发器所在的表的OID。

8.RELNAME:
触发器所在表的名称,这个变量即将废弃,被 TG_TABLE_NAME 变量所替代。

9.TG_TABLE_NAME:
触发器所在的表的名称。

10.TG_TABLE_SCHEMA:
触发器所在表的模式名称。

11.TG_NARGS:
在 CREATE TRIGGER 语句里面赋予触发器过程的参数个数。

12.TG_ARGV[]:
为text类型的一个数组;是 CREATE TRIGGER 语句里的参数。

七、事件触发器

Postgresql从9.3开始支持事件触发器(event trigger),这种触发器使得Postgresql支持DDL触发,目前事件触发器支持以下三种DDL事件:

1.ddl_command_start:一个DDL开始执行前被触发。

2.ddl_command_end:一个DDL执行完成后被触发。

3.sql_drop:删除一个数据库对象前被触发。

由于事件触发器涉及的权限比较大,所以只有超级用户才能创建和修改事件触发器。

各种DDL操作会触发的事件如下:

command tagddl_command_startddl_command_endsql_drop
ALTER AGGREGATEXX-
ALTER COLLATIONXX-
ALTER CONVERSIONXX-
ALTER DOMAINXX-
ALTER EXTENSIONXX-
ALTER FOREIGN DATA WRAPPERXX-
ALTER FOREIGN TABLEXXX
ALTER FUNCTIONXX-
ALTER LANGUAGEXX-
ALTER OPERATORXX-
ALTER OPERATOR CLASSXX-
ALTER OPERATOR FAMILYXX-
ALTER SCHEMAXX-
ALTER SEQUENCEXX-
ALTER SERVERXX-
ALTER TABLEXXX
ALTER TEXT SEARCH CONFIGURATIONXX-
ALTER TEXT SEARCH DICTIONARYXX-
ALTER TEXT SEARCH PARSERXX-
ALTER TEXT SEARCH TEMPLATEXX-
ALTER TRIGGERXX-
ALTER TYPEXX-
ALTER USER MAPPINGXX-
ALTER VIEWXX-
CREATE AGGREGATEXX-
CREATE CASTXX-
CREATE COLLATIONXX-
CREATE CONVERSIONXX-
CREATE DOMAINXX-
CREATE EXTENSIONXX-
CREATE FOREIGN DATA WRAPPERXX-
CREATE FOREIGN TABLEXX-
CREATE FUNCTIONXX-
CREATE INDEXXX-
CREATE LANGUAGEXX-
CREATE OPERATORXX-
CREATE OPERATOR CLASSXX-
CREATE OPERATOR FAMILYXX-
CREATE RULEXX-
CREATE SCHEMAXX-
CREATE SEQUENCEXX-
CREATE SERVERXX-
CREATE TABLEXX-
CREATE TABLE ASXX-
CREATE TEXT SEARCH CONFIGURATIONXX-
CREATE TEXT SEARCH DICTIONARYXX-
CREATE TEXT SEARCH PARSERXX-
CREATE TEXT SEARCH TEMPLATEXX-
CREATE TRIGGERXX-
CREATE TYPEXX-
CREATE USER MAPPINGXX-
CREATE VIEWXX-
DROP AGGREGATEXXX
DROP CASTXXX
DROP COLLATIONXXX
DROP CONVERSIONXXX
DROP DOMAINXXX
DROP EXTENSIONXXX
DROP FOREIGN DATA WRAPPERXXX
DROP FOREIGN TABLEXXX
DROP FUNCTIONXXX
DROP INDEXXXX
DROP LANGUAGEXXX
DROP OPERATORXXX
DROP OPERATOR CLASSXXX
DROP OPERATOR FAMILYXXX
DROP OWNEDXXX
DROP RULEXXX
DROP SCHEMAXXX
DROP SEQUENCEXXX
DROP SERVERXXX
DROP TABLEXXX
DROP TEXT SEARCH CONFIGURATIONXXX
DROP TEXT SEARCH DICTIONARYXXX
DROP TEXT SEARCH PARSERXXX
DROP TEXT SEARCH TEMPLATEXXX
DROP TRIGGERXXX
DROP TYPEXXX
DROP USER MAPPINGXXX
DROP VIEWXXX
SELECT INTOXX-
创建事件触发器

语法:

CREATE EVENT TRIGGER name
    ON event
    [ WHEN filter_variable IN (filter_value [, ... ]) [ AND ... ] ]
    EXECUTE { FUNCTION | PROCEDURE } function_name()

在创建事件触发器前,必须先创建触发器函数,事件触发器函数的返回类型与普通触发器的返回类型不一样,它返回的类型为 event_trigger。

示例:

官方文档提供的禁止数据库所有DDL操作的触发器:

CREATE OR REPLACE FUNCTION abort_any_command()
  RETURNS event_trigger
 LANGUAGE plpgsql
  AS $$
BEGIN
  RAISE EXCEPTION 'command % is disabled', tg_tag;
END;
$$;

CREATE EVENT TRIGGER abort_ddl ON ddl_command_start
   EXECUTE FUNCTION abort_any_command();

触发器创建完成后,在数据库中删除一张表就会出现报错:

postgres=# drop table tb_test03;
ERROR:  command DROP TABLE is disabled
CONTEXT:  PL/pgSQL function abort_any_command() line 3 at RAISE

postgres=# create table tb_drop_opr(id int);
ERROR:  command CREATE TABLE is disabled
CONTEXT:  PL/pgSQL function abort_any_command() line 3 at RAISE

但是需要注意的是,truncate table 的操作还是可以执行的,因为在Postgresql‘中 truncate 事件使用普通的触发器触发,事件触发器不会触发 truncate table 操作。

另外事件触发器本省是不会触发事件操作器的。

如果你像再允许数据库进行DDL操作,可以禁止掉事件触发器,命令如下:

postgres=# alter event trigger abort_ddl disable;
ALTER EVENT TRIGGER
postgres=# create table tb_drop_opr(id int);
CREATE TABLE

在Postgresql的9.3版本中,事件触发器函数中仅仅支持TG_EVENT和TG_TAG两个变量。

1.TG_EVENT:为 “ddl_command_start”、“ddl_command_end”、“sql_drop”之一。

2.TG_TAG:指具体的那种DDL操作,如 ”CREATE TABLE"、“DROP TABLE”等。

所以在9.x版本中DDL操作还不太清楚的显示操作了什么数据库对象。
对于 ”sql_drop“ 事件触发器中函数,可以调用一个函数:pg_event_trigger_dropped_objects(),以获取删除数据库对象的信息,这个函数会返回一个结果集,包括如下信息:

列名称列类型列说明
classidOid数据库对象的类型(catalog)的OID
objidOid数据库对象的OID
objsubidint32数据库对象的子对象(如列)
object_typetext数据库对象的类型
schema_nametext数据对象的模式名称
object_nametext数据库对象的名称
object_identitytext数据库对象的标识符

在数据库中通过查询视图PG_EVENT_TRIGGER可以看到已有的事件触发器:

postgres=# select * from pg_event_trigger;
  oid  |  evtname  |     evtevent      | evtowner | evtfoid | evtenabled | evttags 
-------+-----------+-------------------+----------+---------+------------+---------
 16799 | abort_ddl | ddl_command_start |       10 |   16798 | D          | 
(1 row)

示例:

创建一个事件触发器,用于记录数据库中删除对象的审计日志:

# 创建存放删除审计日志的表
create table log_drop_objects(
op_time timestamp,
ddl_tag text,
classid oid,
objid oid,
objsubid oid,
object_type text,
schema_name text,
object_name text,
object_identity text);

# 创建事件触发器函数
create function event_trigger_log_drop()
returns event_trigger language plpgsql as $$
declare
	obj record;
begin
	insert into log_drop_objects select now(), tg_tag, classid, objid, objsubid, object_type, schema_name, object_name, object_identity from pg_event_trigger_dropped_objects();
end
$$;

# 创建事件触发器
create event trigger event_trigger_log_drop
on sql_drop
execute procedure event_trigger_log_drop();

创建测试表进行测试:

postgres=# drop table tb_drop_opr ;
DROP TABLE
postgres=# drop table tb_test03 ;
DROP TABLE
postgres=# drop table tb_test02 ;
DROP TABLE
postgres=# create table tb_drop_adit(id int,name text);
CREATE TABLE
postgres=# alter table tb_drop_adit drop column name;
ALTER TABLE
postgres=# select * from log_drop_objects ;
          op_time           |   ddl_tag   | classid | objid | objsubid |   object_type    | schema_name |     object_name    
  |             object_identity             
----------------------------+-------------+---------+-------+----------+------------------+-------------+--------------------
--+-----------------------------------------
 2020-03-12 11:05:38.564912 | DROP TABLE  |    1259 | 16800 |        0 | table            | public      | tb_drop_opr        
  | public.tb_drop_opr
 2020-03-12 11:05:38.564912 | DROP TABLE  |    1247 | 16802 |        0 | type             | public      | tb_drop_opr        
  | public.tb_drop_opr
 2020-03-12 11:05:38.564912 | DROP TABLE  |    1247 | 16801 |        0 | type             | public      | _tb_drop_opr       
  | public.tb_drop_opr[]
 2020-03-12 11:05:50.58055  | DROP TABLE  |    1259 | 16608 |        0 | table            | public      | tb_test03          
  | public.tb_test03
 2020-03-12 11:05:50.58055  | DROP TABLE  |    1247 | 16610 |        0 | type             | public      | tb_test03          
  | public.tb_test03
 2020-03-12 11:05:50.58055  | DROP TABLE  |    1247 | 16609 |        0 | type             | public      | _tb_test03         
  | public.tb_test03[]
 2020-03-12 11:05:50.58055  | DROP TABLE  |    2606 | 16611 |        0 | table constraint | public      |                    
  | tb_test03_age_check on public.tb_test03
 2020-03-12 11:05:50.58055  | DROP TABLE  |    1259 | 16612 |        0 | toast table      | pg_toast    | pg_toast_16608     
  | pg_toast.pg_toast_16608
 2020-03-12 11:05:50.58055  | DROP TABLE  |    1247 | 16613 |        0 | type             | pg_toast    | pg_toast_16608     
  | pg_toast.pg_toast_16608
 2020-03-12 11:05:50.58055  | DROP TABLE  |    1259 | 16614 |        0 | index            | pg_toast    | pg_toast_16608_inde
x | pg_toast.pg_toast_16608_index
 2020-03-12 11:05:50.58055  | DROP TABLE  |    2606 | 16616 |        0 | table constraint | public      |                    
  | tb_test03_pkey on public.tb_test03
 2020-03-12 11:05:50.58055  | DROP TABLE  |    1259 | 16615 |        0 | index            | public      | tb_test03_pkey     
  | public.tb_test03_pkey
 2020-03-12 11:05:54.308963 | DROP TABLE  |    1259 | 16539 |        0 | table            | public      | tb_test02          
  | public.tb_test02
 2020-03-12 11:05:54.308963 | DROP TABLE  |    1247 | 16541 |        0 | type             | public      | tb_test02          
  | public.tb_test02
 2020-03-12 11:05:54.308963 | DROP TABLE  |    1247 | 16540 |        0 | type             | public      | _tb_test02         
  | public.tb_test02[]
 2020-03-12 11:05:54.308963 | DROP TABLE  |    1259 | 16542 |        0 | toast table      | pg_toast    | pg_toast_16539     
  | pg_toast.pg_toast_16539
 2020-03-12 11:05:54.308963 | DROP TABLE  |    1247 | 16543 |        0 | type             | pg_toast    | pg_toast_16539     
  | pg_toast.pg_toast_16539
 2020-03-12 11:05:54.308963 | DROP TABLE  |    1259 | 16544 |        0 | index            | pg_toast    | pg_toast_16539_inde
x | pg_toast.pg_toast_16539_index
 2020-03-12 11:05:54.308963 | DROP TABLE  |    2606 | 16546 |        0 | table constraint | public      |                    
  | pk_test02_cid_pid on public.tb_test02
 2020-03-12 11:05:54.308963 | DROP TABLE  |    1259 | 16545 |        0 | index            | public      | pk_test02_cid_pid  
  | public.pk_test02_cid_pid
 2020-03-12 11:06:54.213763 | ALTER TABLE |    1259 | 16811 |        2 | table column     | public      |                    
  | public.tb_drop_adit.name
(21 rows)

删除了数据库中的表以及测试表的字段name,在日志表中均能找到删除记录,并且还包含了表删除时附带删除的索引以及大文本存储的TOAST表。

修改事件触发器

修改事件触发器语法:

ALTER EVENT TRIGGER name DISABLE
ALTER EVENT TRIGGER name ENABLE [ REPLICA | ALWAYS ]
ALTER EVENT TRIGGER name OWNER TO { new_owner | CURRENT_USER | SESSION_USER }
ALTER EVENT TRIGGER name RENAME TO new_name

禁止一个事件触发器使用 ”DISABLE“ 。
开启一个事件触发器使用 ”ENABLE“ 。


版权声明:本文为qq_32838955原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。