[pgsql-jp: 34104] Re: JDBC での COPY

Keitaro Tanakamaru marukei @ tcn-catv.ne.jp
2004年 10月 13日 (水) 14:03:10 JST


田中丸です。

私もJava使いではないので、あまりお役に立てないかもしれませんが、
当初のメールにて

> Java上で、copyコマンドでインポートするファイルを作成し、JDBC経由で以下のコマ 
> ンドを発行しようとしたらエラーが起きました。
> 
> (1)  COPY table_name(c1,c2,c3) FROM '/var/sqlcopy_1.txt' WITH DELIMITER ','
> 
> エラーは、
> 
> (1)'  org.postgresql.util.PSQLException: ERROR: must be superuser to COPY 
> to or from a file
> です。
> 
> これはユーザーの権限問題があるのは知っていましたので、今度は、SQL文を以下のも 
> のに変更しました。

と仰っておられましたが、「ユーザの権限問題」というのはPostgreSQLのユーザと
OSのユーザ、どちらを指しておられますか?

COPYコマンドは、PostgreSQLの管理者(PostgreSQL上の通常は「postgres」ユーザ)
でないと動作しません。
また、ファイルのアクセス権限に関しては、PostgreSQLのバックエンドプロセスを
起動しているOSのアカウント(OS上の通常は「postgres」ユーザであることが多い?)で
読めることが条件になります。

従って、
1.JavaからCOPY用のファイルを生成する際に、OSのpostgresユーザで読み取れる
 フォルダに、読み取れる権限でファイルを生成する
2.JDBCのコネクトの際に、"postgres"ユーザを指定して接続する。

ことが出来ればインポートすることが出来る筈です。



参考までに以下のような環境でテストした結果を以下に示します。

・COPY先テーブルはデータベースhoge内に作成、
・PostgreSQLのユーザはfugaおよびpostgres
・PHPの動作アカウントはOSユーザ nobody
・生成されるファイルと同じ内容を /tmp/copydata_r.csv として 
 所有者root 権限600で作成しておく。

以下が実験に使用したスクリプトです。
-------
<?php
$CopyData=<<<EOD
1,'A'
2,'B'
3,'C'
\.

EOD;

$fp = fopen("/tmp/copydata.csv","w");
fwrite($fp,$CopyData);
fclose($fp);
print "A<BR>";// PostgreSQLユーザは管理者以外:ファイルはOSユーザpostgresからアクセス可能
pg_connect("host=localhost port=5432 dbname=hoge user=fuga password=fugapwd");
pg_exec("COPY test FROM '/tmp/copydata.csv' WITH DELIMITER ','");
print "B<BR>";// PostgreSQLユーザは管理者:ファイルはOSユーザpostgresからアクセス可能
pg_connect("host=localhost port=5432 dbname=hoge user=postgres password=rootpwd");
pg_exec("COPY test2 FROM '/tmp/copydata.csv' WITH DELIMITER ','");
print "C<BR>";// PostgreSQLユーザは管理者以外:ファイルはOSユーザpostgresからアクセス不可
pg_connect("host=localhost port=5432 dbname=hoge user=fuga password=fugapwd");
pg_exec("COPY test3 FROM '/tmp/copydata_r.csv' WITH DELIMITER ','");
print "D<BR>";// PostgreSQLユーザは管理者:ファイルはOSユーザpostgresからアクセス不可
pg_connect("host=localhost port=5432 dbname=hoge user=postgres password=rootpwd");
pg_exec("COPY test4 FROM '/tmp/copydata_r.csv' WITH DELIMITER ','");

?>
-------
※非常に乱暴なテストプログラムなので細かいツッコミはなしってことで・・・

これを実行した結果は以下の通りとなりました。
-------
A
Warning: pg_exec(): Query failed: ERROR: must be superuser to COPY to or from a file HINT: Anyone can COPY to stdout or from stdin. psql's \copy command also works for anyone. in /path/to/script/copydata.php on line 15
B
C
Warning: pg_exec(): Query failed: ERROR: must be superuser to COPY to or from a file HINT: Anyone can COPY to stdout or from stdin. psql's \copy command also works for anyone. in /path/to/script/copydata.php on line 21
D
Warning: pg_exec(): Query failed: ERROR: could not open file "/tmp/copydata_r.csv" for reading: Permission denied in /path/to/script/copydata.php on line 24
-------
上記を見て分かるとおり、PostgreSQLの管理者(postgres)で接続し、ファイルがOSユーザpostgresからアクセス可能な場合のみ成功します。

言語は異なりますがご参考になれば幸いです。


余談ですが、PHPの場合 http://php.s3.to/man/function.pg-put-line.html の方法でSTDINからのCOPYが可能です。
/**************************************/
/* 田中丸 桂太郎(Keitaro Tanakamaru)  */
/* marukei @ tcn-catv.ne.jp             */
/**************************************/



pgsql-jp メーリングリストの案内