Chapter 27. libpq - C 库

Table of Contents
27.1. 数据库联接函数
27.2. 连接状态函数
27.3. 命令执行函数
27.3.1. 主函数
27.3.2. 检索查询结果信息
27.3.3. 检索其它命令的结果信息
27.3.4. 逃逸包含在 SQL 命令中的字串
27.3.5. 逃逸包含在 SQL 命令中的二进制字串
27.4. 异步命令处理
27.5. 捷径接口
27.6. 异步通知
27.7. COPY命令相关的函数
27.7.1. 用于发送 COPY 数据的函数
27.7.2. 用于接收 COPY 数据的函数
27.7.3. 用于 COPY 的废弃的函数
27.8. 控制函数
27.9. 注意信息处理
27.10. 环境变量
27.11. 口令文件
27.12. 在多线程程序里的行为
27.13. 制作 libpq 程序
27.14. 例子程序

libpqPostgreSQLC 应用程序接口。 libpq 是一套允许客户程序向 PostgreSQL 服务器服务进程发送查询 并且获得查询返回的库函数. libpq 同时也是其他几个 PostgreSQL 应用接口下面的引擎, 包括 libpq++ (C++), libpgtcl(Tcl),Perl,和 ECPG.所以如果你使用这些软件包,libpq某些方面的特性会对你非常重要.

本章末尾有三个小程序显示如何利用 libpq 书写程序。 (Section 27.14) 在源代码发布的 src/test/examples 目录里面有几个完整的 libpq 应用的例子。

使用 libpq 的前端程序必须包括头文件 libpq-fe.h 并且必须与 libpq 库链接。

27.1. 数据库联接函数

下面的函数处理与 PostgreSQL 服务器服务器联接的事情。 一个应用程序一次可以与多个服务器建立联接。(这么做的原因之一是访问多于一个数据库。) 每个连接都是用一个从函数PQconnectdb()PQsetdbLogin() 获得的PGconn 对象表示。 注意,这些函数总是返回一个非空的对象指针,除非存储器少得连个PGconn对象都分配不出来。 在把查询发送给联接对象之前,可以调用PQstatus函数来检查一下联接是否成功.

PQconnectdb

与服务器数据库服务器建立一个新的联接.

PGconn *PQconnectdb(const char *conninfo);

这个函数用从一个字符串 conninfo来的参数与数据库打开一个新的联接。 与下面的PQsetdbLogin()不同的是, 我们可以不必更换函数签名(名字)就可以扩展参数集, 所以我们建议应用程序中使用这个函数(或者是它的类似的非阻塞的变种 PQconnectStartPQconnectPoll)。

传入的参数可以为空,表明使用所有缺省的参数, 或者可以包含一个或更多个用空白间隔的参数设置。 每个参数以 关键字 = 数值的形式设置。 (要写一个空值或者一个包含空白的值,你可以用一对单引号包围它们,例如, keyword = 'a value' 。数值内部的单引号和反斜杠必须用一个反斜杠逃逸, 比如, \'\\。)等号周围的空白是可选的。

目前可识别的参数键字是:

host

要联接的主机名。 如果主机名以斜杠开头,则它声明使用 Unix 域套接字通讯而不是 TCP/IP 通讯; 该值就是套接字文件所存储的目录。 缺省时是与位于 /tmp 里面的 Unix-域套接字联接。

hostaddr

与之联接的主机的 IP 地址。这个应该是标准的IPv4 地址格式, 比如,172.28.40.9。如果你的机器支持 IPv6, 那么你也可以使用 IPv6 的地址。如果声明了一个非空的字符串,那么使用 TCP/IP 通讯机制。

使用hostaddr取代host可以让应用避免一次主机名查找, 这一点对于那些有时间约束的应用来说可能是非常重要的。 不过,Kerberos 认证系统要求主机(host)名。因此,应用下面的规则: 如果声明了不带hostaddrhost那么就强制进行主机名查找。 如果声明中没有hosthostaddr 的值给出远端的地址; 如果使用了 Kerberos, 将导致一次反向名字查询。如果同时声明了 host 和hostaddr, 除非使用了 Kerberos,否则将使用hostaddr的值作为远端地址; host 的值将被忽略,如果使用了 Kerberos,host 的值用于 Kerberos 认证。 (要注意如果传递给libpq的主机名(host) 不是地址hostaddr处的机器名,那么认证很有可能失败。) 同样,在 $HOME/.pgpass 中是使用 host 而不是 hostaddr 来标识连接。

如果主机名(host)和主机地址都没有, 那么libpq将使用一个本地的 Unix 域套接字进行通讯。

port

主机服务器的端口号,或者在 Unix 域套接字联接时的套接字扩展文件名。

dbname

数据库名。缺省和用户名相同。

user

要联接的 PostgreSQL 用户名。

password

如果服务器要求口令认证,所用的口令。

connect_timeout

连接的最大等待时间,以秒计(用十进制整数字串书写)。 零或者不声明表示无穷。我们不建议把连接超时的值设置得小于 2 秒。

options

发送给服务器的命令行选项。

tty

忽略(以前,这个选项声明服务器日志的输出方向)。

sslmode

这个选项决定是否需要和服务器协商一个 SSL 连接, 以及以什么样的优先级与服务器进行 SSL 连接。 有四种模式可供选择:disable 将只进行一个没有加密的非 SSL 连接; allow 将和服务器进行协商,首先尝试一个非 SSL 连接, 如果失败,尝试一个 SSL 连接;prefer (缺省) 将进行协商, 首先尝试 SSL 连接,如果失败,尝试一个正常的非 SSL 连接; require 将只进行 SSL 连接。

如果 PostgreSQL 编译时没有打开 SSL 支持,那么使用 require 将导致一个错误, 而 libpq 将容忍 allowprefer,但是它无法协商一个 SSL 连接。

requiressl

这个选项因为有了 sslmode 设置之后已经废弃了。

如果设为 1 ,则要求与服务器进行SSL联接(等效于 sslmode require)。 如果服务器不支持SSL,那么libpq将马上拒绝联接。 设置为 0 (缺省)与服务器进行协商连接类型(等效于 sslmode prefer)。 这个选项只有在编译 PostgreSQL 时打开了 SSL 支持才有效。

service

用于额外参数的服务名。它在pg_service.conf里面声明一个服务名, 这个配置文件保存额外的连接参数。这样就允许应用应用只声明一个服务名, 而连接参数就可以在一个地方维护了。参阅 PREFIX/share/pg_service.conf.sample 获取如何设置这个文件的信息。

如果有任何没有声明的参数,那么将检查对应的环境变量(参阅Section 27.10 小节)。 如果环境变量也没有设置,那么使用编译时的内置缺省。

PQsetdbLogin

与服务器数据库服务器建立一个新的联接。

PGconn *PQsetdbLogin(const char *pghost,
		     const char *pgport,
		     const char *pgoptions,
		     const char *pgtty,
		     const char *dbName,
		     const char *login,
		     const char *pwd);

这个函数是 PQconnectdb 前身, 它有固定个数的参数。它有相同的功能,只是在调用中那些它缺少的参数总是用缺省值。 如果么给任意的固定参数设置缺省值,那么写一个 NULL 或者一个空字串给它们。

PQsetdb

与服务器数据库服务器建立一个新的联接。

PGconn *PQsetdb(char *pghost,
		char *pgport,
		char *pgoptions,
		char *pgtty,
		char *dbName);

这是一个调用 PQsetdbLogin() 的宏,只是loginpwd参数用空(null )代替。 提供这个函数是为了与非常老版本的程序兼容。

PQconnectStart
PQconnectPoll

与数据库服务器建立一次非阻塞的联接。

PGconn *PQconnectStart(const char *conninfo);

PostgreSQLPollingStatusType PQconnectPoll(PGconn *conn);

这两个函数用于打开一个与数据库服务器之间的非阻塞的联接: 你的应用的执行线索在执行它的时候不会因远端的 I/O 而阻塞。 这个方法的要点是等待 I/O 结束可以发生在应用的主循环里, 而不是在 PQconnectdb 里,这样应用可以把这件事与其它操作并发起来一起执行。

数据库联接是用从 conninfo 字符串里取得的参数传递给 PQconnectStart 进行的。 这个字符串的格式与上面PQconnectdb里描述的一样。

PQconnectStartPQconnectPoll 都不会阻塞(进程),不过有一些条件:

  • 必须正确提供hostaddrhost 参数以确保不会发生正向或者反向的名字查找。 参阅上面PQconnectdb里的这些参数的文档获取细节。

  • 如果你调用了PQtrace, 确保你跟踪进入的流对象不会阻塞。

  • 你必须在调用PQconnectPoll之前确保 socket 处于正确的状态,象下面描述的那样。

要开始一次非阻塞连接请求,调用 conn=PQconnectStart("connection_info_string")。 如果conn是空,表明libpq无法分配一个新的PGconn结构。 否则,返回一个有效的PGconn指针(尽管还不一定代表一个与数据库有效联接)。 PQconnectStart 一返回,调用status=PQstatus(conn)。 如果status等于CONNECTION_BADPQconnectStart 失败。

如果PQconnectStart成功了,下一个阶段是轮询 libpq, 这样它就可以继续连接序列动作。使用 PQsocket(conn) 获取数据库链接下层的套接字描述符。 象这样循环:如果PQconnectPoll(conn)的最后一个返回是PGRES_POLLING_READING, 那么就等到套接字准备好被读取了的时候(就像系统函数 select()poll(),或者类似的系统调用声明的那样)。 然后再次调用 PQconnectPoll(conn)。 同样,如果 PQconnectPoll(conn) 最后返回 PGRES_POLLING_WRITING, 那么就等到套接字准备好可以写了,然后再次调用 PQconnectPoll(conn)。 如果你还没调用 PQconnectPoll,比如,刚刚调用完 PQconnectStart, 那么按照它刚返回 PGRES_POLLING_WRITING 的原则行动。 继续这个循环直到 PQconnectPoll(conn) 返回 PGRES_POLLING_FAILED, 表明连接失败,或者 PGRES_POLLING_OK,表明连接成功建立。

在联接的任意时刻,我们都可以通过调用PQstatus 来检查联接的状态。 如果这是CONNECTION_BAD, 那么联接过程失败;如果是CONNECTION_OK, 那么联接已经做好。 这两种状态同样也可以从上面的PQconnectPoll 的返回值里检测到。 其他状态可能(也只能)在一次异步联接过程中发生。 这些标识联接过程的当前状态,因而可能对给用户提供反馈有帮助。这些状态可能包括:

CONNECTION_STARTED

等待进行联接。

CONNECTION_MADE

联接成功;等待发送。

CONNECTION_AWAITING_RESPONSE

等待来自服务器的响应。

CONNECTION_AUTH_OK

已收到认证;等待联接启动继续进行。

CONNECTION_SSL_STARTUP

协商 SSL 加密。

CONNECTION_SETENV

协商环境驱动的参数设置。

注意,尽管这些常量将保持下去(为了维持兼容性), 应用决不应该依赖于这些常量以某种特定顺序出现, 或者是根本不应依赖于这些常量, 或者是不应该依赖于这些状态总是某个文档声明的值。 一个应用可能象象下面这样:

switch(PQstatus(conn))
{
    case CONNECTION_STARTED:
	feedback = "正在连接...";
	break;

    case CONNECTION_MADE:
	feedback = "与服务器连接已建立...";
	break;
.
.
.
    default:
	feedback = "正在连接...";
}

在使用 PQconnectPoll 的时候,连接参数 connect_timeout 将被忽略;判断是否超时是应用的责任。否则,后面跟着一个 PQconnectPoll 循环的 PQconnectStart 等效于 PQconnectdb

要注意如果PQconnectStart返回一个非空的指针, 你必须在使用完它(指针)之后调用PQfinish, 以处理那些结构和所有相关的存储块。 甚至调用PQconnectStart或者 PQconnectPoll失败时也要这样处理。

PQconndefaults

返回缺省的联接选项。

PQconninfoOption *PQconndefaults(void);

typedef struct PQconninfoOption
{
    char   *keyword;   /* 选项的键字 */
    char   *envvar;    /* 退守的环境变量名 */
    char   *compiled;  /* 退守的编译时缺省值 */
    char   *val;       /* 选项的当前值,或者 NULL */
    char   *label;     /* 连接对话里字段的标识 */
    char   *dispchar;  /* 在连接对话里为此字段显示的字符。
			  数值有:
			  ""	原样现实输入的数值
			  "*"   口令字段 - 隐藏数值
			  "D"   调试选项 - 缺省的时候不显示 */
    int     dispsize;  /* 对话中字段的以字符计的大小 */
}PQconninfoOption;

返回一个连接选项数组。 可以用于获取所有可能的PQconnectdb选项和它们的当前缺省值。 返回值指向一个PQconninfoOption 结构的数组, 该数组以一个有 NULL keyword 指针的条目结束。注意缺省值(val 域)将依赖于环境变量和其他环境。 调用者必须把连接选项当作只读对待。

在处理完选项数组后,把数组交给PQconninfoFree()释放。 如果没有这么做,每次调用PQconndefaults()都会有一小部分内存泄漏。

PQfinish

关闭与服务器的连接。同时释放被PGconn 对象使用的存储器。

void PQfinish(PGconn *conn);

注意,即使与服务器的连接尝试失败(可由PQstatus判断), 应用也要调用PQfinish释放被PGconn对象使用的存储器。 不应该在调用PQfinish后再使用PGconn 指针。

PQreset

重置与服务器的通讯端口。

void PQreset(PGconn *conn);

此函数将关闭与服务器的连接并且试图与同一个服务器重建新的连接, 使用所有前面使用过的参数。这在失去工作连接后进行故障恢复时很有用。

PQresetStart
PQresetPoll

以非阻塞模式重置与服务器的通讯端口。

int PQresetStart(PGconn *conn);

PostgreSQLPollingStatusType PQresetPoll(PGconn *conn);

此函数将关闭与服务器的连接并且试图与同一个服务器重建新的连接, 使用所有前面使用过的参数。这在失去工作连接后进行故障恢复时很有用。 它们和上面的PQreset的区别是它们工作在非阻塞模式。 这些函数的使用有与上面PQconnectStartPQconnectPoll一样的限制。

要发起一次连接重置,调用PQresetStart。如果它返回 0,那么重置失败。 如果返回 1,用与使用PQconnectPoll 建立连接的同样的方法使用PQresetPoll重置连接。