ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# F.34\. spi spi模块提供几个使用SPI和触发器的可行的示例。 当这些函数是它们自己正确的某些值时,它们对于你自己的目的是更有用的修改的例子。 该函数一般足够任意的表使用,但是你在创建一个触发器时必须指定表和字段名(正如下面描述)。 下面描述的每一组函数都是作为一个独立可安装的扩展提供的。 ## F.34.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` — 设置引用键字段为空), 来自主/唯一键的被触发表的字段名,然后是引用表名和字段名 (重复引用表的次数和第一个参数指定的一样多)。请注意, 主/唯一键字段应该标记为NOT NULL并且应该有一个唯一索引。 示例在`refint.example`。 ## F.34.2\. timetravel — 实现时间行程的函数 很久以前,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 ON。`set_timetravel('mytab', 0)`将为表`mytab` 返回TT OFF。两种情况下都报道老的状态。当TT为off是,可以自由修改start_date和stop_date字段。 请注意,on/off状态对于当前数据库会话来说是局部的—新的会话将对于所有表来说总是以TT ON开始。 `get_timetravel()`为一个表返回TT的状态而不会改变这个表。 在`timetravel.example`中有一个示例。 ## F.34.3\. autoinc — 自增字段函数 `autoinc()`是一个存储序列的下一个值到一个整数字段的触发器。 与内置的"序列字段"特性有些重叠,但是并不相同:`autoinc()` 在插入时重写替代一个不同的字段值的尝试,并且可选择的, 它也可以用于在更新时增加字段。 要使用该函数,创建一个使用该函数的`BEFORE INSERT` (或者可选择的`BEFORE INSERT OR UPDATE`) 触发器。 指定两个触发器参数:要被修改的整数字段的名字,和将要填充值的序列对象名。 (实际上,可以指定任意数量的这样的名字对,如果想要更新多个自增字段。) 在`autoinc.example`中有一个示例。 ## F.34.4\. insert_username — 追踪谁改变了表的函数 `insert_username()`是一个存储当前用户名到一个文本字段的触发器。 这对于追踪谁最后修改了表中指定的行是有用的。 要使用该函数,创建一个使用该函数的`BEFORE INSERT`和/或`UPDATE`触发器。 指定一个触发器参数:要修改的文本字段名。 在`insert_username.example`中有一个示例。 ## F.34.5\. moddatetime — 追踪最后修改时间的函数 `moddatetime()`是一个存储当前时间到`timestamp`字段的触发器。 这对于追踪一个表中指定的行的最后修改时间是有用的。 要使用该函数,创建一个使用这个函数的`BEFORE UPDATE`触发器。 指定一个触发器参数:要修改的字段名。该字段必须是`timestamp` 或`timestamp with time zone`类型。 在`moddatetime.example`中有一个示例。