在 RDS for PostgreSQL 中管理自訂轉換 - Amazon Relational Database Service

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

RDS for PostgreSQL 中管理自訂轉換

PostgreSQL 中的類型轉換是將值從一個資料類型轉換為另一個資料類型的程序。PostgreSQL 提供許多常見轉換的內建轉換,但您也可以建立自訂轉換來定義特定類型轉換應如何運作。

轉換指定如何執行從一個資料類型到另一個資料類型的轉換。例如,將文字轉換為'123'整數 123,或將數值45.67轉換為文字 '45.67'

如需 PostgreSQL 轉換概念和語法的完整資訊,請參閱 PostgreSQL CREATE CAST 文件

RDS for PostgreSQL 13.23、14.20、15.15、16.11、17.7 和 18.1 版開始,您可以使用 rds_casts 擴充功能為內建類型安裝額外的轉換,同時仍然能夠為自訂類型建立自己的轉換。

安裝和使用 rds_casts 延伸模組

若要建立rds_casts擴充功能,請將 RDS for 執行個體,rds_superuser並執行下列命令: PostgreSQL

CREATE EXTENSION IF NOT EXISTS rds_casts;

支援的轉換

在您要使用自訂轉換的每個資料庫中建立延伸。建立擴充功能後,請使用下列命令來檢視所有可用的轉換:

SELECT * FROM rds_casts.list_supported_casts();

此函數會列出可用的轉換組合 (來源類型、目標類型、強制內容和轉換函數)。例如,如果您想要text將 建立numericimplicit 轉換。您可以使用下列查詢來尋找轉換是否可供建立:

SELECT * FROM rds_casts.list_supported_casts() WHERE source_type = 'text' AND target_type = 'numeric'; id | source_type | target_type | qualified_function | coercion_context ----+-------------+-------------+--------------------------------------+------------------ 10 | text | numeric | rds_casts.rds_text_to_numeric_custom | implicit 11 | text | numeric | rds_casts.rds_text_to_numeric_custom | assignment 13 | text | numeric | rds_casts.rds_text_to_numeric_custom | explicit 20 | text | numeric | rds_casts.rds_text_to_numeric_inout | implicit 21 | text | numeric | rds_casts.rds_text_to_numeric_inout | assignment 23 | text | numeric | rds_casts.rds_text_to_numeric_inout | explicit

rds_casts 延伸提供每種轉換函數的兩種類型:

  • _inout 函數 - 使用 PostgreSQL 的標準 I/O 轉換機制,其行為與使用 INOUT 方法建立的轉換完全相同

  • _custom 函數 - 提供處理邊緣案例的增強型轉換邏輯,例如將空字串轉換為 NULL 值以避免轉換錯誤

這些inout函數會複寫 PostgreSQL 的原生轉換行為,而custom函數會透過處理標準 INOUT 轉換無法容納的案例來擴展此功能,例如將空字串轉換為整數。

建立或捨棄轉換

您可以使用兩種方法建立和捨棄支援的轉換:

投射建立

方法 1:使用原生 CREATE CAST 命令

CREATE CAST (text AS numeric) WITH FUNCTION rds_casts.rds_text_to_numeric_custom AS IMPLICIT;

方法 2:使用 rds_casts.create_cast 函數

SELECT rds_casts.create_cast(10);

create_cast 函數會從list_supported_casts()輸出取得 ID。此方法更簡單,並確保您使用正確的函數和內容組合。此 ID 保證在不同 Postgres 版本中保持不變。

若要確認已成功建立轉換,請查詢 pg_cast 系統目錄:

SELECT oid, castsource::regtype, casttarget::regtype, castfunc::regproc, castcontext, castmethod FROM pg_cast WHERE castsource = 'text'::regtype AND casttarget = 'numeric'::regtype; oid | castsource | casttarget | castfunc | castcontext | castmethod --------+------------+------------+--------------------------------------+-------------+------------ 356372 | text | numeric | rds_casts.rds_text_to_numeric_custom | i | f

castcontext 資料欄顯示:e適用於 EXPLICIT、a適用於 ASSIGNMENT 或i適用於 IMPLICIT。

捨棄轉換

方法 1:使用 DROP CAST 命令

DROP CAST IF EXISTS (text AS numeric);

方法 2:使用 rds_casts.drop_cast 函數

SELECT rds_casts.drop_cast(10);

drop_cast 函數會採用與建立投射時相同的 ID。此方法可確保您捨棄使用對應 ID 建立的確切轉換。

使用適當的內容策略建立自訂轉換

為整數類型建立多個轉換時,如果所有轉換都建立為 IMPLICIT,則可能會發生運算子模棱兩可錯誤。下列範例透過建立從文字到不同整數寬度的兩個隱含轉換來示範此問題:

-- Creating multiple IMPLICIT casts causes ambiguity postgres=> CREATE CAST (text AS int4) WITH FUNCTION rds_casts.rds_text_to_int4_custom(text) AS IMPLICIT; CREATE CAST postgres=> CREATE CAST (text AS int8) WITH FUNCTION rds_casts.rds_text_to_int8_custom(text) AS IMPLICIT; CREATE CAST postgres=> CREATE TABLE test_cast(col int); CREATE TABLE postgres=> INSERT INTO test_cast VALUES ('123'::text); INSERT 0 1 postgres=> SELECT * FROM test_cast WHERE col='123'::text; ERROR: operator is not unique: integer = text LINE 1: SELECT * FROM test_cast WHERE col='123'::text; ^ HINT: Could not choose a best candidate operator. You might need to add explicit type casts.

發生錯誤是因為 PostgreSQL 無法判斷在比較整數資料欄與文字值時要使用的隱含轉換。int4 和 int8 隱含轉換都是有效的候選項目,可建立模棱兩可。

若要避免此運算子模棱兩可的情況,請針對較小的整數寬度使用 ASSIGNMENT 內容,針對較大的整數寬度使用 IMPLICIT 內容:

-- Use ASSIGNMENT for smaller integer widths CREATE CAST (text AS int2) WITH FUNCTION rds_casts.rds_text_to_int2_custom(text) AS ASSIGNMENT; CREATE CAST (text AS int4) WITH FUNCTION rds_casts.rds_text_to_int4_custom(text) AS ASSIGNMENT; -- Use IMPLICIT for larger integer widths CREATE CAST (text AS int8) WITH FUNCTION rds_casts.rds_text_to_int8_custom(text) AS IMPLICIT; postgres=> INSERT INTO test_cast VALUES ('123'::text); INSERT 0 1 postgres=> SELECT * FROM test_cast WHERE col='123'::text; col ----- 123 (1 row)

透過此策略,只有 int8 轉換是隱含的,因此 PostgreSQL 可以明確判斷要使用的轉換。