在本节中,我们遵循 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了解更多信息。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。