2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PostgreSQLのECPGで、SQL実行エラー時のみデバッグログを出力する例

Posted at

PostgreSQLに対して、ECPGで以下のSQL実行を行い、SQL実行エラー時のみそのSQL実行のデバッグログを出力する簡単なプログラム例を示します。

  • ローカルで稼働中のPostgreSQLに対して、DBユーザtestuserでデータベースtestdbに接続する。
  • (もし未作成であれば) テーブルtesttblを作成する。テーブルtesttblは、主キーであるinteger型の1カラムnumだけを持つ。
  • プログラムの引数で指定された整数値をテーブルtesttblにINSERTする。
  • SQL実行がエラーになった場合は、そのSQL実行のデバッグログを標準エラー出力に出力する。

これらを実現するECPGプログラムの簡単な例は下記です。

debug.pgc
#include <stdio.h>
#include <stdlib.h>

/*
 * SQL実行でエラーが発生したら、デバッグログを出力のための関数として
 * output_debug()を呼び出すようにグローバルに宣言する。
 */
static void output_debug(void);
EXEC SQL WHENEVER SQLERROR CALL output_debug();

/*
 * デバッグログを一時保存するメモリストリーム関連の変数を宣言する。
 */
static char *debug_buf;
static size_t debug_bufsize;
static FILE *debug_fp;

/*
 * デバッグログを一時保存するメモリストリームをクローズする関数を宣言する。
 */
static void free_debug_buf(void);

/*
 * ECPGの各内部関数を実行する前に、それまでにメモリストリームに
 * 一時保存されていたデバッグログをクリアする。これにより、
 * メモリストリームには、これから実行する各内部関数で生成された
 * デバッグログのみが一時保存される。
 *
 * 今回のコード例ではECPGconnect()、ECPGdo()、ECPGprepare()、
 * ECPGtrans()、ECPGdisconnect()のみに 対応しており、必要に応じて
 * 他の内部関数についても対応しなければならない可能性がある。
 */
#define ECPGconnect(a, b, c, d, e, f, g)	\
	do {	\
		rewind(debug_fp);	\
		ECPGconnect(a, b, c, d, e, f, g);		\
	} while (0)

#define ECPGdo(a, b, c, d, e, f, g, ...)	\
	do {	\
		rewind(debug_fp);	\
		ECPGdo(a, b, c, d, e, f, g, __VA_ARGS__);	\
	} while (0)

#define ECPGprepare(a, b, c, d, e)	\
	do {	\
		rewind(debug_fp);	\
		ECPGprepare(a, b, c, d, e);	\
	} while (0)

#define ECPGtrans(a, b, c)	\
	do {	\
		rewind(debug_fp);	\
		ECPGtrans(a, b, c);	\
	} while (0)

#define ECPGdisconnect(a, b)	\
	do {	\
		rewind(debug_fp);	\
		ECPGdisconnect(a, b);	\
	} while (0)

/*
 * このプログラムのメイン関数。
 * テーブルtesttblにINSERTするレコードの整数値を第1引数で指定できる。
 */
int
main(int argc, char *argv[])
{
	/*
	 * ECPGで使うローカル変数を宣言する。
	 */
	EXEC SQL BEGIN DECLARE SECTION;
	char *sql = "INSERT INTO testtbl VALUES (?)";
	int num = 0;
	EXEC SQL END DECLARE SECTION;

	/*
	 * 第1引数が指定された場合は、引数の整数値をINSERTする。
	 */
	if (argc > 1)
		num = atoi(argv[1]);

	/*
	 * デバッグログを一時保存するメモリストリームをオープンする。
	 */
	debug_fp = open_memstream(&debug_buf, &debug_bufsize);
	if (!debug_fp)
	{
		fprintf(stderr, "could not open dynamic memory buffer stream\n");
		exit(1);
	}

	/*
	 * デバッグログの生成を有効化する。
	 */
	ECPGdebug(1, debug_fp);

	/*
	 * ローカル内で稼働中のPostgreSQLに対して、DBユーザtestuserで
	 * データベースtestdbに接続する。
	 */
	EXEC SQL CONNECT TO testdb@localhost:5432 USER testuser;

	/*
	 * もし未作成であれば、テーブルtesttblを作成する。
	 */
	EXEC SQL CREATE TABLE IF NOT EXISTS testtbl (num integer primary key);

	/*
	 * 動的SQLを使って、テーブルtesttblにレコードを1件INSERTする。
	 */
	EXEC SQL PREPARE teststmt FROM :sql;
	EXEC SQL EXECUTE teststmt USING :num;

	/*
	 * トランザクションを完了する。
	 */
	EXEC SQL COMMIT;

	/*
	 * PostgreSQLへの接続をクローズする。
	 */
	EXEC SQL DISCONNECT;

	/*
	 * デバッグログを一時保存するメモリストリームをクローズする。
	 */
	free_debug_buf();

	return 0;
}

/*
 * SQL実行でエラーが発生したときに呼び出される、
 * デバッグログを出力するための関数。
 */
static void
output_debug(void)
{
	/*
	 * メモリストリームに一時保存されているデバッグログを標準エラー出力に
	 * 出力する。
	 */
	fflush(debug_fp);
	fprintf(stderr, "%s\n", debug_buf);

	/*
	 * デバッグログを一時保存するメモリストリームをクローズする。
	 */
	free_debug_buf();
	exit(1);
}

/*
 * デバッグログを一時保存するメモリストリームをクローズする関数。
 */
static void
free_debug_buf(void)
{
	fclose(debug_fp);
	free(debug_buf);
}

このECPGプログラムは以下のとおりコンパイルします。以下では、PostgreSQLのインストール先を/opt/pgsqlディレクトリとします。

$ ecpg debug.pgc
$ gcc -o debug debug.c -I/opt/pgsql/include -L/opt/pgsql/lib -lecpg

プログラムの実行例は以下のとおりです。

$ ./debug 1
$ ./debug 2
$ ./debug 2
[67125]: ecpg_execute on line 114: query: INSERT INTO testtbl VALUES ($1); with 1 parameter(s) on connection testdb
[67125]: ecpg_execute on line 114: using PQexecPrepared for "INSERT INTO testtbl VALUES ($1)"
[67125]: ecpg_free_params on line 114: parameter 1 = 2
[67125]: ecpg_check_PQresult on line 114: bad response - ERROR:  duplicate key value violates unique constraint "testtbl_pkey"
DETAIL:  Key (num)=(2) already exists.
CONTEXT:  unnamed portal with parameters: $1 = '2'
[67125]: raising sqlstate 23505 (sqlcode -403): duplicate key value violates unique constraint "testtbl_pkey" on line 114
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?