?
This document uses PHP Chinese website manual Release
CREATE TYPE name AS ( attribute_name data_type [, ... ] ) CREATE TYPE name AS ENUM ( [ 'label' [, ... ] ] ) CREATE TYPE name ( INPUT = input_function, OUTPUT = output_function [ , RECEIVE = receive_function ] [ , SEND = send_function ] [ , TYPMOD_IN = type_modifier_input_function ] [ , TYPMOD_OUT = type_modifier_output_function ] [ , ANALYZE = analyze_function ] [ , INTERNALLENGTH = { internallength | VARIABLE } ] [ , PASSEDBYVALUE ] [ , ALIGNMENT = alignment ] [ , STORAGE = storage ] [ , LIKE = like_type ] [ , CATEGORY = category ] [ , PREFERRED = preferred ] [ , DEFAULT = default ] [ , ELEMENT = element ] [ , DELIMITER = delimiter ] ) CREATE TYPE name
CREATE TYPE為當前數(shù)據(jù)庫注冊一個新的數(shù)據(jù)類型。定義該類型的用戶成為其所有者。
如果給出模式名,那么該類型是在指定模式中創(chuàng)建。否則它將在當前模式中創(chuàng)建。類型名必需和同一模式中任何現(xiàn)有的類型或者域不同。因為表和數(shù)據(jù)類型有聯(lián)系,所以類型名也不能和同模式中的表名字沖突。
第一種形式的CREATE TYPE創(chuàng)建一個復合類型。復合類型是通過一列屬性名和數(shù)據(jù)類型聲明的。這樣實際上和一個表的行類型一樣, 但是如果只是想定義一個類型,那么使用CREATE TYPE就可以避免直接創(chuàng)建實際的表。一個獨立的復合類型做一個函數(shù)的參數(shù)或者返回類型是非常有用的。
CREATE TYPE的第二種形式創(chuàng)建一個枚舉類型,就像 Section 8.7中描述的一樣。枚舉類型采取一個列表的 一個或多個引用標簽,其中的每一個都必須是少于NAMEDATALEN 字節(jié)長度的(在一個標準PostgreSQL構建中是64)。
CREATE TYPE的第三種形式創(chuàng)建了一個新的基類型(標量 類型)。為了創(chuàng)建一個新的基類型,你必須是一個超級用戶。(做這個限制的 原因是一個錯誤的類型定義可以困惑甚至摧毀服務器。)
參數(shù)可以按任意順序出現(xiàn),而不是上面顯示的那樣,并且大多數(shù)都是可選的。它要求要在定義類型之前先用CREATE FUNCTION注冊兩個或更多個函數(shù)。 支持函數(shù)input_function和output_function是必須的, 而函數(shù)receive_function,send_function, type_modifier_input_function, type_modifier_output_function, analyze_function是可選的。 通常,這些函數(shù)必須用C或者其它低層語言編寫。
input_function函數(shù)將該類型的外部文本形式轉換成可以被該類型的操作符和函數(shù)識別的內(nèi)部形式。 output_function用途相反。輸入函數(shù)可以聲明為接受一個類型為cstring的參數(shù), 或者接受三個類型分別為cstring,oid,integer的參數(shù)。第一個參數(shù)是C字符串形式的輸入文本, 第二個參數(shù)是該類型自身的OID(數(shù)組類型除外,這種情況下它們接受自身元素的類型OID), 第三個是目標字段的typmod(如果未知則傳遞-1)。輸入函數(shù)必須返回一個自身數(shù)據(jù)類型的值。 通常,輸入函數(shù)應當被聲明為STRICT,否則當讀取NULL輸入時將被使用第一個參數(shù)為NULL進行調(diào)用, 并且必須仍然返回NULL或報錯。這個特性主要是為了支持域輸入函數(shù),這種函數(shù)可能需要拒絕NULL輸入。 輸出函數(shù)必須被聲明為接受一個新數(shù)據(jù)類型的參數(shù),并且必須返回cstring類型。輸出函數(shù)不會被使用NULL調(diào)用。
可選的receive_function把該類型的外部二進制表現(xiàn)形式轉換成內(nèi)部表現(xiàn)形式。 如果沒有提供這個函數(shù),那么該類型不能用二進制輸入。二進制格式應該選取那種比較容易轉換同時還有一定移植性的內(nèi)部格式。 比如,標準的整數(shù)數(shù)據(jù)類型使用網(wǎng)絡字節(jié)序作為外部的二進制表現(xiàn)形式,而內(nèi)部表現(xiàn)形式則是機器的本機字節(jié)序。 例如,接收函數(shù)應該聲明為接受一個類型為internal的參數(shù),或者是三個類型分別為internal,oid,integer的參數(shù)。 第一個參數(shù)是一個指向一個StringInfo緩沖區(qū)的、保存接受字節(jié)串的指針;可選的參數(shù)和文本輸入函數(shù)一樣。 接收函數(shù)必須返回一個該類型的數(shù)據(jù)值。通常接收函數(shù)應當被聲明為STRICT, 否則否則當讀取NULL輸入時將被使用第一個參數(shù)為NULL進行調(diào)用,并且必須仍然返回NULL或報錯。 這個特性主要是為了支持域接收函數(shù),這種函數(shù)可能需要拒絕NULL輸入。同樣, 可選的send_function把類型的內(nèi)部表現(xiàn)形式轉換為外部二進制表現(xiàn)形式。如果沒有提供這些函數(shù), 那么類型就不能用二進制方式輸出。發(fā)送函數(shù)必須聲明為接收一個新數(shù)據(jù)類型并且必須返回bytea結果。發(fā)送函數(shù)不會被以NULL值調(diào)用。
這個時候你應該覺得奇怪,輸入和輸出函數(shù)怎么可以聲明為返回新類型的結果或者是接受新類型的參數(shù), 而且是在新類型創(chuàng)建之前就需要創(chuàng)建它們。答案是類型必須被首先定義為一個殼類型, 它只是一個除了名稱和屬主之外沒有其他屬性的占位符類型。這可以通過沒有其他額外參數(shù)的CREATE TYPEname命令來完成。 然后就可以引用該殼類型定義輸入輸出函數(shù)。最后,CREATE TYPE把這個殼類型替換成完整的、有效的類型定義,這樣就可以使用新類型了。
可選的type_modifier_input_function 和type_modifier_output_function 是需要的,如果類型支持連接到類型聲明的可選約束修飾符,例如char(5)或者 numeric(30,2)。PostgreSQL允許用戶定義的類型 把一個或多個簡單的常量或標識符作為修飾符。然而,這個信息必須能夠被打包成一個單一的 非負整數(shù)值存儲在系統(tǒng)目錄中。 type_modifier_input_function 以cstring元組的形式傳遞聲明的修飾符。 它必須檢查值的有效性(若是錯的則拋出一個錯誤),如果他們是錯的,返回一個存儲 為列"typmod"的獨立非負整型值。類型修飾符將被拒絕,如果類型 沒有type_modifier_input_function。 type_modifier_output_function 將內(nèi)部整數(shù)typmod值回轉換回到正確的形式給用戶顯示。必須返回一個添加到類型名 的正確字符串的cstring值;比如numeric的函數(shù)會返回 (30,2)。允許省略 type_modifier_output_function, 在這種情況下,默認的顯示格式僅僅是括在圓括號中的存儲的typmod整數(shù)值。
可選的analyze_function為該數(shù)據(jù)類型的字段執(zhí)行與該類型相關的統(tǒng)計信息收集。 缺省的時,如果該類型有個缺省的B-tree操作符類,那么ANALYZE將嘗試使用該類型的"等于"和"小于"操作符收集信息。 對于非標量類型,這種行為很可能不合適,因此可以通過提供一個自定義的分析函數(shù)覆蓋它。 分析函數(shù)必須聲明為接收單獨一個internal類型的參數(shù),并且返回一個boolean結果。 分析函數(shù)的詳細API在 src/include/commands/vacuum.h里。
盡管新類型的內(nèi)部表現(xiàn)形式只有輸入輸出函數(shù)和其它你創(chuàng)建來使用該類型的函數(shù)了解, 但內(nèi)部表現(xiàn)形式還是有幾個屬性必須為PostgreSQL聲明。internallength是最重要的一個。 基本數(shù)據(jù)類型可定義成為定長,這時internallength是一個正整數(shù),也可以是變長的, 這時用把internallength設為VARIABLE表示(在內(nèi)部, 這個狀態(tài)是通過將typlen設置為-1實現(xiàn)的)。所有變長類型的內(nèi)部形式都必須以一個四字節(jié)整數(shù)開頭, 這個整數(shù)給出此類型這個數(shù)值的全長。
可選的標記PASSEDBYVALUE表明該類型的數(shù)值是按值而不是引用傳遞。 你不能傳遞那些內(nèi)部形式大于Datum類型尺寸(大多數(shù)機器上是4字節(jié),有些是8字節(jié))的數(shù)據(jù)類型的值。
alignment參數(shù)聲明該數(shù)據(jù)類型要求的對齊存儲方式。允許的數(shù)值等效于按照1,2,4,8字節(jié)邊界對齊。 請注意變長類型必須有至少4字節(jié)的對齊,因為它們必須包含一個int4作為第一個部分。
storage參數(shù)允許為變長數(shù)據(jù)類型選擇存儲策略(定長類型只允許使用plain)。 plain聲明該數(shù)據(jù)類型總是用內(nèi)聯(lián)的方式而不是壓縮的方式存儲。 extended聲明系統(tǒng)將首先試圖壓縮一個長的數(shù)據(jù)值,然后如果它仍然太長的話就將它的值移出主表, 但系統(tǒng)將不會壓縮它。external聲明禁止系統(tǒng)進行壓縮并且允許將它的值移出主表。 main 允許壓縮,但是不贊成把數(shù)值移動出主表(如果實在不能放在一行里的話,仍將移動出主表), 它比extended和external項更愿意保存在主表里。
like_type參數(shù)提供了一個 指定數(shù)據(jù)類型的基本表示屬性的可選的方法:從一些現(xiàn)有類型復制它們。 internallength, passedbyvalue, alignment, 和 storage的值從命名的類型 復制。(通過用LIKE子句聲明他們來重寫其中的一些值是可能的, 但往往是不可取的。)以這種方式聲明表示法是特別有效的,當新類型 "piggybacks"的底層實現(xiàn)以某種形式的現(xiàn)有類型存在時。 whenthe low-level implementation of the new type "piggybacks" on an existing type in some fashion.
category和 preferred參數(shù)可以用于幫助控制 隱式強制用于模糊情況的。每個數(shù)據(jù)類型屬于一個由ASCII字符命名的類別,并且每種 類型要么是"preferred"要么未在其類別中。解析器更喜歡強制為優(yōu)先選擇類型 (但僅僅是從相同類別下的其他類型),當這個規(guī)則在解決重載函數(shù)或操作符起作用時。 要獲取更多詳細信息請參閱Chapter 10。 對于那些沒有隱式轉換成其他類型或者由其他類型轉換成隱式轉換的類型,足以 默認保持這些設置。然而,對于有隱式轉換的相關類型的一個組,標記他們?nèi)繉儆? 一個類別并選擇"most general"類型中的一個或者兩個作為范疇內(nèi)首選的, 這是很有效的。當添加一個用戶定義的類型到現(xiàn)有的內(nèi)置類別時, category參數(shù)尤其有用, 如數(shù)字或字符串類型。然而,創(chuàng)建新的完全用戶定義類型類別也是可能的。選擇 任何ASCII字符而不是一個大寫字母來命名這樣一個類別。
如果用戶希望字段的數(shù)據(jù)類型缺省時不是NULL,那么可以在DEFAULT關鍵字里聲明一個缺省值(可以被附著在特定字段上的DEFAULT子句覆蓋)。
用ELEMENT關鍵字聲明數(shù)組元素的類型。比如,ELEMENT = int4定義了一個4字節(jié)整數(shù)(int4)的數(shù)組。有關數(shù)組類型的更多細節(jié)在下面描述。
可用delimiter指定用于這種類型數(shù)組的外部形式的數(shù)值之間的分隔符。缺省的分隔符是逗號(,)。請注意分隔符是和數(shù)組元素類型相關聯(lián),而不是數(shù)組類型本身。
在創(chuàng)建用戶定義數(shù)據(jù)類型的時候,PostgreSQL 自動創(chuàng)建一個與之關聯(lián)的數(shù)組類型,其名字由該基本類型的名字前綴一個下劃線組成, 并且若有必要使其少于NAMEDATALEN字節(jié)長度就縮減。(若如此產(chǎn)生 的名稱與一個已存在的類型名沖突,那么將重復該過程,知道找到不沖突的名稱。) 這個隱式地創(chuàng)建的數(shù)組類型是可變長度的,并使用內(nèi)置輸入和輸出函數(shù)array_in 和array_out。數(shù)組類型會追蹤在其元素類型的所有者或模式的任何改變, 并且若元素類型是則刪除它。and is dropped if the element type is.
You might reasonably ask why there is an ELEMENT option, if the system makes the correct array type automatically. The only case where it's useful to use ELEMENT is when you are making a fixed-length type that happens to be internally an array of a number of identical things, and you want to allow these things to be accessed directly by subscripting, in addition to whatever operations you plan to provide for the type as a whole. For example, type point is represented as just two floating-point numbers, which it allows to be accessed as point[0] and point[1]. Note that this facility only works for fixed-length types whose internal form is exactly a sequence of identical fixed-length fields. A subscriptable variable-length type must have the generalized internal representation used by array_in and array_out. For historical reasons (i.e., this is clearly wrong but it's far too late to change it), subscripting of fixed-length array types starts from zero, rather than from one as for variable-length arrays. 你很可能會問如果系統(tǒng)自動制作正確的數(shù)組類型,那為什么還要有個ELEMENT選項?使用ELEMENT的場合有二: 你定義的定長類型碰巧在內(nèi)部是一個一定數(shù)目相同事物的數(shù)組,而你又想允許這N個事物可以通過下標直接關聯(lián);某些操作符將把該類型當做整體進行處理。 比如,構成point類型代表只有兩個浮點數(shù)。 這個類型允許像point[0]和point[1]一樣訪問。 請注意這個功能只適用于定長類型,并且其內(nèi)部形式是一個相同定長域的序列。 一個可以下標化的變長類型必須有被 array_in 和 array_out 使用的一般化的內(nèi)部表現(xiàn)形式。 出于歷史原因,定長數(shù)組類型的下標從 0 開始,而不是像變長類型那樣的從 1 開始。
將要創(chuàng)建的類型名(可以有模式修飾)。
復合類型的一個屬性(字段)的名字。
要成為一個復合類型的字段的現(xiàn)有數(shù)據(jù)類型的名字。
一個字符串常量代表一個與枚舉類型的值相關的文本標簽。
一個函數(shù)的名稱,將數(shù)據(jù)從外部文本形式轉換成內(nèi)部格式。
一個函數(shù)的名稱,將數(shù)據(jù)從內(nèi)部格式轉換成適于顯示的外部文本形式。
把數(shù)據(jù)從類型的外部二進制形式轉換成內(nèi)部形式的函數(shù)名稱。
把數(shù)據(jù)從類型的內(nèi)部形式轉換成外部二進制形式的函數(shù)名稱。
一個將一個數(shù)組的修飾符(s)類型轉換為內(nèi)部形式的函數(shù)的名稱。
將類型的修飾符(s)的內(nèi)部形式轉換為外部文本形式的函數(shù)的名稱。
為該數(shù)據(jù)類型執(zhí)行統(tǒng)計分析的函數(shù)名。
一個數(shù)值常量,說明新類型的內(nèi)部表現(xiàn)形式的長度。缺省假定它是變長的。
該數(shù)據(jù)類型的存儲對齊要求。如果聲明了,必須是char,int2,int4(缺省), double之一。
該數(shù)據(jù)類型的存儲策略。如果聲明了,必須是plain(缺省), external,extended, main之一。
新類型將用與原有數(shù)據(jù)類型名稱相同的表示法。 internallength, passedbyvalue, alignment和 storage的值會從那種 類型中復制出來,除非通過CREATE TYPE命令用明顯的聲明 重寫。
這個類型的分類碼(一個獨立的ASCII字符)。對于"user-defined type" 默認是'U'。其他標準類別代碼可以在 Table 45-45中找到。為了創(chuàng)建自定義類別 您也可能要選擇其他的ASCII字符。
若在其類型類別中該類型是優(yōu)先類別,則為真,否則為假。默認是假。 在已有類型類別中藥特別小心創(chuàng)建一個新的優(yōu)先類型,因為這能引起 性能上的驚人變化。
該類型的缺省值。若省略則為 NULL。
被創(chuàng)建的類型是數(shù)組;這個聲明數(shù)組元素的類型。
數(shù)組元素之間分隔符。
Because there are no restrictions on use of a data type once it's been created, creating a base type is tantamount to granting public execute permission on the functions mentioned in the type definition. This is usually not an issue for the sorts of functions that are useful in a type definition. But you might want to think twice before designing a type in a way that would require "secret" information to be used while converting it to or from external form. 因為一旦類型被創(chuàng)建之后對它的使用就沒有限制,所以創(chuàng)建一個基本類型就等價 于授予所有用戶執(zhí)行類型定義中指定的各個函數(shù)的權限。這對于大多數(shù)類型定義 中指定的函數(shù)來說不會造成什么不良問題。 但是如果你設計的新類型在內(nèi)部形式和外部形式之間轉換的時候使用"敏感信息", 那么你仍然要再三考慮、多加小心。
在PostgreSQL8.3版本之前,一個生成的元組類型的 名稱總是帶下劃線(_)前綴的完全元素類型的名字。(類型名 限制在比其他名少一個。)盡管這仍然是常見的情況,元組類型名稱可能會在最大 長度名稱或者下劃線開始的用戶類型名沖突情況變化。不推薦根據(jù)該約定寫代碼。 相反地,使用pg_type.typarray來定位與給定類型 相關的元組類型。
避免使用以下劃線打頭的類型和表名是明智的。盡管服務器將改變生成的元組類型名稱 以避免與用戶給定名稱產(chǎn)生沖突,但仍然有混亂的風險,特別是與假定以下劃線開始的 類型名總表示數(shù)組的老客戶端軟件
在PostgreSQL8.2之前的版本中,并不存在CREATE TYPE name語法。 創(chuàng)建新的基本類型之前必須首先創(chuàng)建其輸入函數(shù)。這樣,PostgreSQL將會首先把新類型的名字 看作輸入函數(shù)的返回類型并隱含創(chuàng)建殼類型,然后這個殼類型將被隨后定義的輸入輸出函數(shù)引用。 這種老式的方法目前仍然被支持,但已經(jīng)反對使用,將來可能不再支持。同樣, 為了避免函數(shù)定義中的臨時殼類型偶然地搞亂系統(tǒng)表,當輸入函數(shù)用C語言書寫時, 將只能用這種方法創(chuàng)建殼類型。
在PostgreSQL7.3以前,要通過使用占位偽類型opaque代替函數(shù)的前向引用來避免創(chuàng)建殼類型。 7.3之前cstring參數(shù)和結果同樣需要聲明偽opaque。要支持加載舊的轉儲文件, CREATE TYPE將接受那些用opaque聲明的輸入輸出函數(shù), 但是它將發(fā)出一條通知并且用正確的類型改變函數(shù)的聲明。
這個例子創(chuàng)建一個復合類型并且在一個函數(shù)定義中使用它:
CREATE TYPE compfoo AS (f1 int, f2 text); CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$ SELECT fooid, fooname FROM foo $$ LANGUAGE SQL;
該示例創(chuàng)建了一個枚舉類型并將其用于表定義:
CREATE TYPE bug_status AS ENUM ('new', 'open', 'closed'); CREATE TABLE bug ( id serial, description text, status bug_status );
這個命令創(chuàng)建box數(shù)據(jù)類型,并且將這種類型用于一個表定義:
CREATE TYPE box; CREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ; CREATE FUNCTION my_box_out_function(box) RETURNS cstring AS ... ; CREATE TYPE box ( INTERNALLENGTH = 16, INPUT = my_box_in_function, OUTPUT = my_box_out_function ); CREATE TABLE myboxes ( id integer, description box );
如果box的內(nèi)部結構是一個四個float4的數(shù)組,可以使用:
CREATE TYPE box ( INTERNALLENGTH = 16, INPUT = my_box_in_function, OUTPUT = my_box_out_function, ELEMENT = float4 );
來允許一個box的數(shù)值成分成員可以用下標訪問。否則該類型和前面的行為一樣。
這條命令創(chuàng)建一個大對象類型并將其用于一個表定義:
CREATE TYPE bigobj ( INPUT = lo_filein, OUTPUT = lo_fileout, INTERNALLENGTH = VARIABLE ); CREATE TABLE big_objs ( id integer, obj bigobj );
更多的例子,包括合適的輸入和輸出函數(shù),位于Section 35.11。
CREATE TYPE命令是PostgreSQL擴展。 在SQL里有一個CREATE TYPE語句,但是細節(jié)和PostgreSQL有比較大區(qū)別。