2

bytea パラメーターを持つ Postgresql 用の独自の C 関数を作成します。この関数は次のように定義されます

CREATE OR REPLACE FUNCTION putDoc(entity_type int, entity_id int, 
        doc_type text, doc_data bytea) RETURNS text
     AS 'proj_pg', 'call_putDoc'
     LANGUAGE C STRICT;

call_putDocC で記述された私の関数は、doc_dataそのデータを読み取って別の関数に渡し、データfile_magicの MIME タイプを決定してから、データを適切なファイル コンバーターに渡します。

ファイルの内容を最後のパラメータにロードするphpスクリプトからこのpostgresql関数を呼び出します。したがって、ファイルの内容を で渡す必要がありますpg_escape_bytea

データがC関数に渡されるときcall_putDoc、そのデータはすでにエスケープされていませんか?そうでない場合は、どのようにエスケープ解除しますか?

編集:私が見つけたように、いいえ、C関数に渡されたデータはエスケープされていません。エスケープしない方法は?

4

1 に答える 1

7

PostgreSQL用のC関数のプログラミングに関しては、ドキュメントでいくつかの基本事項が説明されていますが、残りの部分については、通常、PostgreSQLサーバーのソースコードを読むことになります。

ありがたいことに、コードは通常、適切に構造化されており、読みやすくなっています。でも、もっとドキュメントコメントがあればいいのにと思います。

ソースコードをナビゲートするためのいくつかの重要なツールは次のいずれかです。

  • 優れたIDE。また
  • およびfindコマンドgit grep

byteaこの場合、見てみると、あなたの議論解読されていると思います-少なくともPg 9.2では、8.4が異なった振る舞いをする可能性があります(かなりありそうもないですが)。putDocサーバーは関数を呼び出す前に自動的にそれを行う必要があります。SQLから関数を呼び出す方法にプログラミングエラーがあると思われます。ソースがなければ、これ以上言うのは難しいです。

  • 8.4サーバー用に正しくエンコードされていることを確認したサンプルデータを使用しputDocて呼び出してみてくださいpsqlescape
  • byteain関数の前にブレークポイントが呼び出されることを確認するためにブレークポイントを設定してみてください
  • 以下の手順に従って、私が言ったことが8.4に当てはまることを確認してください。
  • 関数にブレークポイントを設定し、変数を調べるときに関数をgdb使用して、をステップスルーします。必要な、、、、、、などのコマンドをprint説明するgdbチュートリアルがたくさんあるので、ここでは繰り返しません。breakbacktracecontstepnextprint

何が問題なのか:データを二重にエンコードしている可能性があります。たとえば、コメントを考えると、データをエンコードして、に設定してbase64渡したのではないかと思います。次に、Pgはそれをデコードします...生のバイト自体ではなく、バイトのエンコーディングの表現を含むものを提供します。(編集はおそらくコメントに基づいていないように聞こえます)。Pgbytea_outputescapebyteabyteabase64

正しい使用法については、以下をbytea参照してください。

もっと言うには、ソースコードが必要です。

これが私がしたことです:


find -name bytea\*ソースツリーのクイックはを見つけますsrc/include/utils/bytea.h。そこにあるコメントは、関数定義がにあることを示していますutils/adt/varlena.c-これは実際にはであることがわかりますsrc/backend/util/adt/varlena.c

には、 GUCパラメータbytea.hの定義もあります。これは、またはで表示されるものです。bytea_outputSHOW bytea_outputSET bytea_outputpsql

のようなbyteaデータを使って何かを行うことがわかっている関数を見てみましょう。非常に短いので、ここにその宣言の1つを含めます。bytea_substrvarlena.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ことを示しています。DatumGetByteaPSlicesrc/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)変換されるのか疑問に思っている場合は、マッピングを確認してください。Cbytea_substrsrc/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バックエンドを終了せず、デバッガーをデタッチして終了するだけです。

于 2012-08-26T21:31:55.927 に答える