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 name
CREATE TYPEは、現在のデータベースで使用できる新しいデータ型を登録します。 型を定義したユーザがその所有者となります。
スキーマ名が与えられている場合、型は指定されたスキーマで作成されます。 スキーマ名がなければ、その型は現在のスキーマで作成されます。 型名は、同じスキーマにある既存の型もしくはドメインとは、異なる名前にする必要があります (さらに、テーブルはデータ型と関連しているため、データ型名は同じスキーマのテーブル名とも競合しないようにしてください)。
CREATE TYPEの最初の構文を使用すると、複合型を作成できます。 複合型は、列名およびデータ型のリストにより指定されます。 これは、本質的にはテーブルの行型と同じです。 しかし、型を定義するだけであれば、CREATE TYPEを使用することで、実際のテーブルを作成する必要をなくすことができます。 スタンドアロンの複合型は、関数の引数や戻り値の型として使用すると有用です。
CREATE TYPEの2つ目の構文を使用すると、基本型(スカラ型)を新しく作成できます。 パラメータは、上述の順番である必要はなく、任意の順番で指定することができます。 型を定義する前に、(CREATE FUNCTIONを用いて)2つ以上の関数を登録しておく必要があります。 サポート関数であるinput_functionとoutput_functionは必須です。 receive_function関数とsend_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 nameコマンドを発行することで行われます。 この後、入出力関数をこのシェル型を参照するように定義することができます。 最後に完全な定義を持ったCREATE TYPEによって、シェル型の項目が完全かつ有効な型定義に置き換わり、新しい型を普通に使用することができるようになります。
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フラグは、このデータ型の値が参照ではなく値によって渡されることを示します。このフラグは省略可能です。 Datum型のサイズ(ほとんどのマシンでは4バイトだが、まれに8バイト)よりも長い内部表現の型は値で渡すことができません。
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文字まで許されます)。 アンダースコアから始まる型名は、内部的に生成される配列型の名前のために予約されています。
一度作成したデータ型の使用には制限はありませんので、基本型の作成は型定義で言及した関数の実行権をPUBLICに対して付与することと同じです。 (したがって型の作成者はこれらの関数の所有者でなければなりません。) この種の型定義において有用な関数では、これは通常問題になりません。 しかし、型を設計する前に、外部形式から、または、外部形式への変換を行う時に、その関数が"秘密の"情報を必要とするかどうか熟考してください。
PostgreSQLバージョン8.2より前まででは、CREATE TYPE name構文は存在しません。 新規に基本型を作成する方法は、最初に入力関数を作成することでした。 この方法では、PostgreSQLはまず新しいデータ型の名称を、入力関数の戻り値型から判断します。 この場合、シェル型が暗黙的に作成され、残りの入出力関数の定義で参照することができます。 この方法もまだ使用できますが、廃止予定で将来のリリースでなくなる可能性があります。 また、関数定義における単純な打ち間違いの結果作成されるシェル型によって起こるカタログの混乱を防止するため、入力関数がCで作成された場合にのみこの方法によってシェル型が作成されます。
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; 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 );
その他の例は、項33.11を参照してください。ここには、入力関数、出力関数などを使った例があります。