35.3. Клиентские интерфейсы
- 35.3.1. Создание большого объекта
- 35.3.2. Импорт большого объекта
- 35.3.3. Экспорт большого объекта
- 35.3.4. Открытие существующего большого объекта
- 35.3.5. Запись данных в большой объект
- 35.3.6. Чтение данных из большого объекта
- 35.3.7. Перемещение в большом объекте
- 35.3.8. Получение текущего положения в большом объекте
- 35.3.9. Усечение большого объекта
- 35.3.10. Закрытие дескриптора большого объекта
- 35.3.11. Удаление большого объекта
- 35.3.2. Импорт большого объекта
В этом разделе описываются средства, которые предоставляет клиентская библиотека PostgreSQL libpq для обращения к большим объектам. Интерфейс работы с большими объектами PostgreSQL создан по подобию интерфейса файловых систем Unix, так что он включает аналоги функций open
, read
, write
, lseek
и т. д.
Все операции с большими объектами с применением этих функций должны иметь место в блоке транзакции SQL, так как дескрипторы больших объектов актуальны только во время транзакции.
Если при выполнении одной из этих функций происходит ошибка, эта функция возвращает значение, иначе невозможное, обычно 0 или -1. Сообщение, описывающее ошибку, сохраняется в объекте соединения; получить его можно с помощью PQerrorMessage
.
Клиентские приложения, которые используют эти функции, должны включать заголовочный файл libpq/libpq-fs.h
и компоноваться с библиотекой libpq.
35.3.1. Создание большого объекта
Oid lo_creat(PGconn *conn, int mode);
создаёт новый большой объект. Возвращаемым значением будет OID, назначенный новому объекту, либо InvalidOid
(ноль) в случае ошибки. Параметр mode
не используется и игнорируется, начиная с PostgreSQL 8.1; однако для обратной совместимости с более ранними выпусками в нём лучше задать значение INV_READ
, INV_WRITE
или INV_READ
|
INV_WRITE
. (Эти константы определены в заголовочном файле libpq/libpq-fs.h
.)
Пример:
inv_oid = lo_creat(conn, INV_READ|INV_WRITE);
Oid lo_create(PGconn *conn, Oid lobjId);
также создаёт новый большой объект. В lobjId
можно задать назначаемый ему OID; при этом произойдёт ошибка, если этот OID уже присвоен какому-либо большому объекту. Если в lobjId
передаётся InvalidOid
(ноль), lo_create
присваивает большому объекту свободный OID (так же, как и lo_creat
). Возвращаемым значением будет OID, назначенный новому большому объекту, либо InvalidOid
(ноль) в случае ошибки.
Функция lo_create
появилась в PostgreSQL 8.1; если попытаться выполнить её с сервером более старой версии, произойдёт ошибка и будет возвращено InvalidOid
.
Пример:
inv_oid = lo_create(conn, desired_oid);
35.3.2. Импорт большого объекта
Чтобы импортировать в качестве большого объекта файл операционной системы, вызовите
Oid lo_import(PGconn *conn, const char *filename);
В filename
задаётся имя файла в операционной системе, который будет импортирован как большой объект. Возвращаемым значением будет OID, назначенный новому большому объекту, либо InvalidOid
(ноль) в случае ошибки. Заметьте, что этот файл читает библиотека клиентского интерфейса, а не сервер; таким образом, он должен существовать в файловой системе на стороне клиента и быть доступным для чтения клиентскому приложению.
Oid lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId);
также импортирует новый большой объект. В lobjId
можно задать назначаемый ему OID; при этом произойдёт ошибка, если этот OID уже присвоен какому-либо большому объекту. Если в lobjId
передаётся InvalidOid
(ноль), lo_import_with_oid
присваивает большому объекту свободный OID (так же, как и lo_import
). Возвращаемым значением будет OID, назначенный новому большому объекту, либо InvalidOid
(ноль) в случае ошибки.
Функция lo_import_with_oid
появилась в PostgreSQL 8.4 и вызывает внутри lo_create
, появившуюся в 8.1; если попытаться выполнить её с сервером версии 8.0 или ранней, она завершится ошибкой и возвратит InvalidOid
.
35.3.3. Экспорт большого объекта
Чтобы экспортировать большой объект в файл операционной системы, вызовите
int lo_export(PGconn *conn, Oid lobjId, const char *filename);
В аргументе lobjId
задаётся OID экспортируемого большого объекта, а в аргументе filename
задаётся имя файла в операционной системе. Заметьте, что файл записывается библиотекой клиентского интерфейса, а не сервером. Возвращает 1 при успешном выполнении, -1 при ошибке.
35.3.4. Открытие существующего большого объекта
Чтобы открыть существующий большой объект для чтения или записи, вызовите
int lo_open(PGconn *conn, Oid lobjId, int mode);
В аргументе lobjId
задаётся OID открываемого большого объекта. Биты в аргументе mode
определяют, открывается ли файл для чтения (INV_READ
), для записи (INV_WRITE
), либо для чтения/записи. (Эти константы определяются в заголовочном файле libpq/libpq-fs.h
.) Функция lo_open
возвращает дескриптор большого объекта (неотрицательный) для последующего использования в функциях lo_read
, lo_write
, lo_lseek
, lo_lseek64
, lo_tell
, lo_tell64
, lo_truncate
, lo_truncate64
и lo_close
. Этот дескриптор актуален только до завершения текущей транзакции. В случае ошибки возвращается -1.
В настоящее время сервер не различает режимы INV_WRITE
и INV_READ
|
INV_WRITE
: с таким дескриптором можно читать данные в любом случае. Однако есть значительное отличие этих режимов от одиночного INV_READ
: с дескриптором INV_READ
записывать данные нельзя, а данные, считываемые через него, будут отражать содержимое большого объекта в снимке транзакции, который был активен при выполнении lo_open
, то есть не будут включать изменения, произведённые позже этой или другими транзакциями. При чтении с дескриптором INV_WRITE
возвращаются данные, отражающие все изменения, произведённые другими зафиксированными транзакциями, а также текущей транзакцией. Это подобно различиям режимов REPEATABLE READ
и READ COMMITTED
для обычных команд SQL SELECT
.
Функция lo_open
завершится ошибкой, если пользователь не имеет права SELECT
для данного большого объекта или если указан флаг INV_WRITE
и отсутствует право UPDATE
. (До PostgreSQL 11 права проверялись при первом фактическом вызове функции чтения или записи с этим дескриптором.) Отключить новые проверки можно с помощью параметра времени выполнения lo_compat_privileges.
Пример:
inv_fd = lo_open(conn, inv_oid, INV_READ|INV_WRITE);
35.3.5. Запись данных в большой объект
int lo_write(PGconn *conn, int fd, const char *buf, size_t len);
записывает len
байт из буфера buf
(который должен иметь размер len
) в дескриптор большого объекта fd
. В fd
должно передаваться значение, возвращённое предыдущим вызовом lo_open
. Возвращает эта функция число фактически записанных байт (в текущей реализации это всегда len
, если только не произошла ошибка). В случае ошибки возвращается значение -1.
Хотя параметр len
объявлен как size_t
, эта функция не принимает значение длины, превышающее INT_MAX
. На практике всё равно лучше передавать данные фрагментами не больше нескольких мегабайт.
35.3.6. Чтение данных из большого объекта
int lo_read(PGconn *conn, int fd, char *buf, size_t len);
читает до len
байт из дескриптора большого объекта fd
в буфер buf
(который должен иметь размер len
). В fd
должно передаваться значение, возвращённое предыдущим вызовом lo_open
. Возвращает эта функция число фактически прочитанных байт; это число должно быть меньше len
, если при чтении был достигнут конец объекта. В случае ошибки возвращается -1.
Хотя параметр len
объявлен как size_t
, эта функция не принимает значение длины, превышающее INT_MAX
. На практике всё равно лучше передавать данные фрагментами не больше нескольких мегабайт.
35.3.7. Перемещение в большом объекте
Чтобы изменить текущее положение чтения или записи, связанное с дескриптором большого объекта, вызовите
int lo_lseek(PGconn *conn, int fd, int offset, int whence);
Эта функция перемещает указатель текущего положения для дескриптора большого объекта fd
в новое положение, заданное аргументом offset
. Для аргумента whence
задаются значения SEEK_SET
(перемещение от начала объекта), SEEK_CUR
(перемещение от текущего положения) и SEEK_END
(перемещение от конца объекта). Возвращает эта функция новое положение указателя, либо -1 в случае ошибки.
Оперируя с большими объектами, размер которых превышает 2 ГБ, используйте
pg_int64 lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence);
Эта функция действует так же, как и lo_lseek
, но может принять значение offset
, превышающее 2 ГБ, и/или вернуть результат, превышающий 2 ГБ. Заметьте, что если новое положение указателя оказывается за границей в 2ГБ, функция lo_lseek
выдаёт ошибку.
Функция lo_lseek64
появилась в PostgreSQL 9.3. Если попытаться выполнить её с сервером более старой версии, произойдёт ошибка и будет возвращено -1.
35.3.8. Получение текущего положения в большом объекте
Чтобы получить текущее положение чтения или записи для дескриптора большого объекта, вызовите
int lo_tell(PGconn *conn, int fd);
Если возникает ошибка, возвращается -1.
Оперируя с большими объектами, размер которых может превышать 2 ГБ, используйте
pg_int64 lo_tell64(PGconn *conn, int fd);
Эта функция действует так же, как lo_tell
, но может выдавать результат, превышающий 2 ГБ. Заметьте, что lo_tell
выдаёт ошибку, если текущее положение чтения/записи оказывается за границей в 2 ГБ.
Функция lo_tell64
появилась в PostgreSQL 9.3. Если попытаться выполнить её с сервером более старой версии, произойдёт ошибка и будет возвращено -1.
35.3.9. Усечение большого объекта
Чтобы усечь большой объект до требуемой длины, вызовите
int lo_truncate(PGconn *conn, int fd, size_t len);
Эта функция усекает большой объект с дескриптором fd
до длины len
. В fd
должно передаваться значение, возвращённое предыдущим вызовом lo_open
. Если len
превышает текущую длину большого объекта, большой объект расширяется до заданной длины нулевыми байтами ('\0'). В случае успеха lo_truncate
возвращает ноль, а при ошибке возвращается -1.
Положение чтения/записи, связанное с дескриптором fd
, при этом не меняется.
Хотя параметр len
объявлен как size_t
, lo_truncate
не принимает значение длины, превышающее INT_MAX
.
Оперируя с большими объектами, размер которых может превышать 2 ГБ, используйте
int lo_truncate64(PGconn *conn, int fd, pg_int64 len);
Эта функция действует так же, как lo_truncate
, но может принимать значения len
, превышающие 2 ГБ.
Функция lo_truncate
появилась в PostgreSQL 8.3; если попытаться выполнить её с сервером более старой версии, произойдёт ошибка и будет возвращено -1.
Функция lo_truncate64
появилась в PostgreSQL 9.3; если попытаться выполнить её с сервером более старой версии, произойдёт ошибка и будет возвращено -1.
35.3.10. Закрытие дескриптора большого объекта
Дескриптор большого объекта можно закрыть, вызвав
int lo_close(PGconn *conn, int fd);
Здесь fd
— дескриптор большого объекта, возвращённый функцией lo_open
. В случае успеха lo_close
возвращает ноль. При ошибке возвращается -1.
Все дескрипторы больших объектов, остающиеся открытыми в конце транзакции, закрываются автоматически.