PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

SPI_execute

SPI_execute — 执行一条命令

Synopsis

int SPI_execute(const char * command, bool read_only, long count)

描述

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_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 函数变量中。