先に述べられているように、PostgreSQLには基本データ型(プログラミング言語で定義されています。 )と複合データ型という2種類のデータ型があります。この章では、新しい基本データ型を定義する方法についてを説明します。
この節で使用した例は、tutorial ディレクトリにcomplex.sql と complex.cという名前でおいてあります。 複合データ型の例は funcs.sql にあります。
ユーザ定義データ型では、必ず入力関数と出力関数が必要です。これらの関数は、型が(ユーザによる入力とユーザへの出力のための)文字列中にどのような形式で表示されるかと、その型がメモリ中でどう構成されるかを決定します。入力関数はその入力として NULL 終端文字列を取り、その型の(メモリ中の)内部表現を返します。出力関数はその型の内部表現を取り、NULL終端文字列を返します。
例えば、複素数を表現する複素数型を定義することを考えます。 私たちはおそらく、次のような C 構造体で複素数をメモリ中で表現し、
typedef struct Complex { double x; double y; } Complex;
そして、外部文字列表現として (x,y) 形式の文字列を使用することを選択するでしょう。
これらの関数、特に出力関数を記述するのは困難ではありません。しかしながら、いくつかの注意点があります。
外部(文字列)表現を定義する時には、その表現のための完全で堅牢なパーサを入力関数として書かなければなりません。
例:
Complex * complex_in(char *str) { double x, y; Complex *result; if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2) { elog(ERROR, "complex_in: error in parsing %s", str); return NULL; } result = (Complex *)palloc(sizeof(Complex)); result->x = x; result->y = y; return (result); }
出力関数は単に下記のようになるでしょう。
char * complex_out(Complex *complex) { char *result; if (complex == NULL) return(NULL); result = (char *) palloc(60); sprintf(result, "(%g,%g)", complex->x, complex->y); return(result); }
入出力関数は、各々の逆関数になるようにするべきです。そうしないと、データをファイルにダンプし、例えばそれを他のコンピュータ上にある別の誰かのデータベースなどに戻そうとする際に、深刻な問題が発生するでしょう。これは、浮動小数が関係する際によく発生する問題です。
complex(複素数)型を定義する時、その型を生成する前に2つのユーザ定義関数complex_in とcomplex_outを生成する必要があります。
CREATE FUNCTION complex_in(cstring) RETURNS complex AS 'PGROOT/tutorial/complex' LANGUAGE C; CREATE FUNCTION complex_out(complex) RETURNS cstring AS 'PGROOT/tutorial/complex' LANGUAGE C;
最後に、データ型を宣言することができます。
CREATE TYPE complex ( internallength = 16, input = complex_in, output = complex_out );
入力関数および出力関数の宣言が、未定義のデータ型を参照しなければならないことに注意してください。 これは有効な操作です。警告のメッセージが表示されますが無視して構いません。
前に述べたように、PostgreSQLは基本型の配列を完全にサポートしています。更に、PostgreSQL ではユーザ定義型の配列もサポートしています。型を定義する時、PostgreSQL は自動的にその型の配列のサポートを提供します。歴史的な理由により、配列型はユーザ定義型の名前の前にアンダースコア文字 _ が付いた名前になります。
複合型の場合は、すでにシステムはそれらが内部的にどのようになっているかを把握しているので、関数を定義する必要はありません。
ユーザ定義データ型の内部形式の大きさが数百バイトを越えるのであれば、TOAST 化を可能とするには注意が必要です。TOAST化のためには、内部表現が可変長データの標準レイアウトに従っていなければなりません。先頭の4バイトはint32型で、それ自身を含めたデータの合計バイト数を入れます。また、その型の値を受け付ける関数はすべて、与えられた値についてpg_detoast_datum() を呼び出すのに注意が必要です。 その関数が厳密でない場合は、値がNULLでないことをあらかじめ検査しなければなりません。最後に、CREATE TYPE コマンドを実行する際に、適当な保存オプションを選択して下さい。