CREATE FUNCTION funcname argument-types) RETURNS return-type AS ' # PL/Tcl function body ' LANGUAGE 'pltcl';当在一个查询里面调用这个函数,参数是作为变量 $1 ... $n 传递给 Tcl 过程语言体的.所以一个简单的返回两个 int4 值的最大值函数可以这样创建:
CREATE FUNCTION tcl_max (int4, int4) RETURNS int4 AS '
if {$1 > $2} {return $1}
return $2
' LANGUAGE 'pltcl';
复合类型参数是作为 Tcl 数组赋予过程的.数组的元素名称就是复合类型的字段名称.如果一个实际行的字段是一个
NULL 值,它将不在数组中出现!这里是一个用 PL/Tcl 定义 overpaid_2 函数的例子(本例可以在旧的Postgres
文挡中找到)
CREATE FUNCTION overpaid_2 (EMP) RETURNS bool AS '
if {200000.0 < $1(salary)} {
return "t"
}
if {$1(age) < 30 && 100000.0 < $1(salary)} {
return "t"
}
return "f"
' LANGUAGE 'pltcl';
下面是一个小的触发器过程的例子,它强制表内的一个整数值对行的更新次数进行跟踪.对插入的新行,该值初始化为 0 并且在每次更新操作中加一:
CREATE FUNCTION trigfunc_modcount() RETURNS OPAQUE AS '
switch $TG_op {
INSERT {
set NEW($1) 0
}
UPDATE {
set NEW($1) $OLD($1)
incr NEW($1)
}
default {
return OK
}
}
return [array get NEW]
' LANGUAGE 'pltcl';
CREATE TABLE mytab (num int4, modcnt int4, desc text);
(译注:desc 在6.5以上版本里面是保留字,应该改成 describe 之类的东西.)
CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
FOR EACH ROW EXECUTE PROCEDURE trigfunc_modcount('modcnt');
"SELECT '$val' AS ret"
"SELECT 'doesn't' AS ret"
"SELECT 'doesn''t' AS ret"
"SELECT '[ quote $val ]' AS ret"
如果查询是一个 SELECT 语句并且给出了可选的循环体(一个 Tcl 命令的语句体,象一个 foreach 命令),它就会计算每个选择的行并且如期望的那样继续/中断。选择的字段的值被放到命名为列名称的变量里面去了.所以一个
spi_exec "SELECT count(*) AS cnt FROM pg_proc"将把变量 $cnt 置为 pg_proc 系统表里的行数.如果给出了可选的 -array ,列/字段的值将保存在相关的名为 'name' 的数组里,而不是分离的变量.
spi_exec -array C "SELECT * FROM pg_class" {
elog DEBUG "have table $C(relname)"
}
将为 pg_class 的每一行打印一个 DEBUG 日志信息.spi_exec 返回的值是查询涉及到的保存在全局变量
SPI_processed 里的行数.
如果查询引用了参数,类型名必须做为 Tcl 数组给出.从 spi_prepare 返回的值是一个查询
ID,该 ID 将被后继的 spi_execp 调用使用.参阅 spi_execp 中的例子.
queryid 是 spi_prepare 调用返回的 ID.(译注:query?)
如果有一个类型列表给予了 spi_prepare,必须在查询后面给 spi_execp 一个相同长度的 Tcl 数值列表(数组).如果 spi_prepare 里的类型表是空的,此参数必须忽略.
如果查询是一个 SELECT 语句,有与 spi_exec 里描述的循环体和用于所选的字段的变量有一样的现象.
这里是一个使用准备好了的规划的 PL/Tcl 函数例子:
CREATE FUNCTION t1_count(int4, int4) RETURNS int4 AS '
if {![ info exists GD(plan) ]} {
# prepare the saved plan on the first call
set GD(plan) [ spi_prepare \\
"SELECT count(*) AS cnt FROM t1 WHERE num >= \\$1 AND num <= \\$2" \\
int4 ]
}
spi_execp -count 1 $GD(plan) [ list $1 $2 ]
return $cnt
' LANGUAGE 'pltcl';
注意创建函数时每个 Tcl 会看到的反斜杠必须写双份,因为在 CREATE FUNCTION
时主分析器也处理反斜杠.在给予 spi_prepare 的查询字符串里面应该是真正的标识参数位置的美圆符号,而不应让第一次函数调用给出的值把
$1 给替换掉.
在 PL/Tcl 源文件的模块子目录里有一些维护这些表的脚本,包括在最初必须安装的未知模块的源文件.