2
1

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 5 years have passed since last update.

PostgreSQLでbyteaデータをファイルに書き出す関数

Posted at

PostgreSQLのpg_file_write()を参考に、byteaデータをファイルに書き出す関数pg_file_write_binary()を作成します。

以下の内容のpg_file_write_binary.cを用意。

# include "postgres.h"

# include <sys/stat.h>

# include "utils/builtins.h"

# ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
# endif

PG_FUNCTION_INFO_V1(pg_file_write_binary);

Datum
pg_file_write_binary(PG_FUNCTION_ARGS)
{
	FILE	   *f;
	char	   *filename;
	text	   *data;
	int64		count = 0;

	if (!superuser())
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
			  (errmsg("only superuser may write file"))));

	/*
	 * Basically convert_and_check_filename() should be called to
	 * validate the given filepath. But text_to_cstring() is used instead
	 * for simplicity's sake.
	 */
	filename = text_to_cstring(PG_GETARG_TEXT_P(0));
	data = PG_GETARG_BYTEA_P(1);

	if (!PG_GETARG_BOOL(2))
	{
		struct stat fst;

		if (stat(filename, &fst) >= 0)
			ereport(ERROR,
					(ERRCODE_DUPLICATE_FILE,
					 errmsg("file \"%s\" exists", filename)));

		f = fopen(filename, "wb");
	}
	else
		f = fopen(filename, "ab");

	if (!f)
		ereport(ERROR,
				(errcode_for_file_access(),
				 errmsg("could not open file \"%s\" for writing: %m",
						filename)));

	if (VARSIZE(data) != 0)
	{
		count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f);

		if (count != VARSIZE(data) - VARHDRSZ)
			ereport(ERROR,
					(errcode_for_file_access(),
					 errmsg("could not write file \"%s\": %m", filename)));
	}
	fclose(f);

	PG_RETURN_INT64(count);
}

pg_file_write_binary.cをコンパイル。
/PATH_TO_PGSQLにはPostgreSQLのインストール先ディレクトリを指定。

$ gcc -fpic -c pg_file_write_binary.c -I/PATH_TO_PGSQL/include/server
$ gcc -shared -o /PATH_TO_PGSQL/lib/pg_file_write_binary.so pg_file_write_binary.o

pg_file_write_binary()をPostgreSQLに登録。

CREATE FUNCTION pg_file_write_binary(text, bytea, boolean default false) RETURNS bigint AS 'pg_file_write_binary' LANGUAGE C STRICT VOLATILE;

pg_file_write_binary()は、以下の引数を受けとり、書き出したデータのバイト数をbigint型で返却します。

  • 引数1: データを書き出すファイルのパス (text型)
  • 引数2: 書き出すデータ (bytea型)
  • 引数3: データをファイルに追記するかどうか (boolean型)
  • 未指定の場合はfalseで、追記しない

pg_read_binary_file()で読み込んだバイナリデータ(bytea型)を、pg_file_write_binary()で別ファイルに書き出してみる。

SELECT pg_file_write_binary('pg_control.bak', pg_read_binary_file('global/pg_control'));

元のファイルglobal/pg_controlと書き出し先のファイルpg_control.bakを比較する。

$ diff $PGDATA/global/pg_control $PGDATA/pg_conrol.bak
2
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?