第 27 章 libpq - C 库
目录
libpq 是 PostgreSQL 的 C 应用程序员接口。libpq 是一组库函数,客户端程序通过它们可以向 PostgreSQL 后端服务器传送查询并接收这些查询的结果。libpq 也是其他几个 PostgreSQL 应用接口的底层引擎,包括 libpq++(C++)、libpgtcl(Tcl)、Perl 和 ECPG。因此,即使你使用的是上述某个软件包,libpq行为的某些方面对你来说也很重要。
本章末尾(第 27.14 节)包含一些简短程序,展示如何编写使用libpq的程序。源代码发行包的src/test/examples目录中还提供了几个完整的libpq应用程序示例。
使用libpq的客户端程序必须包含头文件libpq-fe.h,并且必须与libpq库链接。
27.1. 数据库连接控制函数 #
下面的函数用于建立与 PostgreSQL
后端服务器的连接。一个应用程序可以同时打开多个后端连接(原因之一是需要访问多个数据库)。每个连接由一个
PGconn
对象表示,该对象通过 PQconnectdb 或
PQsetdbLogin 函数获得。注意,除非内存太少以至于连
PGconn 对象都无法分配,这些函数总是返回一个非空的对象指针。在通过连接对象发送查询之前,应当调用
PQstatus 函数检查连接是否成功建立。
PQconnectdb与数据库服务器建立一个新连接。
PGconn *PQconnectdb(const char *conninfo);
此函数使用从字符串
conninfo中取得的参数打开一个新的数据库连接。与下面的PQsetdbLogin不同,该函数的参数集可以在不改变函数签名的情况下扩展,因此新的应用程序编程首选使用此函数(或其非阻塞版本PQconnectStart和PQconnectPoll)。传入的字符串可以为空以使用全部默认参数,也可以包含一个或多个用空白分隔的参数设置。每个参数设置的形式为
keyword = value。(要写入空值或包含空格的值,请用单引号包围,例如keyword = 'a value'。值中的单引号和反斜杠必须用反斜杠转义,即\'和\\。)等号两边的空格是可选的。目前可识别的参数关键字有:
host要连接的主机名。如果它以斜杠开头,则表示使用 Unix 域通信而非 TCP/IP 通信;该值是存放套接字文件的目录名。默认连接到
/tmp中的 Unix 域套接字。hostaddr要连接的主机的数字 IP 地址。其格式应为标准 IPv4 地址格式,例如
172.28.40.9。如果你的机器支持 IPv6,也可以使用 IPv6 地址。为此参数指定非空字符串时总是使用 TCP/IP 通信。使用
hostaddr代替host允许应用程序避免主机名查找,这对于有时间约束的应用可能很重要。但 Kerberos 认证需要主机名。因此适用以下规则:如果只指定了host而没有指定hostaddr,则进行主机名查找。如果只指定了hostaddr而没有指定host,则hostaddr的值给出远程地址。使用 Kerberos 时,会进行反向名称查询以获得 Kerberos 所需的主机名。如果host和hostaddr都被指定,hostaddr的值给出远程地址;host的值被忽略;但使用 Kerberos 时例外,此时该值用于 Kerberos 认证。(注意,如果传给 libpq 的主机名不是位于hostaddr的机器的名称,认证很可能失败。)此外,在$HOME/.pgpass中标识连接使用的是host而不是hostaddr。既没有主机名也没有主机地址时,libpq 将使用本地 Unix 域套接字连接。
portdbname数据库名。默认与用户名相同。
user要以哪个 PostgreSQL 用户名连接。
password如果服务器要求密码认证则使用的密码。
connect_timeout连接的最大等待时间,以秒为单位(写成十进制整数字符串)。零或未指定表示无限等待。不建议使用小于 2 秒的超时。
options要发送给服务器的命令行选项。
tty忽略(以前此参数指定服务器调试输出发送到哪里)。
sslmode此选项决定是否或以何种优先级与服务器协商 SSL 连接。共有四种模式:
disable只尝试非 SSL 加密连接;allow协商时先尝试非 SSL 连接,失败后再尝试 SSL 连接;prefer(默认值)协商时先尝试 SSL 连接,失败后再尝试常规非 SSL 连接;require只尝试 SSL 连接。如果 PostgreSQL 编译时未包含 SSL 支持,使用选项
require将导致错误,选项allow和prefer可以被接受,但 libpq 无法协商建立 SSL 连接。requiressl此选项已废弃,由
sslmode设置取代。设为 1 时,要求与服务器的 SSL 连接(等价于
sslmoderequire)。如果服务器不接受 SSL 连接,libpq 将拒绝连接。设为 0(默认值)时,libpq 将与服务器协商连接类型(等价于sslmodeprefer)。仅当 PostgreSQL 编译时包含 SSL 支持时此选项才可用。service用于附加参数的服务名。它指定
pg_service.conf中一个持有附加连接参数的服务名。这样应用只需指定一个服务名,连接参数便可以集中维护。有关如何设置该文件,参见。PREFIX/share/pg_service.conf.sample
如果任何参数未指定,则检查相应的环境变量(见第 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);这是一个宏,以空指针作为
login和pwd参数调用PQsetdbLogin。它只是为了与很老的程序保持向后兼容而保留。PQconnectStartPQconnectPollPGconn *PQconnectStart(const char *conninfo);
PostgresPollingStatusType PQconnectPoll(PGconn *conn);
这两个函数用于打开到数据库服务器的连接,同时应用程序的执行线程不会在远程 I/O 上阻塞。这种做法的意义在于,对 I/O 完成的等待可以发生在应用的主循环中,而不是在
PQconnectdb内部,因此应用可以将此操作与其他活动并行管理。数据库连接使用传给
PQconnectStart的字符串conninfo中的参数建立。该字符串的格式与上面PQconnectdb中描述的相同。只要满足若干限制条件,
PQconnectStart和PQconnectPoll都不会阻塞:恰当地使用
hostaddr和host参数,确保不进行(正向)名称和反向名称查询。详情见上面PQconnectdb下对这些参数的说明。如果调用
PQtrace,确保要写入跟踪信息的流对象不会阻塞。在调用
PQconnectPoll之前,确保套接字处于适当的状态,如下所述。
要开始一个非阻塞连接请求,调用
conn = PQconnectStart("。如果connection_info_string")conn为空,说明 libpq 无法分配新的PGconn结构。否则返回一个有效的PGconn指针(尽管它尚未表示一个有效的数据库连接)。从PQconnectStart返回后,调用status = PQstatus(conn)。如果status等于CONNECTION_BAD,则PQconnectStart失败。如果
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 = "Connecting..."; break; case CONNECTION_MADE: feedback = "Connected to server..."; break; . . . default: feedback = "Connecting..."; }使用
PQconnectPoll时会忽略connect_timeout连接参数;由应用负责判断是否已经耗时过长。除此之外,PQconnectStart加上PQconnectPoll循环等价于PQconnectdb。注意,如果
PQconnectStart返回非空指针,使用完毕后必须调用PQfinish,以释放该结构和所有关联的内存块。即使连接尝试失败或被放弃,也必须这样做。PQconndefaults返回默认的连接选项。
PQconninfoOption *PQconndefaults(void); typedef struct { char *keyword; /* The keyword of the option */ char *envvar; /* Fallback environment variable name */ char *compiled; /* Fallback compiled in default value */ char *val; /* Option's current value, or NULL */ char *label; /* Label for field in connect dialog */ char *dispchar; /* Character to display for this field in a connect dialog. Values are: "" Display entered value as is "*" Password field - hide value "D" Debug option - don't show by default */ int dispsize; /* Field size in characters for dialog */ } PQconninfoOption;返回一个连接选项数组。它可用来确定
PQconnectdb的所有可用选项及其当前默认值。返回值指向一个PQconninfoOption结构数组,该数组以一个keyword指针为空的条目结尾。注意,当前默认值(val字段)依赖于环境变量和其他上下文。调用者必须将连接选项数据视为只读。处理完选项数组后,将它传递给
PQconninfoFree释放。如果不这样做,每次调用PQconndefaults都会泄漏少量内存。PQfinish关闭与服务器的连接,同时释放
PGconn对象使用的内存。void PQfinish(PGconn *conn);
注意,即使与服务器的连接尝试失败(由
PQstatus指示),应用也应调用PQfinish释放PGconn对象使用的内存。在调用过PQfinish之后,不得再使用该PGconn指针。PQreset重置与服务器的通信通道。
void PQreset(PGconn *conn);
此函数将关闭与服务器的连接,并尝试使用先前使用的全部相同参数与同一服务器重新建立新连接。如果工作中的连接丢失,这可用于错误恢复。
PQresetStartPQresetPoll以非阻塞方式重置与服务器的通信通道。
int PQresetStart(PGconn *conn);
PostgresPollingStatusType PQresetPoll(PGconn *conn);
这些函数将关闭与服务器的连接,并尝试使用先前使用的全部相同参数与同一服务器重新建立新连接。如果工作中的连接丢失,这可用于错误恢复。它们与上面的
PQreset的不同之处在于以非阻塞方式运作。这些函数受到与PQconnectStart和PQconnectPoll相同的限制。要发起连接重置,调用
PQresetStart。如果返回 0,重置失败。如果返回 1,用与使用PQconnectPoll建立连接完全相同的方式,使用PQresetPoll对重置进行轮询。