SPI_execute
Name
SPI_execute -- 执行一条命令
Synopsis
int SPI_execute(const char * command, bool read_only, long count)
描述
SPI_execute
执行声明的 SQL 命令获取count
行。如果read_only
为true
,命令必须是只读的, 因此可以略微降低一些执行的开销。
这个函数只能在已连接的过程中调用。
如果count
是零,则在命令适合的所有行上执行。 如果count
大于 0 ,那么将不会超过 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行,因为在检索到第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
,那么你可以使用全局指针 SPITupleTable *SPI_tuptable
访问结果行。一些实用命令 (比如EXPLAIN
)还返回行集合,并且SPI_tuptable
也将在这种情况下包含结果。一些实用命令(COPY
, CREATE TABLE AS
) 并不返回行集,所以SPI_tuptable
为NULL,但是它们仍然返回 SPI_processed
中处理了的行数。
结构SPITupleTable
是这样定义的:
typedef struct
{
MemoryContext tuptabcxt; /* memory context of result table */
uint32 alloced; /* number of alloced vals */
uint32 free; /* number of free vals */
TupleDesc tupdesc; /* row descriptor */
HeapTuple *vals; /* rows */
} SPITupleTable;
vals
是一个指向数据行的的指针数组(有效记录的数目由 SPI_processed
给出)。tupdesc
是一个行描述符, 你可以传递给 SPI 函数处理这些数据行。tuptabcxt
、 alloced
和free
是 SPI 的内部字段, 并非给 SPI 调用者使用的。
SPI_finish
释放所有在当前过程中分配的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
如果从一个未连接的过程中调用
注意
所有SPI查询执行函数设置了SPI_processed
和SPI_tuptable
(只是一个指针,不是结构的内容)。如果你需要跨越后面的调用访问SPI_execute
或者另一个查询执行函数的结果表,那么需要把这两个全局变量保存到一个局部过程变量中。