F.27. lo
Модуль lo
поддерживает управление большими объектами (БО или LO, Large Objects, иногда BLOB, Binary Large OBjects). Он реализует тип данных lo
и триггер lo_manage
.
F.27.1. Обоснование
Одна из проблем драйвера JDBC (она распространяется и на драйвер ODBC) в том, что спецификация типа предполагает, что ссылки на BLOB хранятся в таблице, и если запись меняется, связанный BLOB удаляется из базы.
Но с Postgres Pro этого не происходит. Большие объекты обрабатываются как самостоятельные объекты; запись в таблице может ссылаться на большой объект по OID, но при этом на один и тот же объект могут ссылаться несколько записей таблицы, так что система не удаляет большой объект, только потому что вы меняете или удаляете такую запись.
Это не проблема для приложений, ориентированных на Postgres Pro, но стандартный код, использующий JDBC или ODBC, не будет удалять эти объекты, в результате чего они окажутся потерянными — объектами, которые никак не задействованы, а просто занимают место на диске.
Модуль lo
позволяет решить эту проблему, добавляя триггер к таблицам, которые содержат столбцы, ссылающиеся на БО. Этот триггер по сути просто вызывает lo_unlink
, когда вы удаляете или изменяете значение, ссылающееся на большой объект. Данный триггер предполагает, что на любой большой объект, на который ссылается контролируемый им столбец, указывает только одна ссылка!
Этот модуль также предоставляет тип данных lo
, который просто является доменом на базе oid
. Он может быть полезен для выделения столбцов, содержащих ссылки на большие объекты, среди столбцов, содержащих другие OID. Для использования триггера применять тип lo
необязательно, но этот тип может быть полезен для отслеживания столбцов в вашей базе, представляющих большие объекты, с которыми работает триггер. Кроме того, поступали сообщения, что драйвер ODBC не работает корректно, если для столбцов BLOB используется не тип lo
.
F.27.2. Как его использовать
Пример его использования:
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
имя_столбца
. Если вам нужно иметь в одной таблице несколько столбцов lo
, создайте отдельный триггер для каждого (при этом обязательно нужно дать всем триггерам в одной таблице разные имена).
F.27.3. Ограничения
При удалении таблицы, однако, всё равно будут потеряны относящиеся к ней объекты, так как триггер не будет выполняться. Этого можно избежать, выполнив перед
DROP TABLE
командуDELETE FROM
.таблица
То же касается и команды
TRUNCATE
.Если у вас уже есть, или вы подозреваете, что есть потерянные большие объекты, обратите внимание на модуль vacuumlo, который может помочь вычистить их. Имеет смысл периодически запускать vacuumlo в качестве меры, дополняющей действие триггера
lo_manage
.Некоторые клиентские программы могут создавать собственные таблицы, но не создавать для них соответствующие триггеры. Кроме того, и пользователи могут не создавать такие триггеры (забывая о них, либо не зная, как это сделать).
F.27. lo
The lo
module provides support for managing Large Objects (also called LOs or BLOBs). This includes a data type lo
and a trigger lo_manage
.
F.27.1. Rationale
One of the problems with the JDBC driver (and this affects the ODBC driver also), is that the specification assumes that references to BLOBs (Binary Large OBjects) are stored within a table, and if that entry is changed, the associated BLOB is deleted from the database.
As Postgres Pro stands, this doesn't occur. Large objects are treated as objects in their own right; a table entry can reference a large object by OID, but there can be multiple table entries referencing the same large object OID, so the system doesn't delete the large object just because you change or remove one such entry.
Now this is fine for Postgres Pro-specific applications, but standard code using JDBC or ODBC won't delete the objects, resulting in orphan objects — objects that are not referenced by anything, and simply occupy disk space.
The lo
module allows fixing this by attaching a trigger to tables that contain LO reference columns. The trigger essentially just does a lo_unlink
whenever you delete or modify a value referencing a large object. When you use this trigger, you are assuming that there is only one database reference to any large object that is referenced in a trigger-controlled column!
The module also provides a data type lo
, which is really just a domain of the oid
type. This is useful for differentiating database columns that hold large object references from those that are OIDs of other things. You don't have to use the lo
type to use the trigger, but it may be convenient to use it to keep track of which columns in your database represent large objects that you are managing with the trigger. It is also rumored that the ODBC driver gets confused if you don't use lo
for BLOB columns.
F.27.2. How to Use It
Here's a simple example of usage:
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);
For each column that will contain unique references to large objects, create a BEFORE UPDATE OR DELETE
trigger, and give the column name as the sole trigger argument. You can also restrict the trigger to only execute on updates to the column by using BEFORE UPDATE OF
column_name
. If you need multiple lo
columns in the same table, create a separate trigger for each one, remembering to give a different name to each trigger on the same table.
F.27.3. Limitations
Dropping a table will still orphan any objects it contains, as the trigger is not executed. You can avoid this by preceding the
DROP TABLE
withDELETE FROM
.table
TRUNCATE
has the same hazard.If you already have, or suspect you have, orphaned large objects, see the vacuumlo module to help you clean them up. It's a good idea to run vacuumlo occasionally as a back-stop to the
lo_manage
trigger.Some frontends may create their own tables, and will not create the associated trigger(s). Also, users may not remember (or know) to create the triggers.
F.27.4. Author
Peter Mount <peter@retep.org.uk>