SlideShare ist ein Scribd-Unternehmen logo
1 von 41
PostgreSQL
C言語によるユーザ定義関数の作り方

   日本PostgreSQLユーザ会
        永安悟史
    snaga@snaga.org
Contents

PostgreSQL関数の基礎知識
もっとも簡単な関数の作成
関数に引数を渡す
レコードを返却する関数の作成
複数行を返却する関数の作成
テーブルを返却する関数の作成
PostgreSQL関数の基礎知識
C言語で関数を作るメリット

PostgreSQLの内部構造にアクセス・操作できる
  共有メモリ
  システムカタログ
外部のさまざまなライブラリと連携できる
  外部ライブラリの機能をPostgreSQLの関数の
  延長で使用できる
高速
  Cですから
関数の種類

引数
 引数無し
 引数有り
戻り値
 値(単一行、単一列)
 レコード(単一行、複数列)
 複数行(複数行、単一列)
 テーブル(複数行、複数列)
開発のおおまかな流れ

  C言語で関数本体を作成する
  Makefileを作成する
  関数を登録するSQLを作成する
  C言語関数のコンパイルとインストール
  SQL文で関数を登録
                      共有              バックエンド
C言語ソース
                    オブジェクト              登録



         Makefile            登録用SQL
もっとも簡単な関数の作成
サンプル(1)

  もっとも簡単な関数
    引数:無し
    戻り値:常にtrueを返す

snaga=# SELECT testfunc1();
 testfunc1
-----------
 t
(1 row)

snaga=#
サンプル(1) ~ C関数の作成

 まず、“testfunc.c” を作る

 1:#include "postgres.h"
 2:#include "fmgr.h"
 3:#include "funcapi.h"
 4:
 5:PG_FUNCTION_INFO_V1(testfunc1);           /*   お約束 */
 6:
 7:extern Datum testfunc1(PG_FUNCTION_ARGS); /*   お約束 */
 8:
 9:Datum                            /* 戻り値は       ‘Datum’ になる */
10:testfunc1(PG_FUNCTION_ARGS)               /*   引数定義 */
11:{
12:        PG_RETURN_BOOL(true);             /*   値を返す */
13:}
サンプル(1) ~ Makefileの作成

 次に Makefile を作成
 1:SRCS            = testfunc.c
 2:
 3:MODULE_big      = testfunc
 4:OBJS            = $(SRCS:.c=.o)
 5:DOCS            =
 6:DATA_built      = testfunc.sql
 7:
 8:ifdef USE_PGXS
 9:PGXS = $(shell pg_config --pgxs)
10:include $(PGXS)
11:else
12:subdir = contrib/testfunc
13:top_builddir = ../..
14:include $(top_builddir)/src/Makefile.global
15:include $(top_srcdir)/contrib/contrib-global.mk
16:endif
サンプル(1) ~ 登録用SQLの作成

    登録用のSQL文を作成する
     “testfunc.sql.in” として作成


                        SQLの関数名

戻り値の型
                                           C言語の関数名


  CREATE OR REPLACE FUNCTION testfunc1()
  RETURNS boolean
  AS 'MODULE_PATHNAME', 'testfunc1'
  LANGUAGE 'C' STRICT;
サンプル(1) ~ 関数のコンパイル

     作成したファイルを contrib/testfunc に置く
      contrib はソースを展開したディレクトリにある
{657}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% pwd
/home/snaga/postgresql-8.1beta2/contrib/testfunc
{658}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% ls -l
合計 12
-rw-r--r--    1 snaga    users         585 9月 24 20:34 Makefile
-rw-r--r--    1 snaga    users         200 9月 24 20:34 testfunc.c
-rw-r--r--    1 snaga    users         110 9月 24 20:36 testfunc.sql.in
{659}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc%
サンプル(1) ~ 関数のコンパイル
      make する(makeコマンドを実行)
{659}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% make
sed 's,MODULE_PATHNAME,$libdir/testfunc,g' testfunc.sql.in >testfunc.sql
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -fno-strict-aliasing
 -fpic -I. -I../../src/include -D_GNU_SOURCE   -c -o testfunc.o testfunc.c
ar crs libtestfunc.a testfunc.o
ranlib libtestfunc.a
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -fno-strict-aliasing
 -fpic -shared -Wl,-soname,libtestfunc.so.0 testfunc.o -L../../src/port
 -Wl,-rpath,/home/snaga/pgsql81b2/lib -o libtestfunc.so.0.0
rm -f libtestfunc.so.0
ln -s libtestfunc.so.0.0 libtestfunc.so.0
rm -f libtestfunc.so
ln -s libtestfunc.so.0.0 libtestfunc.so
{660}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% ls
Makefile         libtestfunc.so.0@    testfunc.o
libtestfunc.a    libtestfunc.so.0.0* testfunc.sql
libtestfunc.so@ testfunc.c            testfunc.sql.in
{661}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc%
サンプル(1) ~ 関数のインストール
                                                            testfunc.sql が
      make install を実行                                      share/contrib に
                                                            インストールされる



{662}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% make install
/bin/sh ../../config/install-sh -c -m 644 testfunc.sql
  /home/snaga/pgsql81b2/share/contrib
/bin/sh ../../config/install-sh -c -m 755 libtestfunc.so.0.0
  /home/snaga/pgsql81b2/lib/testfunc.so
{663}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc%


             Libtestfunc.so.0.0 が
             lib にインストールされる
サンプル(1) ~ 関数の登録

      データベースに対して関数を登録する
{663}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% psql -f ¥
 /home/snaga/pgsql81b2/share/contrib/testfunc.sql
CREATE FUNCTION
{664}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc%


             データベースに対して
             testfunc.sql を実行する
             (実際には一行)
サンプル(1) ~ 動作確認

      psql を使って動作を確認する
{87}snaga@athena:~/pgsql81b2% ./bin/psql
Welcome to psql 8.1beta2, the PostgreSQL interactive terminal.

Type: ¥copyright for distribution terms
      ¥h for help with SQL commands
      ¥? for help with psql commands
      ¥g or terminate with semicolon to execute query
      ¥q to quit

snaga=# SELECT testfunc1();
 testfunc1
-----------
 t
(1 row)

snaga=#
関数に引数を渡す
引数を渡すには

必要な処理は二ヶ所にある
 C言語関数における引数受け取り
 CREATE FUNCTIONによる定義
引数の受け取り方

 マクロ “PG_GETARG_xxx” を使う
   型に対応したマクロは include/fmgr.h を参照
 1:#include "postgres.h"
 2:#include "fmgr.h"
 3:#include "funcapi.h"
 4:
 5:PG_FUNCTION_INFO_V1(testfunc2);
 6:
 7:extern Datum testfunc2(PG_FUNCTION_ARGS);
 8:
                                        ここの定義は変わらない
 9:Datum
10:testfunc2(PG_FUNCTION_ARGS)
11:{
12:      int i = PG_GETARG_INT32(0);         “0” は1番目の引数の意。
13:                                          PG_GETARG_INT32は
14:      PG_RETURN_BOOL(true);               int4型を受け取る場合。
15:}
関数定義のしかた

  関数登録用SQLで引数の型を宣言する
   複数引数の宣言も可能
CREATE OR REPLACE FUNCTION testfunc2(int4)
RETURNS boolean
AS 'MODULE_PATHNAME', 'testfunc2'          渡す引数の型を宣言する
LANGUAGE 'C' STRICT;                       (ここではint4)
レコードを返却する関数の作成
レコードの返し方(1/2)

     レコード(=タプル)として返却するために
       ここでは2つの int8 の組みをレコードとして返す
   Datum
   testfunc3(PG_FUNCTION_ARGS)
   {
       TupleDesc tupd;                 /* タプルの型情報の構造体 */
       HeapTupleData tupleData;        /* タプルのデータ用構造体 */
       HeapTuple tuple = &tupleData;   /* タプルのデータ用ポインタ */
       char *values[2];
                                               タプルの型情報(の入れ物)を作る
       Datum result;
                                                            型情報を作成する
       tupd = CreateTemplateTupleDesc(2, false);
       TupleDescInitEntry(tupd, 1, "c1", INT8OID, -1, 0);
       TupleDescInitEntry(tupd, 2, "c2", INT8OID, -1, 0);

これらのカラムを組みに
してレコードとする。              カラム番号           カラム名          カラムの型
レコードの返し方(2/2)

    データをレコードとして組み立てて返却する
                                バッファを作成して
                                文字列として作成する
                                                 データを文字列の配列と
                                                 して用意する
     values[0] = palloc(32);
     snprintf(values[0], 32, "%d", 128);
     values[1] = palloc(32);                          先に作成した型情報と
     snprintf(values[1], 32, "%d", 256);              データからタプルを作る

     tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupd),
                                    values);

     result = TupleGetDatum(TupleDescGetSlot(tupd), tuple);

     PG_RETURN_DATUM(result);
                                  タプルをDatum型に変換
}
    Datumを返却
関数定義のしかた

  返却される型として “RECORD” を指定する
CREATE OR REPLACE FUNCTION testfunc3()
RETURNS RECORD
AS 'MODULE_PATHNAME', 'testfunc3'
LANGUAGE 'C' STRICT;
動作確認

      関数の呼び出し方
       レコードを返却する場合には、レコードの型情報
       を指定する必要がある。

snaga=# SELECT * FROM testfunc3() f(c1 int8, c2 int8);
 c1 | c2
-----+-----
 128 | 256
(1 row)                                       testfunc3()が返却するのは
                                             int8型のカラム“c1”と
                                             int8型のカラム“c2”である。
snaga=#
                 レコードとして返却される
複数行を返却する関数の作成
概要

SET RETURNING FUNCTION(SRF)とも
呼ばれる
返却する行数と同じ回数、関数が呼び出される
  一回目の呼び出しで初期化
  呼び出し一回につき、一行を返却する
二つのメモリコンテキストを使う
  関数用コンテキスト
  ユーザデータ用コンテキスト
   関数用コンテキストの中にある
コード概要
                                        関数コンテキスト
Datum testfunc4(PG_FUNCTION_ARGS)
{                                            一回目の呼び出し
  FuncCallContext *funcctx;

    if (SRF_IS_FIRSTCALL())                           コンテキスト初期化
    {
      funcctx = SRF_FIRSTCALL_INIT();             呼び出し最大回数を
                                                  設定
        funcctx->max_calls = 3;
    }                                       関数コンテキストを
                                            取り出す
    funcctx = SRF_PERCALL_SETUP();
                                                          回数がMAXに達して
    if (call_cntr < max_calls)                            いなければ行を返す
        SRF_RETURN_NEXT(funcctx, Int32GetDatum(call_cntr));
    else
        SRF_RETURN_DONE(funcctx);
}                                                             Datum型を渡す
                                        呼び出し回数が
                                        最大に達したら
レコードの返し方(1/3)

  関数コンテキスト用のポインタを宣言する
Datum
testfunc4(PG_FUNCTION_ARGS)
{
  FuncCallContext *funcctx;   /* 関数コンテキスト */
  MemoryContext oldcontext;
レコードの返し方(2/3)

       最初の呼び出し時には、関数コンテキストを初期
       化し、ユーザデータ用のメモリ領域も初期化する
       if (SRF_IS_FIRSTCALL())                  関数コンテキスト
                                                初期化
       {                                                       ユーザデータ用コンテ
         funcctx = SRF_FIRSTCALL_INIT();                       キストに切り替え

呼び出し
一回目        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

           /* MyData *fctx = (MyData *) palloc(sizeof(MyData)); */
                                                                     ユーザ用領域を
           funcctx->max_calls = 3;                 呼び出し              確保
           /* funcctx->user_fctx = fctx; */        最大回数を設定

           MemoryContextSwitchTo(oldcontext);       ユーザデータ用コンテ
       }                                            キストを設定
                前のコンテキストに
                切り替え
レコードの返し方(3/3)

    関数コンテキストを取り出す
     呼び出し最大回数を越えてなければ値を
     Datum型で返却する
            SRF_RETURN_NEXT()
           最大回数を越えていたら終了する
            SRF_RETURN_DONE()
    funcctx = SRF_PERCALL_SETUP();

    if (funcctx->call_cntr < funcctx->max_calls)
     SRF_RETURN_NEXT(funcctx, Int32GetDatum(call_cntr));
    else
     SRF_RETURN_DONE(funcctx);
}
コード全体
Datum testfunc4(PG_FUNCTION_ARGS)
{
  FuncCallContext *funcctx;
  MemoryContext oldcontext;

    if (SRF_IS_FIRSTCALL())
    {
      funcctx = SRF_FIRSTCALL_INIT();

        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        /* MyData *fctx = (MyData *) palloc(sizeof(MyData)); */

        funcctx->max_calls = 3;
        /* funcctx->user_fctx = fctx; */

        MemoryContextSwitchTo(oldcontext);
    }

    funcctx = SRF_PERCALL_SETUP();

    if (funcctx->call_cntr < funcctx->max_calls)
      SRF_RETURN_NEXT(funcctx, Int32GetDatum(funcctx->call_cntr));
    else
      SRF_RETURN_DONE(funcctx);
}
関数定義のしかた

  返却される型に追加して “SETOF” を指定する
CREATE OR REPLACE FUNCTION testfunc4()
RETURNS SETOF INT4
AS 'MODULE_PATHNAME', 'testfunc4'
LANGUAGE 'C' STRICT;
動作確認

      関数の呼び出し方
snaga=# SELECT testfunc4();
 testfunc4
-----------
         1
         2
         3
(3 rows)

snaga=#         int4型の値が複数行に
                渡って返却される
テーブルを返却する関数の作成
概要

マニュアルではTable Functionと呼ばれている
ここまで解説した手法を組み合わせる
  「複数行」の「レコード」を返却する関数として
  実装する
コード全体(1/2)
Datum
testfunc5(PG_FUNCTION_ARGS)
{
                                    最初の呼び出しの場合
  FuncCallContext *funcctx;
  MemoryContext oldcontext;

                                             関数コンテキスト初期化
  if (SRF_IS_FIRSTCALL())
  {
    TupleDesc tupd;                                                 ユーザ領域用コンテキス
                                                                    トに切り替え
      funcctx = SRF_FIRSTCALL_INIT();

      oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
                                                                            タプルデスクリプタ作成
      tupd = CreateTemplateTupleDesc(2, false);
      TupleDescInitEntry(tupd, 1, "c1", INT8OID, -1, 0);
      TupleDescInitEntry(tupd, 2, "c2", INT8OID, -1, 0);

      funcctx->max_calls = 3;                      タプルデスクリプタを
      funcctx->user_fctx = tupd;                   ユーザ領域に保存
                                                                            前のコンテキストに
      MemoryContextSwitchTo(oldcontext);                                    戻す
  }
コード全体(2/2)
    funcctx = SRF_PERCALL_SETUP();
                                                         関数コンテキストを取り出す
    if (funcctx->call_cntr < funcctx->max_calls)         (毎回呼ばれる)
    {
      TupleDesc tupd;
      HeapTupleData tupleData;
      HeapTuple tuple = &tupleData;              ユーザ用コンテキストから
      Datum result;                              タプルデスクリプタを取り出す
      char *values[2];
                                                                   タプルデータを組み立てる
      tupd = (TupleDesc)funcctx->user_fctx;
                                                                   (適当な数値データを作
                                                                   成)
      values[0] = palloc(32);
      snprintf(values[0], 32, "%d", 128 * funcctx->call_cntr);                   タプルデスクリプタとデータ
      values[1] = palloc(32);                                                    からレコードを作製
      snprintf(values[1], 32, "%d", 256 * funcctx->call_cntr);

      tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupd), values);
      result = TupleGetDatum(TupleDescGetSlot(tupd), tuple);

      SRF_RETURN_NEXT(funcctx, result);
    }                                               レコードを返却
    else
      SRF_RETURN_DONE(funcctx);
}
関数定義のしかた

  “SETOF” な “RECORD” を 返却する
CREATE OR REPLACE FUNCTION testfunc5()
RETURNS SETOF RECORD
AS 'MODULE_PATHNAME', 'testfunc5'
LANGUAGE 'C' STRICT;
動作確認

      関数の呼び出し方
snaga=# SELECT * FROM testfunc5() f(c1 int8, c2 int8);
 c1 | c2
-----+-----
   0 | 0
 128 | 256
 256 | 512                                   testfunc5()が返却するのは
(3 rows)                                     int8型のカラム“c1”と
                                           int8型のカラム“c2”である。
snaga=#
          “c1”, “c2” から成るレコードが
          複数返却される
Appendix

引数の受け取り方(include/fmgr.h)
 PG_GETARG_xxxx()
値の返却(include/fmgr.h)
 PG_RETURN_xxxx()
値とDatumとの変換(include/postgres.h)
 xxxxGetDatum()
 DatumGetxxxx()

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)
統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)
統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
Vacuum徹底解説
Vacuum徹底解説Vacuum徹底解説
Vacuum徹底解説
 
アーキテクチャから理解するPostgreSQLのレプリケーション
アーキテクチャから理解するPostgreSQLのレプリケーションアーキテクチャから理解するPostgreSQLのレプリケーション
アーキテクチャから理解するPostgreSQLのレプリケーション
 
pg_bigmで全文検索するときに気を付けたい5つのポイント(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_bigmで全文検索するときに気を付けたい5つのポイント(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)pg_bigmで全文検索するときに気を付けたい5つのポイント(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_bigmで全文検索するときに気を付けたい5つのポイント(第23回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
押さえておきたい、PostgreSQL 13 の新機能!!(Open Source Conference 2021 Online/Hokkaido 発表資料)
押さえておきたい、PostgreSQL 13 の新機能!!(Open Source Conference 2021 Online/Hokkaido 発表資料)押さえておきたい、PostgreSQL 13 の新機能!!(Open Source Conference 2021 Online/Hokkaido 発表資料)
押さえておきたい、PostgreSQL 13 の新機能!!(Open Source Conference 2021 Online/Hokkaido 発表資料)
 
PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
PostgreSQL開発コミュニティに参加しよう! ~2022年版~(Open Source Conference 2022 Online/Kyoto 発...
PostgreSQL開発コミュニティに参加しよう! ~2022年版~(Open Source Conference 2022 Online/Kyoto 発...PostgreSQL開発コミュニティに参加しよう! ~2022年版~(Open Source Conference 2022 Online/Kyoto 発...
PostgreSQL開発コミュニティに参加しよう! ~2022年版~(Open Source Conference 2022 Online/Kyoto 発...
 
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
速習!論理レプリケーション ~基礎から最新動向まで~(PostgreSQL Conference Japan 2022 発表資料)
速習!論理レプリケーション ~基礎から最新動向まで~(PostgreSQL Conference Japan 2022 発表資料)速習!論理レプリケーション ~基礎から最新動向まで~(PostgreSQL Conference Japan 2022 発表資料)
速習!論理レプリケーション ~基礎から最新動向まで~(PostgreSQL Conference Japan 2022 発表資料)
 
PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQLのfull_page_writesについて(第24回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
Memoizeの仕組み(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
Memoizeの仕組み(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)Memoizeの仕組み(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
Memoizeの仕組み(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
 
PostgreSQL 15の新機能を徹底解説
PostgreSQL 15の新機能を徹底解説PostgreSQL 15の新機能を徹底解説
PostgreSQL 15の新機能を徹底解説
 
PostgreSQL16でのロールに関する変更点(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL16でのロールに関する変更点(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)PostgreSQL16でのロールに関する変更点(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL16でのロールに関する変更点(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
NTT DATA と PostgreSQL が挑んだ総力戦
NTT DATA と PostgreSQL が挑んだ総力戦NTT DATA と PostgreSQL が挑んだ総力戦
NTT DATA と PostgreSQL が挑んだ総力戦
 
PostgreSQL Unconference #29 Unicode IVS
PostgreSQL Unconference #29 Unicode IVSPostgreSQL Unconference #29 Unicode IVS
PostgreSQL Unconference #29 Unicode IVS
 
PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)
PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)
PostgreSQLレプリケーション10周年!徹底紹介!(PostgreSQL Conference Japan 2019講演資料)
 
MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法
 
PostgreSQL 12は ここがスゴイ! ~性能改善やpluggable storage engineなどの新機能を徹底解説~ (NTTデータ テクノ...
PostgreSQL 12は ここがスゴイ! ~性能改善やpluggable storage engineなどの新機能を徹底解説~ (NTTデータ テクノ...PostgreSQL 12は ここがスゴイ! ~性能改善やpluggable storage engineなどの新機能を徹底解説~ (NTTデータ テクノ...
PostgreSQL 12は ここがスゴイ! ~性能改善やpluggable storage engineなどの新機能を徹底解説~ (NTTデータ テクノ...
 
PostgreSQL: XID周回問題に潜む別の問題
PostgreSQL: XID周回問題に潜む別の問題PostgreSQL: XID周回問題に潜む別の問題
PostgreSQL: XID周回問題に潜む別の問題
 

Andere mochten auch

HAクラスタで PostgreSQLレプリケーション構成の 高可用化
HAクラスタで PostgreSQLレプリケーション構成の 高可用化HAクラスタで PostgreSQLレプリケーション構成の 高可用化
HAクラスタで PostgreSQLレプリケーション構成の 高可用化
Takatoshi Matsuo
 
明日から使えるPostgre sql運用管理テクニック(監視編)
明日から使えるPostgre sql運用管理テクニック(監視編)明日から使えるPostgre sql運用管理テクニック(監視編)
明日から使えるPostgre sql運用管理テクニック(監視編)
kasaharatt
 

Andere mochten auch (9)

PostgreSQLコミュニティに飛び込もう
PostgreSQLコミュニティに飛び込もうPostgreSQLコミュニティに飛び込もう
PostgreSQLコミュニティに飛び込もう
 
Psycopg2 - Connect to PostgreSQL using Python Script
Psycopg2 - Connect to PostgreSQL using Python ScriptPsycopg2 - Connect to PostgreSQL using Python Script
Psycopg2 - Connect to PostgreSQL using Python Script
 
"PostgreSQL and Python" Lightning Talk @EuroPython2014
"PostgreSQL and Python" Lightning Talk @EuroPython2014"PostgreSQL and Python" Lightning Talk @EuroPython2014
"PostgreSQL and Python" Lightning Talk @EuroPython2014
 
HAクラスタで PostgreSQLレプリケーション構成の 高可用化
HAクラスタで PostgreSQLレプリケーション構成の 高可用化HAクラスタで PostgreSQLレプリケーション構成の 高可用化
HAクラスタで PostgreSQLレプリケーション構成の 高可用化
 
PostgreSQLの運用・監視にまつわるエトセトラ
PostgreSQLの運用・監視にまつわるエトセトラPostgreSQLの運用・監視にまつわるエトセトラ
PostgreSQLの運用・監視にまつわるエトセトラ
 
Webアプリケーション負荷試験実践入門
Webアプリケーション負荷試験実践入門Webアプリケーション負荷試験実践入門
Webアプリケーション負荷試験実践入門
 
RDB技術者のためのNoSQLガイド NoSQLの必要性と位置づけ
RDB技術者のためのNoSQLガイド NoSQLの必要性と位置づけRDB技術者のためのNoSQLガイド NoSQLの必要性と位置づけ
RDB技術者のためのNoSQLガイド NoSQLの必要性と位置づけ
 
まずやっとくPostgreSQLチューニング
まずやっとくPostgreSQLチューニングまずやっとくPostgreSQLチューニング
まずやっとくPostgreSQLチューニング
 
明日から使えるPostgre sql運用管理テクニック(監視編)
明日から使えるPostgre sql運用管理テクニック(監視編)明日から使えるPostgre sql運用管理テクニック(監視編)
明日から使えるPostgre sql運用管理テクニック(監視編)
 

Ähnlich wie PostgreSQL - C言語によるユーザ定義関数の作り方

ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)
Shinichi Awamoto
 
エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7
Tetsuya Morimoto
 
HandlerSocket plugin for MySQL
HandlerSocket plugin for MySQLHandlerSocket plugin for MySQL
HandlerSocket plugin for MySQL
akirahiguchi
 
Apache Camel Netty component
Apache Camel Netty componentApache Camel Netty component
Apache Camel Netty component
ssogabe
 

Ähnlich wie PostgreSQL - C言語によるユーザ定義関数の作り方 (20)

x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
 
ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
エキ Py 読書会02 2章後半
エキ Py 読書会02 2章後半エキ Py 読書会02 2章後半
エキ Py 読書会02 2章後半
 
TensorFlow XLA 「XLAとは、から、最近の利用事例について」
TensorFlow XLA 「XLAとは、から、最近の利用事例について」TensorFlow XLA 「XLAとは、から、最近の利用事例について」
TensorFlow XLA 「XLAとは、から、最近の利用事例について」
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
 
Ylug 110th kpatch code reading
Ylug 110th kpatch code readingYlug 110th kpatch code reading
Ylug 110th kpatch code reading
 
Apache Torqueについて
Apache TorqueについてApache Torqueについて
Apache Torqueについて
 
C++14 Overview
C++14 OverviewC++14 Overview
C++14 Overview
 
20071030
2007103020071030
20071030
 
エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7
 
HandlerSocket plugin for MySQL
HandlerSocket plugin for MySQLHandlerSocket plugin for MySQL
HandlerSocket plugin for MySQL
 
Apache Camel Netty component
Apache Camel Netty componentApache Camel Netty component
Apache Camel Netty component
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
 
PHP AST 徹底解説
PHP AST 徹底解説PHP AST 徹底解説
PHP AST 徹底解説
 
TypeScript 言語処理系ことはじめ
TypeScript 言語処理系ことはじめTypeScript 言語処理系ことはじめ
TypeScript 言語処理系ことはじめ
 
研究生のためのC++ no.2
研究生のためのC++ no.2研究生のためのC++ no.2
研究生のためのC++ no.2
 
Prosym2012
Prosym2012Prosym2012
Prosym2012
 
Junit4
Junit4Junit4
Junit4
 
Rakuten tech conf
Rakuten tech confRakuten tech conf
Rakuten tech conf
 

Mehr von Satoshi Nagayasu

映画「マネーボール」に学ぶデータ分析と組織行動論
映画「マネーボール」に学ぶデータ分析と組織行動論映画「マネーボール」に学ぶデータ分析と組織行動論
映画「マネーボール」に学ぶデータ分析と組織行動論
Satoshi Nagayasu
 
統計勉強会 分割表とカイ二乗検定
統計勉強会 分割表とカイ二乗検定統計勉強会 分割表とカイ二乗検定
統計勉強会 分割表とカイ二乗検定
Satoshi Nagayasu
 
PostgreSQL Internals - Buffer Management
PostgreSQL Internals - Buffer ManagementPostgreSQL Internals - Buffer Management
PostgreSQL Internals - Buffer Management
Satoshi Nagayasu
 
遊休リソースを用いた 相同性検索処理の並列化とその評価
遊休リソースを用いた相同性検索処理の並列化とその評価遊休リソースを用いた相同性検索処理の並列化とその評価
遊休リソースを用いた 相同性検索処理の並列化とその評価
Satoshi Nagayasu
 

Mehr von Satoshi Nagayasu (20)

データウェアハウスモデリング入門(ダイジェスト版)(事前公開版)
データウェアハウスモデリング入門(ダイジェスト版)(事前公開版) データウェアハウスモデリング入門(ダイジェスト版)(事前公開版)
データウェアハウスモデリング入門(ダイジェスト版)(事前公開版)
 
Oracle対応アプリケーションのDockerize事始め
Oracle対応アプリケーションのDockerize事始めOracle対応アプリケーションのDockerize事始め
Oracle対応アプリケーションのDockerize事始め
 
アナリティクスをPostgreSQLで始めるべき10の理由@第6回 関西DB勉強会
アナリティクスをPostgreSQLで始めるべき10の理由@第6回 関西DB勉強会アナリティクスをPostgreSQLで始めるべき10の理由@第6回 関西DB勉強会
アナリティクスをPostgreSQLで始めるべき10の理由@第6回 関西DB勉強会
 
In-Database Analyticsの必要性と可能性
In-Database Analyticsの必要性と可能性In-Database Analyticsの必要性と可能性
In-Database Analyticsの必要性と可能性
 
10 Reasons to Start Your Analytics Project with PostgreSQL
10 Reasons to Start Your Analytics Project with PostgreSQL10 Reasons to Start Your Analytics Project with PostgreSQL
10 Reasons to Start Your Analytics Project with PostgreSQL
 
pgDay Asia 2016 & 2017
pgDay Asia 2016 & 2017pgDay Asia 2016 & 2017
pgDay Asia 2016 & 2017
 
A Story Behind the Conference, or How pgDay Asia was born
A Story Behind the Conference, or How pgDay Asia was bornA Story Behind the Conference, or How pgDay Asia was born
A Story Behind the Conference, or How pgDay Asia was born
 
データベースエンジニアがデータヘルスの2年間で見たもの(仮)
データベースエンジニアがデータヘルスの2年間で見たもの(仮)データベースエンジニアがデータヘルスの2年間で見たもの(仮)
データベースエンジニアがデータヘルスの2年間で見たもの(仮)
 
PostgreSQL 9.4, 9.5 and Beyond @ COSCUP 2015 Taipei
PostgreSQL 9.4, 9.5 and Beyond @ COSCUP 2015 TaipeiPostgreSQL 9.4, 9.5 and Beyond @ COSCUP 2015 Taipei
PostgreSQL 9.4, 9.5 and Beyond @ COSCUP 2015 Taipei
 
[WIP] pgDay Asia 2016
[WIP] pgDay Asia 2016[WIP] pgDay Asia 2016
[WIP] pgDay Asia 2016
 
PostgreSQL 9.4 and Beyond @ FOSSASIA 2015 Singapore
PostgreSQL 9.4 and Beyond @ FOSSASIA 2015 SingaporePostgreSQL 9.4 and Beyond @ FOSSASIA 2015 Singapore
PostgreSQL 9.4 and Beyond @ FOSSASIA 2015 Singapore
 
PostgreSQL 9.4
PostgreSQL 9.4PostgreSQL 9.4
PostgreSQL 9.4
 
PostgreSQL Community in Japan
PostgreSQL Community in JapanPostgreSQL Community in Japan
PostgreSQL Community in Japan
 
海外の技術カンファレンスに行こう! Let’s go tech conferences overseas!
海外の技術カンファレンスに行こう! Let’s go tech conferences overseas!海外の技術カンファレンスに行こう! Let’s go tech conferences overseas!
海外の技術カンファレンスに行こう! Let’s go tech conferences overseas!
 
Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装
Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装
Django/Celeyを用いたデータ分析Webアプリケーションにおける非同期処理の設計と実装
 
映画「マネーボール」に学ぶデータ分析と組織行動論
映画「マネーボール」に学ぶデータ分析と組織行動論映画「マネーボール」に学ぶデータ分析と組織行動論
映画「マネーボール」に学ぶデータ分析と組織行動論
 
統計勉強会 分割表とカイ二乗検定
統計勉強会 分割表とカイ二乗検定統計勉強会 分割表とカイ二乗検定
統計勉強会 分割表とカイ二乗検定
 
PgAccelerator
PgAcceleratorPgAccelerator
PgAccelerator
 
PostgreSQL Internals - Buffer Management
PostgreSQL Internals - Buffer ManagementPostgreSQL Internals - Buffer Management
PostgreSQL Internals - Buffer Management
 
遊休リソースを用いた 相同性検索処理の並列化とその評価
遊休リソースを用いた相同性検索処理の並列化とその評価遊休リソースを用いた相同性検索処理の並列化とその評価
遊休リソースを用いた 相同性検索処理の並列化とその評価
 

Kürzlich hochgeladen

Kürzlich hochgeladen (11)

論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
 
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native Integrations
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 

PostgreSQL - C言語によるユーザ定義関数の作り方

  • 1. PostgreSQL C言語によるユーザ定義関数の作り方 日本PostgreSQLユーザ会 永安悟史 snaga@snaga.org
  • 4. C言語で関数を作るメリット PostgreSQLの内部構造にアクセス・操作できる 共有メモリ システムカタログ 外部のさまざまなライブラリと連携できる 外部ライブラリの機能をPostgreSQLの関数の 延長で使用できる 高速 Cですから
  • 5. 関数の種類 引数 引数無し 引数有り 戻り値 値(単一行、単一列) レコード(単一行、複数列) 複数行(複数行、単一列) テーブル(複数行、複数列)
  • 6. 開発のおおまかな流れ C言語で関数本体を作成する Makefileを作成する 関数を登録するSQLを作成する C言語関数のコンパイルとインストール SQL文で関数を登録 共有 バックエンド C言語ソース オブジェクト 登録 Makefile 登録用SQL
  • 8. サンプル(1) もっとも簡単な関数 引数:無し 戻り値:常にtrueを返す snaga=# SELECT testfunc1(); testfunc1 ----------- t (1 row) snaga=#
  • 9. サンプル(1) ~ C関数の作成 まず、“testfunc.c” を作る 1:#include "postgres.h" 2:#include "fmgr.h" 3:#include "funcapi.h" 4: 5:PG_FUNCTION_INFO_V1(testfunc1); /* お約束 */ 6: 7:extern Datum testfunc1(PG_FUNCTION_ARGS); /* お約束 */ 8: 9:Datum /* 戻り値は ‘Datum’ になる */ 10:testfunc1(PG_FUNCTION_ARGS) /* 引数定義 */ 11:{ 12: PG_RETURN_BOOL(true); /* 値を返す */ 13:}
  • 10. サンプル(1) ~ Makefileの作成 次に Makefile を作成 1:SRCS = testfunc.c 2: 3:MODULE_big = testfunc 4:OBJS = $(SRCS:.c=.o) 5:DOCS = 6:DATA_built = testfunc.sql 7: 8:ifdef USE_PGXS 9:PGXS = $(shell pg_config --pgxs) 10:include $(PGXS) 11:else 12:subdir = contrib/testfunc 13:top_builddir = ../.. 14:include $(top_builddir)/src/Makefile.global 15:include $(top_srcdir)/contrib/contrib-global.mk 16:endif
  • 11. サンプル(1) ~ 登録用SQLの作成 登録用のSQL文を作成する “testfunc.sql.in” として作成 SQLの関数名 戻り値の型 C言語の関数名 CREATE OR REPLACE FUNCTION testfunc1() RETURNS boolean AS 'MODULE_PATHNAME', 'testfunc1' LANGUAGE 'C' STRICT;
  • 12. サンプル(1) ~ 関数のコンパイル 作成したファイルを contrib/testfunc に置く contrib はソースを展開したディレクトリにある {657}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% pwd /home/snaga/postgresql-8.1beta2/contrib/testfunc {658}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% ls -l 合計 12 -rw-r--r-- 1 snaga users 585 9月 24 20:34 Makefile -rw-r--r-- 1 snaga users 200 9月 24 20:34 testfunc.c -rw-r--r-- 1 snaga users 110 9月 24 20:36 testfunc.sql.in {659}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc%
  • 13. サンプル(1) ~ 関数のコンパイル make する(makeコマンドを実行) {659}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% make sed 's,MODULE_PATHNAME,$libdir/testfunc,g' testfunc.sql.in >testfunc.sql gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -fno-strict-aliasing -fpic -I. -I../../src/include -D_GNU_SOURCE -c -o testfunc.o testfunc.c ar crs libtestfunc.a testfunc.o ranlib libtestfunc.a gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -fno-strict-aliasing -fpic -shared -Wl,-soname,libtestfunc.so.0 testfunc.o -L../../src/port -Wl,-rpath,/home/snaga/pgsql81b2/lib -o libtestfunc.so.0.0 rm -f libtestfunc.so.0 ln -s libtestfunc.so.0.0 libtestfunc.so.0 rm -f libtestfunc.so ln -s libtestfunc.so.0.0 libtestfunc.so {660}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% ls Makefile libtestfunc.so.0@ testfunc.o libtestfunc.a libtestfunc.so.0.0* testfunc.sql libtestfunc.so@ testfunc.c testfunc.sql.in {661}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc%
  • 14. サンプル(1) ~ 関数のインストール testfunc.sql が make install を実行 share/contrib に インストールされる {662}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% make install /bin/sh ../../config/install-sh -c -m 644 testfunc.sql /home/snaga/pgsql81b2/share/contrib /bin/sh ../../config/install-sh -c -m 755 libtestfunc.so.0.0 /home/snaga/pgsql81b2/lib/testfunc.so {663}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% Libtestfunc.so.0.0 が lib にインストールされる
  • 15. サンプル(1) ~ 関数の登録 データベースに対して関数を登録する {663}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% psql -f ¥ /home/snaga/pgsql81b2/share/contrib/testfunc.sql CREATE FUNCTION {664}snaga@athena:~/postgresql-8.1beta2/contrib/testfunc% データベースに対して testfunc.sql を実行する (実際には一行)
  • 16. サンプル(1) ~ 動作確認 psql を使って動作を確認する {87}snaga@athena:~/pgsql81b2% ./bin/psql Welcome to psql 8.1beta2, the PostgreSQL interactive terminal. Type: ¥copyright for distribution terms ¥h for help with SQL commands ¥? for help with psql commands ¥g or terminate with semicolon to execute query ¥q to quit snaga=# SELECT testfunc1(); testfunc1 ----------- t (1 row) snaga=#
  • 19. 引数の受け取り方 マクロ “PG_GETARG_xxx” を使う 型に対応したマクロは include/fmgr.h を参照 1:#include "postgres.h" 2:#include "fmgr.h" 3:#include "funcapi.h" 4: 5:PG_FUNCTION_INFO_V1(testfunc2); 6: 7:extern Datum testfunc2(PG_FUNCTION_ARGS); 8: ここの定義は変わらない 9:Datum 10:testfunc2(PG_FUNCTION_ARGS) 11:{ 12: int i = PG_GETARG_INT32(0); “0” は1番目の引数の意。 13: PG_GETARG_INT32は 14: PG_RETURN_BOOL(true); int4型を受け取る場合。 15:}
  • 20. 関数定義のしかた 関数登録用SQLで引数の型を宣言する 複数引数の宣言も可能 CREATE OR REPLACE FUNCTION testfunc2(int4) RETURNS boolean AS 'MODULE_PATHNAME', 'testfunc2' 渡す引数の型を宣言する LANGUAGE 'C' STRICT; (ここではint4)
  • 22. レコードの返し方(1/2) レコード(=タプル)として返却するために ここでは2つの int8 の組みをレコードとして返す Datum testfunc3(PG_FUNCTION_ARGS) { TupleDesc tupd; /* タプルの型情報の構造体 */ HeapTupleData tupleData; /* タプルのデータ用構造体 */ HeapTuple tuple = &tupleData; /* タプルのデータ用ポインタ */ char *values[2]; タプルの型情報(の入れ物)を作る Datum result; 型情報を作成する tupd = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupd, 1, "c1", INT8OID, -1, 0); TupleDescInitEntry(tupd, 2, "c2", INT8OID, -1, 0); これらのカラムを組みに してレコードとする。 カラム番号 カラム名 カラムの型
  • 23. レコードの返し方(2/2) データをレコードとして組み立てて返却する バッファを作成して 文字列として作成する データを文字列の配列と して用意する values[0] = palloc(32); snprintf(values[0], 32, "%d", 128); values[1] = palloc(32); 先に作成した型情報と snprintf(values[1], 32, "%d", 256); データからタプルを作る tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupd), values); result = TupleGetDatum(TupleDescGetSlot(tupd), tuple); PG_RETURN_DATUM(result); タプルをDatum型に変換 } Datumを返却
  • 24. 関数定義のしかた 返却される型として “RECORD” を指定する CREATE OR REPLACE FUNCTION testfunc3() RETURNS RECORD AS 'MODULE_PATHNAME', 'testfunc3' LANGUAGE 'C' STRICT;
  • 25. 動作確認 関数の呼び出し方 レコードを返却する場合には、レコードの型情報 を指定する必要がある。 snaga=# SELECT * FROM testfunc3() f(c1 int8, c2 int8); c1 | c2 -----+----- 128 | 256 (1 row) testfunc3()が返却するのは int8型のカラム“c1”と int8型のカラム“c2”である。 snaga=# レコードとして返却される
  • 27. 概要 SET RETURNING FUNCTION(SRF)とも 呼ばれる 返却する行数と同じ回数、関数が呼び出される 一回目の呼び出しで初期化 呼び出し一回につき、一行を返却する 二つのメモリコンテキストを使う 関数用コンテキスト ユーザデータ用コンテキスト 関数用コンテキストの中にある
  • 28. コード概要 関数コンテキスト Datum testfunc4(PG_FUNCTION_ARGS) { 一回目の呼び出し FuncCallContext *funcctx; if (SRF_IS_FIRSTCALL()) コンテキスト初期化 { funcctx = SRF_FIRSTCALL_INIT(); 呼び出し最大回数を 設定 funcctx->max_calls = 3; } 関数コンテキストを 取り出す funcctx = SRF_PERCALL_SETUP(); 回数がMAXに達して if (call_cntr < max_calls) いなければ行を返す SRF_RETURN_NEXT(funcctx, Int32GetDatum(call_cntr)); else SRF_RETURN_DONE(funcctx); } Datum型を渡す 呼び出し回数が 最大に達したら
  • 29. レコードの返し方(1/3) 関数コンテキスト用のポインタを宣言する Datum testfunc4(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; /* 関数コンテキスト */ MemoryContext oldcontext;
  • 30. レコードの返し方(2/3) 最初の呼び出し時には、関数コンテキストを初期 化し、ユーザデータ用のメモリ領域も初期化する if (SRF_IS_FIRSTCALL()) 関数コンテキスト 初期化 { ユーザデータ用コンテ funcctx = SRF_FIRSTCALL_INIT(); キストに切り替え 呼び出し 一回目 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* MyData *fctx = (MyData *) palloc(sizeof(MyData)); */ ユーザ用領域を funcctx->max_calls = 3; 呼び出し 確保 /* funcctx->user_fctx = fctx; */ 最大回数を設定 MemoryContextSwitchTo(oldcontext); ユーザデータ用コンテ } キストを設定 前のコンテキストに 切り替え
  • 31. レコードの返し方(3/3) 関数コンテキストを取り出す 呼び出し最大回数を越えてなければ値を Datum型で返却する SRF_RETURN_NEXT() 最大回数を越えていたら終了する SRF_RETURN_DONE() funcctx = SRF_PERCALL_SETUP(); if (funcctx->call_cntr < funcctx->max_calls) SRF_RETURN_NEXT(funcctx, Int32GetDatum(call_cntr)); else SRF_RETURN_DONE(funcctx); }
  • 32. コード全体 Datum testfunc4(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; MemoryContext oldcontext; if (SRF_IS_FIRSTCALL()) { funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* MyData *fctx = (MyData *) palloc(sizeof(MyData)); */ funcctx->max_calls = 3; /* funcctx->user_fctx = fctx; */ MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); if (funcctx->call_cntr < funcctx->max_calls) SRF_RETURN_NEXT(funcctx, Int32GetDatum(funcctx->call_cntr)); else SRF_RETURN_DONE(funcctx); }
  • 33. 関数定義のしかた 返却される型に追加して “SETOF” を指定する CREATE OR REPLACE FUNCTION testfunc4() RETURNS SETOF INT4 AS 'MODULE_PATHNAME', 'testfunc4' LANGUAGE 'C' STRICT;
  • 34. 動作確認 関数の呼び出し方 snaga=# SELECT testfunc4(); testfunc4 ----------- 1 2 3 (3 rows) snaga=# int4型の値が複数行に 渡って返却される
  • 36. 概要 マニュアルではTable Functionと呼ばれている ここまで解説した手法を組み合わせる 「複数行」の「レコード」を返却する関数として 実装する
  • 37. コード全体(1/2) Datum testfunc5(PG_FUNCTION_ARGS) { 最初の呼び出しの場合 FuncCallContext *funcctx; MemoryContext oldcontext; 関数コンテキスト初期化 if (SRF_IS_FIRSTCALL()) { TupleDesc tupd; ユーザ領域用コンテキス トに切り替え funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); タプルデスクリプタ作成 tupd = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupd, 1, "c1", INT8OID, -1, 0); TupleDescInitEntry(tupd, 2, "c2", INT8OID, -1, 0); funcctx->max_calls = 3; タプルデスクリプタを funcctx->user_fctx = tupd; ユーザ領域に保存 前のコンテキストに MemoryContextSwitchTo(oldcontext); 戻す }
  • 38. コード全体(2/2) funcctx = SRF_PERCALL_SETUP(); 関数コンテキストを取り出す if (funcctx->call_cntr < funcctx->max_calls) (毎回呼ばれる) { TupleDesc tupd; HeapTupleData tupleData; HeapTuple tuple = &tupleData; ユーザ用コンテキストから Datum result; タプルデスクリプタを取り出す char *values[2]; タプルデータを組み立てる tupd = (TupleDesc)funcctx->user_fctx; (適当な数値データを作 成) values[0] = palloc(32); snprintf(values[0], 32, "%d", 128 * funcctx->call_cntr); タプルデスクリプタとデータ values[1] = palloc(32); からレコードを作製 snprintf(values[1], 32, "%d", 256 * funcctx->call_cntr); tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupd), values); result = TupleGetDatum(TupleDescGetSlot(tupd), tuple); SRF_RETURN_NEXT(funcctx, result); } レコードを返却 else SRF_RETURN_DONE(funcctx); }
  • 39. 関数定義のしかた “SETOF” な “RECORD” を 返却する CREATE OR REPLACE FUNCTION testfunc5() RETURNS SETOF RECORD AS 'MODULE_PATHNAME', 'testfunc5' LANGUAGE 'C' STRICT;
  • 40. 動作確認 関数の呼び出し方 snaga=# SELECT * FROM testfunc5() f(c1 int8, c2 int8); c1 | c2 -----+----- 0 | 0 128 | 256 256 | 512 testfunc5()が返却するのは (3 rows) int8型のカラム“c1”と int8型のカラム“c2”である。 snaga=# “c1”, “c2” から成るレコードが 複数返却される