- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2017-06-26T23:08:39+09:00","default:haikikyou","haikikyou")
#author("2017-06-28T23:25:26+09:00","default:haikikyou","haikikyou")
[[PostgreSQL/開発]]
#contents
* 概要 [#x22e14be]
ここでは,拡張機能の開発で必要となる知識について整理する。~
具体的には,拡張機能のディレクトリ構造,ビルドスクリプト,制御ファイルについて記述する。
* 拡張機能のディレクトリ構造 [#y89187af]
CREATE EXTENSIONとしてインストールされる拡張機能のディレクトリ構造は,以下のようになっている(ここでは,拡張機能を「myext」として説明を進める)。
#geshi{{{
myext
|- myext.control
|- myext--xx.sql
|- Makefile
|- myext.c
}}}
- myext.control
-- CREATE EXTENSIONやALTER EXTENSIONが実行されたときに読み込まれる。
- myext--xx.sql
-- CREATE EXTENSIONやALTER EXTENSIONが実行されたときに実行されるターゲットバージョンのスクリプト。xxからyyへのアップデートに段階的な更新が必要な場合は,myext--xx--yy.sqlのようにする。
- Makefile
-- ビルド定義
- myex.c
-- ソースコード。もちろん複数のソースコードのコンパイル&リンクも問題ない。
&size(12){&color(white,#00afcc){ サンプル1};}; trueを返すだけのmyext関数の作成
各ファイルの内容はざっと最小限で書いて以下のような感じになる。各ファイルの定義内容については後述する。
''Makefile''
#geshi{{{
MODULES = myext
EXTENSION = myext
DATA = myext--1.0.sql
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
}}}
''myext--1.0.sql''
#geshi(sql){{{
\echo Use "CREATE EXTENSION myext" to load this file. \quit
CREATE OR REPLACE FUNCTION myext()
RETURNS BOOL
AS 'MODULE_PATHNAME'
LANGUAGE C STRICT;
}}}
''myext.c''
#geshi(c){{{
#include "postgres.h"
#include "fmgr.h"
#include "funcapi.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(myext);
Datum
myext(PG_FUNCTION_ARGS)
{
PG_RETURN_BOOL(true); // ただtrueを返すだけの関数
}
}}}
この内容で作成される拡張関数だが,以下のような結果を返すものである。
#geshi{{{
postgres=# select myext();
myext
-------
t
(1 row)
}}}
* Makefile [#f07ae49f]
- MODULES
-- 同じ系のソースから生成される共有ライブラリのリスト。
-- myext.cとmyext2.cがあれば,myext.soとmyext2.soが作成される。
#geshi(Make){{{
# myext.soとmyext2.soがターゲットリストに加わる
MODULES = myext myext2
}}}
- MODULE_big
-- 作成する共有ライブラリ。
-- OBJSにオブジェクトファイルを列挙する。
#geshi(Make){{{
# myext.soターゲットが作成される
# イメージ)
# myext.so: $(OBJS)
MODULE_big = myext
OBJS = myext.o hoge.o
}}}
- PROGRAM
-- $(pg_config --bindir)にプログラムがインストールされる実行ファイル。
-- OBJSにオブジェクトファイルを列挙する。
#geshi(Make){{{
PROGRAM = myext
OBJS = myext.o hoge.o
}}}
- EXTENSION
-- 拡張の名前を指定する。$(EXTENSION).controlファイルもパッケージに必要。
#geshi(Make){{{
MODULES = myext
# 拡張の名前
# $(pg_config --sharedir)/extension/にmyext.controlがインストールされる
EXTENSION = myext
}}}
- MODULEDIR
-- DATAやDOCSのインストール先ディレクトリ。
-- $(pg_config --sharedir)/$(MODULEDIR)となる。~
指定がない場合は,EXTENSIONが使われる。EXTENSIONがなければcontribとなる。
#geshi(Make){{{
MODULES = myext
EXTENSION = myext
MODULEDIR = myext
DATA = myext--1.0.sql
}}}
- DATA
-- $(pg_config --sharedir)にインストールされるデータ。
#geshi(Make){{{
MODULES = myext
EXTENSION = myext
DATA = myext--1.0.sql
}}}
- DATA_built
-- $(pg_config --sharedir)にインストールされるデータ。
-- メモ:DATAとの違いがよく分からない,DATAとの違いは$(srcdir)のプリフィックスはつかないこと?
#geshi(Make){{{
MODULES = myext
EXTENSION = myext
DATA_built = myext--1.0.sql
}}}
- DOCS
-- $(pg_config --docdir)にインストールされるドキュメント。
#geshi(Make){{{
MODULES = myext
DOCS = $(addsuffix .example, $(MODULES))
}}}
- SCRIPTS
-- $(pg_config --bindir)にプログラムがインストールされるスクリプト。
#geshi(Make){{{
SCRIPTS = myext.sh
}}}
- SCRIPTS_built
-- $(pg_config --bindir)にプログラムがインストールされるスクリプト。
-- メモ:SCRIPTSとの違いがよく分からない,SCRIPTSとの違いは$(srcdir)のプリフィックスはつかないこと?
#geshi(Make){{{
SCRIPTS_built = myext.sh
}}}
- REGRESS
--リグレッションテストのリスト(.sqlは不要)。
#geshi(Make){{{
# sql/myext.sqlが実行される
REGRESS = myext
}}}
- REGRESS_OPTS
-- リグレッションテストの実行引数。pg_regressに渡すオプション。
#geshi(Make){{{
# portオプションを渡す。
# (デフォルトと異なるportで動作している場合)
REGRESS_OPTS += --port $(PG_PORT)
}}}
- EXTRA_CLEAN
--
#geshi(Make){{{
}}}
- PG_CPPFLAGS
--
#geshi(Make){{{
}}}
- PG_LIBS
--
#geshi(Make){{{
}}}
- SHLIB_LINK
--
#geshi(Make){{{
}}}
- PG_CONFIG
--
#geshi(Make){{{
}}}
- PGFILEDESC
--
#geshi(Make){{{
}}}
* 制御ファイル(.control) [#lb562e94]
* CreateExtension実行の流れ [#x42a29a9]
CREATE EXTENSION呼び出しの流れをデバッガのスタックトレースを実行し俯瞰する。~
まずは,以下のコマンドを実行してみる。
#geshi(sql){{{
CREATE EXTENSION myext;
}}}
最終的にはpg_dlsymが呼ばれるだろうと想定しブレークポイントを貼っておく。以下,コマンドを実行しブレークポイントで中断させた時のスタックトレースである。
#geshi(){{{
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 24.1
* frame #0: 0x000000010edba000 postgres`pg_dlsym(...) at dynloader.c:38 <-- 最終的にシステムコールで共有オブジェクトの読み込み
frame #1: 0x000000010f0083bd postgres`internal_load_library(...) at dfmgr.c:240 <-- ライブラリのロード
frame #2: 0x000000010f007d7f postgres`load_external_function(...) at dfmgr.c:105
frame #3: 0x000000010eb8f532 postgres`fmgr_c_validator(...) at pg_proc.c:823
frame #4: 0x000000010f00c143 postgres`OidFunctionCall1Coll(...) at fmgr.c:1596
frame #5: 0x000000010eb8f0bb postgres`ProcedureCreate(...) at pg_proc.c:726
frame #6: 0x000000010ec45204 postgres`CreateFunction(...) at functioncmds.c:1048
frame #7: 0x000000010ee7520e postgres`ProcessUtilitySlow(...) at utility.c:1361
frame #8: 0x000000010ee73878 postgres`standard_ProcessUtility(...) at utility.c:892
frame #9: 0x000000010ee7299d postgres`ProcessUtility(...) at utility.c:334
frame #10: 0x000000010ec3f486 postgres`execute_sql_string(...) at extension.c:744 <-- インストールスクリプト実行
frame #11: 0x000000010ec39764 postgres`execute_extension_script(...) at extension.c:904
frame #12: 0x000000010ec386af postgres`CreateExtension(...) at extension.c:1461 <-- ここでCREATE EXTENSIONコマンド実行
frame #13: 0x000000010ee74cb9 postgres`ProcessUtilitySlow(...) at utility.c:1281
frame #14: 0x000000010ee73878 postgres`standard_ProcessUtility(...) at utility.c:892
frame #15: 0x000000010ee7299d postgres`ProcessUtility(...) at utility.c:334
frame #16: 0x000000010ee72318 postgres`PortalRunUtility(...) at pquery.c:1183
frame #17: 0x000000010ee7155c postgres`PortalRunMulti(...) at pquery.c:1314
frame #18: 0x000000010ee70b6d postgres`PortalRun(...) at pquery.c:812
frame #19: 0x000000010ee6c527 postgres`exec_simple_query(...) at postgres.c:1104
frame #20: 0x000000010ee6b730 postgres`PostgresMain(...) at postgres.c:4045
frame #21: 0x000000010edd45e2 postgres`BackendRun(...) at postmaster.c:4253
frame #22: 0x000000010edd389d postgres`BackendStartup(...) at postmaster.c:3927
frame #23: 0x000000010edd2965 postgres`ServerLoop at postmaster.c:1698
frame #24: 0x000000010edd02d6 postgres`PostmasterMain(...) at postmaster.c:1306
frame #25: 0x000000010ed1097f postgres`main(...) at main.c:228
frame #26: 0x00007fffdb4e0235 libdyld.dylib`start + 1
frame #27: 0x00007fffdb4e0235 libdyld.dylib`start + 1
}}}
* 参考リンク [#w9a5a10f]
- [[extension.c>https://doxygen.postgresql.org/extension_8c.html]] - &size(11){&color(gray){ on doxygen.postgresql.org };};
- [[CreateExtension()>https://doxygen.postgresql.org/extension_8c.html#a2993f062a957c566d558e3b7eb4f3ef7]] - &size(11){&color(gray){ on doxygen.postgresql.org };};
- [[AlterExtension()>https://doxygen.postgresql.org/extension_8c.html#a97cfb4bd687671e9ff78ce6bfed81381]] - &size(11){&color(gray){ on doxygen.postgresql.org };};
- [[parse_extension_control_file()>https://doxygen.postgresql.org/extension_8c.html#a58f04078439229aa40e334f9bea7ae50]] - &size(11){&color(gray){ on doxygen.postgresql.org };};
- [[PostgreSQL 9.5.4文書 35.15. 関連するオブジェクトを拡張としてパッケージ化>https://www.postgresql.jp/document/9.5/html/extend-extensions.html]] - &size(11){&color(gray){ [[PostgreSQL 9.5.4文書>https://www.postgresql.jp/document/9.5/]] };};
- [[PostgreSQL 9.5.4文書 35.16. 拡張構築基盤>https://www.postgresql.jp/document/9.5/html/extend-pgxs.html]] - &size(11){&color(gray){ [[PostgreSQL 9.5.4文書>https://www.postgresql.jp/document/9.5/]] };};