33.3. Клиентские интерфейсы#

33.3. Клиентские интерфейсы

33.3. Клиентские интерфейсы

Этот раздел описывает возможности, которые предоставляет библиотека интерфейса клиента libpq Tantor SE для доступа к большим объектам. Интерфейс больших объектов Tantor SE моделируется по аналогии с интерфейсом файловой системы Unix, с аналогами функций open, read, write, lseek и т. д.

Все операции с большими объектами, использующие эти функции, должны выполняться внутри блока SQL-транзакции, поскольку дескрипторы файлов больших объектов действительны только в течение транзакции.

Если происходит ошибка при выполнении любой из этих функций, функция вернет значение, которое в обычных условиях невозможно, обычно 0 или -1. Сообщение, описывающее ошибку, сохраняется в объекте соединения и может быть получено с помощью PQerrorMessage.

Клиентские приложения, использующие эти функции, должны включать заголовочный файл libpq/libpq-fs.h и связываться с библиотекой libpq.

Клиентские приложения не могут использовать эти функции, пока соединение libpq находится в режиме конвейера.

33.3.1. Создание большого объекта

Функция

Oid lo_create(PGconn *conn, Oid lobjId);

создает новый большой объект. OID, который будет назначен, может быть указан с помощью lobjId; в случае, если этот OID уже используется для какого-либо большого объекта, происходит сбой. Если lobjId равен InvalidOid (ноль), то lo_create назначает неиспользуемый OID. Возвращаемое значение - OID, который был назначен новому большому объекту, или InvalidOid (ноль) в случае сбоя.

Пример:

inv_oid = lo_create(conn, desired_oid);

Старая функция

Oid lo_creat(PGconn *conn, int mode);

также создает новый большой объект, всегда назначая неиспользуемый OID. Возвращаемое значение - OID, который был назначен новому большому объекту, или InvalidOid (ноль) в случае ошибки.

В релизах PostgreSQL 8.1 и более поздних версий, параметр mode игнорируется, поэтому функция lo_creat полностью эквивалентна функции lo_create с нулевым вторым аргументом. Однако, использование функции lo_creat имеет мало смысла, если необходимо работать с серверами старше 8.1. Для работы с таким старым сервером вы должны использовать функцию lo_creat, а не lo_create, и установить параметр mode в одно из значений INV_READ, INV_WRITE, или INV_READ | INV_WRITE. (Эти символические константы определены в заголовочном файле libpq/libpq-fs.h).

Пример:

inv_oid = lo_creat(conn, INV_READ|INV_WRITE);

33.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);

также импортирует новый большой объект. OID, который будет назначен, может быть указан с помощью lobjId; в случае, если этот OID уже используется для какого-либо большого объекта, произойдет сбой. Если lobjId равен InvalidOid (ноль), то lo_import_with_oid назначает неиспользуемый OID (это то же поведение, что и у lo_import). Возвращаемое значение - OID, который был назначен новому большому объекту, или InvalidOid (ноль) в случае сбоя.

lo_import_with_oid является новым с версии Tantor SE 8.4 и использует внутренне функцию lo_create, которая появилась в версии 8.1; если эта функция вызывается в версии 8.0 или ранее, она завершится с ошибкой и вернет значение InvalidOid.

33.3.3. Экспорт большого объекта

Для экспорта большого объекта в файл операционной системы вызовите

int lo_export(PGconn *conn, Oid lobjId, const char *filename);

Аргумент lobjId указывает OID большого объекта для экспорта, а аргумент filename указывает операционную систему имя файла. Обратите внимание, что файл записывается библиотекой клиентского интерфейса, а не сервером. Возвращает 1 в случае успеха, -1 в случае ошибки.

33.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);

33.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. На практике лучше передавать данные порциями размером не более нескольких мегабайт.

33.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. На практике лучше передавать данные порциями размером не более нескольких мегабайт.

33.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 ГБ. Обратите внимание, что lo_lseek завершится с ошибкой, если новый указатель положения будет больше 2 ГБ.

lo_lseek64 является новым с версии PostgreSQL 9.3. Если эта функция выполняется на более старой версии сервера, она завершится с ошибкой и вернет -1.

33.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.

33.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.

33.3.10. Закрытие дескриптора большого объекта

Дескриптор большого объекта может быть закрыт путем вызова

int lo_close(PGconn *conn, int fd);

где fd - это дескриптор большого объекта, возвращаемый функцией lo_open. При успешном выполнении lo_close возвращает ноль. При ошибке возвращается значение -1.

Все дескрипторы больших объектов, которые остаются открытыми в конце транзакции, будут автоматически закрыты.