On this page
44.5. 从 PL/Tcl 访问数据库
可以使用以下命令从 PL/Tcl 函数的主体访问数据库:
spi_exec ?-count n? ?-array name? command ?loop-body?
- 执行以字符串形式给出的 SQL 命令。命令中的错误导致引发错误。否则,返回值
spi_exec
是命令处理(选择,插入,更新或删除)的行数;如果命令是 Util 语句,则返回零。另外,如果命令是SELECT
语句,则如下所述,将所选列的值放置在 Tcl 变量中。
- 执行以字符串形式给出的 SQL 命令。命令中的错误导致引发错误。否则,返回值
可选的-count
值告诉spi_exec
在命令中要处理的最大行数。其效果相当于将查询设置为游标,然后说FETCH n
。
如果命令是SELECT
语句,则将结果列的值放入以这些列命名的 Tcl 变量中。如果提供了-array
选项,则将列值存储到命名关联数组的元素中,而列名用作数组索引。另外,结果中的当前行号(从零开始计数)存储在名为“ .tupno
”的数组元素中,除非该名称被用作结果中的列名。
如果该命令是SELECT
语句,并且没有给出* loop-body
*脚本,则仅将结果的第一行存储到 Tcl 变量或数组元素中;否则,结果将保留为 0.剩余的行(如果有)将被忽略。如果查询不返回任何行,则不进行存储。 (可以通过检查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
在循环体内以通常的方式工作。
如果查询结果的列为空,则其目标变量为“未设置”,而不是被设置。
该查询可以使用参数,即,每当实际执行计划时就提供值的占位符。在查询字符串中,使用符号$1
... $n
来引用参数。如果查询使用参数,则必须以 Tcl 列表的形式给出参数类型的名称。 (如果未使用任何参数,则为* typelist
*写入一个空列表.)
spi_prepare
的返回值是在随后对spi_execp
的调用中使用的查询 ID。有关示例,请参见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
的查询字符串中使用反斜杠,以确保$n
标记将按原样传递给spi_prepare
,而不是被 Tcl 变量替换替代。
-
- 如果命令是单行
INSERT
并且修改后的表包含 OID,则返回由最后spi_exec
或spi_execp
插入的行的 OID。 (如果没有,则为零.)
- 如果命令是单行
subtransaction
command
-
command
*中包含的 Tcl 脚本在 SQL 子事务中执行。如果脚本返回错误,则在将错误返回到周围的 Tcl 代码之前,将回滚整个子事务。有关更多详细信息和示例,请参见Section 44.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 命令字符串的一部分。
-
- 发出日志或错误消息。可能的级别是
DEBUG
,LOG
,INFO
,NOTICE
,WARNING
,ERROR
和FATAL
。ERROR
引发错误情况;如果周围的 Tcl 代码未捕获到该错误,则该错误将传播到调用查询,从而导致当前事务或子事务中止。这实际上与 Tclerror
命令相同。FATAL
中止事务,并导致当前会话关闭。 (可能没有充分的理由在 PL/Tcl 函数中使用此错误级别,但是出于完整性目的提供了此错误级别.)其他级别仅生成不同优先级的消息。由log_min_messages和client_min_messages配置变量控制是否将特定优先级的消息报告给 Client 端,写入服务器日志还是同时将这两者控制。有关更多信息,请参见Chapter 19和Section 44.8。
- 发出日志或错误消息。可能的级别是