SPI_execute — 执行命令
int SPI_execute(const char *command
, boolread_only
, longcount
)
SPI_execute
执行指定的 SQL 命令,最多获取 count
行。如果 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;
SPI 调用者可以使用字段 tupdesc
、vals
和 numvals
;其余字段是内部的。vals
是指向行的指针数组。行的数量由 numvals
给出(出于某些历史原因,此计数也返回在 SPI_processed
中)。tupdesc
是一个行描述符,您可以将其传递给处理行的 SPI 函数。
SPI_finish
释放当前 C 函数期间分配的所有 SPITupleTable
。如果您已完成对特定结果表的处理,则可以通过调用 SPI_freetuptable
更早地释放它。
const char * command
包含要执行的命令的字符串
bool read_only
true
表示只读执行
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 函数变量中。
如果您在文档中看到任何不正确的内容,与您对特定功能的体验不符,或者需要进一步澄清,请使用 此表单 报告文档问题。