とある事情で、 ある Web ベースのシステムのバックエンド DB と フロントエンドのサーバを、 1 日で別のマシンに置き換える準備をすることに。 朝にマシンのインストールを開始。 このついでに、PostgreSQL は 7.0 から 7.2.3 にアップグレードすることにしました。 この作業が…はまった。
まず、ラージオブジェクトを含む PostgreSQL 7.0 データのバックアップ。 やはり pg_dump で取ったデータから、 pg_restore で戻す方が確実だと思うのだけれども、 7.0 時代の pg_dump はラージオブジェクトをダンプする機能がない。 Web を漁ると、pg_dump は過去のバージョンの PostgreSQL サーバからもダンプができるらしく、 ラージオブジェクトを 7.0 のサーバから吸い出すこともできるらしい。
ということで、1 日でやるというリミットから考えて、 試行錯誤の末、安直な手順を考えました。
バックアップとして生成される tar ファイルの中には、 BLOB データのファイルが大量にあり、 ちゃんとラージオブジェクトもバックアップできているようです。 一応、strings(1) で見ると、ラージオブジェクト内のデータが確認できました。
で、さらにここで pg_restore まで順調に動き出したので、 やったぜ、これで OK! と思ったのですが…。 悲しいことに次のエラーが出て中断。
ERROR: Invalid EUC_JP character sequence found (0x....)
Google で調べると、どうも PostgreSQL 7.2 からは、 EUC などの文字コードのチェックが厳しくなっていて、 text のフィールドに EUC として不正なデータが入っていると、 そもそも INSERT できないらしい。 うひゃーっ! だから外字はお断り、って言ったのに… (^^;。
とはいってもすでに時は過ぎ行くのみ。 そういう根本的対策は年が明けたらやることに。 なんとか FreeBSD の distfiles に PostgreSQL 7.1.3 のソースを発見したので、 サーバ側とアプリケーション側の双方の PostgreSQL を 7.1.3 にバージョンダウンすることを決定。
CVSup から昔の ports を持ってくるのも面倒なうえ、 OS も PostgreSQL 7.2.3 より新しい FreeBSD 4.7-RELEASE なので、 そもそも昔の ports の Makefile が動くかどうかも分かりません。 ということで、仕方なく ports を使わずにソースから入れました。
で、上記手順の 7.2.3 を 7.1.3 に変えて一連の処理を実行し、成功! ラージオブジェクトもきちんと書き戻されたようです。
しかし、さらにここで問題が発生。 ラージオブジェクトを使うアプリケーションの一部が動作しない。 どうも lo_creat() が失敗しているらしい。 試行錯誤の結果、 7.0 では lo_creat の引数が、
my $lo = $conn->lo_creat(PGRES_INV_ARCHIVE);
だけでラージオブジェクトを生成できて読み書きできるのですが、 7.1 以降の lo_creat は、
my $lo = $conn->lo_creat(PGRES_INV_ARCHIVE|PGRES_INV_READ|PGRES_INV_WRITE);
にしないとそもそも lo_creat が PGRES_InvalidOid を返してきて、 ラージオブジェクトを生成できない…というのが原因でした。
うーん、久々に全速力ではまったな…。