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 を使用すると、型を定義するだけであれば実際のテーブルを作成する必要がありません。 スタンドアロンの複合型は、関数の戻り値の型として使用すると有用です。
2 つ目の CREATE TYPE の形式を使用すると、基本型 (スカラ型) を新しく作成できます。 パラメータは、上述の順番だけではなく、任意の順番で指定することができます。 型を定義する前に、(CREATE FUNCTIONを用いて) 2 つ以上の関数を登録しておく必要があります。 サポート関数であるinput_functionとoutput_functionは必須です。 関数receive_function と send_function は省略可能です。 通常は、これらの関数はC言語やその他の低レベル言語で作成されなければなりません。
input_function は、型のテキストによる外部表現を内部表現形式に変換するものであり、その型用に定義される演算子や関数で使用されます。 output_functionはこの逆の変換を行うものです。 入力関数は、1つのcstring型の引数、あるいは、3つのcstring型、oid型、integer型の引数を取るように宣言されます。 最初の引数は C スタイルの入力テキスト、2 番目は配列型の場合の要素の型、3 番目は既知の場合、対象列の typmod です。 この入力関数では、データ型自身の値を返さなければなりません。 出力関数は、新しいデータ型の 1 つの引数、または、2 番目の型が oid 型である 2 つの引数をとるように宣言されます。 入力関数と同じく、2 番目の引数は、配列型の場合の配列要素の型です。 出力関数では、cstring 型を返さなければなりません。
省略することができる、receive_function は型のバイナリによる外部表現を内部表現に変換します。 この関数が与えられない場合、この型でバイナリ入力を使用することができません。 バイナリ表現は、内部表現への変換がやりやすくなるように、移植性が高くなるように選択すべきです。 (例えば、標準の整数データ型は外部バイナリ表現としてネットワークバイトオーダを使用し、内部表現ではマシン固有のバイトオーダを使用します。) この受信関数は値が有効かどうかを判定するための適切な検査を行わなければなりません。 受信関数は、internal型の 1 つの引数、または、internal型とoid型の2 つの引数をとるように宣言されます。 そして、データ型自体の値を返す必要があります。 (最初の引数は受信したバイト文字列を保持するStringInfoバッファへのポインタであり、省略可能の2番目の引数は配列型の場合の配列要素の型です。) 同様に、省略することができる、send_function は内部表現からバイナリによる外部表現に変換します。 この関数が与えられない場合、この型でバイナリ出力を使用することができません。 この送信関数は、新しいデータ型の 1 つの引数、または、2番目の引数がoid型の2 つの引数をとるように宣言されます。 受信関数と同じく、2 番目の引数は、配列型の場合の配列要素の型です。 送信関数はbytea型を返さなければなりません。
ここで、新しいデータ型を作成できるより前に入力または出力関数を作成する必要があるのに、どうしてその関数で新しいデータ型の結果や入力を受け取るように宣言できるのか、疑問に思うかもしれません。 その答えは、まず入力関数が最初に作成され、それから出力関数、(必要に応じてバイナリI/O関数、)そして最後にデータ型が作成される必要があるということです。 PostgreSQL では、まず入力関数の戻り値の型として新しいデータ型の名前を参照します。 その際に、"shell" 型を作成します。shell 型は、単に システムカタログ内のプレースホルダエントリであり、入力関数の定義とリンクされます。 同様に、その他の関数も (この時点ですでに作成されている) shell 型とリンクされます。 最後に、CREATE TYPE を実行すると、shell エントリが完全なデータ型定義に置き換えられ、新しいデータ型が使用可能になります。
新しい型の内部表現の詳細を理解しなければならないのは、これらのI/O関数とその型に関連して動作する作成者定義の関数のみですが、内部表現には、PostgreSQL に対し宣言しなければならない複数の属性値があります。 属性の中で最重要なものはinternallengthです。 基本データ型はinternallengthは正の整数となる固定長として作成することも、internallengthにVARIABLEと設定することで示される可変長として作成することもできます。 (内部的には、これはtyplen を -1 に設定することで表現されます。) 全ての可変長型の内部表現は、型の値の全長を示す4バイトの整数値から始まらなければなりません。
オプションのフラグ PASSEDBYVALUE は、このデータ型の値は参照ではなく値によって渡されることを示します。 (ほとんどのマシンでは 4 バイト、まれに 8 バイトとなる) Datum よりも長い内部表現の型は値によって渡すことはできません。
alignment パラメータは、そのデータ型の格納の際に整列が必要であることを示します。 設定可能な値は、1,2,4,8バイト境界での整列と同等のことを意味します。 可変長型の位置配置は最低でも 4 を持たなければならないことに注意して下さい。 最初の要素として int4 を持たなければならないからです。
storage パラメータを 使用することで、可変長データ型を格納する際の戦略を選択することができます。 (固定長の型には plain のみが許されています)。 plain では、その型のデータは常に一列で格納され、圧縮されません。 extended では、システムはまず長いデータ値を圧縮しようとし、それでもまだ長過ぎる場合は値をメインテーブルの行から削除します。 external はメインテーブルから値を削除することを許しますが、システムはデータを圧縮しようとしません。 main はデータの圧縮を許しますが、値をメインテーブルから削除することを止めます。 (この格納戦略を持つデータアイテムは、他に行を適合させる方法がない場合にはメインテーブルから削除されてしまうかもしれませんが、extended やexternal が指定されているアイテムよりも優先してメインテーブルに残されます。)
ユーザがそのデータ型の列のデフォルトを NULL 以外の何かにしたい場合、デフォルト値を指定することができます。 そのデフォルト値を DEFAULT キーワードで指定して下さい。 (この方法で指定されたデフォルト値は、特定の列に付与された、明示的な DEFAULT 句によって上書きされる可能性があります。)
データ型が配列であることを示すには、ELEMENT キーワードを使用して配列要素の型を指定して下さい。 例えば、4 バイト整数 (int4) の配列を定義するには、ELEMENT = int4と指定して下さい。 詳細については、後述の配列型で説明します。
この型による配列の外部形式における値間の区切り文字を示すために、delimiter で特定の文字を設定することができます。 デフォルトの区切り文字はカンマ(',')です。 この区切り文字は、配列要素の型に関係するものであり、配列型自体に関係するものでないことに注意して下さい。
ユーザ定義の基本データ型が作成されると、PostgreSQL は、自動的に、その名前として基本型名の前にアンダースコアを付けた、関連する配列型を作成します。 パーサはこの命名規則を理解し、foo[] 型の列への要求を _foo 型への要求に変換します。 この暗黙的に作成される配列型は可変長で、組み込み入出力関数 array_in と array_out を使用します。
理論的に考えると、「システムが自動的に配列型を正しく作成するのであれば、ELEMENT オプションはどうして存在するのだろう」と不思議に思うでしょう。 ELEMENT が意味を持つ、唯一の場合があります。 それは、内部的に複数の同一のものの配列となり、それらに対し、要素番号を指定して直接アクセスでき、さらに、その型全体として、何らかの操作を用意することを予定する、固定長の型を作成する時です。 例えば、name 型は、その要素である char 型のものにこのようなアクセス方法を許可しています。 2次元の point 型では、その 2 つの浮動小数点の構成要素に point[0] および point[1] というアクセスを行なうことができます。 この機能は、その内部形式が同一の固定長フィールドの正確な並びである、固定長の型でのみ動作することに注意してください。 要素番号指定が可能な可変長型は、array_in と array_out を使用して、汎化された内部表現を持つ必要があります。 歴史的な理由 (つまり、明らかに間違いなのですが、変更するには遅すぎたため) により、固定長配列型への要素番号指定は 0 から始まり、可変長配列の場合は 1 から始まります。
作成するデータ型の名前です (スキーマ修飾名でも可)。
複合型用の属性(列)名です。
複合型の列となる、既存のデータ型の名前です。
この型のテキストによる外部形式のデータをその型の内部形式のデータに変換する関数の名前です。
この型の内部形式のデータをその型のテキストによる外部形式のデータに変換する関数の名前です。
この型のバイナリによる外部形式のデータを内部形式に変換する関数の名前です。
この型の内部形式のデータをバイナリによる外部形式に変換する関数の名前です。
新しいデータ型の内部表現のバイト長を指定する数値定数です。 デフォルトでは、可変長であるとみなされます。
データ型の格納整列条件です。 このオプションが指定された場合、char、 int2、int4またはdoubleである必要があります。 デフォルトはint4です。
データ型の格納戦略です。 指定する場合は、plain、 external、extended、または mainでなければなりません。 デフォルトは plainです。
そのデータ型のデフォルト値です。 省略された場合、デフォルトは NULL です。
配列型を作成する場合、その配列の要素の型を指定します。
このデータ型による配列の値間の区切り文字です。
ユーザ定義型の名前はアンダースコア (_) から始めることはできません。 また、62 文字 (もしくは一般化した表現でいうと NAMEDATALEN-2) 長までです。 他の名前の場合は NAMEDATALEN-1 文字長まで許されます。) アンダースコアから始まる型名は、内部的に作成される配列型の名前のために予約されています。
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;
この例では、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 型が 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 );
第33章には、適切な入力関数、出力関数を含む多くの例があります。