PostgreSQL7.0手册-用户手册-11. PL/Tcl - TCL 过程语言
第十一章. PL/Tcl - TCL 过程语言
内容
概述
描述
PL/Tcl 是一种用于 Postgres 数据库系统的可装载的过程化语言,它让我们可以用 Tcl 语言来创建函数和触发器过程.
这个软件包最初是由 Jan Wieck 开发的.
概述
PL/Tcl 提供 C 语言里面函数开发者所拥有的大多数功能,只有一点点限制除外.
好的限制是,所有东西都是在一个安全的 Tcl 解释器里面运行的.除了有限的安全的 Tcl 命令集外,只有很少的几个命令可以用于跨过 SPI 访问数据库以及通过 elog() 生成错误信息.不象 C 那样,(Tcl)没有办法访问数据库后端内部或者获得 OS 级的 Postgres 用户 ID 的权限.因此,任何非特权的数据库用户都可以被允许使用这种语言.
另外的(内部施加)的限制是 Tcl 过程不能创建用于新数据库类型的输入/输出函数.
如果在安装过程中的配置阶段打开了 Tcl/Tk 支持,那么用于 PL/Tcl 控制器的共享对象自动制作和安装在 Postgres 库目录里面.
--------------------------------------------------------------------------------
描述
Postgres 函数和 Tcl 过程名
在 Postgres 里,一个函数名可以用于不同的函数,只要这些函数的参数个数和类型不同即可.这一点将与 Tcl 过程名(命名规则)冲突.为了在 PL/Tcl 里提供同样的方便,在内部,Tcl 过程名包含该过程在 pg_proc 里的行对象标识(OID)做为它们的名字的一部分.因此,不同参数类型的 Postgres 函数对 Tcl 也是不同的.
用 PL/Tcl 定义函数
要用 PL/Tcl 语言创建一个函数,使用已知的语法
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';
PL/Tcl 里的全局量
有时候(尤其是在使用下面描述的 SPI 函数的时候),在两个过程之间保存一些状态数据和非常有用的.所有在一个后端运行的 PL/Tcl 过程共享同一个安全 Tcl 解释器.为了避免一些 PL/Tcl 过程的副作用,每个过程可以通过 upvar 命令访问一个数组.此变量的全局名称是过程的内部名称,其局部名称是 GD.
PL/Tcl 里的触发器过程
在 Postgres 里的触发器过程定义为没有参数并且返回类型是opaque.在 PL/Tcl 语言里也是这样.
触发器管理器传递给过程体的信息是通过下面变量传递的:
$TG_name
CREATE TRIGGER 语句里的触发器名称.
$TG_relid
导致触发器被调用的表的对象标识.
$TG_relatts
以一个空表元素为前缀的表里的字段名称的 Tcl 数组.所以用 lsearch Tcl 命令在数组里查找元素名称时,返回的从1开始计数的正整数与该字段在 pg_attribute 系统表里该字段的序号一样.
$TG_when
由触发器调用事件决定的字符串 BEFORE 或 AFTER .
$TG_level
由触发器调用事件决定的字符串 ROW 或 STATEMENT .
$TG_op
由触发器调用事件决定的字符串 INSERT,UPDATE 或 DELETE .
$NEW
在 INSERT/UPDATE 时一个包含表的新行的数组或在 DELETE 时的一个空数组.
$OLD
在 UPDATE/DELETE 时一个包含表的旧行的数组或在 INSERT 时的一个空数组.
$GD
前面所述的全局状态数据数组.
$args
如同在 CREATE TRIGGER 语句里给出的参数一样的参数表.这些参数在过程体里可以通过 $1 ... $n 来访问.
触发器过程返回的值是字符串 OK 或 SKIP 之一,或者一个象 'array get' Tcl 命令返回的数组.如果返回值是 OK,触发触发器的操作(INSERT/UPDATE/DELETE)将会发生.显然,SKIP 告诉触发器管理器隐式的忽略操作.从 'array get' 来的数组告诉 PL/Tcl 返回一个修改后的行给触发器管理器,该行将代替在 $NEW (只在 INSERT/UPDATE 中)中给出的行.当然,这些只有在触发器是 BEFORE 和 FOR EACH ROW 时才有意义.
下面是一个小的触发器过程的例子,它强制表内的一个整数值对行的更新次数进行跟踪.对插入的新行,该值初始化为 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');
从 PL/Tcl 里访问数据库
我们可以用下面的命令从一个 PL/Tcl 过程体里面访问数据库:
elog level msg
产生一条日志信息.可能的级别是 NOTICE,WARN,ERROR,FATAL,DEBUG
内容
概述
描述
PL/Tcl 是一种用于 Postgres 数据库系统的可装载的过程化语言,它让我们可以用 Tcl 语言来创建函数和触发器过程.
这个软件包最初是由 Jan Wieck 开发的.
概述
PL/Tcl 提供 C 语言里面函数开发者所拥有的大多数功能,只有一点点限制除外.
好的限制是,所有东西都是在一个安全的 Tcl 解释器里面运行的.除了有限的安全的 Tcl 命令集外,只有很少的几个命令可以用于跨过 SPI 访问数据库以及通过 elog() 生成错误信息.不象 C 那样,(Tcl)没有办法访问数据库后端内部或者获得 OS 级的 Postgres 用户 ID 的权限.因此,任何非特权的数据库用户都可以被允许使用这种语言.
另外的(内部施加)的限制是 Tcl 过程不能创建用于新数据库类型的输入/输出函数.
如果在安装过程中的配置阶段打开了 Tcl/Tk 支持,那么用于 PL/Tcl 控制器的共享对象自动制作和安装在 Postgres 库目录里面.
--------------------------------------------------------------------------------
描述
Postgres 函数和 Tcl 过程名
在 Postgres 里,一个函数名可以用于不同的函数,只要这些函数的参数个数和类型不同即可.这一点将与 Tcl 过程名(命名规则)冲突.为了在 PL/Tcl 里提供同样的方便,在内部,Tcl 过程名包含该过程在 pg_proc 里的行对象标识(OID)做为它们的名字的一部分.因此,不同参数类型的 Postgres 函数对 Tcl 也是不同的.
用 PL/Tcl 定义函数
要用 PL/Tcl 语言创建一个函数,使用已知的语法
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';
PL/Tcl 里的全局量
有时候(尤其是在使用下面描述的 SPI 函数的时候),在两个过程之间保存一些状态数据和非常有用的.所有在一个后端运行的 PL/Tcl 过程共享同一个安全 Tcl 解释器.为了避免一些 PL/Tcl 过程的副作用,每个过程可以通过 upvar 命令访问一个数组.此变量的全局名称是过程的内部名称,其局部名称是 GD.
PL/Tcl 里的触发器过程
在 Postgres 里的触发器过程定义为没有参数并且返回类型是opaque.在 PL/Tcl 语言里也是这样.
触发器管理器传递给过程体的信息是通过下面变量传递的:
$TG_name
CREATE TRIGGER 语句里的触发器名称.
$TG_relid
导致触发器被调用的表的对象标识.
$TG_relatts
以一个空表元素为前缀的表里的字段名称的 Tcl 数组.所以用 lsearch Tcl 命令在数组里查找元素名称时,返回的从1开始计数的正整数与该字段在 pg_attribute 系统表里该字段的序号一样.
$TG_when
由触发器调用事件决定的字符串 BEFORE 或 AFTER .
$TG_level
由触发器调用事件决定的字符串 ROW 或 STATEMENT .
$TG_op
由触发器调用事件决定的字符串 INSERT,UPDATE 或 DELETE .
$NEW
在 INSERT/UPDATE 时一个包含表的新行的数组或在 DELETE 时的一个空数组.
$OLD
在 UPDATE/DELETE 时一个包含表的旧行的数组或在 INSERT 时的一个空数组.
$GD
前面所述的全局状态数据数组.
$args
如同在 CREATE TRIGGER 语句里给出的参数一样的参数表.这些参数在过程体里可以通过 $1 ... $n 来访问.
触发器过程返回的值是字符串 OK 或 SKIP 之一,或者一个象 'array get' Tcl 命令返回的数组.如果返回值是 OK,触发触发器的操作(INSERT/UPDATE/DELETE)将会发生.显然,SKIP 告诉触发器管理器隐式的忽略操作.从 'array get' 来的数组告诉 PL/Tcl 返回一个修改后的行给触发器管理器,该行将代替在 $NEW (只在 INSERT/UPDATE 中)中给出的行.当然,这些只有在触发器是 BEFORE 和 FOR EACH ROW 时才有意义.
下面是一个小的触发器过程的例子,它强制表内的一个整数值对行的更新次数进行跟踪.对插入的新行,该值初始化为 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');
从 PL/Tcl 里访问数据库
我们可以用下面的命令从一个 PL/Tcl 过程体里面访问数据库:
elog level msg
产生一条日志信息.可能的级别是 NOTICE,WARN,ERROR,FATAL,DEBUG
Tags:PostgreSQL,手册,用户,手册,PL,Tcl,TCL,过程,语言

