CREATE TYPE — 新しいデータ型を定義する
CREATE TYPEname
AS ( [attribute_name
data_type
[ COLLATEcollation
] [, ... ] ] ) CREATE TYPEname
AS ENUM ( [ 'label
' [, ... ] ] ) CREATE TYPEname
AS RANGE ( SUBTYPE =subtype
[ , SUBTYPE_OPCLASS =subtype_operator_class
] [ , COLLATION =collation
] [ , CANONICAL =canonical_function
] [ , SUBTYPE_DIFF =subtype_diff_function
] ) CREATE TYPEname
( 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
] [ , COLLATABLE =collatable
] ) CREATE TYPEname
CREATE TYPE
は、現在のデータベースで使用できる新しいデータ型を登録します。
型を定義したユーザがその所有者となります。
スキーマ名が与えられている場合、型は指定されたスキーマに作成されます。 スキーマ名がなければ、その型は現在のスキーマに作成されます。 型名は、同じスキーマにある既存の型もしくはドメインとは、異なる名前にする必要があります (さらに、テーブルはデータ型と関連しているため、データ型名は同じスキーマのテーブル名とも競合しないようにしてください)。
上の構文概要に示すように、CREATE TYPE
には5つの構文があります。
これらはそれぞれ、複合型, 列挙型、範囲型、基本型、シェル型を作成します。
これらの内最初の4個についてはここで順番に説明します。
シェル型は、後で定義される型用の単なるプレースホルダで、型名以外のパラメータをつけずにCREATE TYPE
を実行することで作成されます。
シェル型は、範囲型と基本型を作成するときの前方参照として必要となるもので、それぞれの節で説明します。
CREATE TYPE
の最初の構文を使用すると、複合型を作成できます。
複合型は、属性名およびデータ型のリストにより指定されます。
データ型の照合順序が設定可能である場合、属性の照合順序も指定することができます。
複合型は本質的にはテーブルの行型と同じです。
しかし、型を定義することだけが必要なのであれば、CREATE TYPE
を使用することで、実際のテーブルを作成する必要がなくなります。
スタンドアロンの複合型は、例えば関数の引数や戻り値の型として有用です。
複合型を作成するためには、すべての属性型に対してUSAGE
権限を持たなければなりません。
CREATE TYPE
の2つ目の構文を使用すると、8.7. 列挙型で説明する列挙型(enum)を作成します。
列挙型は、1つ以上の引用符付きのラベルのリストを取ります。
ラベルはNAMEDATALEN
(PostgreSQLの標準のビルドでは64バイト)バイトよりも少ない長さでなければなりません。
CREATE TYPE
の三番目の構文は、8.17. 範囲型で説明する範囲型を新規に作成します。
範囲型のsubtype
は、関連する(範囲型の値を順序を決定するための)b-tree演算子クラスを持つ任意の型を取ることができます。
通常、派生元型のデフォルトのb-tree演算子クラスが順序を決定するために使用されます。
デフォルト以外の演算子クラスを使用するためには、subtype_opclass
でその名前を指定してください。
派生元型が照合順序変更可能であり、範囲の順序付けでデフォルト以外の照合順序を使用したい場合は、collation
オプションで使用したい照合順序を指定してください。
canonical
関数(省略可能)は、定義する範囲型の引数を1つ取り、同じ型の値を返さなければなりません。
これは適切な時に範囲値を正規形式に変換するために使用されます。
詳細については8.17.8. 新しい範囲型の定義を参照してください。
canonical
関数を作成することは多少厄介です、というのは、範囲型を定義できるようになる前に定義されている必要があるからです。
このためには、まず、名前と所有者以外の属性を持たないプレースホルダであるシェル型を作成しなければなりません。
これは、他にパラメータをつけずにCREATE TYPE
を実行することで行われます。
その後、このシェル型を引数と結果として使用する関数を宣言することができます。
最後に同じ名前を用いて範囲型を宣言することができます。
これは自動的にシェル型の項目を有効な範囲型に置き換えます。
name
subtype_diff
関数(省略可能)は、subtype
型の2つの値を引数として取り、与えられた2つの値の差異を表すdouble precision
型を返さなければなりません。
これは省略することができますが、提供することでその範囲型の列に対するGiSTインデックスの効率を大きく向上させることができます。
詳細については8.17.8. 新しい範囲型の定義を参照してください。
CREATE TYPE
の4つ目の構文を使用すると、基本型(スカラ型)を新しく作成できます。
新しい基本型を作成するにはスーパーユーザでなければなりません。
(エラーがある型定義が混乱を招き、サーバがクラッシュすることすらあるため、この制限がなされました。)
パラメータは、上述の順番である必要はなく、任意の順番で指定することができ、多くは省略可能です。
型を定義する前に、(CREATE FUNCTION
を用いて)2つ以上の関数を登録しておく必要があります。
サポート関数であるinput_function
とoutput_function
は必須です。
receive_function
関数、send_function
関数、type_modifier_input_function
関数、type_modifier_output_function
関数、およびanalyze_function
関数は省略可能です。
通常、これらの関数は、C言語やその他の低レベル言語で作成されなければなりません。
input_function
は、型のテキストによる外部表現を内部表現形式に変換するものであり、その型用に定義される演算子や関数で使用されます。
output_function
はこの逆の変換を行うものです。
入力関数は、1つのcstring
型の引数、あるいは、cstring
型、oid
型、integer
型という3つの引数を取るように宣言されます。
最初の引数にはC言語文字列の入力テキスト、2番目には型自体のOID(配列型の場合は例外で要素の型のOIDとなります)、3番目は、判明していれば対象列のtypmod
を渡します
(不明な場合は-1を渡します)。
この入力関数では、データ型自身の値を返さなければなりません。
通常入力関数はSTRICTとして宣言しなければなりません。
そうしないと、NULLという入力値を読み取った時、NULLという最初のパラメータを持って呼び出されます。
この場合でもエラーを発生させるのでなければ、関数はNULLを返さなければなりません。
(こうした状況はほとんどの場合、ドメイン入力関数をサポートすることを意図しています。ドメイン入力関数ではNULL入力を拒絶しなければならない可能性があります。)
出力関数は、新しいデータ型の引数を1つ取るように宣言しなければなりません。
出力関数は、cstring
型を返さなければなりません。
出力関数はNULL値に対して呼び出されることはありません。
receive_function
では、型のバイナリによる外部表現を内部表現に変換します。この関数は省略可能です。
この関数が与えられない場合、この型ではバイナリ入力を行うことができません。
バイナリ表現の方法は、適度な可搬性を保ちつつ、内部表現への変換コストが小さくなるよう選択すべきです
(例えば標準の整数データ型は、外部バイナリ表現としてはネットワークバイトオーダを使用し、内部表現ではマシン固有のバイトオーダを使用します)。
この受信関数では、値が有効かどうかを判定するための適切な検査を行わなければなりません。
受信関数は、internal
型の引数1つ、または、internal
型とoid
、integer
型の3つの引数を取るように宣言されます。
最初の引数は受信したバイト文字列を保持するStringInfo
バッファへのポインタ、省略可能な引数は、テキスト入力関数の説明と同じです。
受信関数は、データ型自体の値を返す必要があります。
通常受信関数はSTRICTとして宣言しなければなりません。
そうしないと、NULLという入力値を読み取った時、NULLという最初のパラメータを持って呼び出されます。
この場合でも関数はエラーを発生させるのでなければNULLを返さなければなりません。
(こうした状況はほとんどの場合、ドメイン受信関数をサポートすることを意図しています。ドメイン受信関数ではNULL入力を拒絶しなければならない可能性があります。)
同様に、send_function
は、内部表現からバイナリによる外部表現に変換します。この関数も省略可能です。
この関数が与えられない場合、この型ではバイナリ出力を行うことができません。
この送信関数は、新しいデータ型の引数1つを取るように宣言しなければなりません。
送信関数はbytea
型を返さなければなりません。
送信関数はNULL値に対して呼び出されません。
ここで、新しいデータ型を作成する前に入力関数と出力関数を作成する必要があるのに、どのようにしてそれらの関数で新しいデータ型を戻り値や入力として宣言できるのか、疑問に思うかもしれません。
その答えは、まず型が最初にシェル型として定義されます。
これは名称と所有者以外の属性を持たないプレースホルダ型です。
これは、コマンドCREATE TYPE
を他にパラメータをつけずに発行することで行われます。
この後、Cの入出力関数をこのシェル型を参照するように定義することができます。
最後に完全な定義を持ったname
CREATE TYPE
によって、シェル型の項目が完全かつ有効な型定義に置き換わり、新しい型を普通に使用することができるようになります。
type_modifier_input_function
とtype_modifier_output_function
は必須ではありませんが、型が修飾子をサポートする場合は必要です。
修飾子とは、char(5)
やnumeric(30,2)
などの型宣言に付与されるオプションの制約です。
PostgreSQLでは、ユーザ定義型が1つ以上の整数定数または識別子を修飾子として取ることができます。
しかし、この情報はシステムカタログに格納される時に0以上の整数1つにまとめられるものでなければなりません。
type_modifier_input_function
には、cstring
型配列の形で宣言された修飾子が渡されます。
その値について妥当性を検査しなければなりません(不当な場合はエラーとします)。
そして、正しい場合は、「typmod」列として格納される、0以上のinteger
値を1つ返さなければなりません。
型がtype_modifier_input_function
を持たない場合、型修飾子は拒否されます。
type_modifier_output_function
は内部的な整数typmod値をユーザ側の表示に合わせて変換します。
この関数は型名に付与する正確な文字列となるcstring
値を返さなければなりません。
たとえばnumeric
用の関数では(30,2)
を返すかもしれません。
デフォルトの表示用書式が保管されたtypmod整数値を括弧で括ったものと一致している場合は、type_modifier_output_function
を省略することができます。
オプションのanalyze_function
は、このデータ型の列に対する、型固有の統計情報の収集を行います。
その型用のデフォルトのB-tree演算子クラスがあれば、ANALYZE
はデフォルトでは型の「等価」演算子と「小なり」演算子を使用して統計情報を集めようと試みます。
非スカラ型には、この振舞いはあまり適していません。
そのため、独自の解析関数を指定することで、この振舞いを上書きすることができます。
この解析関数は、internal
型の引数を1つ取り、戻り値としてboolean
を返すように宣言する必要があります。
解析関数用のAPIの詳細は、src/include/commands/vacuum.h
にあります。
新しい型の内部表現の詳細を理解しなければならないのは、これらのI/O関数とその型に関連して動作するユーザ定義の関数のみですが、内部表現には、PostgreSQLに対し宣言しなければならない複数の属性値があります。
属性の中で最も重要なものはinternallength
です。
基本データ型は、internallength
に正の整数を指定して固定長として作成するだけでなく、internallength
にVARIABLE
と設定し可変長として作成することもできます
(内部的には、これはtyplen
を-1に設定することで表現されます)。
全ての可変長型の内部表現は、型の値の全長を示す4バイトの整数値から始まらなければなりません。
(長さフィールドは多くの場合63.2. TOASTに記述されているようにエンコードされており、それに直接アクセスすることは賢明ではないことに注意してください。)
オプションのPASSEDBYVALUE
フラグは、このデータ型の値が参照ではなく値によって渡されることを示します。
値によって渡される型は固定長でなければならず、その内部表現はDatum
型のサイズ(4バイトのマシンもあれば8バイトのマシンもあります)を超えてはいけません。
alignment
パラメータは、そのデータ型の格納の際に必要な整列を指定します。
設定可能な値は、1、2、4、8バイト境界での整列です。
可変長の型は最低でも4の整列を持たなければならないことに注意してください。
最初の要素としてint4
を持たなければならないからです。
storage
パラメータを使用することで、可変長データ型を格納する際の戦略を選択することができます
(固定長の型にはplain
のみが使用できます)。
plain
を指定すると、その型のデータは常にインラインで格納され、圧縮されません。
extended
を指定すると、システムはまず長いデータ値を圧縮しようとし、それでもまだ長過ぎる場合は値をメインテーブルの行から削除して移動します。
external
はメインテーブルから値を削除して移動することを許しますが、システムはデータを圧縮しようとしません。
main
はデータの圧縮を許しますが、できるだけ値をメインテーブルから削除しないようにします
(行を収めるために他に方法がない場合にはメインテーブルから削除されてしまう可能性がありますが、extended
やexternal
が指定されたアイテムよりも優先してメインテーブルに残されます)。
plain
を除くすべてのstorage
の値は、そのデータ型の関数が、63.2. TOASTおよび35.11.1. TOASTの考慮に記述されているようにtoastされた値を処理できることを暗示します。
その他の特定の値を指定するのは、TOAST可能なデータ型の列について、単にデフォルトのTOAST戦略を決めるだけです。
ユーザは個々の列についてALTER TABLE SET STORAGE
を使って他の戦略を選択できます。
like_type
パラメータは、何らかの既存のデータ型から複製するという、データ型の基本表現プロパティを指定する、別の方法を提供します。
internallength
、passedbyvalue
、alignment
、storage
の値が指定された型から複製されます。
(通常は望ましくありませんが、LIKE
句と一緒にこれらの値を指定することで、値を上書きすることも可能です。)
新しい型の低レベル実装にある流儀に従った既存の型を「移す」時に、この方法で表現を指定することが特に有用です。
category
とpreferred
パラメータは、あいまいな状況でどの暗黙的なキャストが適用されるかについての制御を補助するために使用することができます。
各データ型は単一のASCII文字で命名されるカテゴリに属しており、各型はそのカテゴリ内で「優先される(preferred)」か否かです。
オーバーロードされた関数または演算子の解決に、この規則が有用な場合には、パーサは優先される型へのキャストを優先します(ただし、同一のカテゴリ内の他の型からだけです)。
より詳細は10章型変換を参照してください。
他の型への、または、ほかの型からの暗黙的なキャストを持たない型では、これらの設定をデフォルトのままにしておくことで十分です。
しかし、暗黙的なキャストを持つ関連する型のグループでは、それらすべてを1つのカテゴリに属すものとし、「最も汎用的な」型の1つまたは2つをカテゴリ内で優先されるものとして選択することが有用となる場合が多くあります。
ユーザ定義型を、数値型や文字列型などの既存の組み込みカテゴリに追加する場合に、category
パラメータは特に有用です。
しかし、完全にユーザ定義の新しい型カテゴリを作成することもできます。
そのようなカテゴリの命名には大文字以外の任意のASCII文字を選択してください。
ユーザがそのデータ型の列のデフォルトをNULL以外にしたい場合は、デフォルト値を指定することができます。
デフォルト値はDEFAULT
キーワードで指定してください
(この方法で指定されたデフォルト値を、特定の列に付与された、明示的なDEFAULT
句によって上書きすることができます)。
データ型が配列であることを示すには、ELEMENT
キーワードを使用して配列要素の型を指定してください。
例えば、4バイト整数(int4
)の配列を定義するには、ELEMENT = int4
と指定してください。
配列型の詳細は後述します。
この型による配列の外部形式における値間の区切り文字を示すために、delimiter
で特定の文字を設定することができます。
デフォルトの区切り文字はカンマ(',
')です。
この区切り文字は、配列要素の型に関係するものであり、配列型自体に関係するものでないことに注意してください。
論理型のcollatable
パラメータ(省略可能)が真の場合、COLLATE
句を使用することによって、型の列定義と式は照合順序情報を持つことができます。
照合順序情報を実際に使用するかどうかは、型に対する操作を行う関数実装に任されています。
照合順序を設定可能な型を作成することにより、これが自動的に行われることはありません。
ユーザ定義型が作成されると、PostgreSQLは、自動的に関連する配列型を作成します。
その要素型の名前の前にアンダースコアを付け、必要に応じてNAMEDATALEN
長より短くなるように切り詰められた名前になります。
(こうして付けられた名前が既存の型名と競合する場合、競合する名称がなくなるまでこの処理が繰り返されます。)
この暗黙的に作成される配列型は可変長で、組み込み入出力関数array_in
とarray_out
を使用します。
配列型はその要素となる型の所有者とスキーマのなんらかの変更に追従し、また、要素となる型が削除された場合に削除されます。
「システムが自動的に配列型を正しく作成するのであれば、ELEMENT
オプションはどうして存在するのだろう」と疑問に思うのも道理です。
ELEMENT
が意味を持つ、唯一の場合は次のような条件を満たす固定長の型を作成する時です。
その条件とは、内部的に複数の同一の要素からなる配列となっていること、その配列に対して添字を指定して直接アクセスできること、加えて、今後作成する型全体に対する操作がどのようなものであっても、それらから直接アクセスできることです。
例えば、point
型は、2つの浮動小数点だけから構成され、それらはpoint[0]
およびpoint[1]
を用いてアクセスすることができます。
この機能は、その内部形式が同一の固定長フィールドの正確な並びである、固定長の型でのみ動作することに注意してください。
添字による指定が可能な可変長型は、array_in
とarray_out
を使用して、一般化された内部表現を持つ必要があります。
歴史的な理由(明らかに間違いなのですが、変更するには遅すぎたため)により、固定長配列型への要素番号指定は0から始まり、可変長配列の場合は1から始まります。
name
作成するデータ型の名前です(スキーマ修飾名も可)。
attribute_name
複合型用の属性(列)名です。
data_type
複合型の列となる、既存のデータ型の名前です。
collation
複合型の列または範囲型に関連付けされる、既存の照合順序の名前です。
label
列挙型の1つの値に関連付けられるテキスト形式のラベルを表す、文字列リテラルです。
subtype
範囲型がその範囲の対象として表現する、要素型の名前です。
subtype_operator_class
派生元型のb-tree演算子クラスの名前です。
canonical_function
範囲型の正規化関数の名前です。
subtype_diff_function
派生元型の差異をとる関数の名前です。
input_function
指定された型のテキストによる外部形式のデータを内部形式に変換する関数の名前です。
output_function
指定された型の内部形式のデータをテキストによる外部形式に変換する関数の名前です。
receive_function
指定された型のバイナリによる外部形式のデータを内部形式に変換する関数の名前です。
send_function
指定された型の内部形式のデータをバイナリによる外部形式に変換する関数の名前です。
type_modifier_input_function
型に関する修飾子の配列を内部形式に変換する関数の名前です。
type_modifier_output_function
内部形式の型修飾子をテキストの外部形式に変換する関数の名前です。
analyze_function
指定したデータ型の統計情報解析を行う関数の名前です。
internallength
新しいデータ型の内部表現のバイト長を表す数値定数です。 デフォルトでは、可変長であるとみなされます。
alignment
データ型の格納整列条件です。
このオプションを指定する場合は、char
、int2
、int4
、double
のいずれかでなければなりません。
デフォルトはint4
です。
storage
データ型の格納戦略です。
このオプションを指定する場合は、plain
、external
、extended
、main
のいずれかでなければなりません。
デフォルトはplain
です。
like_type
新しい型に同じ表現を持たせる既存のデータ型の名前です。
internallength
、passedbyvalue
、alignment
、storage
の値が、このCREATE TYPE
コマンドのどこかで明示的な指定により上書きされない限り、型から複製されます。
category
この型用のカテゴリコード(単一のASCII文字)です。
デフォルトは「ユーザ定義型」を表す'U'
です。
他の標準カテゴリコードを表49.55「typcategory
のコード」に示します。
独自のカテゴリを作成するために他のASCII文字を選択することもできます。
preferred
この型がカテゴリ内で優先される型である場合に真、さもなくば偽です。 デフォルトは偽です。 動作に予想外の変化を引き起こしますので既存の型カテゴリに新しく優先される型を作成することには十分注意してください。
default
そのデータ型のデフォルト値です。 省略された場合、デフォルトはNULLです。
element
配列型を作成する場合、その配列の要素の型を指定します。
delimiter
このデータ型による配列で、値間の区切り文字として使われる文字です。
collatable
この型を操作する時に照合順序情報を使用することができる場合に真を取ります。 デフォルトは偽です。
一度作成したデータ型の使用には制限はありませんので、基本型または範囲型の作成は型定義で言及した関数の実行権をPUBLICに対して付与することと同じです。 この種の型定義において有用な関数では、これは通常問題になりません。 しかし、外部形式から、または、外部形式への変換を行う時に、その関数が「秘密の」情報を必要とする場合、型を設計する前に熟考してください。
PostgreSQLバージョン8.3より前のバージョンでは、生成される配列型の名前は常に要素型の名前の前に1つのアンダースコア文字(_
)を付けたものになりました。
(このため型の名前は他の名前よりも1文字短く制限されていました。)
通常はこのように名付けられることは変わりありませんが、最大長の名前の場合やアンダースコアから始まるユーザ定義の型と競合する場合、配列型の名前はこの変換とは変わることがあります。
このため、この規則に依存したコードを書くことは避けてください。
代わりに、pg_type
.typarray
を使用して、指定した型に関連した配列型を特定してください。
アンダースコアから始まる型やテーブル名の使用を避けることが賢明です。 サーバは生成された配列型名称をユーザ指定の名前と競合しないように変更しますが、混乱する危険があります。 特に古いクライアントソフトウェアを使用する場合、名前がアンダースコアから始まる型を常に配列を表すものと想定しているかもしれません。
PostgreSQLバージョン8.2より前まででは、シェル型を作成するCREATE TYPE
構文は存在しません。
新規に基本型を作成する方法は、最初に入力関数を作成することでした。
この方法では、PostgreSQLは新しいデータ型の名称を、入力関数の戻り値型で初めて見ます。
このときに、シェル型が暗黙的に作成され、残りの入出力関数の定義で参照することができます。
この方法もまだ使用できますが、廃止予定であり、将来のリリースで禁止される可能性があります。
また、関数定義における単純なタイプミスの結果作成されるシェル型によって起こるカタログの混乱を防止するため、入力関数がCで作成された場合にのみこの方法によってシェル型が作成されます。
name
PostgreSQL 7.3より前のバージョンでは、関数の下位参照を、プレースホルダとなる疑似データ型であるopaque
型のデータ型名と置き換えることによって、shell型を作成することを完全に、慣習的に避けていました。
また、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;
次の例では、列挙型を作成し、それをテーブル定義に使用します。
CREATE TYPE bug_status AS ENUM ('new', 'open', 'closed'); CREATE TABLE bug ( id serial, description text, status bug_status );
次の例では、範囲型を作成します。
CREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);
次の例では、基本データ型box
を作成し、その型をテーブル定義の中で使用しています。
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
型の内部構造がfloat4
型が4つの配列の場合、このように書き換えることもできます。
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 );
その他の例は、35.11. ユーザ定義の型を参照してください。ここには、入力関数、出力関数などを使った例があります。
複合型を作成する、最初のCREATE TYPE
コマンドの構文は標準SQLに従います。
他の構文はPostgreSQLの拡張です。
標準SQLではまた他のCREATE TYPE
構文を定義していますが、PostgreSQLでは実装されていません。
ゼロ個の要素を持つ複合型を作成する機能は標準から派生したPostgreSQL固有のもの(CREATE TABLE
の場合と同様)です。