在本节中,我们遵循 Tcl 的通常约定,使用问号而非方括号来表示语法 概要中的可选元素。以下命令可用于从 PL/Tcl 函数体中访问 数据库:
spi_exec ?-count n? ?-array name? command ?loop-body?
执行以字符串形式给出的 SQL 命令。
命令中的错误会导致错误被抛出。
否则,spi_exec 的返回值是
该命令处理(选择、插入、更新或删除)的行数,如果命令是实用工具
语句则为零。
此外,如果命令是 SELECT 语句,被选中列的值
会按下文所述放入 Tcl 变量中。
可选的 -count 值告诉
spi_exec 在取回
n 行后停止,
就像查询包含 LIMIT 子句那样。
如果 n 为零,查询会一直运行到
完成,与省略 -count 时相同。
如果命令是 SELECT 语句,结果列的值会被放入
以列名命名的 Tcl 变量中。
如果给出了 -array 选项,列值会被存储到
具名关联数组的元素中,列名用作数组索引。
此外,结果中的当前行号(从零计数)会被存储到名为
“.tupno” 的数组元素中,除非该
名称已被用作结果中的列名。
如果命令是 SELECT 语句且没有给出
loop-body
脚本,则只有第一行结果会被存储进 Tcl 变量或数组元素;其余行
(如果有)会被忽略。如果查询不返回任何行,则不发生任何存储。
(这种情况可以通过检查 spi_exec 的结果
来检测。)例如:
spi_exec "SELECT count(*) AS cnt FROM pg_proc"
会把 Tcl 变量 $cnt 设为
pg_proc 系统目录中的行数。
如果给出了可选的 loop-body 参数,它是
一段对查询结果中的每一行执行一次的 Tcl 脚本。
(如果给出的命令不是 SELECT,
loop-body 会被忽略。)
当前行的各列的值会在每次迭代之前被存储进 Tcl 变量或数组
元素。例如:
spi_exec -array C "SELECT * FROM pg_class" {
elog DEBUG "have table $C(relname)"
}
会为 pg_class 的每一行打印一条日志消息。
这一特性的工作方式与其他 Tcl 循环结构类似;特别地,
continue 和 break 在循环
体内按通常方式工作。
如果查询结果的某个列为空,它的目标变量会被 “取消设置”(unset),而不是被设置。
spi_prepare query typelist准备并保存一个查询计划以供稍后执行。 被保存的计划会在当前会话的生命期内保留。
查询可以使用参数,即每次实际执行计划时都要提供值的占位符。
在查询字符串中,用符号 $1 ...
$ 引用参数。
如果查询使用参数,参数类型的名称必须以 Tcl 列表的形式给出。
(如果未使用参数,为
ntypelist 写一个空列表即可。)
spi_prepare 的返回值是一个查询 ID,用于
随后对 spi_execp 的调用。
示例见 spi_execp。
spi_execp ?-count n? ?-array name? ?-nulls string? queryid ?value-list? ?loop-body?
执行之前用 spi_prepare 准备的查询。
queryid 是
spi_prepare 返回的 ID。
如果查询引用了参数,必须提供一个
value-list。它是
参数实际值的 Tcl 列表。该列表的长度必须与之前给
spi_prepare 的参数类型列表相同。
如果查询没有参数,则省略
value-list。
-nulls 的可选值是一个由空格和
'n' 字符组成的字符串,告诉
spi_execp 哪些参数是空值。
如果给出,它的长度必须与
value-list 完全相同。
如果未给出,所有参数值都非空。
除了查询及其参数的指定方式之外,
spi_execp 的工作方式与
spi_exec 完全一样。
-count、-array 和
loop-body 选项相同,结果值也相同。
下面是一个使用已准备计划的 PL/Tcl 函数示例:
CREATE FUNCTION t1_count(integer, integer) RETURNS integer 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" \
[ list int4 int4 ] ]
}
spi_execp -count 1 $GD(plan) [ list $1 $2 ]
return $cnt
$$ LANGUAGE pltcl;
我们需要在传给
spi_prepare 的查询字符串内部使用反斜杠,
以确保
$ 标记会按原样
传递给 nspi_prepare,而不被 Tcl 变量替换
掉。
subtransaction command
包含在 command 中的 Tcl 脚本会在
一个 SQL 子事务内执行。
如果脚本返回一个错误,整个子事务会在把错误返回给外围 Tcl 代码
之前被回滚。
更多细节和示例见
Section 42.9。
quote string
把给定字符串中出现的所有单引号和反斜杠字符都加倍。
这可以用来安全地为要插入到给
spi_exec 或
spi_prepare 的 SQL 命令中的字符串加
引号。
例如,考虑一个形如下式的 SQL 命令字符串:
"SELECT '$val' AS ret"
其中 Tcl 变量 val 实际上包含
doesn't。这会产生最终的命令字符串:
SELECT 'doesn't' AS ret
这会导致
spi_exec 或
spi_prepare 期间发生解析错误。
要正确工作,提交的命令应当包含:
SELECT 'doesn''t' AS ret
在 PL/Tcl 中可以这样构造:
"SELECT '[ quote $val ]' AS ret"
spi_execp 的一个优点是您不必像这样为参数
值加引号,因为参数永远不会被当作 SQL 命令字符串的一部分
解析。
elog level msg
发出一条日志或错误消息。可能的级别有
DEBUG、LOG、
INFO、
NOTICE、WARNING、
ERROR 和
FATAL。ERROR
会抛出错误条件;如果外围 Tcl 代码没有捕获它,该错误会传播到
调用查询,导致当前事务或子事务被中止。
这实际上与 Tcl 的 error 命令相同。
FATAL 会中止事务并导致当前会话关闭。
(在 PL/Tcl 函数中使用这个错误级别可能没有什么好理由,但为了
完整性还是提供了它。)
其他级别只会生成不同优先级的消息。
特定优先级的消息是否被报告给客户端、写入服务器日志或两者兼有,
由
log_min_messages 和
client_min_messages 配置
变量控制。更多信息见
Chapter 19
和 Section 42.8。