PostgreSQL/開発

概要

  • 関数マネージャと関数呼び出しインターフェースの定義ファイル
fmgr_overview.png

定義

変数,エイリアス

マクロ

列挙型

構造体

FmgrInfo

番号データ型フィールド説明
1PGFunctionfn_addr実行される関数のポインタ
2Oidfn_oid関数のOID
3shortfn_nargs関数の引数の数
4boolfn_strict関数がstrictモードが否か。
true:strictモード,false:strictモードでない
5boolfn_retsetsetを返す関数か否か。
true:setを返す,false:setを返さない
6unsigned charfn_stats関数が統計情報を収集するか。この値より大きな値の場合に収集する。
 参考  enum TrackFunctionsLevel - on doxygen.postgresql.org
7void*fn_extra関数で利用可能な領域
8MemoryContextfn_mcxtfn_extraを格納するためのメモリコンテキスト
9fmNodePtrfn_exprパースツリーのノード表現

システムカタログの関数情報を保持する。

 サンプル 

// 指定されたOIDの関数情報を取得する。
FmgrInfo *fmgr = palloc(sizeof(FmgrInfo));
fmgr_info((Oid)1396, fmgr); // abs(int64)の情報を構造体に格納する

FunctionCallInfoData

番号データ型フィールド説明
1FmgrInfo*flinfo関数情報を保持する構造体のポインタ
2fmNodePtrcontext関数呼び出しのコンテキスト。
例:TriggerData,AggState,WindowAggState
3fmNodePtrresultinfo実行結果に関する情報。
例:ReturnSetInfo
4Oidfncollationcollation
5boolisnull結果がNULLを返すか否か。
true:返す,false:返さない
6shortnargs関数の引数の数
7Datumarg[FUNC_MAX_ARGS]引数
8boolargnull[FUNC_MAX_ARGS]arg[i]がNULLであるか否か
true:NULL,false:NULLでない

関数呼び出しに関する情報を保持する構造体。

 参考  FunctionCallInfoData - on doxygen.postgresql.org

 サンプル 

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

番号データ型フィールド説明
1intapi_versionapiのバージョン

関数インターフェースのバージョンを示す情報を格納する。独自の拡張機能や関数を作成するときに,以下のサンプルのようにマクロを使った際に展開され定義される。

 サンプル 

#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;
/*

関数

fmgr_info

// 引数1:関数のOid
// 引数2:FmgrInfo構造体のポインタ
extern void fmgr_info(Oid functionId, FmgrInfo *finfo);
  • 指定されたfunctionIdの関数情報を探索し,finfoに設定する。

 参考  fmgr_info() - on doxygen.postgresql.org

 サンプル 

FmgrInfo flinfo;
fmgr_info(functionId, &flinfo); // fill flinfo

fmgr_info_cxt

// 引数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

// 引数1:コピー先のFmgrInfo構造体のポインタ
// 引数2:コピー元のFmgrInfo構造体のポインタ
// 引数3:fx_extraを使用する際のメモリコンテキスト
extern void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
  • FmgrInfo構造体のデータをコピーする(memcpy)

 サンプル 

FmgrInfo destinfo, srcinfo;
fmgr_info(1396, &srcinfo);
fmgr_info_copy(&destinfo, &srcinfo, CurrentMemoryContext);

DirectFunctionCall<N>Coll

// 引数1:呼び出す関数のポインタ
// 引数2:collation
// 引数3:関数の引数
extern Datum DirectFunctionCall<N>Coll(PGFunction func, Oid collation, Datum arg1[, ...arg9]);
  • fmgrを経由せず直接関数を呼び出す。

 サンプル 

#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

// 引数1:FmgrInfo構造体のポインタ
// 引数2:collation
// 引数3:関数の引数
extern Datum FunctionCall<N>Coll(FmgrInfo *flinfo, Oid collation, Datum arg1[, ...arg9]);
  • 既に解決済みの関数情報を使って関数を呼び出す。

 サンプル 

#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

// 引数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フィールドを使用する場合に使う。

 サンプル 

#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);
}

InputFunctionCall

// 引数1:入力変換関数の関数情報
// 引数2:引数文字列
// 引数3:引数の型を示すOid
// 引数4:ドメイン(ドメインを使用していない場合は、-1を指定すれば良い)
// 戻り値:入力変換関数の実行結果
extern Datum InputFunctionCall(FmgrInfo *flinfo, char *str,  Oid typioparam, int32 typmod);
  • 指定された引数文字列を、入力変換関数を使って指定した型に変換する。

サンプル

/*
 * select myfunc('100') + 1 => 101
 */
Datum
myfunc(PG_FUNCTION_ARGS)
{
	FmgrInfo fminfo;
	Oid pronOid,
		typinput,
		typioparam;
	Datum result;
	int32 typmod = -1;

	pronOid = fmgr_internal_function("int4in");
	fmgr_info(pronOid, &fminfo);
	if (pronOid == InvalidOid) {
		elog(ERROR, "not found int4in function");
	}

	text *txt = PG_GETARG_TEXT_PP(0);
	char *str = text_to_cstring(txt);

	/* Get input function and parameter information of type INT4 */
	getTypeInputInfo(INT4OID, &typinput, &typioparam);
	getBaseTypeAndTypmod(INT4OID, &typmod);

	/* Call input function with the specified string 'str' */
	result = InputFunctionCall(&fminfo, str, typioparam, typmod);
	return result;
}

Datatype I/O functions

OidInputFunctionCall

// 引数1:入力変換関数のOid
// 引数2:引数文字列
// 引数3:引数の型を示すOid
// 引数4:ドメイン(ドメインを使用していない場合は、-1を指定すれば良い)
// 戻り値:input関数の実行結果
extern Datum OidInputFunctionCall(Oid functionId, char *str,  Oid typioparam, int32 typmod);
  • 指定された引数文字列を、入力変換関数を使って指定した型に変換する。

サンプル

/*
 * select myfunc('100') + 1 => 101
 */
Datum
myfunc(PG_FUNCTION_ARGS)
{
	Datum 	result;
	Oid		typinput,
			typioparam;
	int32	typmod = -1;

	text *txt = PG_GETARG_TEXT_PP(0);
	char *str = text_to_cstring(txt);

	/* Get input function and parameter information of type INT4 */
	getTypeInputInfo(INT4OID, &typinput, &typioparam);
	getBaseTypeAndTypmod(INT4OID, &typmod);

	/* Call input function with the specified string 'str' */
	result = OidInputFunctionCall(typinput, str, typioparam, typmod);
	return result;
}

OutputFunctionCall

// 引数1:出力関数の関数情報
// 引数2:変換するデータ
// 戻り値:出力変換後の文字列
extern char *OutputFunctionCall(FmgrInfo *flinfo, Datum val);
  • 指定されたデータを出力変換関数で文字列表現に変換する。

OidOutputFunctionCall

// 引数1:出力関数のOid
// 引数2:変換するデータ
// 戻り値:出力変換後の文字列
extern char *OidOutputFunctionCall(Oid functionId, Datum val);
  • 指定されたデータを出力変換関数で文字列表現に変換する。

サンプル

Datum
myfunc(PG_FUNCTION_ARGS)
{
	Oid typoutput;
	bool typisvarlena;
	char *outputstr;

	Datum arg1 = PG_GETARG_DATUM(0);

	/* Get output function information of type INT4 */
	getTypeOutputInfo(INT4OID, &typoutput, &typisvarlena);

	/* Call output function with the specified Datum data */
	outputstr = OidOutputFunctionCall(typoutput, arg1);
	elog(INFO, "converted to string '%s'", outputstr);
	PG_RETURN_TEXT_P(cstring_to_text(outputstr));
}

ReceiveFunctionCall

// 引数1:
// 引数2:
// 戻り値:
extern Datum ReceiveFunctionCall(FmgrInfo *flinfo, fmStringInfo buf,  Oid typioparam, int32 typmod);
  • 説明

OidReceiveFunctionCall

// 引数1:
// 引数2:
// 戻り値:
extern Datum OidReceiveFunctionCall(Oid functionId, fmStringInfo buf,  Oid typioparam, int32 typmod);
  • 説明

SendFunctionCall

// 引数1:
// 引数2:
// 戻り値:
extern bytea *SendFunctionCall(FmgrInfo *flinfo, Datum val);
  • 説明

OidSendFunctionCall

// 引数1:
// 引数2:
// 戻り値:
extern bytea *OidSendFunctionCall(Oid functionId, Datum val);
  • 説明

Routines in fmgr.c


Routines in dfmgr.c


Fook function entry/exit

サンプルプログラム

#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
*/

参考・関連

 関連

コメント



添付ファイル: filefmgr_overview.png 84件 [詳細]
[PR]

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-02-20 (火) 23:47:02 (270d)
GO TO TOP