Pg lo close: примеры (PHP)

Использование pg_lo_close для управления большими объектами в PostgreSQL
Раздел: Базы данных (PostgreSQL)
pg_lo_close(PgSql\Lob $lob): bool
Описание функции pg_lo_close

Функция pg_lo_close в PHP предназначена для закрытия дескриптора большого объекта (Large Object) PostgreSQL. Она используется после завершения операций чтения или записи с большим объектом для освобождения ресурсов на стороне сервера и клиента.

Работа с большими объектами в PostgreSQL через модуль pgsql требует явного открытия и закрытия дескрипторов. Функция применяется в сценариях, где необходимо хранить или извлекать большие двоичные данные (BLOB), такие как изображения, документы или аудиофайлы, превышающие обычные ограничения на размер данных.

Аргументы функции

Функция принимает один обязательный аргумент:

  • $lob (ресурс) - дескриптор большого объекта, полученный с помощью функций pg_lo_open или pg_lo_create. Этот ресурс должен быть валидным и открытым.

Возвращаемое значение: bool - true в случае успешного закрытия, false при возникновении ошибки.

Примеры использования pg_lo_close

Базовый пример: чтение и закрытие объекта.

<?php
$conn = pg_connect("dbname=test user=postgres");
$lob = pg_lo_open($conn, 123456, "r"); // Открытие объекта с OID 123456 для чтения
if ($lob) {
    // ... операции чтения с использованием pg_lo_read ...
    $result = pg_lo_close($lob); // Закрытие дескриптора
    if ($result) {
        echo "Дескриптор успешно закрыт";
    }
}
?>
Дескриптор успешно закрыт

Пример с записью в объект.

<?php
$conn = pg_connect("dbname=test user=postgres");
$lob = pg_lo_open($conn, 123457, "w"); // Открытие для записи
if ($lob) {
    // ... операции записи с использованием pg_lo_write ...
    var_dump(pg_lo_close($lob)); // Закрытие
}
?>
bool(true)
Похожие функции в PHP

Для работы с большими объектами в PostgreSQL через модуль pgsql существуют другие функции:

  • pg_lo_unlink - удаляет большой объект из базы данных по его OID. В отличие от pg_lo_close, которая лишь закрывает дескриптор, эта функция безвозвратно удаляет данные.
  • pg_lo_import - создает большой объект из файла в файловой системе и возвращает его OID. После импорта может потребоваться открыть и закрыть объект через pg_lo_open/pg_lo_close для дополнительных операций.
  • pg_lo_export - сохраняет большой объект в файл. После экспорта дескриптор также следует закрыть.

pg_lo_close предпочтительнее использовать всегда после завершения операций с открытым дескриптором для избежания утечек ресурсов. Удаление или экспорт объекта могут выполняться независимо после закрытия.

Альтернативы в других языках и системах
Python (библиотека psycopg2)

В psycopg2 работа с большими объектами осуществляется через методы lo_open(), lo_close() объекта LargeObject.

import psycopg2
conn = psycopg2.connect("dbname=test user=postgres")
lobj = conn.lobject(123456, 'r')
# ... операции чтения ...
lobj.close()  # Аналог pg_lo_close
JavaScript (Node.js, библиотека pg)

В Node.js обычно используются потоки (streams) для работы с большими объектами. Явного закрытия дескриптора может не требоваться, если используется потоковый интерфейс.

const { Client } = require('pg');
const client = new Client();
await client.connect();
const stream = client.query(new 
QueryStream('SELECT lo_get(123456)'));
// ... обработка потока ...
// Закрытие соединения освобождает ресурсы
await client.end();

Pg lo close в MySQL

В MySQL для хранения больших двоичных данных часто используют тип LONGBLOB. Операции чтения/записи выполняются стандартными запросами SELECT/UPDATE, а не через отдельные дескрипторы, поэтому аналога pg_lo_close не существует.

Типичные ошибки

1. Попытка закрыть уже закрытый или невалидный дескриптор.

<?php
$conn = pg_connect("dbname=test user=postgres");
$lob = null;
$result = pg_lo_close($lob); // Неверный дескриптор
var_dump($result);
?>
Warning: pg_lo_close() expects parameter 1 to be resource, null given
bool(false)

2. Использование закрытого дескриптора для операций чтения/записи после вызова pg_lo_close.

<?php
$conn = pg_connect("dbname=test user=postgres");
$lob = pg_lo_open($conn, 123456, "r");
pg_lo_close($lob);
$data = pg_lo_read($lob); // Ошибка: дескриптор закрыт
?>
Warning: pg_lo_read(): supplied resource is not a valid large object resource

3. Отсутствие проверки соединения с базой данных перед операциями.

Изменения в последних версиях PHP

В PHP 8.0 и выше значительных изменений в работе функции pg_lo_close не произошло. Однако, в PHP 8.1 были ужесточены типы аргументов для многих функций, что может приводить к более строгим ошибкам при передаче неверных значений. Сам модуль pgsql продолжает поддерживаться, но рекомендуется для новых проектов рассматривать использование расширения PDO_PGSQL или более высокоуровневых ORM.

Расширенные примеры использования
Закрытие дескриптора в транзакции

Большие объекты в PostgreSQL часто требуют работы внутри транзакции.

Пример php
<?php
$conn = pg_connect("dbname=test user=postgres");
pg_query($conn, "BEGIN");
$lob = pg_lo_open($conn, 123456, "r");
if ($lob) {
    $content = pg_lo_read($lob, 4096);
    // Обработка данных
    pg_lo_close($lob); // Важно закрыть до commit/rollback
}
pg_query($conn, "COMMIT");
?>
Автоматическое закрытие с помощью try-finally

Для гарантированного освобождения ресурсов даже при возникновении исключений.

Пример php
<?php
$conn = pg_connect("dbname=test user=postgres");
$lob = pg_lo_open($conn, 123456, "w");
try {
    // ... операции записи, которые могут вызвать исключение ...
    pg_lo_write($lob, "data");
} finally {
    if (is_resource($lob)) {
        pg_lo_close($lob); // Всегда выполнится
    }
}
?>
Работа с несколькими объектами
Пример php
<?php
$conn = pg_connect("dbname=test user=postgres");
$oids = [123456, 123457, 123458];
$handles = [];
foreach ($oids as $oid) {
    $lob = pg_lo_open($conn, $oid, "r");
    if ($lob) {
        $handles[] = $lob;
    }
}
// ... параллельная обработка ...
foreach ($handles as $handle) {
    pg_lo_close($handle); // Закрытие всех открытых дескрипторов
}
?>
Интеграция с pg_lo_create

Создание нового объекта, запись данных и немедленное закрытие.

Пример php
<?php
$conn = pg_connect("dbname=test user=postgres");
pg_query($conn, "BEGIN");
$oid = pg_lo_create($conn);
$lob = pg_lo_open($conn, $oid, "w");
pg_lo_write($lob, "Новые данные большого объекта");
pg_lo_close($lob); // Дескриптор закрыт, но объект с OID сохранен
pg_query($conn, "COMMIT");
echo "Создан объект с OID: " . $oid;
?>
Создан объект с OID: 123459

PHP pg_lo_close function comments

En
Pg lo close Close a large object