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
增加命令计数器并且在执行字符串中每一个命令之前
计算一个新的snapshot。如果当前事务隔离级别是SERIALIZABLE
或REPEATABLE READ
,
该快照并不会实际改变。但是在READ COMMITTED
模式中,快照更新允许每个命令看到来自其他会话中新近已提交事务
的结果。当命令正在修改数据库时,这对一致性行为非常重要。
当read_only
是true
时,
SPI_execute
不更新快照或者命令计数器,并且它只允许纯
SELECT
命令出现在命令字符串中。这些命令被使用之前为周围查询
建立的快照来执行。这种执行模式要比读/写模式更快,因为消除了每个命令跟新快照的开销。
它也允许建立真正stable的函数:因为连续执行将会使用同一个快照,因此结果不会有改变。
在一个使用 SPI 的单一函数中混合只读和读写命令通常是不明智的, 这样可能会导致非常令人困惑的行为,因为只读查询将看不到任何 由读写查询完成的数据库更新结果。
被执行的(最后一个)命令的实际行数使用全局变量SPI_processed
返回。
如果该函数的返回值是SPI_OK_SELECT
、
SPI_OK_INSERT_RETURNING
、
SPI_OK_DELETE_RETURNING
或者
SPI_OK_UPDATE_RETURNING
,
那么你可以使用全局指针SPITupleTable *SPI_tuptable
来访问结果行。
某些工具命令(例如EXPLAIN
)也返回行集合,并且在这些情况中SPI_tuptable
也会包含该结果。某些工具命令(COPY
、CREATE TABLE AS
)不返回一个行集合,
因此SPI_tuptable
为 NULL,但是它们仍然会在SPI_processed
中返回被处理的行数。
结构SPITupleTable
被定义为:
typedef struct { MemoryContext tuptabcxt; /* 结果表的内存上下文 */ uint64 alloced; /* 已分配值的数量 */ uint64 free; /* 空限值的数量 */ TupleDesc tupdesc; /* 行描述符 */ HeapTuple *vals; /* 行 */ } SPITupleTable;
vals
是一个行指针的数组(可用项的数量由SPI_processed
给出)。
tupdesc
是一个行描述符,你可以把它传递给 SPI 函数来处理行。tuptabcxt
、
alloced
和free
是不准备给 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_INSERT_RETURNING
如果执行了一个INSERT RETURNING
SPI_OK_DELETE_RETURNING
如果执行了一个DELETE RETURNING
SPI_OK_UPDATE_RETURNING
如果执行了一个UPDATE 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函数变量中。