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 — 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()
を書くことで示されます。
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
コマンドで与えられた名前に基づいて、共有オブジェクトファイルの場所を見つける際に以下のアルゴリズムが使用されます。
If the name is an absolute path, the given file is loaded. 名前が絶対パスの場合、指定されたファイルが読み込まれます。
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パッケージのライブラリディレクトリで置き換えられます。
このディレクトリはビルド時に決定されます。
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設定変数で指定されたパス内から検索されます。
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 --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型を返さなければなりません。
現在、動的にロードされたファイルをアンロードする方法はありません。
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
と呼びます。
int
がXX
XX
ビットであることは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.
VARHDRSZ
はsizeof(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の型
SQL Type SQL型 | C Type C 言語型 | Defined In 定義場所 |
---|---|---|
boolean | bool | postgres.h (コンパイラで組み込み済みの可能性があります) |
box | BOX* | utils/geo_decls.h |
bytea | bytea* | postgres.h |
"char" | char | (コンパイラで組み込み済み) |
character | BpChar* | postgres.h |
cid | CommandId | postgres.h |
date | DateADT | utils/date.h |
float4 (real ) | float4 | postgres.h |
float8 (double precision ) | float8 | postgres.h |
int2 (smallint ) | int16 | postgres.h |
int4 (integer ) | int32 | postgres.h |
int8 (bigint ) | int64 | postgres.h |
interval | Interval* | datatype/timestamp.h |
lseg | LSEG* | utils/geo_decls.h |
name | Name | postgres.h |
numeric | Numeric | utils/numeric.h |
oid | Oid | postgres.h |
oidvector | oidvector* | postgres.h |
path | PATH* | utils/geo_decls.h |
point | POINT* | utils/geo_decls.h |
regproc | RegProcedure | postgres.h |
text | text* | postgres.h |
tid | ItemPointer | storage/itemptr.h |
time | TimeADT | utils/date.h |
time with time zone | TimeTzADT | utils/date.h |
timestamp | Timestamp | datatype/timestamp.h |
timestamp with time zone | TimestampTz | datatype/timestamp.h |
varchar | VarChar* | postgres.h |
xid | TransactionId | postgres.h |
Now that we've gone over all of the possible structures for base types, we can show some examples of real functions. ここまでで基本型に関してあり得る構造体のすべてを記述しましたので、実際の関数の例をいくつか示すことができます。
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; -- 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(
マクロにより関数は各入力がNULLであるかどうかの検査を行うことができます。
(もちろんこれは、「厳密」と宣言されていない関数でのみ必要です。)
n
)PG_GETARG_
マクロと同様、入力引数の番号はゼロから始まります。
引数がNULLでないことを確認するまでは、xxx
()PG_GETARG_
の実行は控えなければなりません。
結果としてNULLを返す場合は、xxx
()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_
マクロの変形を2つ提供しています。
1つ目のxxx
()PG_GETARG_
によって、安全に書き込むことができる指定引数のコピーが確実に返されます。
(通常のマクロは、物理的にテーブルに格納されている値へのポインタを返すことがあるので、書き込んではなりません。
xxx
_COPY()PG_GETARG_
マクロの結果は書き込み可能であることが保証されています。)
2つ目の変形は、引数を3つ取るxxx
_COPY()PG_GETARG_
マクロからなります。
1つ目は関数の引数の番号(上記の通り)です。
2つ目と3つ目は、オフセットと返されるセグメントの長さです。
オフセットはゼロから始まり、負の長さは残りの値を返すことを要求します。
これらのマクロを使用すると、ストレージ種類が「external」(外部)である大きな値の一部へアクセスする際に非常に効果的です。
(列のストレージ種類はxxx
_SLICE()ALTER TABLE
を使用して指定できます。
tablename
ALTER COLUMN colname
SET STORAGE storagetype
storagetype
は、plain
、external
、extended
、または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
を参照してください。
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
--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ライブラリのmalloc
とfree
ではなく、PostgreSQLのpalloc
とpfree
を使用してください。
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.h
、palloc.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サーバの実行ファイルで定義されているものと異なっている必要があります。 これに関するエラーが表示される場合は、関数名または変数名を変更する必要があります。
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 — 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つしか使いません。
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.
これはFreeBSDのバージョン13.0に適用されます。古いバージョンではgcc
コンパイラを使用していました。
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
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
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
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
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を見直してください。
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
は適切なDatumGet
関数を使用して適切なデータ型に変換可能なXXX
()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
を使用していることに注意してください。
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を使用する場合は、TupleDesc
をBlessTupleDesc
に渡し、各行に対してheap_form_tuple
を呼び出します。
C文字列を使用する場合は、TupleDesc
をTupleDescGetAttInMetadata
に渡し、各行に対して 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呼び出し規約を使用していることが必要です。)
resultTypeId
をNULL
とすることも、ローカル変数のアドレスを指定して関数の戻り値型の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 — use the
<structfield>tuple_desc</structfield> or <structfield>attinmeta</structfield> field
respectively.
集合を返す関数を作成する場合は、これらの関数の結果をFuncCallContext
構造体に格納してください。
それぞれtuple_desc
とattinmeta
を使用します。
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. 次節に例を示します。
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->flinfo->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:
を使用して、そのデータを呼び出し側に返します。
(先に説明した通り result
はDatum
型、つまり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->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_
マクロにより透過的に行なわれます)、TOAST解除されたコピーが各サイクルで解放されます。
従って、xxx
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
型になることに注意してください。
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->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
付きであることを検出した場合に、その動作を実装しなければなりません。
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.
《機械翻訳》この関数がfoundPtr
をfalse
に設定する場合、呼び出し元は予約された共有メモリの内容を初期化する必要があります。
foundPtr
がtrue
に設定されている場合、共有メモリは他のバックエンドによって既に初期化されており、呼び出し元はそれ以上初期化する必要はありません。
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_hook
とshmem_startup_hook
の例は、PostgreSQLソースツリーのcontrib/pg_stat_statements/pg_stat_statements.c
にあります。
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
にあります。
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)
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.
《機械翻訳》LWLockNewTrancheId
、LWLockInitialize
、LWLockRegisterTranche
の完全な使用例は、PostgreSQLソースツリーのcontrib/pg_prewarm/autoprewarm.c
にあります。
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)
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>--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
を指定します。
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++コードを配置して、例外、メモリ、呼び出しスタックそれぞれの漏れを避けるのが最善です。