PostgreSQL CREATE CAST

2021-09-09 10:07 更新

CREATE CAST — 定義一種新的造型

大綱

CREATE CAST (source_type AS target_type)
    WITH FUNCTION function_name [ (argument_type [, ...]) ]
    [ AS ASSIGNMENT | AS IMPLICIT ]

CREATE CAST (source_type AS target_type)
    WITHOUT FUNCTION
    [ AS ASSIGNMENT | AS IMPLICIT ]

CREATE CAST (source_type AS target_type)
    WITH INOUT
    [ AS ASSIGNMENT | AS IMPLICIT ]

描述

CREATE CAST定義一種新的造型。 一種造型指定如何在兩種數(shù)據(jù)類型之間執(zhí)行轉(zhuǎn)換。例如,

SELECT CAST(42 AS float8);

通過調(diào)用一個之前指定的函數(shù)(這種情況中是 float8(int4))把整型常量 42 轉(zhuǎn)換成類型 float8(如果沒有定義合適的造型, 該轉(zhuǎn)換會失?。?/p>

兩種類型可以是二進(jìn)制可強(qiáng)制,這表示該轉(zhuǎn)換 可以被免費(fèi)執(zhí)行而不用調(diào)用任何函數(shù)。這要求相應(yīng)的 值使用同樣的內(nèi)部表示。例如,類型textvarchar在雙向都是二進(jìn)制可強(qiáng)制的。二進(jìn)制可強(qiáng)制性并 不必是一種對稱關(guān)系。例如,在當(dāng)前實現(xiàn)中從 xmltext的造型可以被免費(fèi)執(zhí)行,但是反向則需要一個函數(shù)來 執(zhí)行至少一次語法檢查(兩種在雙向都二進(jìn)制值兼容的類型也被稱作二進(jìn) 制兼容)。

通過使用WITH INOUT語法,你可以把一種造型定義 成I/O 轉(zhuǎn)換造型。一種 I/O 轉(zhuǎn)換造型執(zhí)行時,會調(diào)用源 數(shù)據(jù)類型的輸出函數(shù),并且把結(jié)果字符串傳遞給目標(biāo)數(shù)據(jù)類型的輸入函數(shù)。 在很多常見情況中,這種特性避免了為轉(zhuǎn)換單獨(dú)定義一個造型函數(shù)。一種 I/O 轉(zhuǎn)換造型表現(xiàn)得和一個常規(guī)的基于函數(shù)的造型相同,只是實現(xiàn)不同而已。

默認(rèn)情況下,只有一次顯式造型請求才會調(diào)用造型, 形式是CAST(x AS typename)or x::typename。

如果造型被標(biāo)記為AS ASSIGNMENT,那么在為一個目標(biāo)數(shù)據(jù) 類型的列賦值時會隱式地調(diào)用它。例如,假設(shè)foo.f1是 一個類型text的列,那么如果從類型integer 到類型text的造型被標(biāo)記為AS ASSIGNMENT, 則:

INSERT INTO foo (f1) VALUES (42);

將被允許,否則不會允許(我們通常使用賦值造型 來描述此類造型)。

如果造型被標(biāo)記為AS IMPLICIT,那么可以在任何上下文 中隱式地調(diào)用它,無論是賦值還是在一個表達(dá)式內(nèi)部(我們通常用術(shù)語 隱式造型來描述這類造型)。例如,考慮這個 查詢:

SELECT 2 + 4.0;

解析器初始會把常量分別標(biāo)記為類型integernumeric。在系統(tǒng)目錄中沒有integer + numeric操作符,但是有一個 numeric + numeric操作符。 因此,如果有一種可用的從integernumeric的造型且被標(biāo)記為AS IMPLICIT — 實際上確實有 — 該查詢將會成功。解析器將應(yīng)用該隱式造型 并且解決該查詢,就好像它被寫成:

SELECT CAST ( 2 AS numeric ) + 4.0;

現(xiàn)在,系統(tǒng)目錄也提供一種從numericinteger 的造型。如果這種造型被標(biāo)記為AS IMPLICIT — 實際上并沒有 — 那么解析器將面臨選擇:是用前面介紹的過程, 還是把numeric常量造型成integer并且應(yīng)用 integer + integer操作符。由于 缺少哪種選擇更好的知識,解析器會放棄并且說明查詢有歧義。我們能 告訴解析器把一個混合了numericinteger的 表達(dá)式解析成numeric更好的方法就是只讓這兩種造型中的 一個是隱式的,沒有有關(guān)于此的內(nèi)建知識。

對標(biāo)記造型為隱式持保守態(tài)度是明智的。過多的隱式造型路徑可能導(dǎo)致 PostgreSQL以令人吃驚的方式解 釋命令,或者由于有多種可能解釋而根本無法解析命令。一種好的經(jīng)驗 是讓一種造型只對于同一種一般類型分類中的類型間的信息保持轉(zhuǎn)換隱式 可調(diào)用。例如,從int2int4的造型 可以被合理地標(biāo)記為隱式,但是從float8int4的造型可能應(yīng)該只能在賦值時使用??珙愋头诸?的造型(如textint4)最好只被用于顯式使用。

注意

有時為了可用性或者標(biāo)準(zhǔn)兼容的原因,有必要提供在一個類型集合之間 的多種隱式造型,這會導(dǎo)致上述不可避免的歧義。解析器還有一招基于 類型分類優(yōu)先類型的后手,它能幫助 提供這類情況下預(yù)期的行為。詳見 CREATE TYPE

要創(chuàng)建一種造型,你必須擁有源數(shù)據(jù)類型和目標(biāo)數(shù)據(jù)類型并且具有在其他類型上 的USAGE特權(quán)。要創(chuàng)建一種二進(jìn)制可強(qiáng)制造型,你必須是一 個超級用戶(這種限制是因為錯誤的二進(jìn)制可強(qiáng)制造型轉(zhuǎn)換很容易讓服務(wù)器崩潰)。

參數(shù)

source_type

該造型的源數(shù)據(jù)類型的名稱。

target_type

該造型的目標(biāo)數(shù)據(jù)類型的名稱。

function_name[(argument_type [, ...])]

被用于執(zhí)行該造型的函數(shù)。函數(shù)名稱可以用模式限定。如果沒有被限定, 將在模式搜索路徑中查找該函數(shù)。函數(shù)的結(jié)果數(shù)據(jù)類型必須是該造型的 目標(biāo)數(shù)據(jù)類型。它的參數(shù)討論如下。 如果沒有指定參數(shù)列表,則該函數(shù)名稱在其模式中必須是唯一的。

WITHOUT FUNCTION

指示源類型可以二進(jìn)制強(qiáng)制到目標(biāo)類型,因此執(zhí)行該造型不需要函數(shù)。

WITH INOUT

指示該造型是一種 I/O 轉(zhuǎn)換造型,執(zhí)行需要調(diào)用源數(shù)據(jù)類型的輸出函數(shù), 并且把結(jié)果字符串傳遞給目標(biāo)數(shù)據(jù)類型的輸入函數(shù)。

AS ASSIGNMENT

指示該造型可以在賦值的情況下被隱式調(diào)用。

AS IMPLICIT

指示該造型可以在任何上下文中被隱式調(diào)用。

造型實現(xiàn)函數(shù)可以具有 1 到 3 個參數(shù)。第一個參數(shù)類型必須等于源類型或者 能從源類型二進(jìn)制強(qiáng)制得到。第二個參數(shù)(如果存在)必須是類型 integer,它接收與目標(biāo)類型相關(guān)聯(lián)的類型修飾符,如果沒有類型 修飾符,它會收到-1。第三個參數(shù)(如果存在)必須是類型 boolean,如果該造型是一種顯式造型,它會收到 true,否則會收到 false(奇怪地是,SQL 標(biāo)準(zhǔn)在 某些情況中對顯式和隱式造型要求不同的行為。這個參數(shù)被提供給必須實現(xiàn)這 類造型的函數(shù)。不推薦在設(shè)計自己的數(shù)據(jù)類型時用它)。

一個造型函數(shù)的返回類型必須等于目標(biāo)類型或者能二進(jìn)制強(qiáng)制到目標(biāo)類型。

通常,強(qiáng)制轉(zhuǎn)換必須具有不同的源和目標(biāo)數(shù)據(jù)類型。但是,如果它有一個帶有多個參數(shù)的強(qiáng)制轉(zhuǎn)換實現(xiàn)函數(shù),則可以聲明具有相同源類型和目標(biāo)類型的造型。它用于表示系統(tǒng)目錄中特定類型的長度強(qiáng)制函數(shù)。命名函數(shù)用于將類型的值強(qiáng)制轉(zhuǎn)為其第二個參數(shù)提供的類型修飾符的值。

當(dāng)強(qiáng)制轉(zhuǎn)換具有不同的源類型和目標(biāo)類型,并且一個函數(shù)使用多個參數(shù)時,它支持從一種類型轉(zhuǎn)換為另一種類型,并在單個步驟中應(yīng)用長度強(qiáng)制。如果沒有這樣的條目,強(qiáng)制轉(zhuǎn)換為使用類型修飾符的類型將涉及兩個強(qiáng)制轉(zhuǎn)換步驟,一個是在數(shù)據(jù)類型之間進(jìn)行轉(zhuǎn)換,另一個是應(yīng)用修飾符。

向域類型強(qiáng)制轉(zhuǎn)換或從域類型強(qiáng)制轉(zhuǎn)換當(dāng)前無效。向域或從域強(qiáng)制轉(zhuǎn)換使用與其基礎(chǔ)類型關(guān)聯(lián)的造型。

注解

使用DROP CAST移除用戶定義的造型。

記住如果你想要能夠雙向轉(zhuǎn)換類型,你需要在兩個方向上都 顯式聲明造型。

通常沒有必要創(chuàng)建用戶定義類型和標(biāo)準(zhǔn)字符串類型(textvarcharchar(n ), 以及被定義在字符串分類中的用戶定義類型)之間的造型。 PostgreSQL會為它們提供自動的 I/O 轉(zhuǎn)換造型。 到字符串類型的自動造型被當(dāng)做賦值造型,而字符串類型作為源的自動 造型只能是顯式的。通過聲明你自己的造型來替換自動造型可以覆蓋這 種行為,但是這樣做的唯一原因是你想讓該轉(zhuǎn)換比標(biāo)準(zhǔn)的設(shè)置更容易被 調(diào)用。另一種可能的原因是你想讓該轉(zhuǎn)換的行為與該類型的 I/O 函數(shù)不 同,但這種原因足夠令人感到意外,你應(yīng)該考慮再三它是不是個好主意 (確實有少量內(nèi)建類型對轉(zhuǎn)換具有不同的行為,絕大部分是因為 SQL 標(biāo)準(zhǔn)的要求)。

雖然不必要,推薦你繼續(xù)遵循這種在目標(biāo)數(shù)據(jù)類型后面命名造型 實現(xiàn)函數(shù)的習(xí)慣。很多用戶習(xí)慣于能夠使用一種函數(shù)風(fēng)格的記法來造型 數(shù)據(jù)類型,即typename(x)。 這種記法正好是對造型實現(xiàn)函數(shù)的調(diào)用,這里它沒有被作為造型特殊對待。 如果你的轉(zhuǎn)換函數(shù)沒有被指定支持這種習(xí)慣,那么你的用戶會覺得意外。 由于PostgreSQL允許用不同的參數(shù)類型重載同一個 函數(shù)名,因此存在多個從不同類型到同一目標(biāo)類型的同名轉(zhuǎn)換函數(shù)并不困難。

注意

實際上前一段過于簡化了:有兩種情況中一個函數(shù)調(diào)用結(jié)構(gòu)在沒有被匹配到 一個實際函數(shù)時將被當(dāng)作一次造型請求。如果函數(shù)調(diào)用 name(x)沒有正好匹配任何現(xiàn)有函數(shù), 但name是一種數(shù)據(jù)類型的名稱并且 pg_cast提供了一種從 x 的類型到這種 類型的二進(jìn)制可強(qiáng)制造型,那么該調(diào)用將被翻譯為一次二進(jìn)制可強(qiáng)制造型。 通過這種例外,二進(jìn)制可強(qiáng)制造型能夠以函數(shù)語法調(diào)用,即便沒有該函數(shù)。 同樣的,如果沒有pg_cast項,但是該造型是要造型到一種 字符串類型或者是要從一種字符串類型造型,調(diào)用將被翻譯成一次 I/O 轉(zhuǎn)換 造型。這種例外允許以函數(shù)語法調(diào)用 I/O 轉(zhuǎn)換造型。

注意

還有一種例外中的例外:從組合類型到字符串類型的 I/O 轉(zhuǎn)換造型不能使用 函數(shù)語法調(diào)用,而必須被寫成顯式造型語法(CAST或者 ::記號)。增加這種例外是因為在引入了自動提供的 I/O 轉(zhuǎn)換 造型之后,在想要引用一個函數(shù)或者列時太容易意外地調(diào)用這種造型。

示例

要使用函數(shù)int4(bigint)創(chuàng)建一種從類型 bigint到類型int4的賦值造型:

CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT;

(在系統(tǒng)中這種造型已經(jīng)被預(yù)定義)。

兼容性

CREATE CAST命令符合 SQL標(biāo)準(zhǔn),不過 SQL 沒有為二進(jìn)制可強(qiáng)制 類型或者實現(xiàn)函數(shù)的額外參數(shù)做好準(zhǔn)備。 AS IMPLICIT也是一種 PostgreSQL擴(kuò)展。


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號