PostgreSQL SPI_execute

2021-09-06 10:52 更新

SPI_execute — 執(zhí)行一個命令

大綱

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

描述

SPI_execute執(zhí)行指定的 SQL 命令以獲得count行。如果read_onlytrue,該命令必須是只讀的,并且執(zhí)行開銷也會有所降低。

只能從一個已連接的C函數(shù)中調(diào)用這個函數(shù)。

如果count為零,那么該命令會為其所適用的所有行執(zhí)行。如果count大于零,那么會檢索不超過count行,當(dāng)?shù)竭_(dá)該計數(shù)時執(zhí)行會停止,這很像為查詢增加一個LIMIT子句。例如:

SPI_execute("SELECT * FROM foo", true, 5);

會從表中檢索至多 5 行。注意這樣一個限制只有當(dāng)命令真正返回行時才有效。例如:

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

插入所有來自于bar的行,而忽略count參數(shù)。不過,通過

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

將插入至多 5 行,因為在第五個RETURNING結(jié)果行被檢索到后執(zhí)行就會停止。

你可以在一個字符串中傳遞多個命令,SPI_execute會返回最后一個被執(zhí)行的命令的結(jié)果。 count限制單獨適用于每一個命令(即便只有最后一個結(jié)果會被實際返回)。該限制 不適用于由規(guī)則產(chǎn)生的任何隱藏命令。

當(dāng)read_onlyfalse時, SPI_execute增加命令計數(shù)器并且在執(zhí)行字符串中每一個命令之前 計算一個新的snapshot。如果當(dāng)前事務(wù)隔離級別是SERIALIZABLEREPEATABLE READ, 該快照并不會實際改變。但是在READ COMMITTED模式中,快照更新允許每個命令看到來自其他會話中新近已提交事務(wù) 的結(jié)果。當(dāng)命令正在修改數(shù)據(jù)庫時,這對一致性行為非常重要。

當(dāng)read_onlytrue時, SPI_execute不更新快照或者命令計數(shù)器,并且它只允許純 SELECT命令出現(xiàn)在命令字符串中。這些命令被使用之前為周圍查詢 建立的快照來執(zhí)行。這種執(zhí)行模式要比讀/寫模式更快,因為消除了每個命令跟新快照的開銷。 它也允許建立真正stable的函數(shù):因為連續(xù)執(zhí)行將會使用同一個快照,因此結(jié)果不會有改變。

在一個使用 SPI 的單一函數(shù)中混合只讀和讀寫命令通常是不明智的, 這樣可能會導(dǎo)致非常令人困惑的行為,因為只讀查詢將看不到任何 由讀寫查詢完成的數(shù)據(jù)庫更新結(jié)果。

被執(zhí)行的(最后一個)命令的實際行數(shù)使用全局變量SPI_processed返回。 如果該函數(shù)的返回值是SPI_OK_SELECTSPI_OK_INSERT_RETURNING、 SPI_OK_DELETE_RETURNING或者 SPI_OK_UPDATE_RETURNING, 那么你可以使用全局指針SPITupleTable *SPI_tuptable來訪問結(jié)果行。 某些工具命令(例如EXPLAIN)也返回行集合,并且在這些情況中SPI_tuptable 也會包含該結(jié)果。某些工具命令(COPY、CREATE TABLE AS)不返回一個行集合, 因此SPI_tuptable為 NULL,但是它們?nèi)匀粫?code class="varname">SPI_processed中返回被處理的行數(shù)。

結(jié)構(gòu)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 調(diào)用者可以使用字段tupdesc、valsnumvals; 其余字段是內(nèi)部的。 vals 是一個指向行的指針數(shù)組。 行數(shù)由 numvals 給出(由于某些歷史原因,這個計數(shù)也在 SPI_processed中返回)。 tupdesc 是一個行描述符,您可以將其傳遞給處理行的 SPI 函數(shù)。

SPI_finish釋放在當(dāng)前的C函數(shù)中已分配的所有SPITupleTable。 如果你已經(jīng)用完了一個結(jié)果表,你可以通過調(diào)用SPI_freetuptable提早釋放它。

參數(shù)

const char * command

包含要執(zhí)行命令的字符串

bool read_only

對只讀執(zhí)行為true

long count

要返回的最大行數(shù),或者用0表示沒有限制

返回值

如果命令的執(zhí)行成功,那么將會返回下列(非負(fù))值之一:

SPI_OK_SELECT

如果執(zhí)行了一個SELECT(但不是SELECT INTO

SPI_OK_SELINTO

如果執(zhí)行了一個SELECT INTO

SPI_OK_INSERT

如果執(zhí)行了一個INSERT

SPI_OK_DELETE

如果執(zhí)行了一個DELETE

SPI_OK_UPDATE

如果執(zhí)行了一個UPDATE

SPI_OK_INSERT_RETURNING

如果執(zhí)行了一個INSERT RETURNING

SPI_OK_DELETE_RETURNING

如果執(zhí)行了一個DELETE RETURNING

SPI_OK_UPDATE_RETURNING

如果執(zhí)行了一個UPDATE RETURNING

SPI_OK_UTILITY

如果執(zhí)行了一個工具命令(例如CREATE TABLE

SPI_OK_REWRITTEN

如果該命令被一個規(guī)則重寫成了另一類命令(例如UPDATE變成了一個INSERT

發(fā)生錯誤時,將會返回下列負(fù)值之一:

SPI_ERROR_ARGUMENT

如果commandNULL或者count小于 0

SPI_ERROR_COPY

如果嘗試COPY TO stdout或者COPY FROM stdin

SPI_ERROR_TRANSACTION

如果嘗試了一個事務(wù)操縱命令( BEGIN、 COMMIT、 ROLLBACKSAVEPOINT、 PREPARE TRANSACTION、 COMMIT PREPARED、 ROLLBACK PREPARED或者其他變體)

SPI_ERROR_OPUNKNOWN

如果命令類型位置(不應(yīng)該會發(fā)生)

SPI_ERROR_UNCONNECTED

如果從未連接的C函數(shù)中調(diào)用

注解

所有 SPI 查詢執(zhí)行函數(shù)都會設(shè)置SPI_processedSPI_tuptable(只是指針, 而不是結(jié)構(gòu)的內(nèi)容)。如果你需要在以后訪問SPI_execute或另一個查詢執(zhí)行函數(shù)的結(jié)果表, 請將這兩個全局變量保存到本地的C函數(shù)變量中。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號