バージョンごとのドキュメント一覧

36.10. C言語関数 #

<title>C-Language Functions</title>

User-defined functions can be written in C (or a language that can be made compatible with C, such as C++). Such functions are compiled into dynamically loadable objects (also called shared libraries) and are loaded by the server on demand. The dynamic loading feature is what distinguishes <quote>C language</quote> functions from <quote>internal</quote> functions &mdash; the actual coding conventions are essentially the same for both. (Hence, the standard internal function library is a rich source of coding examples for user-defined C functions.) ユーザ定義の関数はC(もしくはC++のようなCと互換性のある言語)で作成できます。 そのような関数は動的ロード可能オブジェクト(共有ライブラリとも呼ばれます)としてコンパイルされ、必要に応じてサーバにロードされます。 動的ロード機能が、C言語関数を内部関数と区別するものです。 コーディング方法は基本的に両方とも同じです。 (したがって、標準内部関数ライブラリはユーザ定義のC関数のコーディング例の豊富な情報源となります。)

Currently only one calling convention is used for C functions (<quote>version 1</quote>). Support for that calling convention is indicated by writing a <literal>PG_FUNCTION_INFO_V1()</literal> macro call for the function, as illustrated below. 現在、1つの呼び出し規約だけがC関数で使用されています(version 1)。 その呼び出し規約をサポートしていることは、以下に示すように、その関数用に呼び出しマクロPG_FUNCTION_INFO_V1()を書くことで示されます。

36.10.1. 動的ロード #

<title>Dynamic Loading</title>

The first time a user-defined function in a particular loadable object file is called in a session, the dynamic loader loads that object file into memory so that the function can be called. The <command>CREATE FUNCTION</command> for a user-defined C function must therefore specify two pieces of information for the function: the name of the loadable object file, and the C name (link symbol) of the specific function to call within that object file. If the C name is not explicitly specified then it is assumed to be the same as the SQL function name. 特定のロード可能オブジェクト内のユーザ定義の関数がセッションで最初に呼び出されると、動的ローダは、その関数を呼び出すことができるように、オブジェクトファイルをメモリ内に読み込みます。 そのため、ユーザ定義のC関数用のCREATE FUNCTIONはその関数について、ロード可能オブジェクトファイルの名前とオブジェクトファイル中の呼び出される特定の関数のC名称(リンクシンボル)という2つの情報を指定しなければなりません。 C名称が明示的に指定されなかった場合、SQLにおける関数名と同じものと仮定されます。

The following algorithm is used to locate the shared object file based on the name given in the <command>CREATE FUNCTION</command> command: CREATE FUNCTIONコマンドで与えられた名前に基づいて、共有オブジェクトファイルの場所を見つける際に以下のアルゴリズムが使用されます。

  1. If the name is an absolute path, the given file is loaded. 名前が絶対パスの場合、指定されたファイルが読み込まれます。

  2. If the name starts with the string <literal>$libdir</literal>, that part is replaced by the <productname>PostgreSQL</productname> package library directory name, which is determined at build time.<indexterm><primary>$libdir</primary></indexterm> 名前が$libdirという文字列から始まる場合、その部分はPostgreSQLパッケージのライブラリディレクトリで置き換えられます。 このディレクトリはビルド時に決定されます。

  3. If the name does not contain a directory part, the file is searched for in the path specified by the configuration variable <xref linkend="guc-dynamic-library-path"/>.<indexterm><primary>dynamic_library_path</primary></indexterm> 名前にディレクトリ部分がない場合、そのファイルはdynamic_library_path設定変数で指定されたパス内から検索されます。

  4. Otherwise (the file was not found in the path, or it contains a non-absolute directory part), the dynamic loader will try to take the name as given, which will most likely fail. (It is unreliable to depend on the current working directory.) 上記以外の場合(ファイルがパス内に存在しない場合や相対ディレクトリ部分を持つ場合)、動的ローダは指定された名前をそのまま使用し、ほとんどの場合は失敗します。 (これは現在の作業ディレクトリに依存するため信頼できません。)

If this sequence does not work, the platform-specific shared library file name extension (often <filename>.so</filename>) is appended to the given name and this sequence is tried again. If that fails as well, the load will fail. ここまでの流れがうまくいかなかった場合、プラットフォーム独自の共有ライブラリファイル拡張子(多くの場合.so)が指定された名前に追加され、再度この流れを試みます。 同様に失敗した場合は、読み込みは失敗します。

It is recommended to locate shared libraries either relative to <literal>$libdir</literal> or through the dynamic library path. This simplifies version upgrades if the new installation is at a different location. The actual directory that <literal>$libdir</literal> stands for can be found out with the command <literal>pg_config &#45;-pkglibdir</literal>. 共有ライブラリを$libdirから相対的に、もしくは動的ライブラリパスの通った所に配置することを推奨します。 異なる場所に新しいインストレーションを配置する場合にバージョンアップを簡単にします。 $libdirが示す実際のディレクトリはpg_config --pkglibdirコマンドを使用することでわかります。

The user ID the <productname>PostgreSQL</productname> server runs as must be able to traverse the path to the file you intend to load. Making the file or a higher-level directory not readable and/or not executable by the <systemitem>postgres</systemitem> user is a common mistake. PostgreSQLサーバの実効ユーザIDはロード予定のファイルのパスまで到達できなければなりません。 よくある失敗として、postgresユーザに対して読み込み、実行、または両方の権限がそのファイルとその上位ディレクトリに与えられていないことがあります。

In any case, the file name that is given in the <command>CREATE FUNCTION</command> command is recorded literally in the system catalogs, so if the file needs to be loaded again the same procedure is applied. どの場合でも、CREATE FUNCTIONコマンドに与えたファイル名はそのままシステムカタログに保存されます。 ですので、もしそのファイルを再度読み込む必要がある場合、同じ処理が適用されます。

注記

<productname>PostgreSQL</productname> will not compile a C function automatically. The object file must be compiled before it is referenced in a <command>CREATE FUNCTION</command> command. See <xref linkend="dfunc"/> for additional information. PostgreSQLはC関数を自動的にコンパイルしません。 CREATE FUNCTIONコマンドで参照する前に、そのオブジェクトファイルはコンパイルされていなければなりません。 さらなる情報については36.10.5を参照してください。

To ensure that a dynamically loaded object file is not loaded into an incompatible server, <productname>PostgreSQL</productname> checks that the file contains a <quote>magic block</quote> with the appropriate contents. This allows the server to detect obvious incompatibilities, such as code compiled for a different major version of <productname>PostgreSQL</productname>. To include a magic block, write this in one (and only one) of the module source files, after having included the header <filename>fmgr.h</filename>: 確実に、動的にロードされるモジュールが互換性がないサーバにロードされないように、PostgreSQLは、そのファイルに適切な内容を持つマジックブロックが含まれているかどうか検査します。 これによりサーバは、メジャーバージョンが異なるPostgreSQL用にコンパイルされたモジュールなど、明確に互換性がないことを検知できます。 マジックブロックを含めるためには、以下をモジュールのソースファイルに一度(一度だけ)、fmgr.hヘッダファイルをincludeさせた後で、記述してください。

PG_MODULE_MAGIC;

After it is used for the first time, a dynamically loaded object file is retained in memory. Future calls in the same session to the function(s) in that file will only incur the small overhead of a symbol table lookup. If you need to force a reload of an object file, for example after recompiling it, begin a fresh session. 最初に使用された後も、動的にロードされたオブジェクトファイルはメモリ内に保持されます。 同一セッションにおいてそのファイル内の関数をその後に呼び出した場合、シンボルテーブルの検索に要する小さなオーバーヘッドしかかかりません。 例えば再コンパイルした後など、そのオブジェクトファイルを強制的に再度読み込ませる必要がある場合は、新しいセッションを開始してください。

Optionally, a dynamically loaded file can contain an initialization function. If the file includes a function named <function>_PG_init</function>, that function will be called immediately after loading the file. The function receives no parameters and should return void. There is presently no way to unload a dynamically loaded file. 省略できますが、動的にロードされるファイルに初期化処理関数を含めることができます。 _PG_initという関数がファイルに存在すると、この関数はファイルがロードされた直後に呼び出されます。 この関数は引数を取らずvoid型を返さなければなりません。 現在、動的にロードされたファイルをアンロードする方法はありません。

36.10.2. C言語関数における基本型 #

<title>Base Types in C-Language Functions</title>

To know how to write C-language functions, you need to know how <productname>PostgreSQL</productname> internally represents base data types and how they can be passed to and from functions. Internally, <productname>PostgreSQL</productname> regards a base type as a <quote>blob of memory</quote>. The user-defined functions that you define over a type in turn define the way that <productname>PostgreSQL</productname> can operate on it. That is, <productname>PostgreSQL</productname> will only store and retrieve the data from disk and use your user-defined functions to input, process, and output the data. C言語関数の作成方法を理解するためには、PostgreSQLが基本データ型を内部でどのように表現し、どのようにそれらを関数とやり取りしているかを理解する必要があります。 内部的にPostgreSQLは基本型をメモリの小さな塊とみなします。 ある型を定義するユーザ定義関数は、言い換えると、PostgreSQLがそれを操作できる方法を定義します。 つまり、PostgreSQLはデータの格納、ディスクからの取り出しのみを行い、データの入力や処理、出力にはユーザ定義関数を使用します。

Base types can have one of three internal formats: 基本型は下記の3つのいずれかの内部書式を使用しています。

  • pass by value, fixed-length 固定長の値渡し

  • pass by reference, fixed-length 固定長の参照渡し

  • pass by reference, variable-length 可変長の参照渡し

By-value types can only be 1, 2, or 4 bytes in length (also 8 bytes, if <literal>sizeof(Datum)</literal> is 8 on your machine). You should be careful to define your types such that they will be the same size (in bytes) on all architectures. For example, the <literal>long</literal> type is dangerous because it is 4 bytes on some machines and 8 bytes on others, whereas <type>int</type> type is 4 bytes on most Unix machines. A reasonable implementation of the <type>int4</type> type on Unix machines might be: 値渡しは、1、2、4バイト長の型のみで使用できます(使用するマシンのsizeof(Datum)が8の場合は8バイトも使用できます)。 データ型を定義する際、その型がすべてのアーキテクチャにおいて同一の大きさ(バイト数)となるように定義するように注意してください。 例えば、long型はマシンによっては4バイトであったり、8バイトであったりして危険ですが、int型はほとんどのUnixマシンでは4バイトです。 Unixマシンにおけるint4の理論的な実装は以下のようになります。


/* 4-byte integer, passed by value */

/* 4 バイト整数、値渡し */
typedef int int4;

(The actual PostgreSQL C code calls this type <type>int32</type>, because it is a convention in C that <type>int<replaceable>XX</replaceable></type> means <replaceable>XX</replaceable> <emphasis>bits</emphasis>. Note therefore also that the C type <type>int8</type> is 1 byte in size. The SQL type <type>int8</type> is called <type>int64</type> in C. See also <xref linkend="xfunc-c-type-table"/>.) (実際のPostgreSQLのCコードではこの型をint32と呼びます。 intXXXX ビットであることはCにおける規約だからです。 したがってint8というCの型のサイズは1バイトであることに注意してください。 int8というSQLの型はCではint64と呼ばれます。 表 36.2も参照してください。)

On the other hand, fixed-length types of any size can be passed by-reference. For example, here is a sample implementation of a <productname>PostgreSQL</productname> type: 一方、任意の大きさの固定長の型は参照として引き渡すことができます。 例として以下にPostgreSQLの型の実装サンプルを示します。


/* 16-byte structure, passed by reference */

/* 16 バイト構造体、参照渡し */
typedef struct
{
    double  x, y;
} Point;

Only pointers to such types can be used when passing them in and out of <productname>PostgreSQL</productname> functions. To return a value of such a type, allocate the right amount of memory with <literal>palloc</literal>, fill in the allocated memory, and return a pointer to it. (Also, if you just want to return the same value as one of your input arguments that's of the same data type, you can skip the extra <literal>palloc</literal> and just return the pointer to the input value.) それらの型のポインタのみがPostgreSQL関数の入出力時に使用できます。 それらの型の値を返すためには、palloc()を使用して正しい大きさのメモリ領域を割り当て、そのメモリ領域に値を入力し、それのポインタを返します。 (また、入力引数の1つと同じ型かつ同じ値を返したいのであれば、pallocを行う手間を省くことができます。 この場合は入力値へのポインタを単に返してください。)

Finally, all variable-length types must also be passed by reference. All variable-length types must begin with an opaque length field of exactly 4 bytes, which will be set by <symbol>SET_VARSIZE</symbol>; never set this field directly! All data to be stored within that type must be located in the memory immediately following that length field. The length field contains the total length of the structure, that is, it includes the size of the length field itself. 最後に、すべての可変長型は参照として引き渡す必要があります。 また、すべての可変長型は正確に4バイトの不透明なlengthフィールドから始まる必要があります。 このフィールドはSET_VARSIZEで設定されます。決して直接このフィールドを設定してはいけません。 その型に格納されるすべてのデータはlengthフィールドのすぐ後のメモリ領域に置かれる必要があります。 lengthフィールドにはその構造体の総長が格納されます。つまり、lengthフィールドそのものもその大きさに含まれます。

Another important point is to avoid leaving any uninitialized bits within data type values; for example, take care to zero out any alignment padding bytes that might be present in structs. Without this, logically-equivalent constants of your data type might be seen as unequal by the planner, leading to inefficient (though not incorrect) plans. この他の重要な点は、データ型の値の中で初期化されていないビットを残さないことです。 例えば、構造体内に存在する可能性がある整列用のパディングバイトを注意してすべてゼロクリアしてください。 こうしないと、独自データ型の論理的に等価な定数がプランナにより一致しないものと判断され、(不正確ではありませんが)非効率的な計画をもたらすかもしれません。

警告

<emphasis>Never</emphasis> modify the contents of a pass-by-reference input value. If you do so you are likely to corrupt on-disk data, since the pointer you are given might point directly into a disk buffer. The sole exception to this rule is explained in <xref linkend="xaggr"/>. 参照渡しの入力値の内容を決して変更しないでください。 指定したポインタがディスクバッファを直接指し示している可能性がよくありますので、変更すると、ディスク上のデータを破壊してしまうかもしれません。 この規則の唯一の例外について36.12で説明します。

As an example, we can define the type <type>text</type> as follows: 例えば、text型を定義するには、下記のように行えます。

typedef struct {
    int32 length;
    char data[FLEXIBLE_ARRAY_MEMBER];
} text;

The <literal>[FLEXIBLE_ARRAY_MEMBER]</literal> notation means that the actual length of the data part is not specified by this declaration. [FLEXIBLE_ARRAY_MEMBER]表記は、データ部分の実際の長さはこの宣言では指定されないことを意味します。

When manipulating variable-length types, we must be careful to allocate the correct amount of memory and set the length field correctly. For example, if we wanted to store 40 bytes in a <structname>text</structname> structure, we might use a code fragment like this: 可変長型を操作する時、正確な大きさのメモリを割り当て、lengthフィールドを正確に設定することに注意する必要があります。 例えば、40バイトをtext構造体に保持させたい場合、下記のようなコードを使用します。

#include "postgres.h"
...

char buffer[40]; /* our source data */

char buffer[40]; /* 私たちの元のデータ */
...
text *destination = (text *) palloc(VARHDRSZ + 40);
SET_VARSIZE(destination, VARHDRSZ + 40);
memcpy(destination->data, buffer, 40);
...

<literal>VARHDRSZ</literal> is the same as <literal>sizeof(int32)</literal>, but it's considered good style to use the macro <literal>VARHDRSZ</literal> to refer to the size of the overhead for a variable-length type. Also, the length field <emphasis>must</emphasis> be set using the <literal>SET_VARSIZE</literal> macro, not by simple assignment. VARHDRSZsizeof(int32)と同一ですが、可変長型のオーバーヘッド分の大きさを参照する時には、VARHDRSZマクロを使用する方が好ましい形式とみなされています。 また長さフィールドを単なる代入ではなくSET_VARSIZEマクロを使用して設定しなければなりません

<xref linkend="xfunc-c-type-table"/> shows the C types corresponding to many of the built-in SQL data types of <productname>PostgreSQL</productname>. The <quote>Defined In</quote> column gives the header file that needs to be included to get the type definition. (The actual definition might be in a different file that is included by the listed file. It is recommended that users stick to the defined interface.) Note that you should always include <filename>postgres.h</filename> first in any source file of server code, because it declares a number of things that you will need anyway, and because including other headers first can cause portability issues. 表 36.2に、PostgreSQLの組み込みSQLデータ型の多くに関連するCの型を示します。 定義場所列でその定義を得るためにincludeすべきヘッダファイルがわかります(実際の定義は、リストされたファイルにincludeされている別のファイルにあるかもしれません。定義されたインタフェースだけをユーザは考慮することをお勧めします。) サーバのコードのソースファイルでは、必ずpostgres.hを最初にincludeすべきであることに注意してください。 なぜなら、結局必要になる多くのことを宣言していること、他のファイルを最初にincludeすると移植性の問題が起きる可能性があるからです。

表36.2 組み込みSQL型に相当するCの型

<title>Equivalent C Types for Built-in SQL Types</title>
SQL Type SQL型 C Type C 言語型 Defined In 定義場所
booleanboolpostgres.h(コンパイラで組み込み済みの可能性があります)
boxBOX*utils/geo_decls.h
byteabytea*postgres.h
"char"char(コンパイラで組み込み済み)
characterBpChar*postgres.h
cidCommandIdpostgres.h
dateDateADTutils/date.h
float4 (real)float4postgres.h
float8 (double precision)float8postgres.h
int2 (smallint)int16postgres.h
int4 (integer)int32postgres.h
int8 (bigint)int64postgres.h
intervalInterval*datatype/timestamp.h
lsegLSEG*utils/geo_decls.h
nameNamepostgres.h
numericNumericutils/numeric.h
oidOidpostgres.h
oidvectoroidvector*postgres.h
pathPATH*utils/geo_decls.h
pointPOINT*utils/geo_decls.h
regprocRegProcedurepostgres.h
texttext*postgres.h
tidItemPointerstorage/itemptr.h
timeTimeADTutils/date.h
time with time zoneTimeTzADTutils/date.h
timestampTimestampdatatype/timestamp.h
timestamp with time zoneTimestampTzdatatype/timestamp.h
varcharVarChar*postgres.h
xidTransactionIdpostgres.h

Now that we've gone over all of the possible structures for base types, we can show some examples of real functions. ここまでで基本型に関してあり得る構造体のすべてを記述しましたので、実際の関数の例をいくつか示すことができます。

36.10.3. Version 1 呼び出し規約 #

<title>Version 1 Calling Conventions</title>

The version-1 calling convention relies on macros to suppress most of the complexity of passing arguments and results. The C declaration of a version-1 function is always: Version-1呼び出し規約では、引数と結果の引き渡しの複雑さをなくすためにマクロを使用しています。 Version-1関数のC言語宣言は必ず下記のように行います。

Datum funcname(PG_FUNCTION_ARGS)

In addition, the macro call: さらに、マクロ呼び出し

PG_FUNCTION_INFO_V1(funcname);

must appear in the same source file. (Conventionally, it's written just before the function itself.) This macro call is not needed for <literal>internal</literal>-language functions, since <productname>PostgreSQL</productname> assumes that all internal functions use the version-1 convention. It is, however, required for dynamically-loaded functions. が同じソースファイルに書かれている必要があります。 (一般には、関数の直前に書かれます。) PostgreSQLではすべての内部関数はVersion-1であると認識するので、このマクロの呼び出しはinternal言語関数では必要ありません。 しかし、動的にロードされる関数では必要です。

In a version-1 function, each actual argument is fetched using a <function>PG_GETARG_<replaceable>xxx</replaceable>()</function> macro that corresponds to the argument's data type. (In non-strict functions there needs to be a previous check about argument null-ness using <function>PG_ARGISNULL()</function>; see below.) The result is returned using a <function>PG_RETURN_<replaceable>xxx</replaceable>()</function> macro for the return type. <function>PG_GETARG_<replaceable>xxx</replaceable>()</function> takes as its argument the number of the function argument to fetch, where the count starts at 0. <function>PG_RETURN_<replaceable>xxx</replaceable>()</function> takes as its argument the actual value to return. Version-1関数では、それぞれの実引数は、引数のデータ型に合ったPG_GETARG_xxx()マクロを使用して取り出されます。 (厳格でない関数では、PG_ARGISNULL()を使って引数がNULLかどうか事前に確認が必要です。下記参照。) 結果は戻り値の型に合ったPG_RETURN_xxx()マクロを使用して返されます。 PG_GETARG_xxx()は、その引数として、取り出す関数引数の番号(ゼロから始まります)を取ります。 PG_RETURN_xxx()は、その引数として、実際に返す値を取ります。

Here are some examples using the version-1 calling convention: Version-1呼出し規約を使った例をいくつか以下に示します。

#include "postgres.h"
#include <string.h>
#include "fmgr.h"
#include "utils/geo_decls.h"
#include "varatt.h"

PG_MODULE_MAGIC;


/* by value */

/* 値渡し */

PG_FUNCTION_INFO_V1(add_one);

Datum
add_one(PG_FUNCTION_ARGS)
{
    int32   arg = PG_GETARG_INT32(0);

    PG_RETURN_INT32(arg + 1);
}


/* by reference, fixed length */

/* 固定長の参照渡し */

PG_FUNCTION_INFO_V1(add_one_float8);

Datum
add_one_float8(PG_FUNCTION_ARGS)
{

    /* The macros for FLOAT8 hide its pass-by-reference nature. */

    /* FLOAT8用のマクロは参照渡しという性質を隠します */
    float8   arg = PG_GETARG_FLOAT8(0);

    PG_RETURN_FLOAT8(arg + 1.0);
}

PG_FUNCTION_INFO_V1(makepoint);

Datum
makepoint(PG_FUNCTION_ARGS)
{

    /* Here, the pass-by-reference nature of Point is not hidden. */

    /* ここのPoint型の参照渡しという性質は隠されていません */
    Point     *pointx = PG_GETARG_POINT_P(0);
    Point     *pointy = PG_GETARG_POINT_P(1);
    Point     *new_point = (Point *) palloc(sizeof(Point));

    new_point->x = pointx->x;
    new_point->y = pointy->y;

    PG_RETURN_POINT_P(new_point);
}


/* by reference, variable length */

/* 可変長の参照渡し */

PG_FUNCTION_INFO_V1(copytext);

Datum
copytext(PG_FUNCTION_ARGS)
{
    text     *t = PG_GETARG_TEXT_PP(0);

    /*

     * VARSIZE_ANY_EXHDR is the size of the struct in bytes, minus the
     * VARHDRSZ or VARHDRSZ_SHORT of its header.  Construct the copy with a
     * full-length header.

     * VARSIZEは、そのヘッダのVARHDRSZまたはVARHDRSZ_SHORTを引いた
     * 構造体の総長をバイト数で表したものです。
     * 完全な長さのヘッダと合わせたコピーを作成します。
     */
    text     *new_t = (text *) palloc(VARSIZE_ANY_EXHDR(t) + VARHDRSZ);
    SET_VARSIZE(new_t, VARSIZE_ANY_EXHDR(t) + VARHDRSZ);

    /*

     * VARDATA is a pointer to the data region of the new struct.  The source
     * could be a short datum, so retrieve its data through VARDATA_ANY.

     * VARDATAは新しい構造体のデータ領域へのポインタです。
     * コピー元はshortデータかもしれませんので、VARDATA_ANYでデータを取り出します。
     */
    memcpy(VARDATA(new_t),          /* destination */
           VARDATA_ANY(t),          /* source */
           VARSIZE_ANY_EXHDR(t));   /* how many bytes */
    PG_RETURN_TEXT_P(new_t);
}

PG_FUNCTION_INFO_V1(concat_text);

Datum
concat_text(PG_FUNCTION_ARGS)
{
    text  *arg1 = PG_GETARG_TEXT_PP(0);
    text  *arg2 = PG_GETARG_TEXT_PP(1);
    int32 arg1_size = VARSIZE_ANY_EXHDR(arg1);
    int32 arg2_size = VARSIZE_ANY_EXHDR(arg2);
    int32 new_text_size = arg1_size + arg2_size + VARHDRSZ;
    text *new_text = (text *) palloc(new_text_size);

    SET_VARSIZE(new_text, new_text_size);
    memcpy(VARDATA(new_text), VARDATA_ANY(arg1), arg1_size);
    memcpy(VARDATA(new_text) + arg1_size, VARDATA_ANY(arg2), arg2_size);
    PG_RETURN_TEXT_P(new_text);
}

Supposing that the above code has been prepared in file <filename>funcs.c</filename> and compiled into a shared object, we could define the functions to <productname>PostgreSQL</productname> with commands like this: 上のコードがファイルfuncs.cに用意されていて、共有オブジェクトにコンパイルされているとしたら、以下のようにPostgreSQLにコマンドで関数を定義できます。

CREATE FUNCTION add_one(integer) RETURNS integer
     AS 'DIRECTORY/funcs', 'add_one'
     LANGUAGE C STRICT;


&#45;- note overloading of SQL function name "add_one"

-- SQL関数名"add_one"のオーバーロードに注意
CREATE FUNCTION add_one(double precision) RETURNS double precision
     AS 'DIRECTORY/funcs', 'add_one_float8'
     LANGUAGE C STRICT;

CREATE FUNCTION makepoint(point, point) RETURNS point
     AS 'DIRECTORY/funcs', 'makepoint'
     LANGUAGE C STRICT;

CREATE FUNCTION copytext(text) RETURNS text
     AS 'DIRECTORY/funcs', 'copytext'
     LANGUAGE C STRICT;

CREATE FUNCTION concat_text(text, text) RETURNS text
     AS 'DIRECTORY/funcs', 'concat_text'
     LANGUAGE C STRICT;

Here, <replaceable>DIRECTORY</replaceable> stands for the directory of the shared library file (for instance the <productname>PostgreSQL</productname> tutorial directory, which contains the code for the examples used in this section). (Better style would be to use just <literal>'funcs'</literal> in the <literal>AS</literal> clause, after having added <replaceable>DIRECTORY</replaceable> to the search path. In any case, we can omit the system-specific extension for a shared library, commonly <literal>.so</literal>.) ここでは、DIRECTORYは共有ライブラリファイルのディレクトリ(例えばPostgreSQLのチュートリアルのディレクトリ、そこにはこの節で使われている例のコードがあります)を表しています。 (DIRECTORYを検索パスに追加した後にAS句で'funcs'だけを使うのがより良いやり方でしょう。 どの場合でも、共有ライブラリを表すシステムに特有の拡張子、普通は.soを省略できます。)

Notice that we have specified the functions as <quote>strict</quote>, meaning that the system should automatically assume a null result if any input value is null. By doing this, we avoid having to check for null inputs in the function code. Without this, we'd have to check for null values explicitly, using <function>PG_ARGISNULL()</function>. 関数をstrictと指定したことに注意してください。これは入力値のいずれかがNULLだった場合、システムが自動的に結果をNULLと決めてしまうことを意味します。 こうすることで、関数のコード内でNULLの入力を確認しなければならないことを避けています。 これがなければ、PG_ARGISNULL()を使ってNULL値を明示的に確認しなければなりません。

The macro <function>PG_ARGISNULL(<replaceable>n</replaceable>)</function> allows a function to test whether each input is null. (Of course, doing this is only necessary in functions not declared <quote>strict</quote>.) As with the <function>PG_GETARG_<replaceable>xxx</replaceable>()</function> macros, the input arguments are counted beginning at zero. Note that one should refrain from executing <function>PG_GETARG_<replaceable>xxx</replaceable>()</function> until one has verified that the argument isn't null. To return a null result, execute <function>PG_RETURN_NULL()</function>; this works in both strict and nonstrict functions. PG_ARGISNULL(n)マクロにより関数は各入力がNULLであるかどうかの検査を行うことができます。 (もちろんこれは、厳密と宣言されていない関数でのみ必要です。) PG_GETARG_xxx()マクロと同様、入力引数の番号はゼロから始まります。 引数がNULLでないことを確認するまでは、PG_GETARG_xxx()の実行は控えなければなりません。 結果としてNULLを返す場合は、PG_RETURN_NULL()を実行します。 これは、厳密な関数と厳密でない関数の両方で使用可能です。

At first glance, the version-1 coding conventions might appear to be just pointless obscurantism, compared to using plain <literal>C</literal> calling conventions. They do however allow us to deal with <literal>NULL</literal>able arguments/return values, and <quote>toasted</quote> (compressed or out-of-line) values. 一見、Version-1のコーディング規約は、普通のCの呼出し規約と比較すると、無意味なあいまいなものの様に見えるかもしれません。 しかし、NULLになりうる引数や戻り値、TOASTされた(圧縮または行外)値を扱うことができます。

Other options provided by the version-1 interface are two variants of the <function>PG_GETARG_<replaceable>xxx</replaceable>()</function> macros. The first of these, <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function>, guarantees to return a copy of the specified argument that is safe for writing into. (The normal macros will sometimes return a pointer to a value that is physically stored in a table, which must not be written to. Using the <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function> macros guarantees a writable result.) The second variant consists of the <function>PG_GETARG_<replaceable>xxx</replaceable>_SLICE()</function> macros which take three arguments. The first is the number of the function argument (as above). The second and third are the offset and length of the segment to be returned. Offsets are counted from zero, and a negative length requests that the remainder of the value be returned. These macros provide more efficient access to parts of large values in the case where they have storage type <quote>external</quote>. (The storage type of a column can be specified using <literal>ALTER TABLE <replaceable>tablename</replaceable> ALTER COLUMN <replaceable>colname</replaceable> SET STORAGE <replaceable>storagetype</replaceable></literal>. <replaceable>storagetype</replaceable> is one of <literal>plain</literal>, <literal>external</literal>, <literal>extended</literal>, or <literal>main</literal>.) Version 1のインタフェースでは、その他のオプションとしてPG_GETARG_xxx()マクロの変形を2つ提供しています。 1つ目のPG_GETARG_xxx_COPY()によって、安全に書き込むことができる指定引数のコピーが確実に返されます。 (通常のマクロは、物理的にテーブルに格納されている値へのポインタを返すことがあるので、書き込んではなりません。 PG_GETARG_xxx_COPY()マクロの結果は書き込み可能であることが保証されています。) 2つ目の変形は、引数を3つ取るPG_GETARG_xxx_SLICE()マクロからなります。 1つ目は関数の引数の番号(上記の通り)です。 2つ目と3つ目は、オフセットと返されるセグメントの長さです。 オフセットはゼロから始まり、負の長さは残りの値を返すことを要求します。 これらのマクロを使用すると、ストレージ種類がexternal(外部)である大きな値の一部へアクセスする際に非常に効果的です。 (列のストレージ種類はALTER TABLE tablename ALTER COLUMN colname SET STORAGE storagetypeを使用して指定できます。 storagetypeは、plainexternalextended、またはmainのいずれかです。)

Finally, the version-1 function call conventions make it possible to return set results (<xref linkend="xfunc-c-return-set"/>) and implement trigger functions (<xref linkend="triggers"/>) and procedural-language call handlers (<xref linkend="plhandler"/>). For more details see <filename>src/backend/utils/fmgr/README</filename> in the source distribution. 最後に、Version-1関数呼び出し規約では、結果集合(36.10.8)を返すこと、およびトリガ関数(第37章)と手続型言語の呼び出しハンドラ(第56章)を実装できます。 詳細についてはソース配布物内のsrc/backend/utils/fmgr/READMEを参照してください。

36.10.4. コードの作成 #

<title>Writing Code</title>

Before we turn to the more advanced topics, we should discuss some coding rules for <productname>PostgreSQL</productname> C-language functions. While it might be possible to load functions written in languages other than C into <productname>PostgreSQL</productname>, this is usually difficult (when it is possible at all) because other languages, such as C++, FORTRAN, or Pascal often do not follow the same calling convention as C. That is, other languages do not pass argument and return values between functions in the same way. For this reason, we will assume that your C-language functions are actually written in C. より先進的な話題に入る前に、PostgreSQL C言語関数のコーディングについての規則をいくつか説明します。 C言語以外の言語で記述した関数をPostgreSQLに組み込みむことは可能であるかもしれませんが、例えばC++、FORTRANやPascalといった言語はC言語と同じ呼び出し規約に従いませんので、多くの場合、(可能であったとしても)困難です。 それはつまり、他の言語では同じ方法で関数に引数を渡したり、関数から結果を返すことを行わないということです。 このため、C言語関数は実際にC言語で書かれているものと仮定します。

The basic rules for writing and building C functions are as follows: C関数の作成と構築の基本規則を以下に示します。

  • Use <literal>pg_config &#45;-includedir-server</literal><indexterm><primary>pg_config</primary><secondary>with user-defined C functions</secondary></indexterm> to find out where the <productname>PostgreSQL</productname> server header files are installed on your system (or the system that your users will be running on). pg_config --includedir-serverを使用して、使用中のシステム(もしくはユーザが実行するシステム)にてPostgreSQLサーバのヘッダファイルがインストールされた場所を見つけます。

  • Compiling and linking your code so that it can be dynamically loaded into <productname>PostgreSQL</productname> always requires special flags. See <xref linkend="dfunc"/> for a detailed explanation of how to do it for your particular operating system. PostgreSQLに動的にロードできるように独自コードをコンパイル/リンクする時には常に、特別なフラグが必要となります。 特定のオペレーティングシステムにおけるコンパイル/リンク方法については36.10.5を参照してください。

  • Remember to define a <quote>magic block</quote> for your shared library, as described in <xref linkend="xfunc-c-dynload"/>. 忘れずに36.10.1で説明したマジックブロックを共有ライブラリで定義してください。

  • When allocating memory, use the <productname>PostgreSQL</productname> functions <function>palloc</function><indexterm><primary>palloc</primary></indexterm> and <function>pfree</function><indexterm><primary>pfree</primary></indexterm> instead of the corresponding C library functions <function>malloc</function> and <function>free</function>. The memory allocated by <function>palloc</function> will be freed automatically at the end of each transaction, preventing memory leaks. メモリを割り当てる際、Cライブラリのmallocfreeではなく、PostgreSQLpallocpfreeを使用してください。 pallocで割り当てられたメモリは各トランザクションの終わりに自動的に解放され、メモリリークを防ぎます。

  • Always zero the bytes of your structures using <function>memset</function> (or allocate them with <function>palloc0</function> in the first place). Even if you assign to each field of your structure, there might be alignment padding (holes in the structure) that contain garbage values. Without this, it's difficult to support hash indexes or hash joins, as you must pick out only the significant bits of your data structure to compute a hash. The planner also sometimes relies on comparing constants via bitwise equality, so you can get undesirable planning results if logically-equivalent values aren't bitwise equal. memsetを使用して、構造体を必ずゼロクリアしてください(または最初の段階でpalloc0を用いて割り当ててください)。 構造体の各フィールドを割り当てたとしても、ゴミの値を持つ整列用のパディング(構造体内の穴)があるかもしれません。 こうしないと、ハッシュインデックスやハッシュ結合をサポートすることが困難です。 ハッシュを計算するには、データ構造体内の有意なビットのみを取り出す必要があるためです。 プランナはまた時折ビット単位の等価性を用いて定数の比較を行います。 このため論理的にな値がビット単位で等価でない場合に望まない計画になってしまう可能性があります。

  • Most of the internal <productname>PostgreSQL</productname> types are declared in <filename>postgres.h</filename>, while the function manager interfaces (<symbol>PG_FUNCTION_ARGS</symbol>, etc.) are in <filename>fmgr.h</filename>, so you will need to include at least these two files. For portability reasons it's best to include <filename>postgres.h</filename> <emphasis>first</emphasis>, before any other system or user header files. Including <filename>postgres.h</filename> will also include <filename>elog.h</filename> and <filename>palloc.h</filename> for you. ほとんどのPostgreSQLの内部型はpostgres.hに宣言されています。 一方、関数管理インタフェース(PG_FUNCTION_ARGSなど)はfmgr.hで宣言されています。 したがって、少なくともこの2つのファイルをincludeする必要があります。 移植性に関する理由により、postgres.hをその他のシステムヘッダファイル、ユーザヘッダファイルよりも先にincludeしておくことが最善です。 postgres.hをincludeすることはelog.hpalloc.hもincludeすることになります。

  • Symbol names defined within object files must not conflict with each other or with symbols defined in the <productname>PostgreSQL</productname> server executable. You will have to rename your functions or variables if you get error messages to this effect. オブジェクトファイルで定義されているシンボル名は、互いに、またはPostgreSQLサーバの実行ファイルで定義されているものと異なっている必要があります。 これに関するエラーが表示される場合は、関数名または変数名を変更する必要があります。

doc/src/sgml/dfunc.sgml

36.10.5. 動的にロードされる関数のコンパイルとリンク #

<title>Compiling and Linking Dynamically-Loaded Functions</title>

Before you are able to use your <productname>PostgreSQL</productname> extension functions written in C, they must be compiled and linked in a special way to produce a file that can be dynamically loaded by the server. To be precise, a <firstterm>shared library</firstterm> needs to be created.<indexterm><primary>shared library</primary></indexterm> Cで書かれたPostgreSQLの拡張関数を使うためには、サーバが動的にロードできるように特別な方法でコンパイルとリンクを行う必要があります。 正確には共有ライブラリを作る必要があります。

For information beyond what is contained in this section you should read the documentation of your operating system, in particular the manual pages for the C compiler, <command>cc</command>, and the link editor, <command>ld</command>. In addition, the <productname>PostgreSQL</productname> source code contains several working examples in the <filename>contrib</filename> directory. If you rely on these examples you will make your modules dependent on the availability of the <productname>PostgreSQL</productname> source code, however. 本節の説明以上の詳しい情報はオペレーティングシステムのドキュメント、特にCコンパイラccとリンクエディタldのマニュアルページを参照してください。 さらに、PostgreSQLのソースコードのcontribディレクトリにいくつか実例があります。 しかし、もしこれらの例に頼るとPostgreSQLソースコードが利用できることに依存したモジュールが作られてしまいます。

Creating shared libraries is generally analogous to linking executables: first the source files are compiled into object files, then the object files are linked together. The object files need to be created as <firstterm>position-independent code</firstterm> (<acronym>PIC</acronym>),<indexterm><primary>PIC</primary></indexterm> which conceptually means that they can be placed at an arbitrary location in memory when they are loaded by the executable. (Object files intended for executables are usually not compiled that way.) The command to link a shared library contains special flags to distinguish it from linking an executable (at least in theory &mdash; on some systems the practice is much uglier). 共有ライブラリの作成は一般的に実行プログラムのリンクに類似しています。 まずソースファイルがオブジェクトファイルにコンパイルされ、そのオブジェクトファイル同士がリンクされます。 これらのオブジェクトファイルは位置独立なコードPIC)として作られる必要があります。 それは概念的には、実行プログラムから呼び出される時にメモリの適当な場所に置くことができるということです (実行プログラム用として作られたオブジェクトファイルはそのようにはコンパイルされません)。 共有ライブラリをリンクするコマンドは実行プログラムのリンクと区別するための特別なフラグがあります(少なくとも理論上ではそのようになっています。システムによってはもっと醜い実際が見受けられます)。

In the following examples we assume that your source code is in a file <filename>foo.c</filename> and we will create a shared library <filename>foo.so</filename>. The intermediate object file will be called <filename>foo.o</filename> unless otherwise noted. A shared library can contain more than one object file, but we only use one here. 次の例ではソースコードはfoo.cファイルにあると仮定し、foo.soという共有ライブラリを作るとします。 中間のオブジェクトファイルは特別な記述がない限りfoo.oと呼ばれます。 共有ライブラリは1つ以上のオブジェクトファイルを持つことができますが、ここでは1つしか使いません。

Note: Reading GNU Libtool sources is generally a good way of figuring out this information. The methods used within PostgreSQL source code are not necessarily ideal.
FreeBSD

The compiler flag to create <acronym>PIC</acronym> is <option>-fPIC</option>. To create shared libraries the compiler flag is <option>-shared</option>. PICを作るためのコンパイラフラグは-fPICです。 共有ライブラリを作るコンパイラフラグは-sharedです。

cc -fPIC -c foo.c
cc -shared -o foo.so foo.o

This is applicable as of version 13.0 of <systemitem class="osname">FreeBSD</systemitem>, older versions used the <filename>gcc</filename> compiler. 《マッチ度[51.351351]》これはFreeBSDのバージョン3.0に適用されます。 《機械翻訳》これはFreeBSDのバージョン13.0で適用されます。 古いバージョンではgccコンパイラを使用していました。

Linux

The compiler flag to create <acronym>PIC</acronym> is <option>-fPIC</option>. The compiler flag to create a shared library is <option>-shared</option>. A complete example looks like this: PICを作るためのコンパイラフラグは-fPICです。 共有ライブラリを作るコンパイラフラグは-sharedです。 完全な例は下記のようになります。

cc -fPIC -c foo.c
cc -shared -o foo.so foo.o

macOS

Here is an example. It assumes the developer tools are installed. 例を以下に示します。 開発者用ツールがインストールされていることが前提です。

cc -c foo.c
cc -bundle -flat_namespace -undefined suppress -o foo.so foo.o

NetBSD

The compiler flag to create <acronym>PIC</acronym> is <option>-fPIC</option>. For <acronym>ELF</acronym> systems, the compiler with the flag <option>-shared</option> is used to link shared libraries. On the older non-ELF systems, <literal>ld -Bshareable</literal> is used. PICを作るためのコンパイラフラグは-fPICです。 ELFシステムでは-sharedコンパイラフラグを使用して共有ライブラリをリンクします。 より古い非ELFシステムではld -Bshareableが使われます。

gcc -fPIC -c foo.c
gcc -shared -o foo.so foo.o

OpenBSD

The compiler flag to create <acronym>PIC</acronym> is <option>-fPIC</option>. <literal>ld -Bshareable</literal> is used to link shared libraries. PICを作成するためのコンパイラフラグは-fPICです。 共有ライブラリをリンクするにはld -Bshareableを使用します。

gcc -fPIC -c foo.c
ld -Bshareable -o foo.so foo.o

Solaris

The compiler flag to create <acronym>PIC</acronym> is <option>-KPIC</option> with the Sun compiler and <option>-fPIC</option> with <application>GCC</application>. To link shared libraries, the compiler option is <option>-G</option> with either compiler or alternatively <option>-shared</option> with <application>GCC</application>. PICを作るためのコンパイラフラグはSunコンパイラでは-KPICで、GCCでは-fPICです。 共有ライブラリをリンクするためには、どちらのコンパイラでもコンパイラオプションは-Gで、GCCの場合、代わりに-sharedオプションを使うこともできます。

cc -KPIC -c foo.c
cc -G -o foo.so foo.o

or もしくは

gcc -fPIC -c foo.c
gcc -G -o foo.so foo.o

ヒント

If this is too complicated for you, you should consider using <ulink url="https://www.gnu.org/software/libtool/"> <productname>GNU Libtool</productname></ulink>, which hides the platform differences behind a uniform interface. これがあまりに難しいようであれば、GNU Libtoolの使用を検討すべきです。 これはプラットフォームの違いを、統一されたインタフェースで判らないようにします。

The resulting shared library file can then be loaded into <productname>PostgreSQL</productname>. When specifying the file name to the <command>CREATE FUNCTION</command> command, one must give it the name of the shared library file, not the intermediate object file. Note that the system's standard shared-library extension (usually <literal>.so</literal> or <literal>.sl</literal>) can be omitted from the <command>CREATE FUNCTION</command> command, and normally should be omitted for best portability. これで完成した共有ライブラリファイルはPostgreSQLにロードすることができます。 CREATE FUNCTIONコマンドにファイル名を指定する時には、中間オブジェクトファイルではなく共有ライブラリファイルの名前を与えてください。 システムの標準共有ライブラリ用の拡張子(通常.soあるいは.sl)はCREATE FUNCTIONで省略することができ、そして移植性を最も高くするため通常は省略されます。

Refer back to <xref linkend="xfunc-c-dynload"/> about where the server expects to find the shared library files. サーバがライブラリファイルをどこに見つけるかに関しては36.10.1を見直してください。

36.10.6. 複合型引数 #

<title>Composite-Type Arguments</title>

Composite types do not have a fixed layout like C structures. Instances of a composite type can contain null fields. In addition, composite types that are part of an inheritance hierarchy can have different fields than other members of the same inheritance hierarchy. Therefore, <productname>PostgreSQL</productname> provides a function interface for accessing fields of composite types from C. 複合型ではCの構造体のような固定のレイアウトがありません。 複合型のインスタンスはNULLフィールドを持つことができます。 さらに、複合型で継承階層の一部であるものは、同じ継承階層の他のメンバとは異なるフィールドを持つこともできます。 そのため、PostgreSQLはC言語から複合型のフィールドにアクセスするための関数インタフェースを提供します。

Suppose we want to write a function to answer the query: 以下のような問い合わせに答える関数を書こうとしていると仮定します。

SELECT name, c_overpaid(emp, 1500) AS overpaid
    FROM emp
    WHERE name = 'Bill' OR name = 'Sam';

Using the version-1 calling conventions, we can define <function>c_overpaid</function> as: Version 1呼び出し規約を使用すると、c_overpaidは以下のように定義できます。

#include "postgres.h"

#include "executor/executor.h"  /* for GetAttributeByName() */

#include "executor/executor.h"  /* GetAttributeByName()用 */

PG_MODULE_MAGIC;

PG_FUNCTION_INFO_V1(c_overpaid);

Datum
c_overpaid(PG_FUNCTION_ARGS)
{
    HeapTupleHeader  t = PG_GETARG_HEAPTUPLEHEADER(0);
    int32            limit = PG_GETARG_INT32(1);
    bool isnull;
    Datum salary;

    salary = GetAttributeByName(t, "salary", &isnull);
    if (isnull)
        PG_RETURN_BOOL(false);

    /* Alternatively, we might prefer to do PG_RETURN_NULL() for null salary. */

    /* この他、salaryがNULLの場合用にPG_RETURN_NULL()を行った方が良いでしょう */

    PG_RETURN_BOOL(DatumGetInt32(salary) > limit);
}

<function>GetAttributeByName</function> is the <productname>PostgreSQL</productname> system function that returns attributes out of the specified row. It has three arguments: the argument of type <type>HeapTupleHeader</type> passed into the function, the name of the desired attribute, and a return parameter that tells whether the attribute is null. <function>GetAttributeByName</function> returns a <type>Datum</type> value that you can convert to the proper data type by using the appropriate <function>DatumGet<replaceable>XXX</replaceable>()</function> function. Note that the return value is meaningless if the null flag is set; always check the null flag before trying to do anything with the result. GetAttributeByNameは、指定された行から属性を返す、PostgreSQLシステム関数です。 これには3つの引数があります。 それらは、関数に渡されたHeapTupleHeader型の引数、求められた属性の名前、属性がNULLであるかどうかを通知する返りパラメータです。 GetAttributeByNameは適切なDatumGetXXX()関数を使用して適切なデータ型に変換可能なDatum型の値を返します。 このNULLフラグが設定されている場合、戻り値の意味がないことに注意し、この結果で何かを行おうとする前に常に、NULLフラグを検査してください。

There is also <function>GetAttributeByNum</function>, which selects the target attribute by column number instead of name. 対象列を名前ではなく列番号で選択するGetAttributeByNumもあります。

The following command declares the function <function>c_overpaid</function> in SQL: 下記のコマンドでc_overpaid関数をSQLで宣言します。

CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean
    AS 'DIRECTORY/funcs', 'c_overpaid'
    LANGUAGE C STRICT;

Notice we have used <literal>STRICT</literal> so that we did not have to check whether the input arguments were NULL. 入力引数がNULLかどうかを検査する必要がないようにSTRICTを使用していることに注意してください。

36.10.7. 行(複合型)を返す #

<title>Returning Rows (Composite Types)</title>

To return a row or composite-type value from a C-language function, you can use a special API that provides macros and functions to hide most of the complexity of building composite data types. To use this API, the source file must include: C言語関数から行もしくは複合型の値を返すために、複合型の複雑な作成のほとんどを隠蔽するマクロや関数を提供する、特別なAPIを使用できます。 このAPIを使用するためには、ソースファイルで以下をincludeする必要があります。

#include "funcapi.h"

There are two ways you can build a composite data value (henceforth a <quote>tuple</quote>): you can build it from an array of Datum values, or from an array of C strings that can be passed to the input conversion functions of the tuple's column data types. In either case, you first need to obtain or construct a <structname>TupleDesc</structname> descriptor for the tuple structure. When working with Datums, you pass the <structname>TupleDesc</structname> to <function>BlessTupleDesc</function>, and then call <function>heap_form_tuple</function> for each row. When working with C strings, you pass the <structname>TupleDesc</structname> to <function>TupleDescGetAttInMetadata</function>, and then call <function>BuildTupleFromCStrings</function> for each row. In the case of a function returning a set of tuples, the setup steps can all be done once during the first call of the function. 複合型のデータ値(以降タプルと記す)を作成する2つの方法があります。 Datum値の配列から作成する方法、もしくはタプルのある列の型の入力変換関数に渡すことができるC文字列の配列から作成することです。 どちらの方法でも、まずタプル構造体用のTupleDesc記述子を入手、あるいは作成しなければなりません。 Datumを使用する場合は、TupleDescBlessTupleDescに渡し、各行に対してheap_form_tupleを呼び出します。 C文字列を使用する場合は、TupleDescTupleDescGetAttInMetadataに渡し、各行に対して BuildTupleFromCStringsを呼び出します。 タプルの集合を返す関数の場合、この設定段階を最初の関数呼び出しで一度にまとめて行うことができます。

Several helper functions are available for setting up the needed <structname>TupleDesc</structname>. The recommended way to do this in most functions returning composite values is to call: 必要なTupleDescの設定用の補助用関数がいくつかあります。 ほとんどの複合型を返す関数での推奨方法は、以下の関数を呼び出し、

TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo,
                                   Oid *resultTypeId,
                                   TupleDesc *resultTupleDesc)

passing the same <literal>fcinfo</literal> struct passed to the calling function itself. (This of course requires that you use the version-1 calling conventions.) <varname>resultTypeId</varname> can be specified as <literal>NULL</literal> or as the address of a local variable to receive the function's result type OID. <varname>resultTupleDesc</varname> should be the address of a local <structname>TupleDesc</structname> variable. Check that the result is <literal>TYPEFUNC_COMPOSITE</literal>; if so, <varname>resultTupleDesc</varname> has been filled with the needed <structname>TupleDesc</structname>. (If it is not, you can report an error along the lines of <quote>function returning record called in context that cannot accept type record</quote>.) 呼び出し元の関数自身に渡されるfcinfo構造体と同じものを渡すことです。 (これにはもちろん、version 1呼び出し規約を使用していることが必要です。) resultTypeIdNULLとすることも、ローカル変数のアドレスを指定して関数の戻り値型のOIDを受け取ることができます。 resultTupleDescはローカルなTupleDesc変数のアドレスでなければなりません。 結果がTYPEFUNC_COMPOSITEかどうかを確認してください。 TYPEFUNC_COMPOSITEであった場合、resultTupleDescには必要なTupleDescが格納されています。 (TYPEFUNC_COMPOSITEではなかった場合、function returning record called in context that cannot accept type record(レコード型を受け付けられないコンテキストでレコードを返す関数が呼び出されました)というエラーを報告できます。)

ヒント

<function>get_call_result_type</function> can resolve the actual type of a polymorphic function result; so it is useful in functions that return scalar polymorphic results, not only functions that return composites. The <varname>resultTypeId</varname> output is primarily useful for functions returning polymorphic scalars. get_call_result_typeは、多様性関数の結果の実際の型を解決できます。 ですので、複合型を返す関数だけではなく、スカラの多様結果を返す関数でも有意です。 resultTypeId出力は主にスカラの多様結果を返す関数で有意です。

注記

<function>get_call_result_type</function> has a sibling <function>get_expr_result_type</function>, which can be used to resolve the expected output type for a function call represented by an expression tree. This can be used when trying to determine the result type from outside the function itself. There is also <function>get_func_result_type</function>, which can be used when only the function's OID is available. However these functions are not able to deal with functions declared to return <structname>record</structname>, and <function>get_func_result_type</function> cannot resolve polymorphic types, so you should preferentially use <function>get_call_result_type</function>. get_call_result_typeは、get_expr_result_typeと似たような関数で、関数呼び出しで想定される出力型を式のツリー構造として解決します。 関数自身以外から結果型を決定したい場合に、これを使用できます。 また、get_func_result_typeという関数もあります。 これは関数のOIDが利用できる場合にのみ使用できます。 しかし、これらの関数は、record型を返すものと宣言された関数では使用できません。 また、get_func_result_typeは多様型を解決できません。 したがって、優先してget_call_result_typeを使用すべきです。

Older, now-deprecated functions for obtaining <structname>TupleDesc</structname>s are: 古く、廃止予定のTupleDescを入手するための関数を以下に示します。

TupleDesc RelationNameGetTupleDesc(const char *relname)

to get a <structname>TupleDesc</structname> for the row type of a named relation, and: これを指名したリレーションの行型用のTupleDescを取り出すために使用してください。 また、

TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)

to get a <structname>TupleDesc</structname> based on a type OID. This can be used to get a <structname>TupleDesc</structname> for a base or composite type. It will not work for a function that returns <structname>record</structname>, however, and it cannot resolve polymorphic types. これを型のOIDに基づいてTupleDescを取り出すために使用してください。 これは、基本型もしくは複合型のTupleDescを取り出すために使用可能です。 これはrecordを返す関数ではうまく動作しません。 また、多様型を解決することもできません。

Once you have a <structname>TupleDesc</structname>, call: TupleDescを獲得した後に、Datumを使用する場合は以下を呼び出してください。

TupleDesc BlessTupleDesc(TupleDesc tupdesc)

if you plan to work with Datums, or: C文字列を使用する場合は以下を呼び出してください。

AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)

if you plan to work with C strings. If you are writing a function returning set, you can save the results of these functions in the <structname>FuncCallContext</structname> structure &mdash; use the <structfield>tuple_desc</structfield> or <structfield>attinmeta</structfield> field respectively. 集合を返す関数を作成する場合は、これらの関数の結果をFuncCallContext構造体に格納してください。 それぞれtuple_descattinmetaを使用します。

When working with Datums, use: Datumを使用する場合は、以下を使用して

HeapTuple heap_form_tuple(TupleDesc tupdesc, Datum *values, bool *isnull)

to build a <structname>HeapTuple</structname> given user data in Datum form. ユーザデータをDatum形式に格納したHeapTupleを構築し、

When working with C strings, use: C文字列を使用する場合は、以下を使用して

HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)

to build a <structname>HeapTuple</structname> given user data in C string form. <parameter>values</parameter> is an array of C strings, one for each attribute of the return row. Each C string should be in the form expected by the input function of the attribute data type. In order to return a null value for one of the attributes, the corresponding pointer in the <parameter>values</parameter> array should be set to <symbol>NULL</symbol>. This function will need to be called again for each row you return. ユーザデータをC文字列形式に格納したHeapTupleを構築します。 valuesは行の各属性を1要素としたC文字列の配列です。 各C文字列は、属性のデータ型用の入力関数が受け付け可能な形式でなければなりません。 属性の値をNULL値として返すためには、values配列の対応するポインタにNULLを設定してください。 この関数は返す行それぞれに対して繰り返し呼び出す必要があります。

Once you have built a tuple to return from your function, it must be converted into a <type>Datum</type>. Use: 関数から返すタプルを構築し終わったら、それをDatumに変換しなければなりません。 以下を使用して、

HeapTupleGetDatum(HeapTuple tuple)

to convert a <structname>HeapTuple</structname> into a valid Datum. This <type>Datum</type> can be returned directly if you intend to return just a single row, or it can be used as the current return value in a set-returning function. HeapTupleを有効なDatumに変換してください。 単一行のみを返すのであれば、このDatumを直接返すことができます。 さもなくば、集合を返す関数における現在の戻り値として使用できます。

An example appears in the next section. 次節に例を示します。

36.10.8. 集合を返す #

<title>Returning Sets</title>

C-language functions have two options for returning sets (multiple rows). In one method, called <firstterm>ValuePerCall</firstterm> mode, a set-returning function is called repeatedly (passing the same arguments each time) and it returns one new row on each call, until it has no more rows to return and signals that by returning NULL. The set-returning function (<acronym>SRF</acronym>) must therefore save enough state across calls to remember what it was doing and return the correct next item on each call. In the other method, called <firstterm>Materialize</firstterm> mode, an SRF fills and returns a tuplestore object containing its entire result; then only one call occurs for the whole result, and no inter-call state is needed. C言語関数から集合(複数行)を返すには2つ選択肢があります。 一つは、ValuePerCallモードと呼ばれる方法で、集合を返す関数が繰り返し呼び出され(毎回同じ引数を渡します)、返す行がなくなるまで呼び出しごとに1つの新しい行を返し、返す行がなくなったらNULLを返します。 したがって、集合を返す関数(SRF)は、呼び出し間に十分な状態を保存し何をしていたかを記憶して、呼び出しの度に次の項目を返す必要があります。 もう一つは、Materializeモードと呼ばれる方法で、集合を返す関数は結果全体を含むタプルストアオブジェクトを埋めて返します。 結果全体に対して1つの呼び出しだけが発生し、呼び出し間の状態は必要ありません。

When using ValuePerCall mode, it is important to remember that the query is not guaranteed to be run to completion; that is, due to options such as <literal>LIMIT</literal>, the executor might stop making calls to the set-returning function before all rows have been fetched. This means it is not safe to perform cleanup activities in the last call, because that might not ever happen. It's recommended to use Materialize mode for functions that need access to external resources, such as file descriptors. ValuePerCallモードを使用する場合、問い合わせが完全に実行される保証はないことに注意してください。 つまり、LIMITなどのオプションがあるため、全ての行をフェッチする前に、エグゼキュータが集合を返す関数の呼び出しを中止することがあります。 これは、実行されない可能性があるため、最後の呼び出しでクリーンアップ活動を実行するのは安全ではないことを意味します。 ファイル記述子などの外部リソースにアクセスする必要がある関数には、Materializeモードを使用することをお勧めします。

The remainder of this section documents a set of helper macros that are commonly used (though not required to be used) for SRFs using ValuePerCall mode. Additional details about Materialize mode can be found in <filename>src/backend/utils/fmgr/README</filename>. Also, the <filename>contrib</filename> modules in the <productname>PostgreSQL</productname> source distribution contain many examples of SRFs using both ValuePerCall and Materialize mode. 本節の残りの部分では、ValuePerCallモードを使用する集合を返す関数で一般に使用される補助マクロのセット(ただし、使用は必須ではありませんが)について説明します。 Materializeモードの詳細については、src/backend/utils/fmgr/READMEを参照してください。 また、PostgreSQLソース配布物内のcontribモジュールには、ValuePerCallとMaterializeモードの両方を使用する、集合を返す関数のより多くの例があります。

To use the ValuePerCall support macros described here, include <filename>funcapi.h</filename>. These macros work with a structure <structname>FuncCallContext</structname> that contains the state that needs to be saved across calls. Within the calling SRF, <literal>fcinfo-&gt;flinfo-&gt;fn_extra</literal> is used to hold a pointer to <structname>FuncCallContext</structname> across calls. The macros automatically fill that field on first use, and expect to find the same pointer there on subsequent uses. ここで説明するValuePerCallサポートマクロを使用するには、funcapi.hをincludeします。 これらのマクロは、複数の呼び出しにわたって保存する必要がある状態を含むFuncCallContext構造体が備わっています。 集合を返す関数内では、fcinfo->flinfo->fn_extraは、呼び出し間でFuncCallContextへのポインタを保持するために使用されます。 マクロは、最初の使用時に自動的にそのフィールドを埋め、その後の使用時に同じポインタを見つけることを期待します。

typedef struct FuncCallContext
{
    /*

     * Number of times we've been called before

     * 既に行われた呼び出しの回数。
     *

     * call_cntr is initialized to 0 for you by SRF_FIRSTCALL_INIT(), and
     * incremented for you every time SRF_RETURN_NEXT() is called.

     * SRF_FIRSTCALL_INIT()によってcall_cntrが0に初期化され、
     * SRF_RETURN_NEXT()が呼び出される度に増分されます。
     */
    uint64 call_cntr;

    /*

     * OPTIONAL maximum number of calls
     *
     * max_calls is here for convenience only and setting it is optional.
     * If not set, you must provide alternative means to know when the
     * function is done.

     * 省略可能 : 呼び出しの最大数
     *
     * max_callsは、便宜上用意されているだけで、設定は省略可能です。
     * 設定されていなければ、関数が終了したことを知るための別の方法を
     * 用意する必要があります。
     */
    uint64 max_calls;

    /*

     * OPTIONAL pointer to miscellaneous user-provided context information
     *
     * user_fctx is for use as a pointer to your own data to retain
     * arbitrary context information between calls of your function.

     * 省略可能 : 様々なユーザによるコンテキスト情報へのポインタ
     *
     * user_fctxは、関数の呼び出し間の任意のコンテキスト情報を
     * 取得するためのユーザ独自の構造へのポインタとして使用されます。
     */
    void *user_fctx;

    /*

     * OPTIONAL pointer to struct containing attribute type input metadata
     *
     * attinmeta is for use when returning tuples (i.e., composite data types)
     * and is not used when returning base data types. It is only needed
     * if you intend to use BuildTupleFromCStrings() to create the return
     * tuple.

     * 省略可能 : 属性型入力メタ情報を含んだ構造体へのポインタ
     *
     * attinmeta はタプル(つまり複合データ型)を返す際に使用され、
     * 基本データ型を返す場合には必要ありません。
     * BuildTupleFromCStrings()を使用して返されるタプルを作成する場合にのみ必要です。
     */
    AttInMetadata *attinmeta;

    /*

     * memory context used for structures that must live for multiple calls
     *
     * multi_call_memory_ctx is set by SRF_FIRSTCALL_INIT() for you, and used
     * by SRF_RETURN_DONE() for cleanup. It is the most appropriate memory
     * context for any memory that is to be reused across multiple calls
     * of the SRF.

     *  複数の呼び出しで必要とされる構造体に使われるメモリコンテキスト
     *
     * multi_call_memory_ctxは、SRF_FIRSTCALL_INIT()によってに設定され、
     * SRF_RETURN_DONE()がクリーンアップの際に使用します。
     * これはSRFの複数呼び出しで再利用される全てのメモリ用に最も適切なメモリコンテキストです。
     */
    MemoryContext multi_call_memory_ctx;

    /*

     * OPTIONAL pointer to struct containing tuple description
     *
     * tuple_desc is for use when returning tuples (i.e., composite data types)
     * and is only needed if you are going to build the tuples with
     * heap_form_tuple() rather than with BuildTupleFromCStrings().  Note that
     * the TupleDesc pointer stored here should usually have been run through
     * BlessTupleDesc() first.

     * 省略可能: タプル説明を含む構造体へのポインタ。
     * tuple_descはタプル(つまり複合データ型)を返す場合に使用され、BuildTupleFromCStrings()
     * ではなくheap_form_tuple()を使用してタプルを作成する場合にのみ必要です。
     * 通常ここに格納されるTupleDescは最初にBlessTupleDesc()を最初に実行したものでなければなり
     * ません。
     */
    TupleDesc tuple_desc;

} FuncCallContext;

The macros to be used by an <acronym>SRF</acronym> using this infrastructure are: この基盤を使用して、SRFが使用するマクロは以下の通りです。

SRF_IS_FIRSTCALL()

Use this to determine if your function is being called for the first or a subsequent time. On the first call (only), call: これを使用して、関数が初めて呼び出されたのか、2回目以降に呼び出されたのかを判別します。 最初の呼び出し(のみ)で、

SRF_FIRSTCALL_INIT()

to initialize the <structname>FuncCallContext</structname>. On every function call, including the first, call: を呼び出し、FuncCallContextを初期化します。 最初の呼び出しを含むすべての呼び出しで、

SRF_PERCALL_SETUP()

to set up for using the <structname>FuncCallContext</structname>. を呼び出し、FuncCallContextを使用するように設定します。

If your function has data to return in the current call, use: 現在の呼び出しで返すべきデータが関数にある場合は、次の

SRF_RETURN_NEXT(funcctx, result)

to return it to the caller. (<literal>result</literal> must be of type <type>Datum</type>, either a single value or a tuple prepared as described above.) Finally, when your function is finished returning data, use: を使用して、そのデータを呼び出し側に返します。 (先に説明した通り resultDatum型、つまり1つの値またはタプルである必要があります。) 最後に、関数がデータを返し終わったら、

SRF_RETURN_DONE(funcctx)

to clean up and end the <acronym>SRF</acronym>. を使用してSRFを片付け、終了します。

The memory context that is current when the <acronym>SRF</acronym> is called is a transient context that will be cleared between calls. This means that you do not need to call <function>pfree</function> on everything you allocated using <function>palloc</function>; it will go away anyway. However, if you want to allocate any data structures to live across calls, you need to put them somewhere else. The memory context referenced by <structfield>multi_call_memory_ctx</structfield> is a suitable location for any data that needs to survive until the <acronym>SRF</acronym> is finished running. In most cases, this means that you should switch into <structfield>multi_call_memory_ctx</structfield> while doing the first-call setup. Use <literal>funcctx-&gt;user_fctx</literal> to hold a pointer to any such cross-call data structures. (Data you allocate in <structfield>multi_call_memory_ctx</structfield> will go away automatically when the query ends, so it is not necessary to free that data manually, either.) SRFの呼び出し時に現行になっているメモリコンテキストは一時的なコンテキストで、各呼び出しの間に消去されます。 つまりpallocを使用して割り当てたもののすべてをpfreeする必要はありません。 これらはいずれ消去されるものだからです。 しかし、データ構造体を複数の呼び出しに渡って使用するように割り当てる場合は、どこか別の場所に置いておく必要があります。 multi_call_memory_ctxによって参照されるメモリコンテキストは、SRFの実行が終わるまで使用可能にしなければならないデータの保管場所として適しています。 つまり、ほとんどの場合、最初の呼び出しのセットアップ中にmulti_call_memory_ctxへ切り替える必要があるということです。 funcctx->user_fctxを使用して、このような複数の呼び出しに渡るデータ構造体へのポインタを保持します。 (multi_call_memory_ctxに配置したデータは、問い合わせが終了すると自動的に削除されるので、そのデータを手動で解放する必要はありません。)

警告

While the actual arguments to the function remain unchanged between calls, if you detoast the argument values (which is normally done transparently by the <function>PG_GETARG_<replaceable>xxx</replaceable></function> macro) in the transient context then the detoasted copies will be freed on each cycle. Accordingly, if you keep references to such values in your <structfield>user_fctx</structfield>, you must either copy them into the <structfield>multi_call_memory_ctx</structfield> after detoasting, or ensure that you detoast the values only in that context. 関数の実引数は呼出しの間変わらないままですが、一時的なコンテキストで引数の値をTOAST解除した場合には(これは通常、PG_GETARG_xxxマクロにより透過的に行なわれます)、TOAST解除されたコピーが各サイクルで解放されます。 従って、user_fctx内のその値への参照を保持する場合には、TOAST解除した後にmulti_call_memory_ctxにそれらをコピーするか、その値をTOAST解除するのはそのコンテキストの中だけであること確実にしなければなりません。

A complete pseudo-code example looks like the following: 完全な疑似コードの例を示します。

Datum
my_set_returning_function(PG_FUNCTION_ARGS)
{
    FuncCallContext  *funcctx;
    Datum             result;
    further declarations as needed

    if (SRF_IS_FIRSTCALL())
    {
        MemoryContext oldcontext;

        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        /* One-time setup code appears here: */

        /* 一度限りのセットアップコードがここに入ります: */
        user code
        if returning composite
            build TupleDesc, and perhaps AttInMetadata
        endif returning composite
        user code
        MemoryContextSwitchTo(oldcontext);
    }


    /* Each-time setup code appears here: */

    /* 毎回実行するセットアップコードがここに入ります: */
    user code
    funcctx = SRF_PERCALL_SETUP();
    user code


    /* this is just one way we might test whether we are done: */

    /* これは、終了したかどうかをテストする方法の1つです: */
    if (funcctx->call_cntr < funcctx->max_calls)
    {

        /* Here we want to return another item: */

        /* ここで、別の項目を返します: */
        user code
        obtain result Datum
        SRF_RETURN_NEXT(funcctx, result);
    }
    else
    {

        /* Here we are done returning items, so just report that fact. */
        /* (Resist the temptation to put cleanup code here.) */

        /* これで項目を返し終わりました。 その事実を報告します。 */
        /* (ここにクリーンアップコードを置く誘惑に抵抗してください。) */
        SRF_RETURN_DONE(funcctx);
    }
}

A complete example of a simple <acronym>SRF</acronym> returning a composite type looks like: 複合型を返す単純なSRFの完全な例は以下の通りです。

PG_FUNCTION_INFO_V1(retcomposite);

Datum
retcomposite(PG_FUNCTION_ARGS)
{
    FuncCallContext     *funcctx;
    int                  call_cntr;
    int                  max_calls;
    TupleDesc            tupdesc;
    AttInMetadata       *attinmeta;


    /* stuff done only on the first call of the function */

     /* 関数の最初の呼び出し時にのみ実行 */
    if (SRF_IS_FIRSTCALL())
    {
        MemoryContext   oldcontext;


        /* create a function context for cross-call persistence */

        /* 呼び出し間で永続化する関数コンテキストを作成 */
        funcctx = SRF_FIRSTCALL_INIT();


        /* switch to memory context appropriate for multiple function calls */

        /* 複数関数呼び出しに適切なメモリコンテキストへの切り替え */
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);


        /* total number of tuples to be returned */

        /* 返されるタプルの合計数 */
        funcctx->max_calls = PG_GETARG_INT32(0);


        /* Build a tuple descriptor for our result type */

        /*  結果型用のタプル記述子を作成 */
        if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                            "that cannot accept type record")));

        /*

         * generate attribute metadata needed later to produce tuples from raw
         * C strings

         * 後で未加工のC文字列からタプルを作成するために必要となる
         * 属性メタデータの生成
         */
        attinmeta = TupleDescGetAttInMetadata(tupdesc);
        funcctx->attinmeta = attinmeta;

        MemoryContextSwitchTo(oldcontext);
    }


    /* stuff done on every call of the function */

    /* 全ての関数呼び出しで実行 */
    funcctx = SRF_PERCALL_SETUP();

    call_cntr = funcctx->call_cntr;
    max_calls = funcctx->max_calls;
    attinmeta = funcctx->attinmeta;


    if (call_cntr < max_calls)    /* do when there is more left to send */

    if (call_cntr < max_calls)    /* 他にも送るものがある場合  */
    {
        char       **values;
        HeapTuple    tuple;
        Datum        result;

        /*

         * Prepare a values array for building the returned tuple.
         * This should be an array of C strings which will
         * be processed later by the type input functions.

         * 返すタプルを構築するためのvalues配列を用意します。
         * これは、後で適切な入力関数で処理される
         * C文字列の配列でなければなりません。
         */
        values = (char **) palloc(3 * sizeof(char *));
        values[0] = (char *) palloc(16 * sizeof(char));
        values[1] = (char *) palloc(16 * sizeof(char));
        values[2] = (char *) palloc(16 * sizeof(char));

        snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1));
        snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1));
        snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1));


        /* build a tuple */

        /* タプルの作成 */
        tuple = BuildTupleFromCStrings(attinmeta, values);


        /* make the tuple into a datum */

        /* タプルをdatumに変換 */
        result = HeapTupleGetDatum(tuple);


        /* clean up (this is not really necessary) */

        /* クリーンアップ(これは必須ではありません) */
        pfree(values[0]);
        pfree(values[1]);
        pfree(values[2]);
        pfree(values);

        SRF_RETURN_NEXT(funcctx, result);
    }

    else    /* do when there is no more left */

    else    /* 何も残っていない場合 */
    {
        SRF_RETURN_DONE(funcctx);
    }
}

One way to declare this function in SQL is: 以下にこの関数をSQLで宣言する一例を示します。

CREATE TYPE __retcomposite AS (f1 integer, f2 integer, f3 integer);

CREATE OR REPLACE FUNCTION retcomposite(integer, integer)
    RETURNS SETOF __retcomposite
    AS 'filename', 'retcomposite'
    LANGUAGE C IMMUTABLE STRICT;

A different way is to use OUT parameters: 他にも以下のようにOUTパラメータを使用する方法もあります。

CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
    OUT f1 integer, OUT f2 integer, OUT f3 integer)
    RETURNS SETOF record
    AS 'filename', 'retcomposite'
    LANGUAGE C IMMUTABLE STRICT;

Notice that in this method the output type of the function is formally an anonymous <structname>record</structname> type. この方法では、関数の出力型は形式上無名のrecord型になることに注意してください。

36.10.9. 引数と戻り値の多様性 #

<title>Polymorphic Arguments and Return Types</title>

C-language functions can be declared to accept and return the polymorphic types described in <xref linkend="extend-types-polymorphic"/>. When a function's arguments or return types are defined as polymorphic types, the function author cannot know in advance what data type it will be called with, or need to return. There are two routines provided in <filename>fmgr.h</filename> to allow a version-1 C function to discover the actual data types of its arguments and the type it is expected to return. The routines are called <literal>get_fn_expr_rettype(FmgrInfo *flinfo)</literal> and <literal>get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)</literal>. They return the result or argument type OID, or <symbol>InvalidOid</symbol> if the information is not available. The structure <literal>flinfo</literal> is normally accessed as <literal>fcinfo-&gt;flinfo</literal>. The parameter <literal>argnum</literal> is zero based. <function>get_call_result_type</function> can also be used as an alternative to <function>get_fn_expr_rettype</function>. There is also <function>get_fn_expr_variadic</function>, which can be used to find out whether variadic arguments have been merged into an array. This is primarily useful for <literal>VARIADIC "any"</literal> functions, since such merging will always have occurred for variadic functions taking ordinary array types. C言語関数は、36.2.5で説明されている多様型を受け付ける、または返すように宣言できます。 関数の引数もしくは戻り値が多様型として定義される時、関数の作成者は前もって呼び出しにおけるデータ型や返すべきデータ型が何であるかを知ることはできません。 Version-1 C関数で引数の実データ型と、返すべきと想定された型を発見できるための2つのルーチンがfmgr.hに用意されています。 このルーチンはget_fn_expr_rettype(FmgrInfo *flinfo)get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)という名前です。 これらは結果もしくは引数型のOIDを返します。 ただし、もし情報が利用できなければInvalidOidを返します。 flinfo構造体は通常fcinfo->flinfoとしてアクセスされます。 argnumパラメータは0から始まります。 また、get_fn_expr_rettypeの代わりにget_call_result_typeを使用することもできます。 また、variadic変数が配列に吸収されたかどうかを判定するために使用できるget_fn_expr_variadicがあります。 そのような吸収はvariadic関数が普通の配列型をとる場合に必ず起こりますので、これは特にVARIADIC "any"の場合に有用です。

For example, suppose we want to write a function to accept a single element of any type, and return a one-dimensional array of that type: 例えば、任意の型の単一要素を受け付け、その型の1次元配列を返す関数を考えてみます。

PG_FUNCTION_INFO_V1(make_array);
Datum
make_array(PG_FUNCTION_ARGS)
{
    ArrayType  *result;
    Oid         element_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
    Datum       element;
    bool        isnull;
    int16       typlen;
    bool        typbyval;
    char        typalign;
    int         ndims;
    int         dims[MAXDIM];
    int         lbs[MAXDIM];

    if (!OidIsValid(element_type))
        elog(ERROR, "could not determine data type of input");


    /* get the provided element, being careful in case it's NULL */

    /* 与えられた要素がNULLかどうか注意しつつ、要素を取り出します。*/
    isnull = PG_ARGISNULL(0);
    if (isnull)
        element = (Datum) 0;
    else
        element = PG_GETARG_DATUM(0);


    /* we have one dimension */

    /* 次元数は1 */
    ndims = 1;

    /* and one element */

    /* 要素を1つ */
    dims[0] = 1;

    /* and lower bound is 1 */

    /* 下限は1 */
    lbs[0] = 1;


    /* get required info about the element type */

    /* この要素型に関する必要情報を取り出す。 */
    get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);


    /* now build the array */

    /* ここで配列を作成 */
    result = construct_md_array(&element, &isnull, ndims, dims, lbs,
                                element_type, typlen, typbyval, typalign);

    PG_RETURN_ARRAYTYPE_P(result);
}

The following command declares the function <function>make_array</function> in SQL: 以下のコマンドはSQLでmake_array関数を宣言します。

CREATE FUNCTION make_array(anyelement) RETURNS anyarray
    AS 'DIRECTORY/funcs', 'make_array'
    LANGUAGE C IMMUTABLE;

There is a variant of polymorphism that is only available to C-language functions: they can be declared to take parameters of type <literal>"any"</literal>. (Note that this type name must be double-quoted, since it's also an SQL reserved word.) This works like <type>anyelement</type> except that it does not constrain different <literal>"any"</literal> arguments to be the same type, nor do they help determine the function's result type. A C-language function can also declare its final parameter to be <literal>VARIADIC "any"</literal>. This will match one or more actual arguments of any type (not necessarily the same type). These arguments will <emphasis>not</emphasis> be gathered into an array as happens with normal variadic functions; they will just be passed to the function separately. The <function>PG_NARGS()</function> macro and the methods described above must be used to determine the number of actual arguments and their types when using this feature. Also, users of such a function might wish to use the <literal>VARIADIC</literal> keyword in their function call, with the expectation that the function would treat the array elements as separate arguments. The function itself must implement that behavior if wanted, after using <function>get_fn_expr_variadic</function> to detect that the actual argument was marked with <literal>VARIADIC</literal>. C言語関数でのみ使用できる多様性の変異体があります。 "any"型のパラメータを取るように宣言できます。 (この型名は、SQL予約語でもあるため二重引用符で括らなくてはならないことに注意してください。) これは、他の"any"引数が同じ型になることを強要することも、関数の結果型の決定を支援することもない点を除いて、anyelementのように動作します。 C言語関数は最終パラメータがVARIADIC "any"であるように宣言可能です。 これは任意の型の1つ以上の実引数と一致します(同じ型である必要はありません)。 これらの引数は、通常のvariadic関数で起こったように、配列の中にまとめられません。 それらは単に別々に関数に渡されるだけです。 PG_NARGS()マクロと上に記載したメソッドは、この機能を使用するときに実際の引数とその型を決定するため使用されなければなりません。 また、こうした関数のユーザは、その関数呼び出しにおいて、関数が配列要素を分離した引数として扱うだろうという予想のもとでVARIADICキーワードを良く使用するかもしれません。 関数自身は必要ならば、get_fn_expr_variadicを実行した後で、実引数がVARIADIC付きであることを検出した場合に、その動作を実装しなければなりません。

36.10.10. Shared Memory #

36.10.10.1. Requesting Shared Memory at Startup #

Add-ins can reserve shared memory on server startup. To do so, the add-in's shared library must be preloaded by specifying it in <xref linkend="guc-shared-preload-libraries"/><indexterm><primary>shared_preload_libraries</primary></indexterm>. The shared library should also register a <literal>shmem_request_hook</literal> in its <function>_PG_init</function> function. This <literal>shmem_request_hook</literal> can reserve shared memory by calling: 《マッチ度[72.666667]》アドインはLWLocks(軽量ロック)とサーバ起動時に共有メモリの割り当てを保持できます。 shared_preload_librariesで指定して、こうしたアドインの共有ライブラリを事前にロードしなければなりません。 共有ライブラリは、_PG_init関数にshmem_request_hookを登録する必要があります。 このshmem_request_hookは、LWLocksまたは共有メモリを予約できます。 共有メモリは、以下を 《機械翻訳》アドインは、サーバ起動時に共有メモリを予約できます。 そのためには、アドインの共有ライブラリをshared_preload_librariesで指定して事前にロードしておく必要があります。 また、shmem_request_hook_PG_init関数で登録する必要があります。 このshmem_request_hookは以下を呼び出すことで共有メモリを予約できます。

void RequestAddinShmemSpace(Size size)

Each backend should obtain a pointer to the reserved shared memory by calling: 《機械翻訳》各バックエンドは、以下を呼び出すことによって、予約された共有メモリへのポインタを取得する必要があります。

void *ShmemInitStruct(const char *name, Size size, bool *foundPtr)

If this function sets <literal>foundPtr</literal> to <literal>false</literal>, the caller should proceed to initialize the contents of the reserved shared memory. If <literal>foundPtr</literal> is set to <literal>true</literal>, the shared memory was already initialized by another backend, and the caller need not initialize further. 《機械翻訳》この関数がfoundPtrfalseに設定する場合、呼び出し元は予約された共有メモリの内容を初期化する必要があります。 foundPtrtrueに設定されている場合、共有メモリは他のバックエンドによって既に初期化されており、呼び出し元はそれ以上初期化する必要はありません。

To avoid race conditions, each backend should use the LWLock <function>AddinShmemInitLock</function> when initializing its allocation of shared memory, as shown here: 《マッチ度[74.096386]》競合状態の可能性を防止するために、割り当てられた共有メモリへの接続やその初期化時に、以下のように各バックエンドでAddinShmemInitLock軽量ロックを使用しなければなりません。 《機械翻訳》競合を避けるために、各バックエンドは共有メモリの割り当てを初期化する際にLWLockAddinShmemInitLockを使用する必要があります。

static mystruct *ptr = NULL;
bool        found;

LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
ptr = ShmemInitStruct("my struct name", size, &found);
if (!found)
{
    ... initialize contents of shared memory ...
    ptr->locks = GetNamedLWLockTranche("my tranche name");
}
LWLockRelease(AddinShmemInitLock);

<literal>shmem_startup_hook</literal> provides a convenient place for the initialization code, but it is not strictly required that all such code be placed in this hook. Each backend will execute the registered <literal>shmem_startup_hook</literal> shortly after it attaches to shared memory. Note that add-ins should still acquire <function>AddinShmemInitLock</function> within this hook, as shown in the example above. 《機械翻訳》shmem_startup_hookは初期化コードを便利に提供しますが、このフックにすべてのコードを置く必要はありません。 各バックエンドは、共有メモリに接続した直後に登録されたshmem_startup_hookを実行します。 上の例に示すように、アドインはこのフック内でAddinShmemInitLockを取得する必要があります。

An example of a <literal>shmem_request_hook</literal> and <literal>shmem_startup_hook</literal> can be found in <filename>contrib/pg_stat_statements/pg_stat_statements.c</filename> in the <productname>PostgreSQL</productname> source tree. 《マッチ度[76.050420]》shmem_request_hookの例は、PostgreSQLソースツリーのcontrib/pg_stat_statements/pg_stat_statements.cにあります。 《機械翻訳》shmem_request_hookshmem_startup_hookの例は、PostgreSQLソースツリーのcontrib/pg_stat_statements/pg_stat_statements.cにあります。

36.10.10.2. Requesting Shared Memory After Startup #

There is another, more flexible method of reserving shared memory that can be done after server startup and outside a <literal>shmem_request_hook</literal>. To do so, each backend that will use the shared memory should obtain a pointer to it by calling: 《機械翻訳》サーバ起動後にshmem_request_hookの外部で行うことができる、より柔軟な共有メモリの予約方法がもう1つあります。 そのためには、共有メモリを使用する各バックエンドは、以下の関数を呼び出すことで共有メモリへのポインタを取得する必要があります。

void *GetNamedDSMSegment(const char *name, size_t size,
                         void (*init_callback) (void *ptr),
                         bool *found)

If a dynamic shared memory segment with the given name does not yet exist, this function will allocate it and initialize it with the provided <function>init_callback</function> callback function. If the segment has already been allocated and initialized by another backend, this function simply attaches the existing dynamic shared memory segment to the current backend. 《機械翻訳》指定された名前の動的共有メモリセグメントがまだ存在しない場合、この関数はそれを割り当て、init_callbackコールバック関数で初期化します。 セグメントが別のバックエンドによってすでに割り当てられて初期化されている場合、この関数は単に既存の動的共有メモリセグメントを現在のバックエンドにアタッチします。

Unlike shared memory reserved at server startup, there is no need to acquire <function>AddinShmemInitLock</function> or otherwise take action to avoid race conditions when reserving shared memory with <function>GetNamedDSMSegment</function>. This function ensures that only one backend allocates and initializes the segment and that all other backends receive a pointer to the fully allocated and initialized segment. 《機械翻訳》サーバ起動時に予約される共有メモリとは異なり、GetNamedDSMSegmentで共有メモリを予約する際にAddinShmemInitLockを取得したり、競合状態を回避するための他の処理を行う必要はありません。 この関数は、セグメントを割り当てて初期化するバックエンドが1つだけであり、他のすべてのバックエンドが完全に割り当てられ、初期化されたセグメントへのポインタを受け取ることを保証します。

A complete usage example of <function>GetNamedDSMSegment</function> can be found in <filename>src/test/modules/test_dsm_registry/test_dsm_registry.c</filename> in the <productname>PostgreSQL</productname> source tree. 《マッチ度[54.838710]》shmem_request_hookの例は、PostgreSQLソースツリーのcontrib/pg_stat_statements/pg_stat_statements.cにあります。 《機械翻訳》GetNamedDSMSegmentの完全な使用例は、PostgreSQLソースツリーのsrc/test/modules/test_dsm_registry/test_dsm_registry.cにあります。

36.10.11. LWLocks #

36.10.11.1. Requesting LWLocks at Startup #

Add-ins can reserve LWLocks on server startup. As with shared memory reserved at server startup, the add-in's shared library must be preloaded by specifying it in <xref linkend="guc-shared-preload-libraries"/><indexterm><primary>shared_preload_libraries</primary></indexterm>, and the shared library should register a <literal>shmem_request_hook</literal> in its <function>_PG_init</function> function. This <literal>shmem_request_hook</literal> can reserve LWLocks by calling: 《マッチ度[75.052411]》アドインはLWLocks(軽量ロック)とサーバ起動時に共有メモリの割り当てを保持できます。 shared_preload_librariesで指定して、こうしたアドインの共有ライブラリを事前にロードしなければなりません。 共有ライブラリは、_PG_init関数にshmem_request_hookを登録する必要があります。 このshmem_request_hookは、LWLocksまたは共有メモリを予約できます。 共有メモリは、以下を 《機械翻訳》アドインは、サーバ起動時にLWLockを予約できます。 サーバ起動時に予約される共有メモリと同様に、アドインの共有ライブラリはshared_preload_librariesで指定して事前にロードする必要があり、_PG_init関数でshmem_request_hookを登録する必要があります。 このshmem_request_hookは以下を呼び出すことでLWLockを予約できます。

void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)

This ensures that an array of <literal>num_lwlocks</literal> LWLocks is available under the name <literal>tranche_name</literal>. A pointer to this array can be obtained by calling: 《機械翻訳》これにより、num_lwlocks LWLocksの配列がtranche_nameという名前で利用可能になります。 この配列へのポインタは、以下を呼び出すことで取得できます。

LWLockPadded *GetNamedLWLockTranche(const char *tranche_name)

36.10.11.2. Requesting LWLocks After Startup #

There is another, more flexible method of obtaining LWLocks that can be done after server startup and outside a <literal>shmem_request_hook</literal>. To do so, first allocate a <literal>tranche_id</literal> by calling: 《機械翻訳》サーバ起動後、shmem_request_hookの外部で、LWLockを取得するためのもっと柔軟な方法があります。 そのためには、まず以下を呼び出してtranche_idを割り当てます。

int LWLockNewTrancheId(void)

Next, initialize each LWLock, passing the new <literal>tranche_id</literal> as an argument: 《機械翻訳》次に、新しいtranche_idを引数として渡して、各LWLockを初期化します。

void LWLockInitialize(LWLock *lock, int tranche_id)

Similar to shared memory, each backend should ensure that only one process allocates a new <literal>tranche_id</literal> and initializes each new LWLock. One way to do this is to only call these functions in your shared memory initialization code with the <function>AddinShmemInitLock</function> held exclusively. If using <function>GetNamedDSMSegment</function>, calling these functions in the <function>init_callback</function> callback function is sufficient to avoid race conditions. 《機械翻訳》共有メモリと同様に、各バックエンドは、新しいtranche_idを1つのプロセスだけが割り当て、新しいLWLockをそれぞれ初期化するようにする必要があります。 これを行う1つの方法は、AddinShmemInitLockを排他的に保持しておくことで、共有メモリ初期化コード内でこれらの関数を呼び出すことだけです。 GetNamedDSMSegmentを使用する場合、init_callbackコールバック関数でこれらの関数を呼び出すことで、競合状態を回避できます。

Finally, each backend using the <literal>tranche_id</literal> should associate it with a <literal>tranche_name</literal> by calling: 《機械翻訳》最後に、tranche_idを使用する各バックエンドは、次の呼び出しによってtranche_nameを関連付ける必要があります。

void LWLockRegisterTranche(int tranche_id, const char *tranche_name)

A complete usage example of <function>LWLockNewTrancheId</function>, <function>LWLockInitialize</function>, and <function>LWLockRegisterTranche</function> can be found in <filename>contrib/pg_prewarm/autoprewarm.c</filename> in the <productname>PostgreSQL</productname> source tree. 《機械翻訳》LWLockNewTrancheIdLWLockInitializeLWLockRegisterTrancheの完全な使用例は、PostgreSQLソースツリーのcontrib/pg_prewarm/autoprewarm.cにあります。

36.10.12. Custom Wait Events #

Add-ins can define custom wait events under the wait event type <literal>Extension</literal> by calling: 《機械翻訳》アドインは、次の呼び出しを行うことで、待機イベントのタイプExtensionの下にカスタム待機イベントを定義できます。

uint32 WaitEventExtensionNew(const char *wait_event_name)

The wait event is associated to a user-facing custom string. An example can be found in <filename>src/test/modules/worker_spi</filename> in the PostgreSQL source tree. 《機械翻訳》待機イベントはユーザ向けのカスタム文字列に関連付けられています。 例はPostgreSQLソースツリーのsrc/test/modules/worker_spiにあります。

Custom wait events can be viewed in <link linkend="monitoring-pg-stat-activity-view"><structname>pg_stat_activity</structname></link>: 《機械翻訳》カスタム待機イベントはpg_stat_activityで見ることができます。

=# SELECT wait_event_type, wait_event FROM pg_stat_activity
     WHERE backend_type ~ 'worker_spi';
 wait_event_type |  wait_event
-----------------+---------------
 Extension       | WorkerSpiMain
(1 row)

36.10.13. Injection Points #

An injection point with a given <literal>name</literal> is declared using macro: 《機械翻訳》与えられたnameを持つ注入点は、マクロを使って宣言されます。

INJECTION_POINT(name);

There are a few injection points already declared at strategic points within the server code. After adding a new injection point the code needs to be compiled in order for that injection point to be available in the binary. Add-ins written in C-language can declare injection points in their own code using the same macro. 《機械翻訳》サーバコード内の戦略的なポイントに、すでにいくつかのインジェクションポイントが宣言されています。 新しいインジェクションポイントを追加した後、そのインジェクションポイントをバイナリで使用できるようにするには、コードをコンパイルする必要があります。 C言語で記述されたアドインは、同じマクロを使用して、独自のコードでインジェクションポイントを宣言できます。

Add-ins can attach callbacks to an already-declared injection point by calling: 《機械翻訳》アドインは、次の呼び出しを行うことで、すでに宣言されているインジェクションポイントにコールバックをアタッチすることができます。

extern void InjectionPointAttach(const char *name,
                                 const char *library,
                                 const char *function,
                                 const void *private_data,
                                 int private_data_size);

<literal>name</literal> is the name of the injection point, which when reached during execution will execute the <literal>function</literal> loaded from <literal>library</literal>. <literal>private_data</literal> is a private area of data of size <literal>private_data_size</literal> given as argument to the callback when executed. 《機械翻訳》nameは、実行時にlibraryからロードされたfunctionを実行する際の注入ポイントの名前です。 private_dataは、実行時にコールバックに引数として与えられるサイズprivate_data_sizeのデータのプライベート領域です。

Here is an example of callback for <literal>InjectionPointCallback</literal>: 《機械翻訳》InjectionPointCallbackのコールバックの例を以下に示します。

static void
custom_injection_callback(const char *name, const void *private_data)
{
    uint32 wait_event_info = WaitEventInjectionPointNew(name);

    pgstat_report_wait_start(wait_event_info);
    elog(NOTICE, "%s: executed custom callback", name);
    pgstat_report_wait_end();
}

This callback prints a message to server error log with severity <literal>NOTICE</literal>, but callbacks may implement more complex logic. 《機械翻訳》このコールバックは、重大度がNOTICEのメッセージをサーバエラーログに出力しますが、コールバックはより複雑なロジックを実装することができます。

Optionally, it is possible to detach an injection point by calling: 《機械翻訳》オプションで、次の呼び出しによって射出位置を切り離すことができます。

extern bool InjectionPointDetach(const char *name);

On success, <literal>true</literal> is returned, <literal>false</literal> otherwise. 《機械翻訳》成功した場合はtrue、それ以外の場合はfalseを返します。

A callback attached to an injection point is available across all the backends including the backends started after <literal>InjectionPointAttach</literal> is called. It remains attached while the server is running or until the injection point is detached using <literal>InjectionPointDetach</literal>. 《機械翻訳》注入ポイントにアタッチされたコールバックは、InjectionPointAttachが呼び出された後に起動されたバックエンドを含む全てのバックエンドで利用可能です。 サーバが実行中の間はアタッチされたままで、InjectionPointDetachを使用して注入ポイントが切り離されるまでアタッチされたままです。

An example can be found in <filename>src/test/modules/injection_points</filename> in the PostgreSQL source tree. 《機械翻訳》例は、PostgreSQLソースツリーのsrc/テスト/モジュール/インジェクション_pointsにあります。

Enabling injections points requires <option>&#45;-enable-injection-points</option> with <command>configure</command> or <option>-Dinjection_points=true</option> with <application>Meson</application>. 《機械翻訳》インジェクションポイントを有効にするには、configure--enable-injection-pointsを指定するか、Meson-Dinjection_points=trueを指定します。

36.10.14. 拡張へのC++の利用 #

<title>Using C++ for Extensibility</title>

Although the <productname>PostgreSQL</productname> backend is written in C, it is possible to write extensions in C++ if these guidelines are followed: 以下のガイドラインに従うことで、PostgreSQLの拡張を構築するためC++モードのコンパイラを利用できます。

  • All functions accessed by the backend must present a C interface to the backend; these C functions can then call C++ functions. For example, <literal>extern C</literal> linkage is required for backend-accessed functions. This is also necessary for any functions that are passed as pointers between the backend and C++ code. バックエンドからアクセスされる関数はすべてバックエンドに対してCインタフェースを提供しなければなりません。 このC関数はC++関数を呼びだすことができます。 例えば、バックエンドからアクセスされる関数にはextern Cリンクが必要です。 これはバックエンドとC++コードの間でポインタとして渡される関数にも必要です。

  • Free memory using the appropriate deallocation method. For example, most backend memory is allocated using <function>palloc()</function>, so use <function>pfree()</function> to free it. Using C++ <function>delete</function> in such cases will fail. 適切な解放メソッドを使ってメモリを解放してください。 例えば、ほとんどのバックエンドメモリはpalloc()で確保されますので、pfree()を使って解放してください。 この場合にC++のdelete()を使うと失敗するでしょう。

  • Prevent exceptions from propagating into the C code (use a catch-all block at the top level of all <literal>extern C</literal> functions). This is necessary even if the C++ code does not explicitly throw any exceptions, because events like out-of-memory can still throw exceptions. Any exceptions must be caught and appropriate errors passed back to the C interface. If possible, compile C++ with <option>-fno-exceptions</option> to eliminate exceptions entirely; in such cases, you must check for failures in your C++ code, e.g., check for NULL returned by <function>new()</function>. 例外がCコードへ伝播しないようにしてください(extern C関数すべての最上位ですべての例外を捕捉するブロックを使ってください)。 メモリ不足のようなイベントにより例外が発生する可能性がありますので、C++コードが何も例外を発生させない場合であっても、これは必要です。 例外はすべて捕捉しなければなりません。 そして適切なエラーをCインタフェースに渡してください。 可能であれば、例外を完全に除去できるように-fno-exceptionsを付けてC++をコンパイルしてください。 その場合、例えばnew()で返されるNULLの検査など、C++コード内で失敗の検査を行わなければなりません。

  • If calling backend functions from C++ code, be sure that the C++ call stack contains only plain old data structures (<acronym>POD</acronym>). This is necessary because backend errors generate a distant <function>longjmp()</function> that does not properly unroll a C++ call stack with non-POD objects. C++コードからバックエンド関数を呼び出す場合には、C++呼び出しスタック内にC言語互換構造体(POD)のみが含まれていることを確認してください。 バックエンドのエラーは、非PODオブジェクトを持つC++呼び出しスタックを適切に戻すことができない、長距離longjmp()を生成しますので、これは必要です。

In summary, it is best to place C++ code behind a wall of <literal>extern C</literal> functions that interface to the backend, and avoid exception, memory, and call stack leakage. まとめると、バックエンドとやりとりするための壁の役割を担うextern C関数の背後にC++コードを配置して、例外、メモリ、呼び出しスタックそれぞれの漏れを避けるのが最善です。