昨日、PostgreSQLCOPYコマンドに2種類あると書きましたが、その関連で。データ出力しようとして「書き込み用にオープンできません」などエラーが出たら、たいてい(1)パスの記述ミス(2)フォルダへの書き込み権限がない(3)他のアプリがロック中のファイルに出力しようとしてる、のどれか。その例と対策を書きます。
Contents


以下、サーバ・クライアントともWindowsネイティブ版9.5.3での説明。コマンドプロンプトの代わりにConEmupsqlを使ってますが、動作は同じです。


(1)パスの記述ミス

# \copy pg_class to 'c:/user/public/desktop/ex1.txt';
c:/user/public/desktop/ex1.txt: No such file or directory

# copy pg_class to 'c:/user/public/desktop/ex1.txt';
ERROR:  ファイル"c:/user/public/desktop/ex1.txt"を書き込み用にオープンできません 
でした: No such file or directory

普通の単純ミスで、上はWindowsc:/usersフォルダで最後のsを忘れた場合。メッセージで「書き込み用にオープン…」と出るのはSQLCOPYコマンドだけ(上記2つ目)、psqlのメタコマンドのCOPYでは出ません。

Windowsの場合、出力先のパスはスラッシュ区切り・バックスラッシュ区切りのどちらでも可。全体を二重引用符で囲むとエラーになります(二重引用符という文字から始まる相対パスと見なされる。COPYでの出力に相対パスは使えない)。半角空白があってもそのままでOK。
# \copy pg_class to '"c:/users/public/desktop/ex1.txt"';
"c:/users/public/desktop/ex1.txt: Invalid argument

# copy pg_class to '"c:/users/public/desktop/ex1.txt"';
ERROR:  ファイルへのCOPYでは相対パスで指定できません

# \copy pg_class to 'c:/users/public/desktop/ex1 space.txt'; 
(ok)


出力先パスに日本語を使うと ↓psqlの方は正常(コマンドプロンプトやシェルがSJISの場合)。一方SQLCOPYは、実行できるもののファイル名がDBの文字コードで出力されるため文字化けします。下の例はDBUTF-8。
# \copy pg_class to 'c:/users/public/ex1 日本語.txt'; 
(ok)

# copy pg_class to 'c:/users/public/ex1 日本語.txt';
(ok ただしファイル名は文字化けする)


↓ ファイル名の文字化け以外は、正常に出力されてます。


(2)フォルダへの書き込み権限がない

SQLCOPYコマンドでは、出力先に指定したフォルダに「DBサーバの実行ユーザ」が書き込めることが必須。またpsqlではカレントユーザの書き込み権限が必要。これがない場合Permission deniedのエラーが出ます。

対策は出力先フォルダにきちんと書き込み権限を設定するか、とりあえず権限があると分かってる場所(例えばユーザのホーム)に出力して後で移動すること。でもWindowsではなぜか「サーバから、実行ユーザの書き込み権限があってもエラーになる」フォルダがあったりします。

↓ 例えばc:/users/public/desktopに出力する場合。今回サーバ・psqlとも同一の管理者権限ユーザで実行しており、ここに書き込めるはずです。psqlのメタコマンド(クエリ1つ目)は普通に出力できる一方、SQL(サーバ側で実行するCOPYコマンド)は権限がなくエラーという不思議な結果。
# \copy pg_class to 'c:/users/public/desktop/ex1.txt';
(ok)

# copy pg_class to 'c:/users/public/desktop/ex1.txt';
ERROR:  ファイル"c:/users/public/desktop/ex1.txt"を書き込み用にオープンできません 
でした: Permission denied


とくにDBをサービスとして実行している場合、通常のユーザとは違う挙動が多いかも。SQLCOPYでこのエラーが出たら、とりあえずpsqlのメタコマンドでカレントユーザのホームとかに出力し、後で移動するのが簡単。

昨日も書いたとおり、psqlのメタコマンドは全体を1行で書く必要がある(改行を挿入できない)ので、長過ぎるクエリは一時的なビューにするといいです。


(3)出力ファイルを、他のアプリがロック中

Excel用にCSV・TSVで出力してる時にありがち。確認のためExcelで開き、クエリを修正して再度COPYで出力しようとするとExcelが書き込みロック中なのでエラーになります。
# \copy pg_class to 'c:/users/public/desktop/ex2.tsv';
c:/users/public/desktop/ex2.tsv: Permission denied

# copy pg_class to 'c:/users/public/desktop/ex2.tsv';
ERROR:  ファイル"c:/users/public/desktop/ex2.tsv"を書き込み用にオープンできません 
でした: Permission denied


もちろんExcelに限らずエディタ等でも起きます。アプリ側でファイルを閉じるか、別のファイルに出力して下さい。