Postgresql 中文操作指南

SPI_execute

SPI_execute — 执行命令

Synopsis

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

Description

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

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

在使用 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 释放所有 SPITupleTable_s allocated during the current C function. You can free a particular result table earlier, if you are done with it, by calling _SPI_freetuptable

Arguments

  • const char * _command_

    • 包含要执行的命令的字符串

  • bool _read_only_

    • true for read-only execution

  • long _count_

    • 要返回的最大行数,或 0 以表示无限制

Return Value

如果命令执行成功,则将返回以下(非负的)值之一:

  • 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_UTILITY

    • 如果执行了实用程序命令(例如 CREATE TABLE

  • SPI_OK_REWRITTEN

    • 如果命令被 rule 重写为其他类型的命令(例如 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 函数调用

Notes

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