

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

# 在 Aurora PostgreSQL 中管理自訂轉換
<a name="PostgreSQL.CustomCasts"></a>

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

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

如需 PostgreSQL 轉換概念和語法的完整資訊，請參閱 [PostgreSQL CREATE CAST 文件](https://www.postgresql.org/docs/current/sql-createcast.html)。

從 Aurora PostgreSQL 13.23、14.20、15.15、16.11、17.7 和 18.1開始，您可以使用 rds\$1casts 擴充功能為內建類型安裝額外的轉換，同時仍然能夠為自訂類型建立自己的轉換。

**Topics**
+ [安裝和使用 rds\$1casts 延伸模組](#PostgreSQL.CustomCasts.Installing)
+ [支援的轉換](#PostgreSQL.CustomCasts.Supported)
+ [建立或捨棄轉換](#PostgreSQL.CustomCasts.Creating)
+ [使用適當的內容策略建立自訂轉換](#PostgreSQL.CustomCasts.BestPractices)

## 安裝和使用 rds\$1casts 延伸模組
<a name="PostgreSQL.CustomCasts.Installing"></a>

若要建立`rds_casts`擴充功能，請將 RDS for  PostgreSQL 資料庫執行個體連接至 Aurora PostgreSQL 資料庫叢集的寫入器執行個體，`rds_superuser`並執行下列命令： 

```
CREATE EXTENSION IF NOT EXISTS rds_casts;
```

## 支援的轉換
<a name="PostgreSQL.CustomCasts.Supported"></a>

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

```
SELECT * FROM rds_casts.list_supported_casts();
```

此函數會列出可用的轉換組合 （來源類型、目標類型、強制內容和轉換函數）。例如，如果您想要`text`將 建立`numeric`為 `implicit` 轉換。您可以使用下列查詢來尋找轉換是否可供建立：

```
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\$1casts 擴充功能為每個轉換提供兩種類型的轉換函數：
+ *\$1inout 函數* - 使用 PostgreSQL 的標準 I/O 轉換機制，其行為與使用 INOUT 方法建立的轉換完全相同
+ *\$1custom 函數* - 提供處理邊緣案例的增強型轉換邏輯，例如將空字串轉換為 NULL 值以避免轉換錯誤

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

## 建立或捨棄轉換
<a name="PostgreSQL.CustomCasts.Creating"></a>

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

### 投射建立
<a name="PostgreSQL.CustomCasts.Creating.Methods"></a>

**方法 1：使用原生 CREATE CAST 命令**

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

**方法 2：使用 rds\$1casts.create\$1cast 函數**

```
SELECT rds_casts.create_cast(10);
```

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

若要確認已成功建立轉換，請查詢 pg\$1cast 系統目錄：

```
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。

### 捨棄轉換
<a name="PostgreSQL.CustomCasts.Dropping"></a>

**方法 1：使用 DROP CAST 命令**

```
DROP CAST IF EXISTS (text AS numeric);
```

**方法 2：使用 rds\$1casts.drop\$1cast 函數**

```
SELECT rds_casts.drop_cast(10);
```

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

## 使用適當的內容策略建立自訂轉換
<a name="PostgreSQL.CustomCasts.BestPractices"></a>

為整數類型建立多個轉換時，如果所有轉換都建立為 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 可以明確判斷要使用的轉換。