F.37. spi

spi 模块提供了一些使用服务器编程接口(SPI)和触发器的可行示例。虽然这些功能本身具有一定的价值,但它们作为示例进行修改以达到您自己的目的甚至更加有用。这些函数足够通用,可以与任何表一起使用,但是在创建触发器时必须指定表和字段名称(如下所述)。

下面描述的每组功能均作为可单独安装的扩展提供。

F.37.1. refint —实现引用完整性的功能

check_primary_key()check_foreign_key()用于检查外键约束。 (当然,此功能很早就已被内置的外键机制所取代,但是该模块仍然可以作为示例.)

check_primary_key()检查引用表。若要使用,请在引用另一个表的表上使用此函数创建BEFORE INSERT OR UPDATE触发器。指定作为触发参数:构成外键的引用表的列名称,被引用的表名以及构成主/唯一键的被引用表中的列名。要处理多个外键,请为每个引用创建一个触发器。

check_foreign_key()检查引用的表。若要使用,请使用此函数在其他表引用的表上创建BEFORE DELETE OR UPDATE触发器。将以下参数指定为触发参数:函数必须对其进行检查的引用表的数量,找到引用键时的操作(cascade-删除引用行,restrict-如果存在引用键则中止事务,setnull-以将引用键字段设置为 null),构成主键/唯一键的触发表的列名,然后是引用表名和列名(对于第一个参数指定的尽可能多的引用表重复)。请注意,主键/唯一键列应标记为 NOT NULL,并且应具有唯一索引。

refint.example中有示例。

F.37.2. timetravel —实现时间旅行的功能

很久以前,PostgreSQL 具有内置的时间旅行功能,该功能保留每个 Tuples 的插入和删除时间。可以使用这些功能进行仿真。要使用这些功能,必须在表中添加两列abstime类型的字段,以存储插入 Tuples(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的 Tuples 是“立即生效”,可以修改。具有 stop_date 有限的 Tuples 不能再修改-触发器将阻止它。 (如果需要这样做,可以关闭时间旅行,如下所示.)

对于可修改的行,在更新时,只有要更新的 Tuples 中的 stop_date 会更改(更改为当前时间),并且将插入具有已修改数据的新 Tuples。此新 Tuples 中的 Start_date 将设置为当前时间,stop_date 设置为infinity

删除实际上不会删除 Tuples,而只会将其 stop_date 设置为当前时间。

要查询“立即生效”的 Tuples,请在查询的 WHERE 条件中包括stop_date = 'infinity'。 (您可能希望将其合并到视图中.)类似地,您可以查询过去有效的 Tuples,这些 Tuples 在 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 设为 ON。 set_timetravel('mytab', 0)将表mytab的 TT 关闭。在这两种情况下,都会报告旧状态。禁用 TT 后,您可以自由修改 start_date 和 stop_date 列。请注意,打开/关闭状态是当前数据库会话的本地状态-新会话将始终以 TT ON 开头所有表。

get_timetravel()返回表的 TT 状态而不更改它。

timetravel.example中有一个示例。

F.37.3. autoinc —自动递增字段的功能

autoinc()是将序列的下一个值存储到整数字段中的触发器。这与内置的“串行列”功能有一些重叠,但是并不相同:autoinc()将覆盖在插入过程中替换不同字段值的尝试,并且可选地,它也可以用于在更新过程中增加字段。

要使用此功能,请使用此功能创建一个BEFORE INSERT(或可选地BEFORE INSERT OR UPDATE)触发器。指定两个触发器参数:要修改的整数列的名称,以及将提供值的序列对象的名称。 (实际上,如果您要更新多个自动递增列,则可以指定任意数量的成对名称.)

autoinc.example中有一个示例。

F.37.4. insert_username —跟踪谁更改了表的函数

insert_username()是将当前用户名存储到文本字段中的触发器。这对于跟踪谁最后修改了表中的特定行很有用。

要使用此功能,请使用此功能创建一个BEFORE INSERT和/或UPDATE触发器。指定一个触发器参数:要修改的文本列的名称。

insert_username.example中有一个示例。

F.37.5. moddatetime —跟踪上次修改时间的函数

moddatetime()是将当前时间存储到timestamp字段中的触发器。这对于跟踪表中特定行的最后修改时间很有用。

要使用此功能,请使用此功能创建一个BEFORE UPDATE触发器。指定一个触发器参数:要修改的列的名称。该列的类型必须为timestamptimestamp with time zone

moddatetime.example中有一个示例。