第 1 章 libpq - C 库
目录
libpq 是 Postgres
的 C 应用程序员接口。libpq
是一组库例程,客户端程序通过它们可以向
Postgres 后端服务器传送查询并接收这些查询的结果。libpq 也是其他几个
Postgres 应用接口的底层引擎,包括
libpq++(C++)、libpgtcl(Tcl)、Perl 和
ecpg。因此,即使你使用的是上述某个软件包,libpq
行为的某些方面对你来说也很重要。
本节末尾包含三个简短程序,展示如何编写使用
libpq 的程序。下列目录中还有几个完整的
libpq 应用程序示例:
../src/test/regress ../src/test/examples ../src/bin/psql
使用 libpq 的前端程序必须包含头文件
libpq-fe.h,并且必须与
libpq 库链接。
1.1. 数据库连接函数 #
下面的例程用于建立与
Postgres 后端服务器的连接。一个应用程序可以同时打开多个后端连接(原因之一是需要访问多个数据库)。每个连接由一个
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 地址。其格式应为 BSD 函数 inet_aton 等使用的标准点分数字形式。如果指定了非零长度的字符串,则使用 TCP/IP 通信。
使用 hostaddr 代替主机名可以让应用避免主机名查找,这对于有时间约束的应用可能很重要。但 Kerberos 认证需要主机名。因此适用以下规则。如果指定了主机名而没有指定 hostaddr,则强制进行主机名查找。如果指定了 hostaddr 而没有指定主机名,hostaddr 的值给出远程地址;若使用了 Kerberos,这会引起反向名称查询。如果主机名和 hostaddr 都被指定,hostaddr 的值给出远程地址;主机名的值被忽略,但使用 Kerberos 时例外,此时该值用于 Kerberos 认证。注意,如果传给 libpq 的主机名不是位于 hostaddr 的机器的名称,认证很可能失败。
既没有主机名也没有主机地址时,libpq 将使用本地 Unix 域套接字连接。
port服务器主机上要连接的端口号,或 Unix 域连接的套接字文件名扩展。
dbname数据库名。
user要以哪个用户名连接。
password如果服务器要求密码认证则使用的密码。
options要发送给服务器的跟踪/调试选项。
tty用于后端可选调试输出的文件或 tty。
requiressl设为 '1' 时要求与后端的 SSL 连接。如果服务器不支持 SSL,Libpq 将拒绝连接。设为 '0'(默认值)时与服务器协商。
如果任何参数未指定,则检查相应的环境变量(见"环境变量"一节)。如果环境变量也未设置,则使用硬编码的默认值。返回值是指向一个抽象 struct 的指针,该结构表示到后端的连接。
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的前身,参数个数固定但功能相同。PQsetdb与数据库服务器建立一个新连接。PGconn *PQsetdb(char *pghost, char *pgport, char *pgoptions, char *pgtty, char *dbName)这是一个宏,以空指针作为 login 和 pwd 参数调用
PQsetdbLogin()。它主要是为了与旧程序保持向后兼容而保留。PQconnectStart,PQconnectPoll以非阻塞方式建立与数据库服务器的连接。PGconn *PQconnectStart(const char *conninfo)
PostgresPollingStatusType PQconnectPoll(PGconn *conn)
这两个例程用于打开到数据库服务器的连接,同时应用程序的执行线程不会在远程 I/O 上阻塞。
数据库连接使用传给 PQconnectStart 的字符串
conninfo中的参数建立。该字符串的格式与上面 PQconnectdb 中描述的相同。只要满足若干限制条件,PQconnectStart 和 PQconnectPoll 都不会阻塞:
恰当地使用 hostaddr 和 host 参数,确保不进行(正向)名称和反向名称查询。详情见上面 PQconnectdb 下对这些参数的说明。
如果调用 PQtrace,确保要写入跟踪信息的流对象不会阻塞。
在调用 PQconnectPoll 之前,自行确保套接字处于适当的状态,如下所述。
首先,调用
conn=PQconnectStart("<connection_info_string>")。如果 conn 为 NULL,说明 libpq 无法分配新的 PGconn 结构。否则返回一个有效的 PGconn 指针(尽管它尚未表示一个有效的数据库连接)。从 PQconnectStart 返回后,调用 status=PQstatus(conn)。如果 status 等于 CONNECTION_BAD,则 PQconnectStart 失败。如果 PQconnectStart 成功,下一阶段是轮询 libpq,使其继续进行连接序列。循环如下:默认将连接视为'非活跃'。如果 PQconnectPoll 上次返回了 PGRES_POLLING_ACTIVE,则改将其视为'活跃'。如果 PQconnectPoll(conn) 上次返回 PGRES_POLLING_READING,则在 PQsocket(conn) 上为读取执行 select。如果上次返回 PGRES_POLLING_WRITING,则在 PQsocket(conn) 上为写入执行 select。如果尚未调用过 PQconnectPoll(即刚调用完 PQconnectStart 之后),则视同它上次返回的是 PGRES_POLLING_WRITING。如果 select 表明套接字已就绪,将其视为'活跃'。一旦确定此连接处于'活跃'状态,就再次调用 PQconnectPoll(conn)。如果这次调用返回 PGRES_POLLING_FAILED,连接过程已失败。如果返回 PGRES_POLLING_OK,连接已成功建立。
注意,用 select() 确保套接字就绪只是一个(常见的)例子;如果还有其他可用手段,例如 poll() 调用,当然可以改用它。
在连接期间的任何时刻,都可以调用 PQstatus 检查连接状态。如果返回 CONNECTION_BAD,则连接过程已失败;如果返回 CONNECTION_OK,则连接已就绪。如上所述,这两种状态都应能从 PQconnectPoll 的返回值中同样检测到。其他状态只在(且仅会在)异步连接过程中出现,它们指示连接过程的当前阶段,例如可用于向用户提供反馈。这些状态可能包括:
CONNECTION_STARTED:等待建立连接。
CONNECTION_MADE:连接成功;等待发送。
CONNECTION_AWAITING_RESPONSE:等待 postmaster 的响应。
CONNECTION_AUTH_OK:已通过认证;等待后端启动。
CONNECTION_SETENV:正在协商环境。
注意,尽管这些常量会保留(为了维护兼容性),应用程序绝不应依赖它们按特定顺序出现、依赖它们全都出现,或依赖状态总是这些已记录的值之一。应用程序可以这样处理:
switch(PQstatus(conn)) { case CONNECTION_STARTED: feedback = "Connecting..."; break; case CONNECTION_MADE: feedback = "Connected to server..."; break; . . . default: feedback = "Connecting..."; }注意,如果 PQconnectStart 返回非 NULL 指针,使用完毕后必须调用 PQfinish,以释放该结构和所有关联的内存块。即使 PQconnectStart 或 PQconnectPoll 的调用失败,也必须这样做。
当前,如果 libpq 编译时定义了 USE_SSL,PQconnectPoll 会阻塞。此限制将来可能被移除。
当前,在 Windows 下 PQconnectPoll 会阻塞,除非 libpq 编译时定义了 WIN32_NON_BLOCKING_CONNECTIONS。这段代码尚未在 Windows 下测试过,因此目前默认关闭。将来可能改变。
这些函数会把套接字置于非阻塞状态,就像调用过
PQsetnonblocking一样。PQconndefaults返回默认的连接选项。PQconninfoOption *PQconndefaults(void) struct PQconninfoOption { 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 */ }返回一个连接选项数组。它可用来确定 PQconnectdb 的所有可用选项及其当前默认值。返回值指向一个 PQconninfoOption struct 数组,该数组以一个 keyword 指针为 NULL 的条目结尾。注意,默认值("val" 字段)依赖于环境变量和其他上下文。调用者必须将连接选项数据视为只读。
处理完选项数组后,将它传递给 PQconninfoFree() 释放。如果不这样做,每次调用 PQconndefaults() 都会泄漏少量内存。
在 Postgres 7.0 之前的版本中,PQconndefaults() 返回指向静态数组的指针,而不是动态分配的数组。那样不是线程安全的,因此行为已被改变。
PQfinish关闭与后端的连接,同时释放 PGconn 对象使用的内存。void PQfinish(PGconn *conn)
注意,即使与后端的连接尝试失败(由 PQstatus 指示),应用也应调用 PQfinish 释放 PGconn 对象使用的内存。调用过 PQfinish 之后,不应再使用该 PGconn 指针。
PQreset重置与后端的通信端口。void PQreset(PGconn *conn)
此函数将关闭与后端的连接,并尝试使用先前使用的全部相同参数与同一个 postmaster 重新建立新连接。如果工作中的连接丢失,这可用于错误恢复。
PQresetStartPQresetPoll以非阻塞方式重置与后端的通信端口。int PQresetStart(PGconn *conn);
PostgresPollingStatusType PQresetPoll(PGconn *conn);
这些函数将关闭与后端的连接,并尝试使用先前使用的全部相同参数与同一个 postmaster 重新建立新连接。如果工作中的连接丢失,这可用于错误恢复。它们与上面的 PQreset 的不同之处在于以非阻塞方式运作。这些函数受到与 PQconnectStart 和 PQconnectPoll 相同的限制。
调用 PQresetStart。如果返回 0,重置失败。如果返回 1,用与使用 PQconnectPoll 建立连接完全相同的方式,使用 PQresetPoll 对重置进行轮询。
libpq 应用程序员应注意维护 PGconn
的抽象。请使用下面的访问函数获取
PGconn 的内容。避免直接引用
PGconn 结构的字段,因为它们将来可能改变。(从
Postgres 6.4 版开始,libpq-fe.h
中甚至不再提供 struct
PGconn 的定义。如果你有直接访问
PGconn 字段的旧代码,可以通过同时包含
libpq-int.h
继续使用它,但我们建议你尽快修改这些代码。)
PQdb返回连接的数据库名。char *PQdb(const PGconn *conn)
PQdb 及其后面几个函数返回在建立连接时确定的值。这些值在 PGconn 对象的整个生命周期内保持不变。
PQuser返回连接的用户名。char *PQuser(const PGconn *conn)
PQpass返回连接的密码。char *PQpass(const PGconn *conn)
PQhost返回连接的服务器主机名。char *PQhost(const PGconn *conn)
PQport返回连接的端口。char *PQport(const PGconn *conn)
PQtty返回连接的调试 tty。char *PQtty(const PGconn *conn)
PQoptions返回连接中使用的后端选项。char *PQoptions(const PGconn *conn)
PQstatus返回连接的状态。ConnStatusType PQstatus(const PGconn *conn)
状态可以是若干值之一。但在异步连接过程之外只能见到其中两个——
CONNECTION_OK或CONNECTION_BAD。正常的数据库连接状态为 CONNECTION_OK。失败的连接尝试由状态CONNECTION_BAD表示。通常,OK 状态会一直保持到调用PQfinish为止,但通信故障可能导致状态提前变为CONNECTION_BAD。此时应用可以尝试调用PQreset来恢复。关于可能见到的其他状态码,参见 PQconnectStart 和 PQconnectPoll 的条目。
PQerrorMessage返回连接上最近一次操作所产生的错误消息。char *PQerrorMessage(const PGconn* conn);几乎所有 libpq 函数在失败时都会设置
PQerrorMessage。注意,按照 libpq 的惯例,非空的PQerrorMessage会包含一个末尾换行符。PQbackendPID返回处理此连接的后端服务器的进程 ID。int PQbackendPID(const PGconn *conn);后端 PID 可用于调试,也可用于与 NOTIFY 消息(其中包含发出通知的后端的 PID)进行比较。注意,该 PID 属于数据库服务器主机上执行的进程,而不是本地主机上的进程!
PQgetssl返回连接中使用的 SSL 结构;若未使用 SSL 则返回 NULL。SSL *PQgetssl(const PGconn *conn);此结构可用于核实加密级别、检查服务器证书等。有关此结构的信息,请参阅 OpenSSL 文档。
必须定义
USE_SSL才能获得此函数的原型。这样做还会自动包含来自 OpenSSL 的ssl.h。PQgetssl返回连接中使用的 SSL 结构;若未使用 SSL 则返回 NULL。SSL *PQgetssl(const PGconn *conn);此结构可用于核实加密级别、检查服务器证书等。有关此结构的信息,请参阅 OpenSSL 文档。
必须定义
USE_SSL才能获得此函数的原型。这样做还会自动包含来自 OpenSSL 的ssl.h。