CREATE TYPE(7) SQL Commands CREATE TYPE(7)

CREATE TYPE - 定義一個新的資料型別

CREATE TYPE name AS
    ( attribute_name data_type [, ... ] )
CREATE TYPE name (
    INPUT = input_function,
    OUTPUT = output_function
    [ , RECEIVE = receive_function ]
    [ , SEND = send_function ]
    [ , INTERNALLENGTH = { internallength | VARIABLE } ]
    [ , PASSEDBYVALUE ]
    [ , ALIGNMENT = alignment ]
    [ , STORAGE = storage ]
    [ , DEFAULT = default ]
    [ , ELEMENT = element ]
    [ , DELIMITER = delimiter ]
)

CREATE TYPE 為當前資料庫註冊一個新的資料型別。 定義該型別的使用者成為其所有者。


如果給出模式名,那麼該型別是在指定模式中建立。 否則它是在當前模式中建立。型別名必需和同一模式中任何現有的型別或者域不同。 (因為表和資料型別有聯絡,型別名不能和同模式中的表名字衝突。)


第一種形式的 CREATE TYPE 建立一個複合型別。 複合型別是透過一列屬性名和資料型別宣告的。這樣實際上和一個表的行型別一樣, 但是如果我們只是想定義一個型別,那麼使用 CREATE TYPE 避免了直接建立實際的表。 一個獨立的複合型別對於一個函式的返回型別非常有用。


第二種形式的CREATE TYPE建立一種新的基本型別(標量型別)。 引數可以以任意的順序出現,而不是上面顯示的那樣。並且大多數都是可選的。 它要求要在定義型別之前先註冊兩個函式(用CREATE FUNCTION命令)。 支援函式 input_function 和 output_function 是必須的, 而函式 receive_function 和 send_function 是可選的。 通常,這些函式必須用 C 或者其它低層語言編寫。


函式 input_function 將該型別的外部文字形式轉換成可以被對該型別操作的運算子和函式識別的內部形式。 output_function 用做相反用途。 輸入函式可以宣告為接受一個型別為 c_string 的引數,或者接受三個型別分別為 c_string,oid,integer 的引數。 (第一個引數是 C 字串形式的輸入文字,第二個是在該型別為陣列型別時其元素的型別, 第三個是目標欄位的typmod,如果已知的話。) 它應該返回一個該資料型別本身的數值。 輸出函式可以宣告為接受一個型別為新資料型別的引數, 或者接受兩個型別,第二個引數的型別是 oid。 第二個引數也是用於陣列型別的陣列元素型別。輸出函式應該返回型別 cstring。


可選的 receive_function 把該型別的外部二進位制表現形式轉換成內部表現形式。 如果沒有提供這個函式,那麼該型別不能用二進位制輸入。二進位制格式應該選取那種轉換成內部格式比較容易的,同時還有一定移植性的。 (比如,標準的整數資料型別使用網路位元組序作為外部的二進位制表現形式,而內部表現形式是機器的本機位元組序。) 接收函式應該宣告為接受一個型別為 internal 的引數,或者兩個型別分別為 internal 和 oid 的引數。 它必須返回一個數據型別自身的數值。(第一個引數是一個指向一個 StringInfo 緩衝區的,儲存接受位元組串的指標; 可選的第二個引數是元素型別——如果型別是一個數組型別的話。)類似的,可選的 send_function 把型別轉換為外部二進位制表現形式。 如果沒有提供這些函式,那麼型別就不能用二進位制方式輸出。傳送函式可以宣告為接收一個新資料型別, 或者接收兩個引數,第二個引數的型別是 oid。第二個引數仍然是用做陣列型別的。 傳送函式必須返回 bytea。


這個時候你應該覺得奇怪,就是輸入和輸出函式怎麼可以宣告為返回新型別的結果或者是接受新型別的引數, 而且是在新型別建立之前就需要建立它們。 答案是輸入函式必須先建立,然後是輸出函式,最後是資料型別。 PostgreSQL 將首先把新資料型別的名字看作輸入函式的返回型別。 它將建立一個"殼"型別,這個型別只是在 pg_type裡面的一個佔位符,然後把輸入函式定義和這個殼型別連線起來。 類似的是輸出函式將連線到(現在已經存在)的殼型別。最後, CREATE TYPE 把這個殼型別替換成完整的型別定義,這樣就可以使用新型別了。


儘管新型別的內部表現形式只有 I/O 函式和其它你建立來使用該型別的函數了解, 但內部表現還是有幾個屬性必須為 PostgreSQL 宣告。 這些中最重要的是 internallength。 基本資料型別可定義成為定長,這時 internallength 是一個正整數,也可以是變長的,透過把 internallength 設定為 VARIABLE 表示。(在內部,這個狀態 是透過將typlen設定為 -1 實現的。)所有變長型別的內部形式都必須以一個四位元組整數開頭,這個整數給出此型別這個數值的全長。


可選的標記 PASSEDBYVALUE 表明該型別的數值是用值傳遞的, 而不是用引用。你不能傳遞那些內部形式大於 Datum (大多數機器上是 4 位元組,有些是 8 位元組)型別的尺寸的資料型別的值。

alignment 引數宣告該資料型別要求的對齊儲存方式。 允許的數值等效於按照 1,2,4,或者 8 位元組邊界對齊。請注意變長型別必須有至少 4 位元組的對齊, 因為它們必須包含一個 int4 作為它們的第一個成份。

storage 引數允許為變長資料型別選擇儲存策略。 (定長型別只允許使用 plain)。 plain 宣告該資料型別總是用內聯的方式而不是壓縮的方式儲存。 extended 宣告系統將首先試圖壓縮一個長的資料值,然後如果它仍然太長的話就將它的值移出主表的行, 但系統將不會壓縮它。 main 允許壓縮,但是不贊成把數值移動出主表。 (用這種儲存策略的資料項可能仍將移動出主表,如果不能放在一行裡的話, 但是它們將比 extended 和 external 項更願意呆在主表裡。)


如果使用者希望欄位的資料型別預設時不是 NULL,而是其它什麼東西, 那麼你可以宣告一個預設值。 在 DEFAULT 關鍵字裡面宣告預設值。 (這樣的預設可以被附著在特定欄位上的明確的 DEFAULT 子句覆蓋。)


要表示一個型別是陣列,用 ELEMENT 關鍵字宣告陣列元素的型別。 比如,要定義一個 4 位元組整數(int4)的陣列,宣告

ELEMENT = int4

。 有關陣列型別的更多細節在下面描述。


要宣告用於這種型別陣列的外部形式的數值之間的分隔符,可用 delimiter 宣告指定分隔符。預設的分隔符是逗號(,)。 請注意分隔符是和陣列元素型別相關聯,而不是陣列型別本身。


在建立使用者定義資料型別的時候,PostgreSQL 自動建立一個與之關聯的陣列型別,其名字由該基本型別的名字字首一個下劃線組成。 分析器理解這個命名傳統,並且把對型別為 foo[] 的欄位的請求轉換成對型別為 _foo 的欄位的請求。這個隱含建立的陣列型別是變長並且使用內建的輸入和輸出函式 array_in 和 array_out。


你很可能會問如果系統自動製作正確的陣列型別,那為什麼有個 ELEMENT選項?使用 ELEMENT 有用的唯一的場合是在你製作的定長型別碰巧在內部是一個一定數目相同事物的陣列, 而你又想允許這 N 個事物可以透過腳標直接關聯,以及那些你準備把該型別當做整體進行的操作。 比如,型別 name 就允許其構成 char 用這種方法關聯。 一個二維的 point 型別也可以允許其兩個構成浮點型按照類似 point[0] 和 point[1] 的方法關聯。 請注意這個功能只適用與那些內部形式是一個相同的定長域的序列的型別。 一個可以腳標化的變長型別必須有被 array_in 和 array_out 使用的一般化的內部表現形式。 出於歷史原因(也就是說,那些明顯錯誤但補救來得太遲的問題),定長陣列型別的腳標從零開始,而不是象變長型別那樣的從一開始。


將要建立的型別名(可以有模式修飾)。

複合型別的一個屬性(欄位)的名字。

一個要成為一個複合型別的欄位的現有資料型別的名字。

一個函式的名稱, 將資料從外部型別轉換成內部型別。

一個函式的名稱, 將資料從內部格式轉換成適於顯示的形式。

把資料從型別的外部二進位制形式轉換成其內部形式的函式的名字。

把資料從型別的內部形式轉換成其外部二進位制形式的函式名。

一個數值常量,說明新型別的內部表現形式的長度。預設的假設是它是變長的。

該資料型別的儲存對齊要求。如果聲明瞭,必須是 char, int2, int4 或 double; 預設是 int4。

該資料型別的儲存策略。如果聲明瞭,必須是 plain,external, extended,或 main; 預設是 plain。

該型別的預設值。通常是省略它的,所以預設是 NULL。

被建立的型別是陣列;這個宣告陣列元素的型別。

將用做陣列的資料元素之間分隔符的字元。


使用者定義型別名不能以下劃線(_) 開頭而且只能有 62 個字元長。(或者通常是 NAMEDATALEN-2, 而不是其它名字那樣的可以有 NAMEDATALEN-1 個字元)。 以下劃線開頭的型別名被解析成內部建立的陣列型別名。


在 PostgreSQL 版本 7.3 以前,我們要透過使用佔位偽型別 opaque 代替函式的前向引用來避免建立殼型別。 7.3 之前 cstring 引數和結果同樣需要宣告偽 opaque。 要支援裝載舊的轉儲外那間,CREATE TYPE 將接受那些用 opaque宣告的函式, 但是它回發出一條通知並且用正確的型別改變函式的宣告。


這個例子建立一個複合型別並且在一個函式定義中使用它:

CREATE TYPE compfoo AS (f1 int, f2 text);
CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS
  'SELECT fooid, fooname FROM foo' LANGUAGE SQL;


這個命令建立box資料型別,並且將這種型別用於一個表定義:

CREATE TYPE box (
    INTERNALLENGTH = 16,
    INPUT = my_box_in_function,
    OUTPUT = my_box_out_function
);
CREATE TABLE myboxes (
    id integer,
    description box
);


如果 box 的內部結構是一個四個 float4 的陣列,我們可以說

CREATE TYPE box (
    INTERNALLENGTH = 16,
    INPUT = my_box_in_function,
    OUTPUT = my_box_out_function,
    ELEMENT = float4
);
它允許一個 box 的數值成分成員可以用腳標訪問。 否則該型別和前面的行為一樣。


這條命令建立一個大物件型別並將其用於一個表定義:

CREATE TYPE bigobj (
    INPUT = lo_filein, OUTPUT = lo_fileout,
    INTERNALLENGTH = VARIABLE
);
CREATE TABLE big_objs (
    id integer,
    obj bigobj
);


更多的例子,包括合適的輸入和輸出函式,在 Chapter 31``Extending SQL'' in the documentation。

CREATE TYPE 命令是 PostgreSQL 擴充套件。在 SQL99 裡有一個 CREATE TYPE 語句,但是細節上和 PostgreSQL 的有比較大區別。

CREATE FUNCTION [create_function(7)], DROP TYPE [drop_type(l)]

譯者

Postgresql 中文網站 何偉平 <laser@pgsqldb.org>

本頁面中文版由中文 man 手冊頁計劃提供。
中文 man 手冊頁計劃:https://github.com/man-pages-zh/manpages-zh

2003-11-02 SQL - Language Statements