Postgresql 中文操作指南

35.3. Client Interfaces #

本节介绍 PostgreSQL 的 libpq 客户端接口库用于访问大型对象所提供的功能。PostgreSQL 大型对象接口是仿照 Unix 文件系统接口建模的,具有 openreadwritelseek 等类似内容。

使用这些 must 函数的所有大型对象操作都在 SQL 事务块中进行,因为大型对象文件描述符仅在事务持续期间有效。不允许在只读事务中进行写操作,包括带 INV_WRITE 模式的 lo_open

如果在执行以下任意一个函数时发生错误,该函数将返回一个不可能的值,通常为 0 或 -1。描述错误的消息存储在连接对象中,并可以用 PQerrorMessage 检索。

使用这些函数的客户端应用程序应该包括头文件 libpq/libpq-fs.h,并与 libpq 库链接。

客户端应用程序在 libpq 连接处于管道模式时不能使用这些函数。

35.3.1. Creating a Large Object #

函数

Oid lo_create(PGconn *conn, Oid lobjId);

创建一个新的大型对象。可以由 lobjId 指定要分配的 OID;如果指定,则当该 OID 已用于某个大型对象时,会发生故障。如果 lobjIdInvalidOid(零),则 lo_create 会分配一个未使用的 OID。返回值是分配给新大型对象,或故障的 InvalidOid(零)的 OID。

示例:

inv_oid = lo_create(conn, desired_oid);

旧函数

Oid lo_creat(PGconn *conn, int mode);

也创建一个新的大型对象,始终分配未使用的 OID。返回值是分配给新大型对象,或故障的 InvalidOid(零)的 OID。

在 PostgreSQL 8.1 及更高版本中,忽略 mode,所以 lo_creat 完全等于带有零秒参数的 lo_create。但是,除非需要处理早于 8.1 的服务器,否则几乎没有理由使用 lo_creat。要处理这样一个旧服务器,您必须使用 lo_creat,而不是 lo_create,并且必须将 mode 设置为 INV_READINV_WRITEINV_READ | INV_WRITE 中的一个。(这些符号常量在头文件 libpq/libpq-fs.h 中定义。)

示例:

inv_oid = lo_creat(conn, INV_READ|INV_WRITE);

35.3.2. Importing a Large Object #

要将操作系统文件作为大对象导入,请调用

Oid lo_import(PGconn *conn, const char *filename);

filename 指定要作为大型对象导入的文件的操作系统名称。返回值是分配给新大型对象,或故障的 InvalidOid(零)的 OID。请注意,该文件由客户端接口库读取,而不是由服务器读取;因此,该文件必须存在于客户端文件系统中,并且客户端应用程序必须能够读取该文件。

函数

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

也导入一个新的大型对象。可以由 lobjId 指定要分配的 OID;如果指定,则当该 OID 已用于某个大型对象时,会发生故障。如果 lobjIdInvalidOid(零),则 lo_import_with_oid 会分配一个未使用的 OID(这与 lo_import 的行为相同)。返回值是分配给新大型对象,或故障的 InvalidOid(零)的 OID。

lo_import_with_oid 自 PostgreSQL 8.4 起是新的,并在内部使用 lo_create,后者在 8.1 中是新的;如果对 8.0 或更早的版本运行此函数,则会失败并返回 InvalidOid

35.3.3. Exporting a Large Object #

若要将大型对象导出为操作系统文件,调用

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

lobjId 参数指定要导出的大型对象的 OID,filename 参数指定该文件的操作系统名称。请注意,该文件由客户端接口库写入,而不是由服务器写入。成功时返回 1,失败时返回 -1。

35.3.4. Opening an Existing Large Object #

若要打开现有大型对象以便读取或写入,调用

int lo_open(PGconn *conn, Oid lobjId, int mode);

lobjId 参数指定要打开的大型对象的 OID。mode 位控制对象是打开以进行读取 (INV_READ)、写入 (INV_WRITE),还是两者 (libpq/libpq-fs.h)。(这些符号常量在头文件 libpq/libpq-fs.h 中定义。)lo_open 为以后在 lo_readlo_writelo_lseeklo_lseek64lo_telllo_tell64lo_truncatelo_truncate64lo_close 中使用返回一个(非负)大型对象描述符。该描述符仅在当前事务的持续期间有效。在失败时,返回 -1。

服务器当前不会区分模式 INV_WRITEINV_READ | INV_WRITE:无论在何种情况下,您都可以从描述符中读取。但是,这些模式与单独的 INV_READ 之间存在显着差异:使用 INV_READ,您无法写入描述符,并且从该描述符读取的数据将反映在执行 lo_open 时激活的事务快照时间的大型对象内容,而不管此后此事务或其他事务的写入。使用 INV_WRITE 打开的描述符读取的内容反映了其他已提交事务的所有写入以及当前事务的写入。这与普通 SQL SELECT 命令的 REPEATABLE READREAD COMMITTED 事务模式的行为类似。

如果对象没有 SELECT 权限,或指定了 INV_WRITE 且没有 UPDATE 权限,则 lo_open 将失败。(在 PostgreSQL 11 之前,这些权限检查是在使用描述符时在第一个实际读入或写入调用上执行的。)可使用 lo_compat_privileges 运行时参数禁用这些权限检查。

示例:

inv_fd = lo_open(conn, inv_oid, INV_READ|INV_WRITE);

35.3.5. Writing Data to a Large Object #

函数

int lo_write(PGconn *conn, int fd, const char *buf, size_t len);

buf(其大小必须为 len)向大型对象描述符 fd 写入 len 字节。fd 参数必须由前一个 lo_open 返回。返回实际写入的字节数(在当前实现中,这总是等于 len,除非出现错误)。如果出现错误,返回值为 -1。

尽管 len 参数声明为 size_t,但此函数将拒绝大于 INT_MAX 的长度值。实际上,最好的做法是无论如何以几兆字节最多的大小传输数据。

35.3.6. Reading Data from a Large Object #

函数

int lo_read(PGconn *conn, int fd, char *buf, size_t len);

从大型对象描述符 fd 读入 buf(其大小必须为 len)最多 len 字节。fd 参数必须由前一个 lo_open 返回。返回实际读取的字节数;如果先到达大型对象的结尾,这将小于 len。如果出现错误,返回值为 -1。

尽管 len 参数声明为 size_t,但此函数将拒绝大于 INT_MAX 的长度值。实际上,最好的做法是无论如何以几兆字节最多的大小传输数据。

35.3.7. Seeking in a Large Object #

若要更改与大型对象描述符关联的当前读取或写入位置,调用

int lo_lseek(PGconn *conn, int fd, int offset, int whence);

此函数将由 fd 标识的大型对象描述符的当前位置指针移动到由 offset 指定的新位置。whence 的有效值为 SEEK_SET(从对象开始处查找)、SEEK_CUR(从当前位置查找)和 SEEK_END(从对象末尾查找)。返回值为新位置指针,或在发生错误时返回 -1。

在处理大小可能超过 2 GB 的大型对象时,改用

pg_int64 lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence);

此函数的行为与 lo_lseek 相同,但它可以接受大于 2GB 的 offset 和/或提供大于 2GB 的结果。请注意,如果新位置指针大于 2GB,lo_lseek 将失败。

lo_lseek64 自 PostgreSQL 9.3 起新增。如果针对较旧的服务器版本运行此函数,它将失败并返回 -1。

35.3.8. Obtaining the Seek Position of a Large Object #

若要获取大型对象描述符的当前读取或写入位置,调用

int lo_tell(PGconn *conn, int fd);

如果出现错误,返回值为 -1。

在处理大小可能超过 2 GB 的大型对象时,改用

pg_int64 lo_tell64(PGconn *conn, int fd);

此函数的行为与 lo_tell 相同,但它可以提供大于 2GB 的结果。请注意,如果当前读/写位置大于 2GB,lo_tell 将失败。

lo_tell64 自 PostgreSQL 9.3 起新增。如果针对较旧的服务器版本运行此函数,它将失败并返回 -1。

35.3.9. Truncating a Large Object #

若要将大型对象截断为给定长度,调用

int lo_truncate(PGconn *conn, int fd, size_t len);

此函数将大型对象描述符 fd 截断为长度 lenfd 参数必须由前一个 lo_open 返回。如果 len 大于大型对象的当前长度,则大型对象将扩展到指定长度并使用空字节 ('\0') 填充。成功时,lo_truncate 返回零。如果出现错误,返回值为 -1。

与描述符 fd 关联的读/写位置未更改。

尽管 len 参数声明为 size_t,但 lo_truncate 将拒绝大于 INT_MAX 的长度值。

在处理大小可能超过 2 GB 的大型对象时,改用

int lo_truncate64(PGconn *conn, int fd, pg_int64 len);

此函数的行为与 lo_truncate 相同,但它可以接受一个超过 2GB 的 len 值。

lo_truncate 自 PostgreSQL 8.3 起新增;如果针对较旧的服务器版本运行此函数,它将失败并返回 -1。

lo_truncate64 自 PostgreSQL 9.3 起新增;如果针对较旧的服务器版本运行此函数,它将失败并返回 -1。

35.3.10. Closing a Large Object Descriptor #

可以通过调用关闭大型对象描述符

int lo_close(PGconn *conn, int fd);

其中 fd 是由 lo_open 返回的大型对象描述符。成功时,lo_close 返回零。如果出现错误,返回值为 -1。

在事务结束时仍保持打开状态的任何大型对象描述符将自动关闭。

若要从数据库中移除大型对象,调用

int lo_unlink(PGconn *conn, Oid lobjId);

lobjId 参数指定要移除的大型对象的 OID。如果成功,返回 1,如果失败,返回 -1。