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 / 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 的返回值是一個用於後續呼叫 spi_execp 的查詢 ID。請參閱 spi_execp 以獲取示例。

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

執行一個之前使用 spi_prepare 準備的查詢。queryidspi_prepare 返回的 ID。如果查詢引用了引數,則必須提供 value-list。這是一個 Tcl 列表,包含引數的實際值。該列表的長度必須與之前傳遞給 spi_prepare 的引數型別列表相同。如果查詢沒有引數,請省略 value-list

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

除了指定查詢及其引數的方式外,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 節

提交更正

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