Chapter 5. SQLの拡張: 型

上で述べたように、 Postgres には 基本型(プログラミング言語で定義されています。)と複合型 (インスタンス)という 2 種類の型があります。この節からインデッ クスへのインタフェース節までで使用している例は、 complex.sqlcomplex.c にあります。複合型の例は funcs.sql にあります。

ユーザ定義型

ユーザ定義型に必要な関数

A user-defined type must always have input and output functions. These functions determine how the type appears in strings (for input by the user and output to the user) and how the type is organized in memory. The input function takes a null-delimited character string as its input and returns the internal (in memory) representation of the type. The output function takes the internal representation of the type and returns a null delimited character string. Suppose we want to define a complex type which represents complex numbers. Naturally, we choose to represent a complex in memory as the following C structure:

ユーザ定義型では、常に入力関数と出力関数が必要です。これらの 関数は、型が(ユーザによる入力とユーザへの出力のための)文字列中 にどうやって現れるか、またその型がメモリ中でどう構成されるかを 決定します。入力関数はその入力として NULL 終端文字列を取り、 その型の(メモリ中の)内部表現を返します。出力関数はその型の内部 表現を取り、NULL 終端文字列を返します。 ここで私たちは、複素数を表現する複素数型を定義したいとします。 私たちはごく自然に、

         typedef struct Complex {
             double      x;
             double      y;
         } Complex;
and a string of the form (x,y) as the external string representation. These functions are usually not hard to write, especially the output function. However, there are a number of points to remember: という C 構造体のようなメモリ中の複素数表現 と、外部文字列表現として (x,y) という形式の文字列を選びますよね。 これらの関数、特に出力関数を記述する事は困難ではありません。 しかしながら、いくつか忘れてはならない点があります。

  • 外部(文字列)表現を定義する時には、当然の結果として、その表現の ための完全で堅牢なパーサを、入力関数として書かなければならない ことを忘れないでください。

                    Complex *
                    complex_in(char *str)
                    {
                        double x, y;
                        Complex *result;
                        if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2) {
                            elog(WARN, "complex_in: error in parsing
                            return NULL;
                        }
                        result = (Complex *)palloc(sizeof(Complex));
                        result->x = x;
                        result->y = y;
                        return (result);
                    }
    The output function can simply be: 出力関数は単に以下のようになるでしょう。
                    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);
                    }

  • 入出力関数は、各々の逆関数になるようにするべきです。 そうしないと、データをファイル(いや、たとえば他のコンピュータ上 にある別の誰かのデータベースでもいいです)にダンプしてまたそれを 戻そうとする時に、深刻な問題が発生するでしょう。これは、 浮動小数点数が含まれる際に特有な、一般的な問題です。

To define the complex type, we need to create the two user-defined functions complex_in and complex_out before creating the type:

複素数(complex)型を定義するにあたり、その型 を生成する前に 2 つのユーザ定義関数 complex_in と complex_out を生成する必要があります。

         CREATE FUNCTION complex_in(opaque)
            RETURNS complex
            AS 'PGROOT/tutorial/obj/complex.so'
            LANGUAGE 'c';

         CREATE FUNCTION complex_out(opaque)
            RETURNS opaque
            AS 'PGROOT/tutorial/obj/complex.so'
            LANGUAGE 'c';

         CREATE TYPE complex (
            internallength = 16,
            input = complex_in,
            output = complex_out
         );

As discussed earlier, Postgres fully supports arrays of base types. Additionally, Postgres supports arrays of user-defined types as well. When you define a type, Postgres automatically provides support for arrays of that type. For historical reasons, the array type has the same name as the user-defined type with the underscore character _ prepended. Composite types do not need any function defined on them, since the system already understands what they look like inside.

前に述べたように、Postgres は基本 型の配列を完全にサポートしています。これに加えて、 Postgres ではユーザ定義型の配列も サポートします。型を定義する時、Postgres は自動的にその型の配列のサポートを提供します。 歴史的な理由により、配列型はユーザ型の名前の前にアンダースコア 文字 _ が付いた名前になります。複合型の場合は、すでにシステム はそれらが内部的にどう見えるかを理解しているので、それらに対して 関数を定義する必要はありません。

ラージオブジェクト

The types discussed to this point are all "small" objects -- that is, they are smaller than 8KB in size.

ここまでに説明してきたのは、すべて "小さな" オブジェクトに関して だけです。小さいと言うのは、サイズが 8KB 以下のものをいいます。

Note: 1024 longwords == 8192 bytes. In fact, the type must be considerably smaller than 8192 bytes, since the Postgres tuple and page overhead must also fit into this 8KB limitation. The actual value that fits depends on the machine architecture.

1024 ロングワードは 8192 バイトです。実際は、型は 8192 バイトより かなり小さくなければなりません。これは、Postgres のタプルとページ・オーバーヘッドもこの 8KB という 制限に合うように調整されているからです。適合する実際の値は マシンのアーキテクチャに依存します。

If you require a larger type for something like a document retrieval system or for storing bitmaps, you will need to use the Postgres large object interface. もし、文書検索システムやビットマップ格納のような物のための大きな 型を必要とするのであれば、Postgres のラージオブジェクト・インターフェースを使う必要があります。