[英]How can I use a PostgreSQL triggers to store changes (SQL statements and row changes)
Using PostgreSQL triggers, is it possible to record the changes that have happened to a table due to INSERT or UPDATE SQL statements and log them to a file for later execution.使用 PostgreSQL 触发器,是否可以记录由于 INSERT 或 UPDATE SQL 语句而对表发生的更改并将它们记录到文件中以供以后执行。
This is only to be used temporally so just something quick and dirty would do.这只是暂时使用,所以只需要一些快速而肮脏的东西就可以了。
example of an audit trigger from https://www.postgresql.org/docs/current/static/plpgsql-trigger.html来自https://www.postgresql.org/docs/current/static/plpgsql-trigger.html的审计触发器示例
CREATE TABLE emp (
empname text NOT NULL,
salary integer
);
CREATE TABLE emp_audit(
operation char(1) NOT NULL,
stamp timestamp NOT NULL,
userid text NOT NULL,
empname text NOT NULL,
salary integer
);
CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $emp_audit$
BEGIN
--
-- Create a row in emp_audit to reflect the operation performed on emp,
-- make use of the special variable TG_OP to work out the operation.
--
IF (TG_OP = 'DELETE') THEN
INSERT INTO emp_audit SELECT 'D', now(), user, OLD.*;
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO emp_audit SELECT 'U', now(), user, NEW.*;
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO emp_audit SELECT 'I', now(), user, NEW.*;
RETURN NEW;
END IF;
RETURN NULL; -- result is ignored since this is an AFTER trigger
END;
$emp_audit$ LANGUAGE plpgsql;
CREATE TRIGGER emp_audit
AFTER INSERT OR UPDATE OR DELETE ON emp
FOR EACH ROW EXECUTE PROCEDURE process_emp_audit();
Do you actually need the audit log of queries stored in a table?您真的需要存储在表中的查询审计日志吗? The easiest way to get a file with all the queries that have been executed is to use postgresql's built-in logging.
获取包含所有已执行查询的文件的最简单方法是使用 postgresql 的内置日志记录。
In your postgresql.conf (usually in the $PG_DATA dir), set the following options appropriately:在您的 postgresql.conf(通常在 $PG_DATA 目录中)中,适当地设置以下选项:
log_directory '/path/to/log/dir'
log_filename = 'filename.log'
log_statement = 'mod'
That last option makes it log all the INSERT, UPDATE, DELETE, TRUNCATE, and COPY FROM statements.最后一个选项使它记录所有 INSERT、UPDATE、DELETE、TRUNCATE 和 COPY FROM 语句。
More details in the Postgres docs: http://www.postgresql.org/docs/current/static/runtime-config-logging.html Postgres 文档中的更多详细信息: http ://www.postgresql.org/docs/current/static/runtime-config-logging.html
If you are interested only in the statements that are executed, then you can simply activate the PostgreSQL statement log.如果您只对执行的语句感兴趣,那么您可以简单地激活 PostgreSQL 语句日志。
For that, open the postgresql.conf
file and set the following configuration property:为此,打开
postgresql.conf
文件并设置以下配置属性:
log_statement = 'all'
Afterward, you will see the SQL statements logged in a file under the following path:之后,您将看到 SQL 语句记录在以下路径下的文件中:
$PG_DATA/pg_log/postgresql-YYYY-MM-DD_HHMMSS.log
However, if you want to record the row-level changes, then you need an audit logging mechanism which can be implemented using triggers, as follows.然而,如果你想记录行级的变化,那么你需要一个可以使用触发器实现的审计日志记录机制,如下所示。
Let's consider we have the following database tables:假设我们有以下数据库表:
The book_audit_log
is going to store all the changes that happen in the book
table. book_audit_log
将存储book
表中发生的所有更改。
The book_audit_log
is created like this: book_audit_log
是这样创建的:
CREATE TABLE IF NOT EXISTS book_audit_log (
book_id bigint NOT NULL,
old_row_data jsonb,
new_row_data jsonb,
dml_type dml_type NOT NULL,
dml_timestamp timestamp NOT NULL,
dml_created_by varchar(255) NOT NULL,
PRIMARY KEY (book_id, dml_type, dml_timestamp)
)
The book_id
column stores the identifier of the associated book table record that was inserted, updated, or deleted by the current executing DML statement. book_id
列存储当前执行的 DML 语句插入、更新或删除的关联书表记录的标识符。
The old_row_data
and new_row_data
columns are of the JSONB type, and they will capture the state of the book row before and after the execution of the current INSERT, UPDATE, or DELETE statement. old_row_data
和new_row_data
列是 JSONB 类型,它们将捕获当前 INSERT、UPDATE 或 DELETE 语句执行前后的书行状态。
The dml_type
column stores the type of the current executing DML statement (eg, INSERT, UPDATE, and DELETE). dml_type
列存储当前执行的 DML 语句的类型(例如,INSERT、UPDATE 和 DELETE)。 The dml_type type is a PostgreSQL enumeration type, that was created like this: dml_type 类型是一个 PostgreSQL 枚举类型,它是这样创建的:
CREATE TYPE dml_type AS ENUM ('INSERT', 'UPDATE', 'DELETE')
The dml_timestamp
column stores the current timestamp. dml_timestamp
列存储当前时间戳。
The dml_created_by
column stores the application user who generated the current INSERT, UPDATE, or DELETE DML statement. dml_created_by
列存储生成当前 INSERT、UPDATE 或 DELETE DML 语句的应用程序用户。
To capture the INSERT, UPDATE, and DELETE DML statements on the book table, we need to create a trigger function that looks as follows:要捕获 book 表上的 INSERT、UPDATE 和 DELETE DML 语句,我们需要创建一个触发器函数,如下所示:
CREATE OR REPLACE FUNCTION book_audit_trigger_func()
RETURNS trigger AS $body$
BEGIN
if (TG_OP = 'INSERT') then
INSERT INTO book_audit_log (
book_id,
old_row_data,
new_row_data,
dml_type,
dml_timestamp,
dml_created_by
)
VALUES(
NEW.id,
null,
to_jsonb(NEW),
'INSERT',
CURRENT_TIMESTAMP,
current_setting('var.logged_user')
);
RETURN NEW;
elsif (TG_OP = 'UPDATE') then
INSERT INTO book_audit_log (
book_id,
old_row_data,
new_row_data,
dml_type,
dml_timestamp,
dml_created_by
)
VALUES(
NEW.id,
to_jsonb(OLD),
to_jsonb(NEW),
'UPDATE',
CURRENT_TIMESTAMP,
current_setting('var.logged_user')
);
RETURN NEW;
elsif (TG_OP = 'DELETE') then
INSERT INTO book_audit_log (
book_id,
old_row_data,
new_row_data,
dml_type,
dml_timestamp,
dml_created_by
)
VALUES(
OLD.id,
to_jsonb(OLD),
null,
'DELETE',
CURRENT_TIMESTAMP,
current_setting('var.logged_user')
);
RETURN OLD;
end if;
END;
$body$
LANGUAGE plpgsql;
In order for the book_audit_trigger_func
function to be executed after a book table record is inserted, updated or deleted, we have to define the following trigger:为了在插入、更新或删除 book 表记录后执行
book_audit_trigger_func
函数,我们必须定义以下触发器:
CREATE TRIGGER book_audit_trigger
AFTER INSERT OR UPDATE OR DELETE ON book
FOR EACH ROW EXECUTE FUNCTION book_audit_trigger_func();
The dml_created_by
column is set to the value of the var.logged_user
PostgreSQL session variable, which was previously set by the application with the currently logged user, like this: dml_created_by
列设置为var.logged_user
PostgreSQL 会话变量的值,该变量先前由应用程序使用当前登录的用户设置,如下所示:
SET LOCAL var.logged_user = 'Vlad Mihalcea'
When executing an INSERT statement on the book
table:在
book
表上执行 INSERT 语句时:
INSERT INTO book (
id,
author,
price_in_cents,
publisher,
title
)
VALUES (
1,
'Vlad Mihalcea',
3990,
'Amazon',
'High-Performance Java Persistence 1st edition'
)
We can see that a record is inserted in the book_audit_log
that captures the INSERT statement that was just executed on the book
table:我们可以看到在
book_audit_log
中插入了一条记录,记录了刚刚在book
表上执行的 INSERT 语句:
| book_id | old_row_data | new_row_data | dml_type | dml_timestamp | dml_created_by |
|---------|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------|----------|----------------------------|----------------|
| 1 | | {"id": 1, "title": "High-Performance Java Persistence 1st edition", "author": "Vlad Mihalcea", "publisher": "Amazon", "price_in_cents": 3990} | INSERT | 2020-08-25 13:19:57.073026 | Vlad Mihalcea |
When updating the book
table row:更新
book
表行时:
UPDATE book
SET price_in_cents = 4499
WHERE id = 1
We can see that a new record is going to be added to the book_audit_log
by the book_audit_trigger
:我们可以看到
book_audit_trigger
book_audit_log
添加一条新记录:
| book_id | old_row_data | new_row_data | dml_type | dml_timestamp | dml_created_by |
|---------|-----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|----------|----------------------------|----------------|
| 1 | | {"id": 1, "title": "High-Performance Java Persistence 1st edition", "author": "Vlad Mihalcea", "publisher": "Amazon", "price_in_cents": 3990} | INSERT | 2020-08-25 13:19:57.073026 | Vlad Mihalcea |
| 1 | {"id": 1, "title": "High-Performance Java Persistence 1st edition", "author": "Vlad Mihalcea", "publisher": "Amazon", "price_in_cents": 3990} | {"id": 1, "title": "High-Performance Java Persistence 1st edition", "author": "Vlad Mihalcea", "publisher": "Amazon", "price_in_cents": 4499} | UPDATE | 2020-08-25 13:21:15.006365 | Vlad Mihalcea |
When deleting the book
table row:删除
book
表行时:
DELETE FROM book
WHERE id = 1
A new record is added to the book_audit_log
by the book_audit_trigger
: book_audit_trigger
book_audit_log
:
| book_id | old_row_data | new_row_data | dml_type | dml_timestamp | dml_created_by |
|---------|-----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|----------|----------------------------|----------------|
| 1 | | {"id": 1, "title": "High-Performance Java Persistence 1st edition", "author": "Vlad Mihalcea", "publisher": "Amazon", "price_in_cents": 3990} | INSERT | 2020-08-25 13:19:57.073026 | Vlad Mihalcea |
| 1 | {"id": 1, "title": "High-Performance Java Persistence 1st edition", "author": "Vlad Mihalcea", "publisher": "Amazon", "price_in_cents": 3990} | {"id": 1, "title": "High-Performance Java Persistence 1st edition", "author": "Vlad Mihalcea", "publisher": "Amazon", "price_in_cents": 4499} | UPDATE | 2020-08-25 13:21:15.006365 | Vlad Mihalcea |
| 1 | {"id": 1, "title": "High-Performance Java Persistence 1st edition", "author": "Vlad Mihalcea", "publisher": "Amazon", "price_in_cents": 4499} | | DELETE | 2020-08-25 13:21:58.499881 | Vlad Mihalcea |
The link below should point you in the right direction.下面的链接应该指向正确的方向。
https://www.postgresql.org/docs/current/sql-createtrigger.html https://www.postgresql.org/docs/current/sql-createtrigger.html
Depending on what you want to do, it probably is better to turn on logging.根据您想要执行的操作,最好打开日志记录。
PostgreSQL Table Log by Andreas Scherbaum is a Postgresql extension that uses a trigger to log any INSERTs, UPDATEs and DELETEs on a specific table into another table. Andreas Scherbaum 的 PostgreSQL Table Log 是一个 Postgresql 扩展,它使用触发器将特定表上的任何 INSERT、UPDATE 和 DELETE 记录到另一个表中。
The usage is easy: you create a second table which has the same format like your table you want to keep an eye on.用法很简单:您创建第二个表格,其格式与您要关注的表格相同。 Plus you need some additional columns to maintain the logged data.
此外,您还需要一些额外的列来维护记录的数据。
The second part of tablelog is able to restore the state of the original table or of a specific row for any time in the past. tablelog 的第二部分能够恢复原始表或特定行在过去任何时间的状态。
I haven't tried it myself, but it's supposedly working.我自己没有尝试过,但它应该有效。
There's also slides from a talk about tablelog, but I can't post a proper link here due to some stackoverflow antispam weirdness:) (http:// andreas.scherbaum.la/writings/tablelog.pdf).还有关于 tablelog 的讨论的幻灯片,但由于一些 stackoverflow 反垃圾邮件的怪异,我无法在此处发布正确的链接 :) (http://andreas.scherbaum.la/writings/tablelog.pdf)。
http://pgfoundry.org/projects/tablelog/ http://pgfoundry.org/projects/tablelog/
http:// andreas.scherbaum.la/blog/archives/100-Log-Table-Changes-in-PostgreSQL-with-tablelog.html http://andreas.scherbaum.la/blog/archives/100-Log-Table-Changes-in-PostgreSQL-with-tablelog.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.