CREATE TYPE name AS ( attribute_name data_type [, ... ] ) CREATE TYPE name ( INPUT = input_function, OUTPUT = output_function [ , RECEIVE = receive_function ] [ , SEND = send_function ] [ , ANALYZE = analyze_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番目は配列型の場合の要素の型(複合型の場合は型自体のOID)、3番目は既知の場合、対象列のtypmodです。 (不明な場合は-1を渡します。) この入力関数では、データ型自身の値を返さなければなりません。 出力関数は、新しいデータ型の1つの引数、または、2番目の型がoid型である2つの引数を取るように宣言されます。 入力関数と同じく、2番目の引数は、配列型の場合は配列要素の型、複合型の場合は型のOIDです。 出力関数では、cstring型を返さなければなりません。
省略可能なreceive_functionは、型のバイナリによる外部表現を内部表現に変換します。 この関数が与えられない場合、この型でバイナリ入力を使用することができません。 バイナリ表現は、内部表現への変換がやりやすくなるように、移植性が高くなるように選択すべきです。 (例えば、標準の整数データ型は外部バイナリ表現としてネットワークバイトオーダを使用し、内部表現ではマシン固有のバイトオーダを使用します。) この受信関数は、値が有効かどうかを判定するための適切な検査を行わなければなりません。 受信関数は、internal型の1つの引数、または、internal型とoid型の2つの引数を取るように宣言されます。 そして、データ型自体の値を返す必要があります。 (最初の引数は受信したバイト文字列を保持するStringInfoバッファへのポインタであり、省略可能の2番目の引数は、配列型の場合は配列要素の型のOID、複合型の場合は型自体のOIDです。) 同様に、省略可能なsend_functionは、内部表現からバイナリによる外部表現に変換します。 この関数が与えられない場合、この型でバイナリ出力を使用することができません。 この送信関数は、新しいデータ型の1つの引数、または、2番目の引数がoid型の2つの引数を取るように宣言されます。 受信関数と同じく、2番目の引数は、配列型の場合の配列要素の型のOIDもしくは複合型の場合の型のOIDです。 送信関数はbytea型を返さなければなりません。
ここで、新しいデータ型を作成できるより前に入力または出力関数を作成する必要があるのに、どうしてその関数で新しいデータ型の結果や入力を受け取るように宣言できるのか、疑問に思うかもしれません。 その答えは、まず入力関数が最初に作成され、それから出力関数、(必要に応じてバイナリI/O関数、)そして最後にデータ型が作成される必要があるということです。 PostgreSQLでは、まず入力関数の戻り値の型として新しいデータ型の名前を参照します。 その際に、"shell"型を作成します。 shell型は、単にシステムカタログ内のプレースホルダエントリであり、入力関数の定義とリンクされます。 同様に、その他の関数も(この時点ですでに作成されている)shell型とリンクされます。 最後に、CREATE TYPEを実行すると、shellエントリが完全なデータ型定義に置き換えられ、新しいデータ型が使用可能になります。
省略可能なanalyze_functionは、このデータ型の列に対する、型固有の統計情報の収集を行います。 デフォルトでは、もし、その型用のデフォルトのB-tree演算子クラスがあれば、ANALYZEは型の"等価"演算子と"小なり"演算子を使用して統計情報を集めようと試みます。 非スカラ型ではほとんどの場合、この振舞いは適していません。 そのため、独自の解析関数を指定することで、この振舞いを上書きすることができます。 この解析関数は、internal型の1つの引数を取り、boolean結果を返すように宣言する必要があります。 解析関数用のAPIの詳細は、src/include/commands/vacuum.hにあります。
新しい型の内部表現の詳細を理解しなければならないのは、これらの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 );
項31.11には、適切な入力関数、出力関数を含む多くの例があります。