支援的版本:目前 (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 / 7.4

42.5. 從 PL/Tcl 存取資料庫 #

在本節中,我們遵循常用的 Tcl 慣例,使用問號而非方括號來表示語法概要中的可選元素。以下命令可用於從 PL/Tcl 函數的主體存取資料庫

spi_exec ?-count n? ?-array name? command ?loop-body?

執行以字串形式給定的 SQL 命令。命令中的錯誤會引發錯誤。否則,spi_exec 的傳回值是命令處理的列數 (已選取、已插入、已更新或已刪除),如果命令是公用程式陳述式,則傳回零。此外,如果命令是 SELECT 陳述式,則選取欄的值將置於 Tcl 變數中,如下所述。

可選的 -count 值會告知 spi_exec 在擷取 n 列後停止,就像查詢包含 LIMIT 子句一樣。如果 n 為零,則查詢將執行到完成,與省略 -count 時相同。

如果命令是 SELECT 陳述式,則結果欄的值將置於以欄命名的 Tcl 變數中。如果給定了 -array 選項,則欄值會改為儲存到具名關聯陣列的元素中,欄名稱用作陣列索引。此外,結果中的目前列號(從零開始計數)儲存在名為 .tupno的陣列元素中,除非該名稱已用作結果中的欄名稱。

如果命令是 SELECT 陳述式且未給定 loop-body 指令碼,則只有第一列結果儲存到 Tcl 變數或陣列元素中;剩餘的列(如果有的話)將被忽略。如果查詢沒有傳回列,則不會進行儲存。(可以透過檢查 spi_exec 的結果來偵測這種情況。)例如

spi_exec "SELECT count(*) AS cnt FROM pg_proc"

會將 Tcl 變數 $cnt 設定為 pg_proc 系統目錄中的列數。

如果給定了可選的 loop-body 引數,則它是一段 Tcl 指令碼,針對查詢結果中的每一列執行一次。(如果給定的命令不是 SELECT,則會忽略 loop-body。)在每次迭代之前,目前列的欄的值會儲存到 Tcl 變數或陣列元素中。例如

spi_exec -array C "SELECT * FROM pg_class" {
    elog DEBUG "have table $C(relname)"
}

將為 pg_class 的每一列列印一條記錄訊息。此功能的工作方式與其他 Tcl 迴圈結構類似;特別是,continuebreak 在迴圈主體中以通常的方式工作。

如果查詢結果的欄為 null,則該欄的目標變數會取消設定,而不是設定。

spi_prepare query typelist

準備並儲存查詢計劃以供稍後執行。儲存的計劃將在目前會話的生命週期內保留。

查詢可以使用參數,也就是每次實際執行計劃時要提供的數值的預留位置。在查詢字串中,使用符號 $1 ... $n 引用參數。如果查詢使用參數,則必須以 Tcl 清單的形式給定參數類型的名稱。(如果未使用任何參數,請編寫一個空清單作為 typelist。)

spi_prepare 的傳回值是一個查詢 ID,用於後續呼叫 spi_execp。請參閱 spi_execp 以取得範例。

spi_execp ?-count n? ?-array name? ?-nulls string? queryid ?value-list? ?loop-body?

執行先前用 spi_prepare 準備好的查詢。queryid 是由 spi_prepare 傳回的 ID。如果查詢引用了參數,則必須提供 value-list。這是一個 Tcl 清單,包含參數的實際值。清單的長度必須與先前提供給 spi_prepare 的參數類型清單相同。如果查詢沒有參數,則省略 value-list

對於 -nulls 的可選值是一個由空格和 'n' 字元組成的字串,告訴 spi_execp 哪些參數是空值。如果給定,它的長度必須與 value-list 完全相同。如果未給定,則所有參數值都不是空值。

除了指定查詢及其參數的方式之外,spi_execp 的工作方式與 spi_exec 完全相同。-count-arrayloop-body 選項是相同的,結果值也是如此。

這是一個使用預先準備計畫的 PL/Tcl 函數的範例

CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS $$
    if {![ info exists GD(plan) ]} {
        # prepare the saved plan on the first call
        set GD(plan) [ spi_prepare \
                "SELECT count(*) AS cnt FROM t1 WHERE num >= \$1 AND num <= \$2" \
                [ list int4 int4 ] ]
    }
    spi_execp -count 1 $GD(plan) [ list $1 $2 ]
    return $cnt
$$ LANGUAGE pltcl;

我們需要在給 spi_prepare 的查詢字串中使用反斜線,以確保 $n 標記會原封不動地傳遞給 spi_prepare,而不會被 Tcl 變數替換。

subtransaction command

包含在 command 中的 Tcl 腳本在 SQL 子交易中執行。如果腳本返回錯誤,則整個子交易會被回滾,然後將錯誤返回到周圍的 Tcl 程式碼。 有關更多詳細資訊和範例,請參閱第 42.9 節

quote string

在給定的字串中將所有單引號和反斜線字元加倍。這可以用於安全地引用要插入到提供給 spi_execspi_prepare 的 SQL 命令中的字串。例如,考慮一個像這樣的 SQL 命令字串

"SELECT '$val' AS ret"

其中 Tcl 變數 val 實際上包含 doesn't。 這將導致最終的命令字串

SELECT 'doesn't' AS ret

這將在 spi_execspi_prepare 期間導致解析錯誤。 為了正常工作,提交的命令應包含

SELECT 'doesn''t' AS ret

可以在 PL/Tcl 中使用以下方式形成

"SELECT '[ quote $val ]' AS ret"

spi_execp 的一個優點是您不必像這樣引用參數值,因為這些參數永遠不會被解析為 SQL 命令字串的一部分。

elog level msg

發出日誌或錯誤訊息。可能的級別是 DEBUGLOGINFONOTICEWARNINGERRORFATALERROR 引發一個錯誤狀況;如果這沒有被周圍的 Tcl 程式碼捕獲,則該錯誤會傳播到調用的查詢,導致目前的交易或子交易中止。這實際上與 Tcl error 命令相同。FATAL 中止交易並導致目前的會話關閉。(在 PL/Tcl 函數中使用此錯誤級別可能沒有好的理由,但為了完整性而提供它。)其他級別僅產生不同優先順序的消息。是否將特定優先順序的消息報告給客戶端、寫入伺服器日誌,或者兩者都報告,由 log_min_messagesclient_min_messages 配置變數控制。 有關更多資訊,請參閱第 19 章第 42.8 節

提交更正

如果您在文件中發現任何不正確、與您對特定功能的體驗不符或需要進一步澄清的地方,請使用此表單報告文件問題。