IMHO, there's a better way to handle the deletion of lob objects than the suggested here. The programmer can easily forget to unlink the lob. With the following trigger, no programmer actions are required.
By the way, one problem with bytea fields is that when you query the database, if you ask for that field, the data is actually retrieved. When you query for and oid, only the oid is retrieved and then you can open the lob whenever you want (if it's required).
CREATE OR REPLACE FUNCTION oidtable_after_update_delete()
RETURNS "trigger" AS
$BODY$
BEGIN
IF (TG_OP = 'UPDATE') THEN
IF (OLD.oidfield = NEW.oidfield) OR (OLD.oidfield IS NULL) THEN
RETURN NEW;
END IF;
END IF;
IF (EXISTS (SELECT 1 FROM pg_largeobject WHERE loid = OLD.oidfield)) THEN
PERFORM LO_UNLINK (OLD.oidfield);
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
CREATE TRIGGER oidtable_after_update_delete
AFTER UPDATE OR DELETE
ON oidtable
FOR EACH ROW
EXECUTE PROCEDURE oidtable_after_update_delete();
PDO::pgsqlLOBCreate
(PHP 5 >= 5.1.2, PECL pdo_pgsql >= 1.0.2)
PDO::pgsqlLOBCreate — 新しいラージオブジェクトを作成する
説明
PDO::pgsqlLOBCreate() は、 ラージオブジェクトを作成してその OID を返します。 このオブジェクトに対するデータの読み書きを行う際には、 PDO::pgsqlLOBOpen() を使用してストリームをオープンします。 OID は OID 型のカラムに格納され、ラージオブジェクトを参照するために使用されます。 これにより、行のサイズがどんどん拡大してしまうことを防ぎます。 PDO::pgsqlLOBUnlink() をコールして削除するまで、 ラージオブジェクトはデータベース内に残り続けます。
ラージオブジェクトの大きさは最大 2GB まで拡大できますが、扱い方はめんどうです。 オブジェクトの OID を参照している行をデータベースから削除する際には、 必ず事前に PDO::pgsqlLOBUnlink() がコールされていなければなりません。 さらに、ラージオブジェクトにはアクセス権の設定がありません。 ラージオブジェクトの代替策として、bytea 型のカラムも検討ください。 最近のバージョンの PostgreSQL では bytea 型のカラムに最大 1GB まで保存でき、行サイズを最適化したうえでデータを透過的に扱うことができます。
注意: この関数は、トランザクション内でコールしなければなりません。
パラメータ
PDO::pgsqlLOBCreate() は、パラメータを受け取りません。
返り値
新しく作成されたラージオブジェクトの OID、あるいは失敗した場合に FALSE を返します。
例
例1 PDO::pgsqlLOBCreate() の例
この例では、新しいラージオブジェクトを作成し、 ファイルの内容をそこにコピーします。その後、OID がテーブルに保存されます。
<?php
$db = new PDO('pgsql:dbname=test host=localhost', $user, $pass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->beginTransaction();
$oid = $db->pgsqlLOBCreate();
$stream = $db->pgsqlLOBOpen($oid, 'w');
$local = fopen($filename, 'rb');
stream_copy_to_stream($local, $stream);
$local = null;
$stream = null;
$stmt = $db->prepare("INSERT INTO BLOBS (ident, oid) VALUES (?, ?)");
$stmt->execute(array($some_id, $oid));
$db->commit();
?>
参考
- PDO::pgsqlLOBOpen() - 既存のラージオブジェクトのストリームをオープンする
- PDO::pgsqlLOBUnlink() - ラージオブジェクトを削除する
- pg_lo_create() - ラージオブジェクトを生成する
PDO::pgsqlLOBCreate
03-Apr-2006 04:38
