要約:1ヶ月前にCentOS 6.6とPostgreSQL 9.3で行ったのと同じ作業で、新しい点はないけど一応記録まで。仮想マシン内のPostgreSQL 9.5 Alpha 1から、ホストOS(Windows7)のフォルダにアクセスできる環境構築。下のように、PostgreSQLの汎用ファイルアクセス関数でファイル一覧取得や読み込みができます。
実行環境
昨日までと同じで、再掲すると下のとおり。仮想マシンの操作は全てホストOSのコンソールからSSHで。 • ホストOS … Windows7 32bit • ゲストOS … CentOS 7 64bit • ゲストOSの元 … OS Boxes - CentOS 7(VDIファイル)
• 仮想化ソフトウェア … Portable VirtualBox 4.3.6
• ネットワーク設定 … NAT + VirtualBoxのポートフォワーディング • 共有フォルダ … WindowsのRAMDisk(仮想マシン上は/media/sf_win_rにマウント)
仮想マシン上の作業
最低限必要なのは
(1)postgreユーザを、共有フォルダの所有グループvboxsfに追加 (2)PostgreSQLデータディレクトリ下に、共有フォルダへのシンボリックリンクを作成
の二つ。(1)は数日前のSSH接続テスト時に済んでいますが、それを含め一連の流れは次のとおり。
# ログイン
# VirtualBoxのポートフォワーディングを使い、ホスト機からpostgresユーザで
[...\]ssh -p 2233 postgres@localhost

# 設定(root)
# postgresユーザを、共有フォルダの所有グループvboxsfに追加(7月8日の記事の再掲)
su
usermod =G vboxsf postgres

# 上の結果確認
cat /etc/group | grep postgres

# 確認 : postgresユーザが、共有フォルダ内を見たりテキストを書き込めるか
ls /media/sf_win_r
echo 1 > /media/sf_win_r/test1.txt

# 確認 : PostgreSQLデータディレクトリの場所
ls /var/lib/pgsql/9.5/data

# 設定(root)
# PostgreSQLデータフォルダ下に、共有フォルダへのシンボリックリンク作成
su
ln -s /media/sf_win_r /var/lib/pgsql/9.5/data/win_r

# 上の結果確認
# postgresユーザが、シンボリックリンク経由で共有フォルダへ読み書きできるか
ls /var/lib/pgsql/9.5/data/win_r
echo 2 > /var/lib/pgsql/9.5/data/win_r/test2.txt
rm /var/lib/pgsql/9.5/data/win_r/test2.txt
設定を反映するためPostgreSQLを再起動します。
su
service postgresql-9.5 restart
ホストOSから動作確認
昨日の最後に設定したpgAdminを使い、クエリツールで汎用ファイルアクセス関数のテスト。共有フォルダ内の一覧をpg_ls_dir関数で取得し、一つのテキストファイルの中身をpg_read_fileで読み込み。ファイル名に日本語と半角空白があっても特に問題なく読み込めました。画像は冒頭の再掲。
SELECT pg_ls_dir('win_r');
SELECT pg_read_file('win_r/新しいテキスト ドキュメント.txt');
再帰的フォルダ検索のテスト
仮想マシンのPostgreSQLからホスト側フォルダにアクセスできたので、少し実用的に、特定フォルダ下の全フォルダ・ファイル一覧を取得する例。ちょうどPostgreSQL 9.5に関連して下記ブログに例が出てますが(最後の方)、少し違うクエリでやってみました。 » Michael Paquier : Postgres 9.5 feature highlight: New missing_ok option for file access functions
↓ 簡単なサンプルフォルダ・ファイル群を、ホスト側「R:/関東」の下に作成。仮想マシンのPostgreSQLから見れば「./win_r/関東」になります。 ↓ サブフォルダ内を含む全フォルダ・ファイルをリストアップし、ファイルサイズを付けて表示するクエリ。再帰WITH句、pg_ls_dir関数およびpg_stat_file関数を使用。最初の行と再帰部分をつなぐUNIONをUNION ALLにすると無限ループになるので注意です。
WITH RECURSIVE r (path, isdir, size) AS (
    SELECT text 'win_r/関東', TRUE, NULL :: int8
    UNION
    SELECT concat, stat.isdir,
        CASE WHEN stat.isdir THEN NULL ELSE stat.size END
    FROM r, pg_ls_dir(r.path) AS fname,
        concat(r.path, '/', fname),
        pg_stat_file(concat) AS stat
    WHERE r.isdir IS TRUE
)
SELECT * FROM r;
pg_stat_file関数は、ファイルサイズの他に更新時刻も取れます。また上で取得したテキストファイルのpathをpg_read_file関数に渡せば中身も取得可能。そのへんの例はまたいずれ。