2025年9月25日: PostgreSQL 18 发布!
支持的版本: 当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0

SPI_execute

SPI_execute — 执行一条命令

概要

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

描述

SPI_executecount 行执行指定的 SQL 命令。如果 read_onlytrue,则命令必须是只读的,并且执行开销会略有降低。

此函数只能从已连接的 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_onlyfalse 时,SPI_execute 会在执行字符串中的每个命令之前递增命令计数器并计算一个新的快照。如果当前事务隔离级别为 SERIALIZABLEREPEATABLE READ,则快照实际上不会改变,但在 READ COMMITTED 模式下,快照更新允许每个命令都能看到其他会话新提交事务的结果。这对于命令修改数据库时的一致行为至关重要。

read_onlytrue 时,SPI_execute 不会更新快照或命令计数器,并且它只允许在命令字符串中出现纯 SELECT 命令。命令使用之前为周围查询建立的快照执行。由于消除了每个命令的开销,因此此执行模式比读/写模式稍快。它还允许构建真正稳定的函数:由于连续执行都将使用相同的快照,因此结果不会改变。

通常不建议在单个函数中使用 SPI 混合读/写和读/写命令;这可能导致非常令人困惑的行为,因为只读查询将看不到读/写查询所做的任何数据库更新的结果。

(最后一个)命令实际执行的行数在全局变量 SPI_processed 中返回。如果函数的返回值为 SPI_OK_SELECTSPI_OK_INSERT_RETURNINGSPI_OK_DELETE_RETURNINGSPI_OK_UPDATE_RETURNINGSPI_OK_MERGE_RETURNING,则可以使用全局指针 SPITupleTable *SPI_tuptable 来访问结果行。某些实用命令(如 EXPLAIN)也会返回行集,并且 SPI_tuptable 在这些情况下也将包含结果。某些实用命令(COPYCREATE 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;

字段 tupdescvalsnumvals 可以由 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

如果 commandNULLcount 小于 0

SPI_ERROR_COPY

如果尝试了 COPY TO stdoutCOPY FROM stdin

SPI_ERROR_TRANSACTION

如果尝试了事务操作命令(BEGINCOMMITROLLBACKSAVEPOINTPREPARE TRANSACTIONCOMMIT PREPAREDROLLBACK PREPARED 或其任何变体)

SPI_ERROR_OPUNKNOWN

如果命令类型未知(不应发生)

SPI_ERROR_UNCONNECTED

如果从未连接的 C 函数调用

注释

所有 SPI 查询执行函数都会设置 SPI_processedSPI_tuptable(仅指针,不包括结构内容)。如果您需要在后续调用中访问 SPI_execute 或其他查询执行函数的返回表,请将这两个全局变量保存到本地 C 函数变量中。

提交更正

如果您在文档中发现任何不正确、与您对特定功能的经验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。