- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2017-12-25T22:34:39+09:00","default:haikikyou","haikikyou")
#author("2017-12-26T00:49:46+09:00","default:haikikyou","haikikyou")
[[PostgreSQL/開発]]
&size(12){&color(white,red){ ただいま作成中・・・ };};
#contents
* 概要 [#t03f8105]
- 関数マネージャと関数呼び出しインターフェースの定義ファイル
#ref(./fmgr_overview.png,70%)
* 定義 [#m6ff2469]
** 変数,エイリアス [#r6993c38]
** マクロ [#n3bffc31]
** 列挙型 [#jc93a4e3]
** 構造体 [#cb54ce43]
*** FmgrInfo [#dbdc9d3a]
|~番号|~データ型|~フィールド|~説明|h
|1|PGFunction|fn_addr|実行される関数のポインタ|
|2|Oid|fn_oid|関数のOID|
|3|short|fn_nargs|関数の引数の数|
|4|bool|fn_strict|関数がstrictモードが否か。&br;true:strictモード,false:strictモードでない|
|5|bool|fn_retset|setを返す関数か否か。&br;true:setを返す,false:setを返さない|
|6|unsigned char|fn_stats|関数が統計情報を収集するか。この値より大きな値の場合に収集する。&br;&size(12){&color(white,orange){ 参考 };}; [[enum TrackFunctionsLevel>https://doxygen.postgresql.org/pgstat_8h.html#a8674d83a2e7ca33c720348e4b328ab4c]] - on doxygen.postgresql.org|
|7|void*|fn_extra|関数で利用可能な領域|
|8|MemoryContext|fn_mcxt|fn_extraを格納するためのメモリコンテキスト|
|9|fmNodePtr|fn_expr|パースツリーのノード表現|
システムカタログの関数情報を保持する。
&size(12){&color(white,#00afcc){ サンプル };};
#geshi(c){{{
// 指定されたOIDの関数情報を取得する。
FmgrInfo *fmgr = palloc(sizeof(FmgrInfo));
fmgr_info((Oid)1396, fmgr); // abs(int64)の情報を構造体に格納する
}}}
*** FunctionCallInfoData [#vd0ca3c7]
|~番号|~データ型|~フィールド|~説明|h
|1|FmgrInfo*|flinfo|関数情報を保持する構造体のポインタ|
|2|fmNodePtr|context|関数呼び出しのコンテキスト。&br;例:TriggerData,AggState,WindowAggState|
|3|fmNodePtr|resultinfo|実行結果に関する情報。&br;例:ReturnSetInfo|
|4|Oid|fncollation|collation|
|5|bool|isnull|結果がNULLを返すか否か。&br;true:返す,false:返さない|
|6|short|nargs|関数の引数の数|
|7|Datum|arg[FUNC_MAX_ARGS]|引数|
|8|bool|argnull[FUNC_MAX_ARGS]|arg[i]がNULLであるか否か&br;true:NULL,false:NULLでない|
関数呼び出しに関する情報を保持する構造体。
&size(12){&color(white,orange){ 参考 };}; [[FunctionCallInfoData>https://doxygen.postgresql.org/structFunctionCallInfoData.html]] - on doxygen.postgresql.org
&size(12){&color(white,#00afcc){ サンプル };};
#geshi(c){{{
void test_invoke()
{
Datum result;
FunctionCallInfoData fcinfo;
FmgrInfo *fmgr = palloc(sizeof(FmgrInfo));
fmgr_info((Oid)1396, fmgr); // abs(int64);
// Basic way
int64 arg0 = -100;
InitFunctionCallInfoData(fcinfo, fmgr, 1, 0, NULL, NULL);
fcinfo.isnull = false;
fcinfo.argnull[0] = false;
fcinfo.arg[0] = Int64GetDatum(arg0);
result = FunctionCallInvoke(&fcinfo);
elog(INFO, "abs(-100) = %ld", DatumGetInt64(result));
}
/* Output is the following:
------------------------------
INFO: abs(-100) = 100
*/
}}}
*** Pg_finfo_record [#jb9501fe]
|~番号|~データ型|~フィールド|~説明|h
|1|int|api_version|apiのバージョン|
関数インターフェースのバージョンを示す情報を格納する。独自の拡張機能や関数を作成するときに,以下のサンプルのようにマクロを使った際に展開され定義される。
&size(12){&color(white,#00afcc){ サンプル };};
#geshi(c){{{
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(test_fdw_handler);
/* これは以下のように展開される
extern Datum test_fdw_handler(FunctionCallInfo fcinfo);
extern const Pg_finfo_record * pg_finfo_test_fdw_handler(void);
const Pg_finfo_record * pg_finfo_test_fdw_handler(void)
{
static const Pg_finfo_record my_finfo = { 1 };
return &my_finfo;
}
extern int no_such_variable;
/*
}}}
** 関数 [#ydff81f8]
*** fmgr_info [#v3a0be5f]
#geshi(c){{{
// 引数1:関数のOid
// 引数2:FmgrInfo構造体のポインタ
extern void fmgr_info(Oid functionId, FmgrInfo *finfo);
}}}
- 指定されたfunctionIdの関数情報を探索し,finfoに設定する。
&size(12){&color(white,orange){ 参考 };}; [[fmgr_info()>https://doxygen.postgresql.org/fmgr_8c.html#a4aaf89400b4741012e4ee1b715dae0e4]] - on doxygen.postgresql.org
&size(12){&color(white,#00afcc){ サンプル };};
#geshi(c){{{
FmgrInfo flinfo;
fmgr_info(functionId, &flinfo); // fill flinfo
}}}
*** fmgr_info_cxt [#pb3ac2bc]
#geshi(c){{{
// 引数1:関数のOid
// 引数2:FmgrInfo構造体のポインタ
// 引数3:fx_extraを使用する際のメモリコンテキスト
extern void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt);
}}}
- 指定されたfunctionIdの関数情報を探索し,finfoに設定する。
- fn_extraで使用されるスペースを指定されたメモリコンテキストから割り当てるよう設定する。
*** fmgr_info_copy [#m6566276]
#geshi(c){{{
// 引数1:コピー先のFmgrInfo構造体のポインタ
// 引数2:コピー元のFmgrInfo構造体のポインタ
// 引数3:fx_extraを使用する際のメモリコンテキスト
extern void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
}}}
- FmgrInfo構造体のデータをコピーする(memcpy)
&size(12){&color(white,#00afcc){ サンプル };};
#geshi(c){{{
FmgrInfo destinfo, srcinfo;
fmgr_info(1396, &srcinfo);
fmgr_info_copy(&destinfo, &srcinfo, CurrentMemoryContext);
}}}
*** DirectFunctionCall<N>Coll [#g95ad19a]
#geshi(c){{{
// 引数1:呼び出す関数のポインタ
// 引数2:collation
// 引数3:関数の引数
extern Datum DirectFunctionCall<N>Coll(PGFunction func, Oid collation, Datum arg1[, ...arg9]);
}}}
- fmgrを経由せず直接関数を呼び出す。
&size(12){&color(white,#00afcc){ サンプル };};
#geshi(c){{{
#include "postgres.h"
#include "fmgr.h"
#include "catalog/pg_collation.h"
#include "utils/builtins.h"
static void direct_function_sample(Datum arg1)
{
Datum result;
result = DirectFunctionCall1Coll(int4abs, DEFAULT_COLLATION_OID, arg1);
elog(INFO, "result = %d", DatumGetInt32(result));
}
}}}
*** FunctionCall<N>Coll [#f221d4c3]
#geshi(c){{{
// 引数1:FmgrInfo構造体のポインタ
// 引数2:collation
// 引数3:関数の引数
extern Datum FunctionCall<N>Coll(FmgrInfo *flinfo, Oid collation, Datum arg1[, ...arg9]);
}}}
- 既に解決済みの関数情報を使って関数を呼び出す。
&size(12){&color(white,#00afcc){ サンプル };};
#geshi(c){{{
#include "postgres.h"
#include "fmgr.h"
#include "catalog/pg_collation.h"
#include "utils/builtins.h"
static void t_looked_up_function(Datum arg1)
{
FmgrInfo fminfo;
Oid pronOid;
Datum result;
pronOid = fmgr_internal_function("int4abs");
fmgr_info(pronOid, &fminfo);
result = FunctionCall1Coll(&fminfo, DEFAULT_COLLATION_OID, arg1);
elog(INFO, "result = %d", DatumGetInt32(result));
}
}}}
***CallerFInfoFunction<N>Call [#j9befaee]
#geshi(c){{{
// 引数1:呼び出す関数のポインタ
// 引数2:FmgrInfo構造体のポインタ
// 引数2:collation
// 引数3〜:関数の引数
extern Datum CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1);
extern Datum CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2);
}}}
- 関数の呼び出し先でfn_extra、fn_mcxtフィールドを使用する場合に使う。
&size(12){&color(white,#00afcc){ サンプル };};
#geshi(c){{{
#include "postgres.h"
#include "fmgr.h"
#include "catalog/pg_collation.h"
#include "utils/builtins.h"
PG_FUNCTION_INFO_V1(my_txt_func);
Datum test_fn_extra_hash_function(PG_FUNCTION_ARGS);
Datum test_fn_extra_hash_function(PG_FUNCTION_ARGS)
{
text *txt = PG_GETARG_TEXT_PP(0);
MyCache *cache;
cache = (MyCache *)(fcinfo->flinfo->fn_extra);
char *cstring = text_to_cstring(txt);
if (cache == NULL || strcmp(cache->str, cstring) != 0) {
elog(INFO, "cache is null: %s", cstring);
fcinfo->flinfo->fn_extra = (MyCache *)MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(MyCache));
cache = (MyCache *)(fcinfo->flinfo->fn_extra);
cache->str = cstring;
cache->data = DirectFunctionCall1Coll(md5_text, InvalidOid, CStringGetTextDatum(cstring));
} else {
elog(INFO, "cache used: %s", cstring);
}
return cache->data;
}
Datum
my_txt_func(PG_FUNCTION_ARGS)
{
Datum result, result2;
result = CallerFInfoFunctionCall1(test_fn_extra_hash_function,
fcinfo->flinfo,
InvalidOid,
PG_GETARG_DATUM(0));
// fn_extraが使われているのを確認するため、もう一度呼び出してみる
result2 = CallerFInfoFunctionCall1(test_fn_extra_hash_function,
fcinfo->flinfo,
InvalidOid,
PG_GETARG_DATUM(0));
PG_RETURN_TEXT_P(result2);
}
}}}
* サンプルプログラム [#xcd4fcab]
#geshi(c){{
#include "parser/parse_func.h"
#include "fmgr.h"
// 関数呼び出しのサンプル
void test_func_invoke()
{
FmgrInfo *fmgr = palloc(sizeof(FmgrInfo));
FunctionCallInfoData fcinfo;
List *names = list_make1(makeString("abs"));
Oid argtypes[] = { INT8OID };
// abs関数を探索
Oid funcOid = LookupFuncName(names, list_length(names), argtypes, false);
int64 arg0 = -100; // 引数
if (funcOid != InvalidOid) {
fmgr_info(funcOid, fmgr); // abs(int64);
InitFunctionCallInfoData(fcinfo, fmgr, 1, 0, NULL, NULL);
fcinfo.isnull = false; // 結果はnullでない
fcinfo.argnull[0] = false; // 引数なnullでない
fcinfo.arg[0] = Int64GetDatum(arg0); // 引数を設定
// 関数の実行 No.1) fmgr_infoで実際に呼び出される関数ポインタがfcinfoにセットされている
Datum result = FunctionCallInvoke(&fcinfo);
// 結果Datumから値を取り出す
elog(INFO, "abs(-100) = %ld", DatumGetInt64(result));
// 関数の実行 No.2) 上の手続きを簡略化してくれるもっと便利な関数を使って実行してみる
FunctionCall1Coll(fmgr, 0, Int64GetDatum(arg0));
result = FunctionCallInvoke(&fcinfo);
elog(INFO, "abs(-100) = %ld", DatumGetInt64(result));
}
// 関数の実行 No.3) 更に上の手続きをもっと簡略化してくれるもっと便利な関数を使って実行してみる
result = OidFunctionCall1Coll(1396, 0, Int64GetDatum(arg0));
elog(INFO, "abs(-100) = %ld", DatumGetInt64(result));
}
/* Output is the following:
------------------------------
INFO: abs(-100) = 100
INFO: abs(-100) = 100
INFO: abs(-100) = 100
*/
}}
* 参考・関連 [#hbd36355]
- [[fmgr.h>https://doxygen.postgresql.org/fmgr_8h.html]] - on doxygen.postgresql.org
- [[fmgr.c>https://doxygen.postgresql.org/fmgr_8c.html]] - on doxygen.postgresql.org
- [[fmgrtab.h>https://doxygen.postgresql.org/fmgrtab_8h.html]] - on doxygen.postgresql.org
- [[CREATE FUNCTION>https://www.postgresql.jp/document/9.5/html/sql-createfunction.html]] - PostgreSQL 9.5文書
- [[49.37. pg_proc>https://www.postgresql.jp/document/9.5/html/catalog-pg-proc.html]] - PostgreSQL 9.5文書
&size(12){&color(white,orange){ 関連 };};
#related
* コメント [#cd6bf6cf]
#comment