SPI_execute — 执行一条命令
int SPI_execute(const char *command, boolread_only, longcount)
SPI_execute 为
count 行执行指定的 SQL 命令。
如果 read_only
为 true,该命令必须是只读的,并且执行开销会
有所降低。
这个函数只能从已连接的 C 函数中调用。
如果 count 为零,则该命令会对它适用的
所有行执行。
如果 count
大于零,则最多取回
count 行;当达到计数时执行会停止,
很像在查询中加入一个
LIMIT 子句。
例如,
SPI_execute("SELECT * FROM foo", true, 5);
将从表中最多取回 5 行。 注意,这样的限制只在该命令实际返回行时才有效。 例如,
SPI_execute("INSERT INTO foo SELECT * FROM bar", false, 5);
会插入来自
bar 的所有行,忽略
count 参数。
不过,使用
SPI_execute("INSERT INTO foo SELECT * FROM bar RETURNING *", false, 5);
则最多会插入 5 行,因为执行会在取回第五个
RETURNING 结果行之后停止。
您可以在一个字符串中传入多条命令;
SPI_execute 返回最后执行的命令的
结果。
count
限制分别适用于每条命令
(尽管只有最后一个结果会被实际返回)。
该限制不适用于由规则生成的任何隐藏命令。
当 read_only 为
false 时,
SPI_execute 会在执行字符串中的每条命令
之前递增命令计数器并计算一个新的
快照。
如果当前事务隔离级别是
SERIALIZABLE 或
REPEATABLE READ,快照实际上不会变化,
但在
READ COMMITTED 模式下,快照更新允许每条命令
看到来自其他会话的新近提交的事务的结果。
这对于命令在修改数据库时保持一致的行为是必需的。
当 read_only 为
true 时,
SPI_execute 既不更新快照也不更新命令
计数器,并且它只允许普通的
SELECT
命令出现在命令字符串中。
这些命令使用之前为外围查询建立的快照执行。
由于消除了每条命令的开销,这种执行模式比读/写模式略快一些。
它还允许构建真正
稳定的函数:由于相继的执行都使用相同的
快照,结果不会有变化。
在使用 SPI 的单个函数内混用只读和读写命令通常是不明智的; 那可能导致非常令人困惑的行为,因为只读查询不会看到读写查询 所做的任何数据库更新。
(最后一条)命令实际执行的行数被返回在全局变量
SPI_processed 中。
如果函数的返回值是
SPI_OK_SELECT、
SPI_OK_INSERT_RETURNING、
SPI_OK_DELETE_RETURNING、
SPI_OK_UPDATE_RETURNING 或
SPI_OK_MERGE_RETURNING,
那么您可以使用
全局指针 SPITupleTable *SPI_tuptable 来
访问结果行。
一些实用工具命令(例如
EXPLAIN)也返回行集,
SPI_tuptable 在这些情况下也会包含结果。
一些实用工具命令
(
COPY、
CREATE TABLE AS)不返回行集,
因此
SPI_tuptable 为 NULL,但它们仍会在
SPI_processed 中返回被处理的行数。
SPITupleTable 结构定义
如下:
typedef struct SPITupleTable
{
/* Public members */
TupleDesc tupdesc; /* tuple descriptor */
HeapTuple *vals; /* array of tuples */
uint64 numvals; /* number of valid tuples */
/* Private members, not intended for external callers */
uint64 alloced; /* allocated length of vals array */
MemoryContext tuptabcxt; /* memory context of result table */
slist_node next; /* link for internal bookkeeping */
SubTransactionId subid; /* subxact in which tuptable was created */
} SPITupleTable;
字段
tupdesc、
vals 和
numvals
可供 SPI 调用者使用;其余字段是内部的。
vals 是一个指向行的指针数组。
行的数量由
numvals 给出
(出于一些历史原因,这个计数也被返回在
SPI_processed 中)。
tupdesc 是一个行描述符,
您可以把它传给处理行的 SPI 函数。
SPI_finish 会释放在当前
C 函数期间分配的所有
SPITupleTable。
如果您已经用完了某个特定的结果表,
可以通过调用
SPI_freetuptable 更早地释放它。
const char * command包含要执行命令的字符串
bool read_onlytrue 表示只读执行
long count
要返回的最大行数,
0 表示没有限制
如果命令的执行成功,将返回以下(非负)值之一:
SPI_OK_SELECT
如果执行了一条
SELECT(但不是
SELECT
INTO)
SPI_OK_SELINTO
如果执行了一条
SELECT INTO
SPI_OK_INSERT
如果执行了一条
INSERT
SPI_OK_DELETE
如果执行了一条
DELETE
SPI_OK_UPDATE
如果执行了一条
UPDATE
SPI_OK_MERGE
如果执行了一条
MERGE
SPI_OK_INSERT_RETURNING
如果执行了一条
INSERT RETURNING
SPI_OK_DELETE_RETURNING
如果执行了一条
DELETE RETURNING
SPI_OK_UPDATE_RETURNING
如果执行了一条
UPDATE RETURNING
SPI_OK_MERGE_RETURNING
如果执行了一条
MERGE RETURNING
SPI_OK_UTILITY
如果执行了一条实用工具命令
(例如
CREATE TABLE)
SPI_OK_REWRITTEN
如果该命令被一个
规则 重写成了另一种命令
(例如
UPDATE 变成了
INSERT)。
出错时,会返回以下负值之一:
SPI_ERROR_ARGUMENT
如果
command 为
NULL 或
count 小于 0
SPI_ERROR_COPY
如果尝试了
COPY TO stdout 或
COPY FROM stdin
SPI_ERROR_TRANSACTION
如果尝试了一条事务操纵命令
(
BEGIN、
COMMIT、
ROLLBACK、
SAVEPOINT、
PREPARE TRANSACTION、
COMMIT PREPARED、
ROLLBACK PREPARED,
或它们的任何变体)
SPI_ERROR_OPUNKNOWN如果命令类型未知(不应发生)
SPI_ERROR_UNCONNECTED如果从未连接的 C 函数调用
所有 SPI 查询执行函数都会同时设置
SPI_processed 和
SPI_tuptable
(只是指针,不是结构的内容)。
如果您需要在后续调用中访问
SPI_execute 或另一个查询执行函数的
结果表,请把这两个全局变量保存到本地的
C 函数变量中。