36.2. PL/Tcl 函数和参数

要用PL/Tcl语言创建一个函数,使用标准的语法:

CREATE FUNCTION funcname (argument-types) RETURNS return-type AS $$
    # PL/Tcl 函数体
$$ LANGUAGE pltcl;

PL/TclU是一样的,除了语言应该声明为 pltclu 之外。

函数体就是一段 Tcl 代码。 当在一个查询里面调用这个函数, 参数是作为变量 $1 ... $n 传递给 Tcl 脚本的。 结果是用通常的方法从 Tcl 代码中返回的,就是用一个 return 语句。

比如, 一个简单的返回两个整数值的最大值函数可以这样定义:

CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS $$
    if {$1 > $2} {return $1}
    return $2
$$ LANGUAGE pltcl STRICT;

请注意子句 STRICT,它让我们可以不用考虑输入为 NULL 的情况: 如果传递了一个 NULL,该函数实际上就不会被调用, 而只是自动返回一个 NULL 结果。

如果是一个不严格的函数,如果一个参数的实际数值是 NULL, 那么对应的 $n 变量将被设置为一个空字串。 要检测一个特定的参数是否为 NULL,可以使用函数 argisnull。 比如,假设我们要求tcl_max在一个参数为 null 而另外一个为非 null 时返回非 null 参数,而不是 NULL:

CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS $$
    if {[argisnull 1]} {
	if {[argisnull 2]} { return_null }
	return $2
    }
    if {[argisnull 2]} { return $1 }
    if {$1 > $2} {return $1}
    return $2
$$ LANGUAGE pltcl;

如上所述,要从 PL/Tcl 函数中返回一个 NULL 数值, 可以执行 return_null。不管函数是否严格,我们都可以这么做。

复合类型的参数是当做 Tcl 数组传递给过程的。 数组中的元素名字就是复合类型里的属性名字。 如果在实际的行中的一个属性有 NULL 数值,那么它不会在数组中出现。 下面是一个例子:

CREATE TABLE employee (
    name text,
    salary integer,
    age integer
);

CREATE FUNCTION overpaid_2 (EMP) RETURNS boolean AS $$
    if {200000.0 < $1(salary)} {
	return "t"
    }
    if {$1(age) < 30 && 100000.0 < $1(salary)} {
	return "t"
    }
    return "f"
$$ LANGUAGE pltcl;

目前没有返回复合类型结果值的支持。也不支持返回结果集。

PL/Tcl 目前还不是完全支持域类型:它看待域类型和下层的标量类型是一样的。 这就意味着与域关联的约束将不会被强制。对于函数参数,这不是什么问题, 但是如果你把 PL/Tcl 函数声明为返回一个域类型,那么就有危险。