pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
spi 模块提供了几个使用 SPI 和触发器的可行示例。虽然这些函数本身就有一定价值,但作为可按自己目的修改的示例,它们更有用。 The functions are general enough to be used with any table, but you have to specify table and field names (as described below) while creating a trigger.
下文描述的每组函数都作为一个可单独安装的扩展提供。
check_primary_key()和check_foreign_key()用于检查外键约束。(当然,这项功能早已被内置的外键机制取代,不过该模块作为示例仍然有用。)
check_primary_key() 检查引用表。使用时,在引用其他表的表上 创建一个使用该函数的 BEFORE INSERT OR UPDATE 触发器。 触发器参数依次为:引用表中构成外键的列名、被引用表名,以及被引用表中构成 主键/唯一键的列名。 若要处理多个外键,请为每个引用分别创建一个触发器。
check_foreign_key() 检查被引用表。使用时,在被其他表引用的表上 创建一个使用该函数的 BEFORE DELETE OR UPDATE 触发器。 触发器参数依次为:该函数需要检查的引用表数量、发现引用键时采取的动作 (cascade 表示删除引用行, restrict 表示若存在引用键则中止事务, setnull 表示将引用键字段设为空)、 被引用表中构成主键/唯一键的列名,然后是引用表名和列名 (按第一个参数指定的引用表数量重复提供)。请注意,主键/唯一键列应标记为 NOT NULL,并具有唯一索引。
refint.example 中有示例。
很久以前,PostgreSQL曾内置时间旅行功能,为每个元组保存插入和删除时间。可以使用这些函数模拟这一功能。要使用这些函数,必须为表添加两个abstime类型的列,以存储元组插入的时间(start_date)和更改/删除的时间(stop_date):
CREATE TABLE mytab (
... ...
start_date abstime,
stop_date abstime
... ...
);
这些列可以任意命名,不过在这里我们将它们称为 start_date 和 stop_date。
插入新行时,start_date 通常应设置为当前时间,stop_date 应设置为infinity。如果插入的数据在这些列中包含空值,触发器会自动将其替换为上述值。一般来说,只有在重新载入转储数据时,才应向这些列中插入显式的非空数据。
stop_date 等于infinity的元组“当前有效”,可以修改。stop_date 为有限值的元组则不能再修改,触发器会阻止这种操作。(如果需要这样做,可以按下文所示关闭时间旅行。)
对于可修改的行,更新时只会将被更新元组的 stop_date 改为当前时间,并插入一个包含修改后数据的新元组。新元组的 start_date 将设置为当前时间,stop_date 设置为infinity。
删除操作实际上不会删除元组,而只会将其 stop_date 设置为当前时间。
要查询“当前有效”的元组,请在查询的 WHERE 条件中加入stop_date = 'infinity'。(你可能希望将其放入视图中。)类似地,通过为 start_date 和 stop_date 设置合适的条件,也可以查询在过去任何时间有效的元组。
timetravel()是支持此行为的通用触发器函数。在每个使用时间旅行的表上,使用此函数创建一个BEFORE INSERT OR UPDATE OR DELETE触发器。指定两个触发器参数:start_date 和 stop_date 列的实际名称。还可以选择指定一到三个额外参数,它们必须引用text类型的列。触发器会在 INSERT 时将当前用户名存入其中的第一列,在 UPDATE 时存入第二列,在 DELETE 时存入第三列。
set_timetravel()允许为表打开或关闭时间旅行。set_timetravel('mytab', 1)会为表mytab打开 TT。set_timetravel('mytab', 0)会为表mytab关闭 TT。两种情况都会报告原来的状态。在 TT 关闭时,可以自由修改 start_date 和 stop_date 列。请注意,开关状态仅作用于当前数据库会话;新会话总是从所有表的 TT 都打开的状态开始。
get_timetravel()返回表的 TT 状态,而不改变它。
timetravel.example中有一个示例。
autoinc()是一个将序列的下一个值存入整数字段的触发器。它与内置的“序列列”功能有一些重叠,但并不相同:autoinc()会覆盖插入时试图为该字段指定其他值的操作,而且还可以选择在更新时也递增该字段。
使用时,创建一个使用该函数的 BEFORE INSERT (或者可选的 BEFORE INSERT OR UPDATE)触发器。 指定两个触发器参数:要修改的整型列名,以及提供这些值的序列对象名。 (实际上,如果你希望更新多个自动递增列,也可以指定任意多组这样的名称对。)
autoinc.example 中有一个示例。
insert_username() 是一个将当前用户名存入文本字段的触发器。 它有助于跟踪表中某一特定行最后一次是由谁修改的。
使用时,创建一个使用该函数的 BEFORE INSERT 和/或 UPDATE 触发器。指定一个触发器参数:要修改的文本列名。
insert_username.example 中有一个示例。
moddatetime() 是一个将当前时间存入 timestamp 字段的触发器。 它有助于跟踪表中某一特定行最后一次被修改的时间。
使用时,创建一个使用该函数的 BEFORE UPDATE 触发器。 指定一个触发器参数:要修改的列名。该列必须是 timestamp 或 timestamp with time zone 类型。
moddatetime.example 中有一个示例。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。