Developer FAQ/ja

== 開発への参加 ==
=== どのようにすれば PostgreSQL の開発に参加できますか? ===
ソースコードをダウンロードして読んでください。 詳細は「最新のソースツリーをダウンロードする方法、また最新のソースに追随する方法は？」を参照して下さい。
pgsql-hackers メーリングリスト ("hackers" と呼ばれます) に参加し、読んでください。ここはプロジェクトの主要開発者やコアメンバが開発について議論する場です。
=== 最新のソースツリーをダウンロードする方法、また最新のソースに追随する方法は？ ===
ソースツリーを取得する方法は幾つかあります。たまに開発に参加するだけの人は最新のソースツリー・スナップショットを ftp://ftp.postgresql.org/pub/snapshot/ から取得できます。
一般的な開発者はソースコード管理システムに anonymous でアクセスして取得しています。ソースツリーは現在 git で管理されています。git からのソースコード取得について、詳細は http://developer.postgresql.org/pgdocs/postgres/git.html と Working with Git を参考にしてください。
=== どのような開発環境が必要ですか? ===
PostgreSQL は主にC言語で開発されています。ソースコードの対象は、主な UNIX プラットフォームと Windows (XP, 2000 以降) です。
多くの開発者は Unix ライクなOS上で、GCC, GNU Make, GDB, Autoconf などのオープンソースのツールを利用して開発しています。もしあなたがオープンソースソフトウェアに貢献した経験があれば、これらのツールは既に良くご存知でしょう。Windows これらのツールを使う開発者は MinGW を使用します。
もっとも、Windows上のほとんどの開発は、今のところマイクロソフトの Visual Studio 2005(version 8)開発環境と付属のツールで行われています。
PostgreSQL をビルドするために必要なソフトウェアの完全な一覧は「必要条件」を参照してください。
ソースコードを頻繁にリビルドする開発者は configure 時に --enable-depend フラグを指定することもできます。これを使うと、ヘッダファイルを修正した際に、それに依存する全てのソースファイルもリビルドされるようになります。
src/Makefile.custom で環境変数を設定することができます (例: CUSTOM_COPT)。これはすべてのコンパイルで使用されます。
=== どの項目の開発が望まれていますか? ===
未解決の機能は Todo にまとまっています。
それぞれの項目については、ML のアーカイブ、標準SQL、推奨書籍などを参考にしてください。参照: 開発者向けの書籍)
=== どのようにすれば PostgreSQL ウェブサイトの開発に参加できますか? ===
PostgreSQL ウェブサイトの開発は、pgsql-www メーリングリストで議論され、インフラチームによって管理されています。postgresql.orgのウェブサイトのソースコードは Subversion のリポジトリに格納され、Tracプロジェクトの一部として提供されています。
== 開発ツールとヘルプ ==
=== ソースコードの構成はどうなっていますか? ===
『How PostgreSQL Processes a Query (PostgreSQL のクエリ処理方式)』(これはソースコードの src/tools/backend/index.html にもあります) をブラウザで見てください。データフロー、フローチャートの中のバックエンド構成要素、共有メモリ内の構成について、簡単に記述されています。フローチャート内の矩形をクリックすると説明が表示されます。説明文の中のディレクトリ名をクリックすると、ソースディレクトリにジャンプし、実際のソースコードを読むことができます。他にも、ソースコード・ディレクトリの中に README ファイルが幾つかあり、モジュールの関数を説明しています。ブラウザからそれらのファイルを読むこともできます。
ソースツリーに含まれる文書以外には、コードについて記述されている論文や発表資料が http://www.postgresql.org/developer/coding にあります。素晴らしい発表資料は http://neilconway.org/talks/hacking/ でも見つかります。
=== 開発に利用できるツールには何がありますか? ===
まず、src/tools ディレクトリ内にある全てのファイルは開発者のために用意されたものです。
 RELEASE_CHANGES リリースのたびに変更が必要な項目
 backend backend ディレクトリ内の説明と処理の流れ
 ccsym 使用中のコンパイラが作成する標準 define を見つける
 copyright コピーライト
 entab スペース文字をタブ文字に変換する (pgindent で使用される)
 find_static static 関数に変更できる関数を見つける
 find_typedef ソースコード中の typedef を見つける
 find_badmacros 括弧の使い方が不適切なマクロを見つける
 fsync ファイル同期を行うシステムコールのコストを比較するスクリプト
 make_ctags vi 用の 'tags' ファイルを各ディレクトリに作成する
 make_diff *.orig とソースの差分を作成する
 make_etags emacs 用の 'etags' ファイルを作成する
 make_keywords キーワードを SQL'92 と比較する
 make_mkid mkid ID ファイルを作成する
 pgcvslog それぞれのリリースのための変更リストを作成する
 pginclude インクルード・ファイルを追加 / 削除するスクリプト
 pgindent ソースファイルのインデントを行う
 pgtest 半自動化されたビルドシステム
 thread スレッドのテストをするスクリプト
src/include/catalog には以下のファイルもあります。
 unused_oids システムカタログ内で使われていないOIDを見つけるスクリプト
 duplicate_oids システムカタログ内で重複しているOIDを見つけるスクリプト
tools/backend については既に他の Q&A で説明済みです。
第2に、タグファイルを扱えるエディタが必要です。関数呼び出しから関数定義をタグ付けできます。さらに低いレベルの関数を手繰ることができ、その後元の関数へ戻ることができます。tag または etags をサポートしているエディタは数多くあります。
第3に、id-utils を ftp://ftp.gnu.org/gnu/id-utils/ から取得してください。
tools/make_mkid を実行し、ソースのシンボルのアーカイブを作成することで、高速に検索できます。
cscope (http://cscope.sf.net/) を使う開発者もいます。その他には glimpse (http://webglimpse.net/) も使われます。
tools/make_diff は差分パッチファイルを作成するツールです。パッチはコンテキスト形式になります。メーリングリストにパッチを投稿する場合はこのコンテキスト形式にしてください。
pgindent はソースコードのスタイルを標準の書式に修正するツールです。通常は、開発サイクルの最終段階で実行されます。ソースコードのスタイルについてはこの質問も参考にしてください。
pginclude は #include を必要ならば追加、不要ならば削除するスクリプトです。
型や関数のようなビルトイン・オブジェクトを追加する場合、それらに対して OID を割り当てる必要があります。この際の規約は、1-9999 の範囲の OID を重複が無いように手作業で割り当てることです。(機構的にはそれぞれのシステムカタログ内で一意であれば問題ないのですが、分かりやすくするためシステム全体で一意になるようにしています。) unused_oids というスクリプトが src/include/catalog にあり、現在使用していない OID を表示します。新しい OID を割り当てる際には unused_oids を参照して未使用のものを使ってください。可能ならば、関連する機能を持つ既存のオブジェクトの近くの OID を選びます。また、OID の割り当てミスを検出する duplicate_oids スクリプトもあります。
=== どんなスタイルが PostgreSQL ソースコードでは使われますか? ===
私たちの標準スタイルは BSD 式です。コードのインデントにはタブを用い、タブはスペース4個分としています。使用するエディタやファイルビューアのタブ幅をスペース4個に設定しておいてください。
vi の場合には .exrc か .vimrc で以下の設定をします:
 set tabstop=4 shiftwidth=4 noexpandtab
less や more では、-x4 を指定すると適切にインデントされます。
tools/editors ディレクトリには emacs, xemacs, vim 用のサンプル設定ファイルがあります。これは PostgreSQL のコーディング・スタイルを維持するのに役立ちます。
pgindent は OS の indent ツールに適切なフラグを指定して実行し、コードを整形します。pgindent は全てのソースコード・ファイルに対して、ベータテストの時期に実行されます。全てのソースファイルは一貫性のある形式に自動で整形されます。記述したとおりに改行されることが必要なコメントは、ブロックコメント形式にする必要があります。コメントを /*------ から開始してください。ブロックコメントは勝手に整形されることはありません。
ドキュメントの『書式』も参照してください。また、この投稿は変数や関数名の命名方針について述べています。
なぜ私たちがソースコード・スタイルにこれほど気にするのかについては、コーディングスタイルの価値がこの記事で述べられています。
=== システムカタログのダイアグラムはありますか? ===
はい。以下を参照してください
* PNG 形式
* SVG 形式
=== 開発者向きの良書はありますか? ===
5冊挙げておきます:
* An Introduction to Database Systems, by C.J. Date, Addison, Wesley
* A Guide to the SQL Standard, by C.J. Date, et. al, Addison, Wesley
* Fundamentals of Database Systems, by Elmasri and Navathe
* Transaction Processing, by Jim Gray and Andreas Reuter, Morgan Kaufmann
* Transactional Information Systems, by Gerhard Weikum and Gottfried Vossen, Morgan Kaufmann
=== configure とは何ですか? ===
configure と configure.in ファイルは GNU autoconf パッケージの一部です。configure を使うと、OS の様々な機能をチェックし、その結果をCプログラムと Makefile の変数に設定します。autoconf は PostgreSQL のメインサーバにインストールされています。configure にオプションを追加するには、configure.in を編集し、その後 autoconf を実行して configure ファイルを生成してください。
configure がユーザに実行される場合、OS の様々な機能をチェックし、その結果を config.status と config.cache に記録します。そして、複数の *.in ファイルを変更します。例えば、Makefile.in がありますが、configure はその中の全ての @var@ パラメータを設定して Makefile ファイルを生成します。
あなたがファイルを編集する必要が生じた場合、configure によって生成されるファイルを変更するのは時間の無駄になります。代わりに *.in ファイルを編集し、再度 configure を実行することでファイルを生成してください。トップディレクトリで make distclean を実行すると、configure が生成する全てのファイルが削除されます。ソースコードとして配布されるファイルだけが残ることになります。
=== 新しい環境へ移植するためにはどうしたら良いですか? ===
新しい環境へ移植 (port) するためには多くの箇所を変更する必要があります。まず src/template から始めましょう。移植先の OS に対応する適切なエントリを追加します。また、src/config.guess を使ってそのOSを src/template/.similar に追加します。OS のバージョンを厳密に一致させてはいけません。configure テストは、最初に正確なOSバージョンを探し、もし見つからなければ、バージョン番号を除いて探そうとします。src/configure.in を編集し、新しいOSを追加します。(上記の configure に関する質問も参照) その後、autoconf を実行するか、src/configure にもパッチを当てます。
次に、src/include/port をチェックし、新しいOS用のファイルを適切に記述して追加します。願わくば、src/include/storage/s_lock.h に既に移植先のCPU用のロックコードがあることを祈りましょう。src/makefiles ディレクトリにも環境ごとの Makefile があります。専用のファイルが必要な場合には、backend/port ディレクトリへ追加します。
=== なぜスレッド, RAWデバイス, 非同期I/O 等の "イケてる" 機能を使わないのですか? ===
OS はサポートしたばかりの最新機能は非常に魅力的ですが、そういった誘惑には抵抗しています。
1つ目に、我々は 15 以上の OS をサポートしているため、採用する前に新機能は広く採用されていいなければなりません。2つ目に、イケてる機能の多くは、実際には劇的な改善に繋がりません。3つ目に、新機能の中には悪い側面を持つものがあり、信頼性を犠牲にしたり、追加のコードを要求されることがあります。それゆえ、我々は新機能にすぐに飛びつきはせず、こなれるまで見送ります。, then ask for testing to show that a measurable improvement is possible.
例として、現在バックエンド・コードでスレッドが使われていない理由を挙げます:
* 歴史的に、スレッドはサポートしない環境とバグがありました。
* 1つのバックエンドでエラーが生じると他のバックエンドにも悪影響が及びます。
* バックエンドのその他の初期化時間と比較して、スレッドの速度面の利点は微々たるものです。
* バックエンド・コードが複雑になります。
* バックエンドプロセスを終了させることにより、OSが完全に素早くリソースを開放でき、メモリーリークとファイルディスクリプタリークを防止することができます。
* スレッド化されたプログラムをデバッグするのは、プロセスをデバッグするのよりもずっと困難です。それに、コアダンプもスレッドではあまり役に立ちません。
* 読み込み専用の実行形式マップと共有バッファを使用するのはプロセスをスレッドのように扱うことになり、非常にメモリ効率が良いです。
* 頻繁にプロセスを生成、消滅させることによりメモリの断片化を防ぐことができます。これは、長い時間動き続けるプロセスでは管理が難しい問題です。
(一つのクエリを複数のコアで処理するために、個々のバックエンドプロセスが複数のスレッドを使うべきかどうかというのはまた別の問題で、ここでは取り扱いません)。
つまり、私たちは新機能を無視しているわけではありません。採用に慎重なだけなのです。TODO リストには、この分野に関する私たちの見解に関する議論がリンクされている場合があります。
=== ブランチはどのように管理されていますか? ===
ブランチの管理とバックポートに関しては、Using Back BranchesとCommitting with Gitを参照して下さい。
=== どこでSQL標準のコピーが入手できますか? ===
ISO や ANSI で購入してください。ISO/ANSI 9075 を探します。ANSI のほうが安価ですが、内容は同じです。
SQL標準の公式コピーは高価なので、開発者の多くはインターネット上にあるドラフト版を利用しています。そのいくつかを挙げます:
* SQL-92 http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
* SQL:1999 http://www.cse.iitb.ac.in/dbms/Data/Papers-Other/SQL1999/ansi-iso-9075-2-1999.pdf
* SQL:2003 http://www.wiscorp.com/sql_2003_standard.zip
* SQL:2008 (preliminary) http://www.wiscorp.com/sql200n.zip
PostgreSQL 文書には PostgreSQL に関する情報と SQL準拠 に関する記述があります。
SQL標準に関するウェブページを挙げます:
* http://troels.arvin.dk/db/rdbms/links/#standards
* http://www.wiscorp.com/SQLStandards.html
* http://www.contrib.andrew.cmu.edu/~shadow/sql.html#syntax (SQL-92)
* http://dbs.uni-leipzig.de/en/lokal/standards.pdf (paper)
注意として、SQL標準のコピーを読むことは、PostgreSQL の開発者になるためには必ずしも必要ではありません。SQL標準の記述を理解することは難しく、長年の経験も必要です。そして、どのみち PostgreSQL の多くの機能は、SQL標準では規定されていないのです。
 
=== 技術的な質問の回答はどこで得られますか? ===
技術的な質問の多くは pgsql-hackers メーリングリストで応えられています。過去のアーカイブは http://archives.postgresql.org/pgsql-hackers/ にあります。
もし過去の議論や回答が見つからない場合には、気軽にメーリングリストに投稿してください。
IRC (irc.freenode.net #postgresql チャネル) でも、新機能の開発に関する質問も含め、主要開発者 (Major contributors) が技術的な質問に答えてくれるでしょう。
== 開発プロセス ==
=== 開発項目を選んだ後、何をすればよいですか? ===
あなたがやりたいことの提案書を添えて、email を pgsql-hackers に送ってください (即採用とはいかないことを覚悟してください)。あなた1人だけで考えて開発することはお勧めしません。別の人が同じ TODO 項目に取り組んでいるかもしれませんし、あなたが TODO 項目を誤解しているかもしれないからです。email では、あなたが採用するつもりの内部実装と、ユーザから見える変更 (新しい文法など) の両方を議論してください。複雑なパッチの場合には、実際に開発を始める前にコミュニティのフィードバックを受けることが重要です。そのような手順を踏まなければ、パッチは却下されてしまうでしょう。もしあなたの開発が企業にスポンサーされている場合には、より効率的に行えるようこの記事を読んでください。
レビュー待ちのパッチ・キューは wiki の CommitFest で管理されています。
=== どのように変更箇所をテストすれば良いですか? ===
==== 基本システムテスト ====
あなたのコードをテストする最も簡単な方法は、最新バージョンのコードでビルドし、コンパイラの警告が出ないことを確認することです。
configure の際に --enable-cassert オプションを指定してビルドするのも良いでしょう。これはソースコード中のアサーションを有効にし、データ破壊やアクセス違反をより多く検知できるようになります。多くの場合、デバッグが容易になります。
その後、psql を使って性能をテストしてください。
==== リグレッションテスト ====
次のステップは、あなたが行った変更に対して既存のリグレッションテスト (回帰テスト) を行うことです。テストするには、ソースツリーのルート・ディレクトリで "make check" を入力してください。失敗した場合には、調査する必要があります。
もしあなたが既存の動作を意図的に変更した場合には、リグレッションテストには失敗するでしょうが、それは実際には間違った動作ではありません。その場合、リグレッションテストを変更するパッチも作成してください。
==== その他の実行時テスト ====
開発には以下のようなツールもよく利用されています。
* valgrind (http://valgrind.kde.org) : メモリテスト
* gprof (GNU binutils に含まれます), oprofile (http://oprofile.sourceforge.net/) : プロファイリング
==== ユニットテスト、統計的解析、モデルチェックなどはどうですか? ====
テスト用フレームワークについては既に多くの議論があり、れらのアイデアを採用している開発者もいます。
Makefile はインクルードファイルに対して依存性を持たないように注意してください。make clean の後でも make が動作する必要があります。もし GCC を使っているのであれば、--enable-depend オプションを configure 時に指定することで、コンパイラに依存性を自動計算させることができます。
=== パッチの開発後、次に何をすれば良いですか? ===
パッチを pgsql-hackers@postgresql.org へ投稿してください。あなたのパッチが迅速にレビューされ、採用されるようにするため、「パッチの投稿」にあるガイドラインに従うよう努めてください。
=== パッチの投稿後には何がありますか? ===
パッチは他の開発者のレビューを受けることになります。採用されることもあれば、追加開発が必要だとして送り返されることもあります。このプロセスの詳しい解説は、『パッチを投稿するには』にあります。
=== どうすればパッチのレビューに参加できますか? ===
あなたが CommitFest に登録されているパッチのレビューに参加することは大歓迎です。詳細は、「パッチのレビュー」を参考にしてください。
=== 著作権の譲渡に合意する必要がありますか？ ===
いいえ。貢献者は自分の著作権を保持します(ヨーロッパの国々ではどちらにせよそうなります)。貢献者は、PostgreSQL Global Development Groupの成員であると見なされます(PGDGに著作権を与えることはできません。なぜなら、PGDGは法的な実体がないからです)。これは、Linuxカーネルや、他の多くのオープンソースプロジェクトで採用されている方法です。
=== 私の著作権表示を適当な場所に追加しても良いですか？ ===
いいえ、そうしないでください。私達は法律的な事項に関する表示は、短く明快にしておきたいと考えています。また、営利企業のユーザにはこれが問題になることがあると聞いています。
=== PostgreSQLライセンス自身が著作権を完全な形で表示することを要求しているのではありませんか？ ===
その通りです。また、これがPostgreSQL Global Development Groupがすべての著作権を保持している理由です。ちなみに、合衆国の法律では著作権が認められるために著作権表示をする必要はありません。ヨーロッパの国々の法律でも同様です。
== 技術的な質問 ==
=== どうすればバックエンドのコードからシステムカタログへ効率的なアクセスができますか? ===
最初にあなたが必要とするタプル (行) を見つける必要があります。それには2つの方法があります。1つは SearchSysCache() やその類似関数を呼び、既知のカタログ用インデックスを使ってシステムカタログを取得する方法です。これはシステムカタログにアクセスする方法として推奨されています。なぜなら、初回の呼び出して必要な行がキャッシュにロードされ、それ以降の呼び出しでは元の表にアクセスする必要が無くなるためです。利用可能なキャッシュの一覧は、src/backend/utils/cache/syscache.c に記載されています。src/backend/utils/cache/lsyscache.c は数多くの特定の列を取得するためのキャッシュ検索関数が定義されています。
返却される行はキャッシュで管理されています。そのため、SearchSysCache() から返された行を変更や削除してはいけません。使用後には ReleaseSysCache() で行を解放する必要があります。解放されたキャッシュは必要に応じて破棄されます。もし ReleaseSysCache() を呼ばなかった場合、キャッシュのエントリはトランザクションの終了までロックされます。開発時には良いかもしれませんが、実際にリリースされるコードでは許されません。
もしシステムキャッシュが利用できない場合には、全てのバックエンドで共有されるバッファキャッシュを介して、表から直接データを取得する必要があります。バックエンドは行を自動的にバッファキャッシュに読み込みます。これを行うには、heap_open() で表を開いた後に、その表のスキャンを heap_beginscan() で開始し、heap_getnext() を HeapTupleIsValid() が true を返す限り繰り返し呼び出します。最後に heap_endscan() を呼びます。スキャンの際にはキーも指定できますが、インデックスは使われません。全ての行がキーと比較され、適合する行のみが返却されます。
ブロック番号とオフセット番号が分かっている場合には heap_fetch() で行を取得することもできます。heap_fetch() では、バッファキャッシュ上の行のロック / アンロックは自動的に行われますが、利用後には Buffer ポインタを渡して ReleaseBuffer() を呼び出す必要があります。
行が得られた後、全ての行タイプで共通のデータを取得することができます。t_self と t_oid は、単に HeapTuple 構造体のエントリにアクセスするだけで読み取れます。表ごとに異なる列を取得する場合には、HeapTuple ポインタ を GETSTRUCT() マクロに渡します。返却されるポインタは構造体のポインタにキャストして使います。例えば pg_proc ならば Form_pg_proc ポインタ、pg_type ならば Form_pg_type ポインタです。その後は構造体ポインタを介してフィールドにアクセスできます:
 ((Form_pg_class) GETSTRUCT(tuple))->relnatts
注意としては、この方法は、固定長かつ非NULLであり、そのフィールドよりも前方の列も固定長かつ非NULLの列でのみ利用可能なことです。さもなければ列の位置は不定になるため、heap_getattr() やその類似関数を使って行から値を取り出す必要があります。
また、有効な行に対して構造体のフィールドを直接書き換えることは避けてください。最も良い方法は、heap_modifytuple() に変更前の行と変更内容を渡すことです。palloc された新しい行が返却され、heap_update() に渡すことができます。削除の場合は、行の t_self を heap_delete() に渡します。t_self は heap_update() でも使うことができます。覚えておく必要があるのは、行は、ReleaseSysCache() の呼び出しで解放されるシステムキャッシュにあるコピーでも、eap_getnext(), heap_endscan(), heap_fetch() の場合は ReleaseBuffer() で解放されるディスクバッファから直接読み取った行でも、構わないということです。もしくは、palloc された行であれば、使用後には pfree() で解放する必要があります。
=== なぜ表, 列, 型, 関数, ビューの名前は Name, NameData, char * といった異なる型として参照されるのですか? ===
表, 列, 型, 関数, ビューの名前はシステムテーブルに Name 型の列として保持されています。Name は固定長でヌル終端の文字列です。サイズは NAMEDATALEN バイトです (デフォルト64バイト)。
 typedef struct nameData
 {
 char data[NAMEDATALEN];
 } NameData;
 typedef NameData *Name;
表, 列, 型, 関数, ビューの名前はユーザクエリを経由して、可変長のヌル終端された文字列としてバックエンドに渡されます。
heap_open() などの多くの関数は、両方の名前型で呼び出れます。Name 型は NULL 終端されているため、char * 型を引数に取る関数に渡しても大丈夫です。ディスク上の名前 (Name) がユーザから渡された名前 (char *) と比較される機会は多く、Name と char * を入れ替えて使える場合も頻繁にあります。
=== なぜデータ構造体を作成するために Node や List を使うのですか? ===
バックエンドの中で柔軟にデータをやり取りする一貫性のある方法だからです。全ての Node はその型を表す NodeTag フィールド持っています。List は複数の Node を保持する単方向リンクリストです。List 内に要素の順序が意味を持つか否かは用途によります。
以下に List 操作コマンドの一部を示します:
;lfirst(i)
;lfirst_int(i)
;lfirst_oid(i)
:データを返します。(それぞれセル i を ポインタ, 整数, OID として)
;lnext(i)
:i の次のセルを返します。
;foreach(i, list)
:list をループし、それぞれのセルを i に格納します。
重要なのは、i が ListCell * 型であることです。セルに格納されたデータではありません。lfirst 関数のいずれかを使ってセルのデータを取得する必要があります。
以下はループ処理を行う典型的なコードです。List 型は Var * 型のデータを格納しており、要素それぞれを処理したい場合です:
 List *list;
 ListCell *i;
 ...
 foreach(i, list)
 {
 Var *var = (Var *) lfirst(i);
 ...
 /* ここで var を使う */
 }
;lcons(node, list)
:node を list の先頭に追加します。list が NIL ならばリストを新規作成します。
;lappend(list, node)
:node を list の末尾に追加します。
;list_concat(list1, list2)
:list1 の末尾に list2 を追加します。
;list_length(list)
:list の長さを返します。
;list_nth(list, i)
:list の i 番目の要素を返します。番号は 0 から数えます。
;lcons_int, ...
:整数版の lcons_int, lappend_int や、OID 版の lcons_oid, lappend_oid もあります。
gdb を使って、ノードを簡単に表示することができます。最初に gdb の表示切り詰めを無効化してください。
 (gdb) set print elements 0
List, Node, 構造体の内容を表示するには、gdb 形式で値を表示する代わりに次の2つのコマンドを使うと、詳しい情報を得ることができます。List の中の Node は展開され、Node はその詳細が出力されます。1番目の関数は短い形式、2番目の関数は長い形式で表示します:
 (gdb) call print(any_pointer)
 (gdb) call pprint(any_pointer)
出力はサーバログに行われますが、postmaster を使わずバックエンドを直接起動していた場合には画面に表示されます。
=== 構造体にフィールドを追加する際、他に何をする必要がありますか? ===
パーサ、リライタ、オプティマイザ、エグゼキュータ (parser, rewriter, optimizer, executor) に渡す構造体の場合には、処理の追加が必要です。構造体の多くは src/backend/nodes で定義されるルーチンをサポートしており、構造体の作成、コピー、読み取り、書き出しを行うことができます。特に、ほとんどのノード型は copyfuncs.c と equalfuncs.c への対応が必須であり、一部は outfuncs.c や readfuncs.c もサポートする必要があります。新しいフィールドをこれらのファイルでもサポートするよう変更してください。そのほかにも追加したフィールドに対応するコードが無いかを探してください。これには既存のフィールドがどのように扱われているかを参考にするのが良いでしょう。mkid が役に立ちます。(利用可能なツール 参照)
=== なぜメモリ確保に palloc() と pfree() を使うのですか? ===
palloc() と pfree() は malloc() と free() の代わりに使われます。その理由は、クエリの完了時に確保した全てのメモリを容易に解放するためです。たとえどこでメモリを確保したのかが分らなくなっても、全てのメモリを解放することが可能になります。クエリ単位ではないメモリ領域もありますが、バックエンドが定義解放します。
=== ereport() とは何ですか? ===
ereport() はフロントエンドにメッセージを送信します。また、実行中のクエリを終了することもできます。使い方の詳細は「サーバ内部からのエラーの報告」を参照してください。
=== CommandCounterIncrement() とは何ですか? ===
通常は、コマンド文は自身が変更した行を見ることはできません。これは「UPDATE foo SET x = x + 1」が正常に動作するために必要です。
しかしながら、トランザクションの中で、そのトランザクションが直前に行った変更結果が必要になる場合もあります。これはコマンド・カウンタ (Command Counter) を利用することで実現できます。カウンタを増加させることでトランザクションを断片に分割し、それぞれの断片はそれ以前に実行した断片の結果を読み取ることができるようになります。CommandCounterIncrement() はコマンド・カウンタを増加させ、トランザクションに新しい断片を追加する処理です。
=== 問い合わせ処理に変更を加える必要が出てきました。パーサ関係のファイルについて手短に説明して下さい。 ===
パーサ関係のファイルは 「src/backend/parser」ディレクトリにあります。
scan.lは、字句解析器(lexer)を定義します。字句解析機は、SQL文を含む文字列を一連のトークンに分解します。トークンは通常は一個の単語(空白を含まず、空白によって区切られているもの)ですが、単一引用符、二重引用符で囲まれている場合は、文字列全体になり得ます。字句解析機は基本的に正規表現を使って定義されており、様々なトークンのタイプが記述できます。
gram.yは、字句解析器が生成したトークンを基本構成要素として使ってSQL文の文法(構文構造)を定義します。文法は、BNF記法で定義されています。BNFは正規表現に似ていますが、文字ではなく、トークン上で動きます。また、パターン(ルール、あるいはBNFにおける生成規則)には名前が付けられており、再帰的に定義できます。よって、自分自身をパターンとして呼び出すことができます。
実際の字句解析器は、flexというツールを使ってscan.lから生成されます。flexのマニュアルは http://flex.sourceforge.net/manual/ で参照できます。
実際のパーサは、bisonというツールを使ってgram.yから生成されます。bisonのマニュアルは http://www.gnu.org/s/bison/ で参照できます。
一つ注意しておくと、もし以前にflexやbisonを使ったことがない場合、学習曲線はかなり急なものになるでしょう。
=== どのようなデバッグ機能を利用できますか? ===
まず、もしあなたがC言語で開発しているならば、必ず --enable-cassert と --enable-debug オプションを有効にして configure を行った状態で動作することを確認してください。アサーションを有効にすると多くの正常性確認処理が有効になります。デバッグシンボルはデバッガ (例えば gdb) を使って期待通りに動作しないコードを追うのに役立ちます。
PostgreSQL サーバには -d オプションがあり、これは詳細メッセージをログに記録します (elog または ereport で DEBUGn の情報を出力します)。-d オプションはデバッグレベルの数値を1つ引数に取ります。高いデバッグレベルを指定するとログファイルのサイズが大きくなるので注意してください。
postmaster が実行中ならば、ウィンドウ (コンソール) を1つ開いて psql を開始します。その後、その psql が接続している postgres プロセスの PID を、SELECT pg_backend_pid() を使って取得します。デバッガをその postgres の PID にアタッチします。デバッガからブレークポイントを設定し、その後 psql セッションからクエリを発行します。もしエラーやログメッセージを出力している場所を探しているのであれば、errfinish にブレークポイントを設定するのが良いでしょう。もしセッションの開始処理をデバッグしたいのであれば、環境変数 PGOPTIONS="-W n" を指定してから psql を開始してください。開始処理に n 秒の遅延を行うため、その間に postgres プロセスにデバッガをアタッチすることができます。ブレークポイントを適切に設定した後に開始処理を継続することになります。
もし postmaster が実行されていないならば、postgres バックエンドをコマンドラインから開始し、SQL 文を直接入力することもできます。しかしながら、これはあまり良い方法ではありません。psql ほど使いやすい環境ではなく (例えばコマンド履歴がありません)、並行処理をテストすることもできないためです。initdb が正常に動作しなくなってしまった場合には役立つかもしれませんが、それ以外の状況ではお勧めしません。
どの関数の実行に時間がかかっているかを知るためにプロファイリングを有効にしてコンパイルすることもできます。configure の際に --enable-profiling を指定してください (この時、性能を測定したいのであれば --enable-casserts は使わないでください。アサーションのチェックは無視できるほど軽量ではないためです)。
サーバプロセスからのプロファイル・ファイルは pgsql/data ディレクトリに出力されます。psql 等のクライアントからのプロファイル・ファイルは、クライアントのカレントディレクトリに置かれます。
Category:FAQ
Category:Japanese