PostgreSQL用のC関数のプログラミングに関しては、ドキュメントでいくつかの基本事項が説明されていますが、残りの部分については、通常、PostgreSQLサーバーのソースコードを読むことになります。
ありがたいことに、コードは通常、適切に構造化されており、読みやすくなっています。でも、もっとドキュメントコメントがあればいいのにと思います。
ソースコードをナビゲートするためのいくつかの重要なツールは次のいずれかです。
- 優れたIDE。また
- および
find
コマンドgit grep
。
bytea
この場合、見てみると、あなたの議論は解読されていると思います-少なくともPg 9.2では、8.4が異なった振る舞いをする可能性があります(かなりありそうもないですが)。putDoc
サーバーは関数を呼び出す前に自動的にそれを行う必要があります。SQLから関数を呼び出す方法にプログラミングエラーがあると思われます。ソースがなければ、これ以上言うのは難しいです。
- 8.4サーバー用に正しくエンコードされていることを確認したサンプルデータを使用し
putDoc
て呼び出してみてくださいpsql
escape
byteain
関数の前にブレークポイントが呼び出されることを確認するためにブレークポイントを設定してみてください
- 以下の手順に従って、私が言ったことが8.4に当てはまることを確認してください。
- 関数にブレークポイントを設定し、変数を調べるときに関数を
gdb
使用して、をステップスルーします。必要な、、、、、、などのコマンドをprint
説明するgdbチュートリアルがたくさんあるので、ここでは繰り返しません。break
backtrace
cont
step
next
print
何が問題なのか:データを二重にエンコードしている可能性があります。たとえば、コメントを考えると、データをエンコードして、に設定してbase64
渡したのではないかと思います。次に、Pgはそれをデコードします...生のバイト自体ではなく、バイトのエンコーディングの表現を含むものを提供します。(編集はおそらくコメントに基づいていないように聞こえます)。Pg
bytea_output
escape
bytea
bytea
base64
正しい使用法については、以下をbytea
参照してください。
もっと言うには、ソースコードが必要です。
これが私がしたことです:
find -name bytea\*
ソースツリーのクイックはを見つけますsrc/include/utils/bytea.h
。そこにあるコメントは、関数定義がにあることを示していますutils/adt/varlena.c
-これは実際にはであることがわかりますsrc/backend/util/adt/varlena.c
。
には、 GUCパラメータbytea.h
の定義もあります。これは、またはで表示されるものです。bytea_output
SHOW bytea_output
SET bytea_output
psql
のようなbytea
データを使って何かを行うことがわかっている関数を見てみましょう。非常に短いので、ここにその宣言の1つを含めます。bytea_substr
varlena.c
Datum
bytea_substr(PG_FUNCTION_ARGS)
{
PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
PG_GETARG_INT32(1),
PG_GETARG_INT32(2),
false));
}
パブリック関数の多くはプライベート実装のラッパーであるため、プライベート実装は、引数が異なる関数で、または他のプライベートコードからも再利用できます。これはそのような場合です。実際の実装はbytea_substring
です。上記のすべては、SQL関数呼び出しインターフェイスを処理することです。入力をDatum
含むことをまったく混乱させません。bytea
bytea_substring
この特定のケースでは、実際の実装はSQLインターフェイスラッパーのすぐ下に続くので、を読んでvarlena.c
ください。
実装はGUCを参照していないようbytea_output
で、基本的にDatumGetByteaPSlice
は、いくつかの国境のケースを処理した後に作業を行うために呼び出すだけです。にあり、次のように定義されたマクロであるgit grep DatumGetByteaPSlice
ことを示しています。DatumGetByteaPSlice
src/include/fmgr.h
#define DatumGetByteaPSlice(X,m,n) ((bytea *) PG_DETOAST_DATUM_SLICE(X,m,n))
どこにPG_DETOAST_DATUM_SLICE
ありますか
#define PG_DETOAST_DATUM_SLICE(datum,f,c) \
pg_detoast_datum_slice((struct varlena *) DatumGetPointer(datum), \
(int32) (f), (int32) (c))
つまり、データムをデトーストしてメモリスライスを返すだけです。これは私に疑問を残します:関数呼び出しインターフェースの一部として、デコードは他の場所で行われていますか?それとも私は何かを逃したことがありますか?
byteain
の入力関数であるを見ると、bytea
確かにデータをデコードしていることがわかります。その関数にブレークポイントを設定すると、SQLから関数を呼び出すときにブレークポイントが作動し、bytea
データが実際にデコードされていることを示します。
たとえば、次のbyteain
コマンドで呼び出すときに呼び出されるかどうかを確認しましょうbytea_substr
。
SELECT substring('1234'::bytea, 2,2);
どのようにしてへの呼び出しにsubstring(bytea)
変換されるのか疑問に思っている場合は、マッピングを確認してください。C
bytea_substr
src/catalog/pg_proc.h
psqlを起動し、バックエンドのpidを取得します。
$ psql -q regress
regress=# select pg_backend_pid();
pg_backend_pid
----------------
18582
(1 row)
次に、別の端末でgdbを使用してそのpidに接続し、ブレークポイントを設定して、実行を続行します。
$ sudo -u postgres gdb -q -p 18582
Attaching to process 18582
... blah blah ...
(gdb) break bytea_substr
Breakpoint 1 at 0x6a9e40: file varlena.c, line 1845.
(gdb) cont
Continuing.
最初のターミナルでは、psqlで実行します。
SELECT substring('1234'::bytea, 2,2);
...そして結果を返さずにハングすることに注意してください。良い。これは、2番目のターミナルでわかるように、gdbのブレークポイントをトリップしたためです。
Breakpoint 1, bytea_substr (fcinfo=0x1265690) at varlena.c:1845
1845 PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
(gdb)
コマンドのバックトレースは呼び出しパスにbt
表示されませんbytea_substr
。これはすべてSQL関数呼び出し機構です。したがって、Pgはbytea
をに渡す前にデコードしていbytea_substr
ます。
これで、でデバッガーをデタッチできますquit
。これはPgバックエンドを終了せず、デバッガーをデタッチして終了するだけです。