受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

SPI_execute

SPI_execute — 执行一个命令

Synopsis

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

描述

SPI_execute 执行指定的 SQL 命令,并最多检索 count 行。如果 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);

会忽略 count 参数,把 bar 中的所有行都插入进去。不过:

SPI_execute("INSERT INTO foo SELECT * FROM bar RETURNING *", false, 5);

最多只会插入 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_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;

SPI 调用者可以使用 tupdescvalsnumvals 字段;其余字段属于内部实现。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_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

commandNULL,或者 count 小于 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 函数变量中。

提交更正

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