lo 模块提供管理大对象(也称为 LO 或 BLOB)的支持,包括数据类型 lo 与触发器 lo_manage。
该模块被视为“可信”模块,也就是说,拥有当前数据库 CREATE 权限的非超级用户也可以安装它。
JDBC 驱动(ODBC 驱动也受此影响)的一个问题在于,其规范假定对 BLOB(二进制大对象)的引用存储在表内,并且当该表条目被更改时,关联的 BLOB 会从数据库中删除。
PostgreSQL 的实际行为并非如此。大对象被当作独立的对象对待:表条目可以通过 OID 引用一个大对象,但多个表条目可以引用同一个大对象 OID,因此系统不会仅仅因为你更改或删除了其中一个条目就删除该大对象。
这对 PostgreSQL 专属的应用没有问题,但使用 JDBC 或 ODBC 的标准代码不会删除这些对象,从而产生孤儿对象 — 也就是不再被任何东西引用、单纯占用磁盘空间的对象。
lo 模块通过为包含 LO 引用列的表附加触发器来解决这个问题。该触发器的实质是:每当你删除或修改引用大对象的值时,就执行一次 lo_unlink。使用该触发器时,你是在假定触发器控制的列所引用的每个大对象在数据库中只有一个引用!
该模块还提供数据类型 lo,它实际上只是建立在 oid 类型之上的一个 域。这有助于区分保存大对象引用的数据库列与保存其他对象 OID 的列。使用该触发器时并非必须使用 lo 类型,但用它来标记数据库中哪些列代表由触发器管理的大对象会很方便。此外,据说如果 BLOB 列不使用 lo 类型,ODBC 驱动会产生混淆。
下面是一个简单的使用示例:
CREATE TABLE image (title text, raster lo);
CREATE TRIGGER t_raster BEFORE UPDATE OR DELETE ON image
FOR EACH ROW EXECUTE FUNCTION lo_manage(raster);
对每个将包含唯一大对象引用的列,创建一个 BEFORE UPDATE OR DELETE 触发器,并将列名作为唯一的触发器参数。你还可以使用 BEFORE UPDATE OF column_name 将触发器限制为仅在该列被更新时执行。如果同一张表中有多个 lo 列,请为每一列创建单独的触发器,并注意为同一张表上的每个触发器取不同的名称。
删除表时,由于触发器不会被执行,其中包含的对象仍会成为孤儿对象。你可以在执行 DROP
TABLE 之前先执行 DELETE FROM 来避免这个问题。
table
TRUNCATE 也有同样的风险。
如果你已经产生了、或者怀疑产生了孤儿大对象,可以使用 vacuumlo 模块帮助你清理。不时运行 vacuumlo 作为 lo_manage 触发器的兜底手段是一个好主意。
某些前端可能会创建自己的表,并且不会创建关联的触发器。用户也可能忘记(或不知道)需要创建这些触发器。
Peter Mount <peter@retep.org.uk>