32.1. 数据库连接控制函数 #
以下函数用于建立到 PostgreSQL 后端服务器的连接。应用程序可以同时保持多个后端连接。(这样做的原因之一是访问多个数据库。)每个连接由一个 PGconn 对象表示,该对象可以通过以下函数获取:PQconnectdb,PQconnectdbParams 或 PQsetdbLogin。注意,这些函数总是返回非空的对象指针,除非内存不足,甚至无法分配 PGconn 对象。应调用 PQstatus 函数检查返回值,确认连接成功后,再通过连接对象发送查询。
警告
如果不受信任的用户能够访问一个没有采用模式的安全使用方式的数据库,那么每个会话开始时都应从 search_path 中移除公开可写的模式。可以把参数关键词 options 设置为 -csearch_path=。也可以在连接后发出 PQexec(。这种考虑并非专门针对 libpq;它适用于每一种可执行任意 SQL 命令的接口。
conn, "SELECT pg_catalog.set_config('search_path', '', false)")
警告
在 Unix 上,对持有已打开 libpq 连接的进程执行 fork 操作可能导致不可预料的结果,因为父进程和子进程会共享相同的套接字和操作系统资源。出于这个原因,我们不推荐这样的用法,尽管从子进程执行一个 exec 来载入新的可执行程序是安全的。
PQconnectdbParams#开启一个到数据库服务器的新连接。
PGconn *PQconnectdbParams(const char * const *keywords, const char * const *values, int expand_dbname);这个函数使用从两个以
NULL结尾的数组中取得的参数打开一个新的数据库连接。第一个数组keywords是一个字符串数组,其中每个元素都是一个关键词。第二个数组values给出每个关键词的值。和下面的PQsetdbLogin不同,参数集合可以在不改变函数签名的情况下扩展,因此对于新应用,最好使用这个函数(或者相应的非阻塞函数PQconnectStartParams和PQconnectPoll)。当前能被识别的参数关键词被列举在第 32.1.2 节中。
传入的数组可以为空,以使用所有默认参数,也可以包含一个或多个参数设置。两个数组的长度必须相同。处理会在
keywords数组的第一个NULL元素处停止。如果某个非NULL的keywords元素所对应的values元素为NULL或空字符串,则忽略这一项,继续处理下一对数组元素。当
expand_dbname非零时,会检查第一个dbname关键词的值是否为连接字符串。如果是,就将其“展开”为从该字符串中提取的各个连接参数。如果该值包含等号(=),或以 URI 方案标识符开头,就会将其视为连接字符串,而非单纯的数据库名。(连接字符串格式的详细说明见第 32.1.1 节。)只有第一次出现的dbname会按这种方式处理;后续的dbname参数都作为普通数据库名处理。通常会从头到尾处理参数数组。如果某个关键词重复出现,则采用最后一个非
NULL且非空的值。此规则也适用于连接字符串中的关键词与keywords数组中的关键词冲突的情况。因此,程序员可以决定数组元素是覆盖连接字符串中的值,还是被这些值覆盖。出现在要展开的dbname元素之前的数组元素,可以被连接字符串中的字段覆盖;而这些字段又会被出现在dbname之后的数组元素覆盖(同样,只有这些元素提供非空值时才会覆盖)。处理完所有数组元素及展开的连接字符串后,仍未设置的连接参数将填入默认值。如果某个未设置参数对应的环境变量(见第 32.14 节)已经设置,就使用该环境变量的值;否则使用该参数的内置默认值。
PQconnectdb#开启一个到数据库服务器的新连接。
PGconn *PQconnectdb(const char *conninfo);
这个函数使用从字符串
conninfo中得到的参数开启一个新的数据库连接。被传递的字符串可以为空,这样将会使用所有的默认参数。也可以包含由空白分隔的一个或多个参数设置,还可以包含一个 URI。详见第 32.1.1 节。
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或空字符串。如果
dbName包含=符号,或具有有效的连接 URI 前缀,就会将其当作conninfo字符串处理,方式与将其传给PQconnectdb完全相同,然后按照PQconnectdbParams的规则应用其余参数。pgtty已经不再使用,任何传递的值将被忽略。PQsetdb#开启一个到数据库服务器的新连接。
PGconn *PQsetdb(char *pghost, char *pgport, char *pgoptions, char *pgtty, char *dbName);这是一个调用
PQsetdbLogin的宏,其中为login和pwd参数使用空指针。提供它是为了向后兼容非常老的程序。PQconnectStartParamsPQconnectStartPQconnectPoll#PGconn *PQconnectStartParams(const char * const *keywords, const char * const *values, int expand_dbname); PGconn *PQconnectStart(const char *conninfo); PostgresPollingStatusType PQconnectPoll(PGconn *conn);这三个函数被用来开启一个到数据库服务器的连接,这样你的应用的执行线程不会因为远程的 I/O 而被阻塞。这种方法的要点在于等待 I/O 完成可能在应用的主循环中发生,而不是在
PQconnectdbParams或PQconnectdb中,并且因此应用能够把这种操作和其他动作并行处理。在
PQconnectStartParams中,数据库连接使用从keywords和values数组中取得的参数创建,并且被expand_dbname控制,这和之前描述的PQconnectdbParams相同。在
PQconnectStart中,数据库连接使用从字符串conninfo中取得的参数创建,这和之前描述的PQconnectdb相同。只要满足一些限制,
PQconnectStartParams或PQconnectStart或PQconnectPoll都不会阻塞:必须正确使用
hostaddr参数,以避免执行 DNS 查询。详细信息请参见第 32.1.2 节中该参数的说明。如果你调用
PQtrace,确保接收追踪输出的流对象不会阻塞。如后文所述,你必须要确保在调用
PQconnectPoll之前,套接字处于合适的状态。
要开始非阻塞连接请求,可调用
PQconnectStart或者PQconnectStartParams。如果结果为空指针,则 libpq 无法分配一个新的PGconn结构体。否则,一个有效的PGconn指针会被返回(不过还没有表示一个到数据库的有效连接)。接下来调用PQstatus(conn)。如果结果是CONNECTION_BAD,则连接尝试已经失败,通常是因为有无效的连接参数。如果
PQconnectStart或PQconnectStartParams成功,下一个阶段是轮询 libpq,这样它能够继续进行连接序列。使用PQsocket(conn)来获得该数据库连接底层的套接字描述符(警告:不要假定在PQconnectPoll调用之间套接字会保持相同)。这样循环:如果PQconnectPoll(conn)上一次返回PGRES_POLLING_READING,等到该套接字准备好读取(按照select()、poll()或类似的系统函数所指示的)。注意,PQsocketPoll封装了select(2)或poll(2)(如果系统支持)的设置,可减少重复代码。然后再次调用PQconnectPoll(conn)。反之,如果PQconnectPoll(conn)上一次返回PGRES_POLLING_WRITING,等到该套接字准备好写入,则再次调用PQconnectPoll(conn)。在第一次迭代时,即如果你还没有调用PQconnectPoll,行为就像是它上次返回了PGRES_POLLING_WRITING。持续这个循环直到PQconnectPoll(conn)返回PGRES_POLLING_FAILED指示连接过程已经失败,或者返回PGRES_POLLING_OK指示连接已经被成功地建立。在连接期间的任意时刻,该连接的状态可以通过调用
PQstatus来检查。如果这个调用返回CONNECTION_BAD,那么连接过程已经失败。如果该调用返回CONNECTION_OK,则该连接已经准备好。如前所述,这些状态同样都可以从PQconnectPoll的返回值检测。在一个异步连接过程中(也只有在这个过程中)也可能出现其他状态。这些状态指示该连接过程的当前阶段,并且可能有助于为用户提供反馈。这些状态是:CONNECTION_STARTED#等待连接被建立。
CONNECTION_MADE#连接 OK,等待发送。
CONNECTION_AWAITING_RESPONSE#等待来自服务器的一个回应。
CONNECTION_AUTH_OK#收到认证,等待后端启动结束。
CONNECTION_SSL_STARTUP#协商 SSL 加密。
CONNECTION_GSS_STARTUP#协商 GSS 加密。
CONNECTION_CHECK_WRITABLE#检查连接是否能够处理写事务。
CONNECTION_CHECK_STANDBY#检查连接的服务器是否处于备库模式。
CONNECTION_CONSUME#消费连接上的任何剩下的响应消息。
注意,虽然为保持兼容性会保留这些常量,但应用程序不应依赖它们按特定顺序出现,不应假定它们一定出现,也不应假定状态值一定是这里列出的某个值。应用程序可以采用如下方式:
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或PQconnectStartParams返回一个非空的指针时,你必须在用完它之后调用PQfinish来释放该结构体及其关联的所有内存块。即使连接尝试失败或被放弃时也必须完成这些工作。PQsocketPoll#轮询通过
PQsocket取得的连接底层套接字描述符。此函数主要用于逐步执行PQconnectStartParams文档中描述的连接过程。typedef int64_t pg_usec_time_t; int PQsocketPoll(int sock, int forRead, int forWrite, pg_usec_time_t end_time);此函数对文件描述符进行轮询,并可选择设置超时。如果
forRead非零,则在套接字可读时结束。如果forWrite非零,则在套接字可写时结束。超时由
end_time指定,它表示停止等待的时刻,以自 Unix 纪元以来的微秒数表示(即time_t乘以一百万)。如果end_time为-1,则无限等待。如果end_time为0(或任何早于当前时刻的时间),则立即超时(不阻塞)。将所需的微秒数加到PQgetCurrentTimeUSec的结果上,即可方便地计算超时值。注意,底层系统调用的精度可能低于微秒,因此实际延迟可能不精确。如果满足指定条件,函数返回大于
0的值;如果发生超时,返回0;如果发生错误,返回-1。可以通过检查errno(3)的值获取错误信息。如果forRead和forWrite都为零,函数会立即返回超时指示。PQsocketPoll根据平台使用poll(2)或select(2)实现。更多信息请参见poll(2)中的POLLIN和POLLOUT,或select(2)中的readfds和writefds。PQconndefaults#返回默认连接选项。
PQconninfoOption *PQconndefaults(void); typedef struct { char *keyword; /* 该选项的关键词 */ char *envvar; /* 后备环境变量名 */ char *compiled; /* 编译时设置的后备默认值 */ char *val; /* 选项的当前值,或者 NULL */ char *label; /* 连接对话框中字段的标签 */ char *dispchar; /* 指示如何在连接对话框中显示此字段。可取值: "" 显示输入的值 "*" 密码字段 - 隐藏值 "D" 调试选项 - 默认不显示 */ int dispsize; /* 对话框中的字段宽度,以字符计 */ } PQconninfoOption;返回一个连接选项数组。这可以用来确定用于连接服务器的所有可能的
PQconnectdb选项和它们的当前默认值。返回值指向一个PQconninfoOption结构体的数组,该数组以一个包含空keyword指针的条目结束。如果无法分配内存,则返回空指针。注意当前默认值(val字段)将依赖于环境变量和其他上下文。一个缺失或者无效的服务文件将会被无声地忽略掉。调用者必须把连接选项当作只读对待。在处理完选项数组后,把它交给
PQconninfoFree释放。如果没有这么做,每次调用PQconndefaults都会导致一小部分内存泄漏。PQconninfo#返回被一个活动连接使用的连接选项。
PQconninfoOption *PQconninfo(PGconn *conn);
返回一个连接选项数组。可以用它确定所有可能的
PQconnectdb选项,以及实际用于连接服务器的值。返回值指向一个PQconninfoOption结构体数组,该数组以keyword指针为空的条目结束。上文针对PQconndefaults的所有注意事项,也适用于PQconninfo的结果。PQconninfoParse#返回从提供的连接字符串中解析到的连接选项。
PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg);
解析一个连接字符串并且将结果选项作为一个数组返回,或者在连接字符串有问题时返回
NULL。这个函数可以用来抽取所提供的连接字符串中的PQconnectdb选项。返回值指向一个PQconninfoOption结构体的数组,该数组以一个包含空keyword指针的条目结束。所有合法选项将出现在结果数组中,但是任何在连接字符串中没有出现的选项的
PQconninfoOption的val会被设置为NULL,默认值不会被插入。如果
errmsg不是NULL,则成功时将*errmsg设为NULL;失败时将其设为由malloc分配的、用于说明问题的错误字符串。(也可能出现*errmsg被设为NULL,同时函数返回NULL的情况;这表示内存不足。)在处理完选项数组后,把它交给
PQconninfoFree释放。如果没有这么做,每次调用PQconninfoParse都会导致一小部分内存泄漏。反过来,如果发生一个错误并且errmsg不是NULL,确保使用PQfreemem释放错误字符串。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的不同在于它们以非阻塞方式工作。这些函数受到与PQconnectStartParams、PQconnectStart和PQconnectPoll相同的限制。要开始重置连接,请调用
PQresetStart。如果返回 0,表示重置失败。如果返回 1,则使用PQresetPoll轮询重置过程,方式与使用PQconnectPoll建立连接完全相同。PQpingParams#PQpingParams报告服务器的状态。它接受与PQconnectdbParams相同的连接参数,如上所述。获得服务器状态不需要提供正确的用户名、密码或数据库名。不过,如果提供了不正确的值,服务器将记录一次失败的连接尝试。PGPing PQpingParams(const char * const *keywords, const char * const *values, int expand_dbname);该函数返回下列值之一:
PQping#PQping报告服务器的状态。它接受与PQconnectdb相同的连接参数。获得服务器状态不需要提供正确的用户名、密码或数据库名。不过,如果提供了不正确的值,服务器将记录一次失败的连接尝试。PGPing PQping(const char *conninfo);
返回值和
PQpingParams相同。PQsetSSLKeyPassHook_OpenSSL#PQsetSSLKeyPassHook_OpenSSL允许应用覆盖 libpq 对加密客户端证书密钥文件的默认处理方式,包括使用 sslpassword 或交互式提示输入密码的处理。void PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook);
应用程序传入一个指向回调函数的指针,其签名为:
int callback_fn(char *buf, int size, PGconn *conn);
随后,libpq 会调用该回调,而不是调用其默认的
PQdefaultSSLKeyPassHook_OpenSSL处理程序。回调函数应确定密钥密码,并将其复制到大小为size的结果缓冲区buf中。buf中的字符串必须以空字符结尾。回调函数必须返回存储在buf中的密码长度,不包括结尾的空字符。如果失败,回调函数应设置buf[0] = '\0'并返回 0。参见 libpq 源代码中的PQdefaultSSLKeyPassHook_OpenSSL以获得示例。如果用户指定了一个显式的密钥位置,那么当调用回调时,它的路径将在
conn->sslkey中。如果使用默认密钥路径,则这将为空。对于作为引擎说明符的密钥,由引擎实现决定它们是使用 OpenSSL 密码回调还是定义自己的处理方式。应用回调可以选择把未处理的情况委派给
PQdefaultSSLKeyPassHook_OpenSSL,也可以先调用它,如果它返回 0 再尝试其他方法,或者完全覆盖它。回调不得通过异常、
longjmp(...)等方式跳出正常控制流。它必须正常返回。PQgetSSLKeyPassHook_OpenSSL#PQgetSSLKeyPassHook_OpenSSL返回当前客户端证书密钥密码钩子,如果没有设置则返回NULL。PQsslKeyPassHook_OpenSSL_type PQgetSSLKeyPassHook_OpenSSL(void);
32.1.1. 连接字符串 #
几个 libpq 函数解析用户指定的字符串以获取连接参数。这些字符串有两种被接受的格式:普通的关键词/值字符串和 URI。URI 通常遵循 RFC 3986,但也允许使用多主机连接字符串,详见下文。
32.1.1.1. 关键词/值连接字符串 #
在关键词/值格式中,每一个参数设置的形式都是关键词 = 值,设置之间以空格分隔。设置的等号周围的空格是可选的。要写一个空值或一个包含空格的值,将它用单引号包围,例如 keyword = 'a value'。值里面的单引号和反斜杠必须用一个反斜杠转义,即\' 和\\。
示例:
host=localhost port=5432 dbname=mydb connect_timeout=10
能被识别的参数关键词在第 32.1.2 节中列出。
32.1.1.2. 连接 URI #
一个连接 URI 的一般形式是:
postgresql://[userspec@][hostspec][/dbname][?paramspec] 其中userspec为:user[:password]hostspec为: [host][:port][,...]paramspec为:name=value[&...]
URI 方案标识符可以是 postgresql://或 postgres://。每一个剩下的 URI 部分都是可选的。下列示例展示了合法的 URI 语法:
postgresql:// postgresql://localhost postgresql://localhost:5433 postgresql://localhost/mydb postgresql://user@localhost postgresql://user:secret@localhost postgresql://other@localhost/otherdb?connect_timeout=10&application_name=myapp postgresql://host1:123,host2:456/somedb?target_session_attrs=any&application_name=myapp
通常出现在 URI 的层次部分的值,也能够以命名参数的方式给出。例如:
postgresql:///mydb?host=localhost&port=5433
所有命名参数都必须与第 32.1.2 节中列出的关键词匹配;唯一的例外是,为兼容 JDBC 连接 URI,会将 ssl=true 转换为 sslmode=require。
如果连接 URI 的任意部分包含具有特殊含义的符号,就需要使用百分号编码。下面的示例将等号(=)替换为 %3D,将空格字符替换为 %20:
postgresql://user@localhost:5433/mydb?options=-c%20synchronous_commit%3Doff
主机部分可能是主机名或一个 IP 地址。要指定一个 IPv6 地址,将它封闭在方括号中:
postgresql://[2001:db8::1234]/database
主机组件会被按照参数 host 对应的描述来解释。特别地,如果主机部分是空或看起来像一个绝对路径名称,将使用一个 Unix 域套接字连接,否则将启动一个 TCP/IP 连接。不过要注意,斜线是 URI 层次部分中的一个保留字符。因此,要指定一个非标准的 Unix 域套接字目录,要么省略 URI 中的主机部分并且指定该主机为一个命名参数,要么在 URI 的主机部分用百分号编码路径:
postgresql:///dbname?host=/var/lib/postgresql postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
可以在一个 URI 中指定多个主机,每一个都有一个可选的端口。一个形式为 postgresql://host1:port1,host2:port2,host3:port3/的 URI 等效于 host=host1,host2,host3 port=port1,port2,port3 形式的连接字符串。如下所述,每一个主机都将被依次尝试,直到成功地建立一个连接。
32.1.1.3. 指定多个主机 #
可以指定多个要连接的主机,这样它们会按给定的顺序被尝试。在关键词/值格式中,host、hostaddr 和 port 选项都接受逗号分隔的值列表。在指定的每一个选项中都必须给出相同数量的元素,这样第一个 hostaddr 对应于第一个主机名,第二个 hostaddr 对应于第二个主机名,以此类推。不过,如果仅指定一个 port,它将被应用于所有的主机。
在连接 URI 格式中,在 URI 的 host 部分我们可以列出多个由逗号分隔的 host:port 对。
不管是哪一种格式,单一的主机名可以被解析成多个网络地址。常见的示例是一个主机同时具有 IPv4 和 IPv6 地址。
当多个主机被指定时或者单个主机名被解析成多个地址时,所有的主机和地址都将按照顺序被尝试,直至遇到一个成功的。如果没有主机可以到达,则连接失败。如果成功地建立一个连接但是认证失败,也不会尝试列表中剩下的主机。
如果使用了密码文件,可以为不同的主机使用不同的密码。所有其他连接选项对列表中的每一台主机都是相同的,例如不能为不同的主机指定不同的用户名。
32.1.2. 参数关键词 #
目前被识别的参数关键字包括:
host#要连接的主机名。如果主机名看起来像绝对路径名,则指定的是 Unix 域通信,而非 TCP/IP 通信;此值是存放套接字文件的目录名。(在 Unix 上,绝对路径名以斜杠开头。在 Windows 上,也会识别以驱动器号开头的路径。)如果主机名以
@开头,则将其视为抽象命名空间中的 Unix 域套接字(目前在 Linux 和 Windows 上支持)。当未指定host或其值为空时,默认连接到/tmp(或构建 PostgreSQL 时指定的套接字目录)中的 Unix 域套接字。在 Windows 上,默认连接到localhost。也可以接受一个逗号分隔的主机名列表,此时列表中的每个主机名将按顺序尝试;列表中的空项将选择上述默认行为。详细信息请参见第 32.1.1.3 节。
hostaddr#要连接的主机的数字 IP 地址。这应该是标准的 IPv4 地址格式,例如,
172.28.40.9。如果您的机器支持 IPv6,也可以使用这些地址。当为此参数指定非空字符串时,总是使用 TCP/IP 通信。如果未指定此参数,则会根据host的值查找相应的 IP 地址 — 或者,如果host指定了 IP 地址,则将直接使用该值。使用
hostaddr允许应用程序避免主机名查找,这在有时间限制的应用程序中可能很重要。但是,对于 GSSAPI 或 SSPI 认证方法以及verify-fullSSL 证书验证,需要主机名。使用以下规则:如果指定了
host而没有指定hostaddr,则会发生主机名查找。(当使用PQconnectPoll时,查找发生在PQconnectPoll首次考虑此主机名时,并且可能导致PQconnectPoll阻塞相当长的时间。)如果指定了
hostaddr而没有指定host,则hostaddr的值给出服务器的网络地址。如果认证方法需要主机名,则连接尝试将失败。如果同时指定了
host和hostaddr,则hostaddr的值给出服务器的网络地址。只有认证方法需要主机名时,才会将host的值用作主机名;否则忽略该值。
请注意,如果
host不是网络地址hostaddr上服务器的名称,则认证可能会失败。此外,当同时指定host和hostaddr时,host用于在密码文件中标识连接(请参阅第 32.15 节)。也可以接受一个逗号分隔的
hostaddr值列表,此时将按顺序尝试列表中的每个主机。列表中的空项会导致使用相应的主机名,如果主机名也为空,则使用默认主机名。详见第 32.1.1.3 节。如果既没有主机名也没有主机地址,libpq 会使用本地 Unix 域套接字连接;在 Windows 上,则会尝试连接到
localhost。port#连接到服务器主机的端口号,或者 Unix 域连接的套接字文件名扩展。如果在
host或hostaddr参数中给出了多个主机,则此参数可以指定与主机列表长度相同的逗号分隔的端口列表,或者可以指定用于所有主机的单个端口号。空字符串,或逗号分隔列表中的空项,指定了在构建 PostgreSQL 时建立的默认端口号。dbname#数据库名称。默认为与用户名相同。在某些情况下,该值会被检查是否为扩展格式;有关更多详细信息,请参阅第 32.1.1 节。
user#建立连接所用的 PostgreSQL 用户名。默认与运行应用程序的操作系统用户名相同。
password#服务器要求密码认证时所使用的密码。
passfile#指定用于存储密码的文件名(参见第 32.15 节)。默认为
~/.pgpass,或在 Microsoft Windows 上为%APPDATA%\postgresql\pgpass.conf。(如果此文件不存在,则不会报告错误。)require_auth#指定客户端要求服务器采用的认证方法。如果服务器没有使用所要求的方法来认证客户端,或者服务器没有完整完成认证握手,则连接将失败。也可以提供一个以逗号分隔的方法列表,此时服务器必须恰好使用其中一种方法,连接才会成功。默认情况下接受任意认证方法,并且服务器也可以完全跳过认证。
可以在方法名前加上
!前缀以表示否定,此时服务器不得尝试所列方法;除此之外,任何其他方法都可接受,并且服务器也可以完全不认证客户端。如果提供的是逗号分隔列表,服务器不得尝试其中任何一个被否定的方法。否定形式和非否定形式不能在同一设置中混用。最后还有一种特殊情况:
none方法要求服务器不使用认证质询。(它也可以被否定,用来要求必须进行某种认证。)可指定的方法如下:
password服务器必须请求明文密码认证。
md5服务器必须请求 MD5 hash 密码认证。
警告
对 MD5 加密密码的支持已弃用,并将在 PostgreSQL 的未来版本中移除。迁移到其他密码类型的详细信息见第 20.5 节。
gss服务器必须通过 GSSAPI 请求 Kerberos 握手,或者建立一个经过 GSS 加密的通道(另见 gssencmode)。
sspi服务器必须请求 Windows SSPI 认证。
scram-sha-256服务器必须与客户端成功完成一次 SCRAM-SHA-256 认证交换。
oauth服务器必须向客户端请求 OAuth Bearer 令牌。
none服务器不得提示客户端执行认证交换。(这并不禁止通过 TLS 进行客户端证书认证,也不禁止通过 GSS 自身的加密传输进行 GSS 认证。)
channel_binding#这个选项控制客户端对通道绑定的使用。设置为
require表示连接必须使用通道绑定,prefer表示客户端将在可用时选择通道绑定,而disable则阻止使用通道绑定。默认情况下,如果 PostgreSQL 是使用 SSL 支持编译的,则默认为prefer;否则默认为disable。通道绑定是服务器向客户端证明自身身份的一种方法。它只在使用 PostgreSQL 11 或更高版本服务器、并采用
SCRAM认证方法的 SSL 连接上受支持。connect_timeout#连接时的最长等待时间,以秒为单位(写成十进制整数,例如,
10)。零、负值或未指定表示无限等待。此超时时间分别适用于每个主机名或 IP 地址。例如,如果指定了两个主机且connect_timeout为 5,那么每个主机在 5 秒内未建立连接就会超时,因此等待连接的总时间可能长达 10 秒。client_encoding#这将为此连接设置
client_encoding配置参数。除了对应服务器选项接受的值外,您还可以使用auto来从客户端的当前区域设置(Unix 系统上的LC_CTYPE环境变量)确定正确的编码。options#指定连接开始时发送到服务器的命令行选项。例如,将其设置为
-c geqo=off或--geqo=off会把会话的geqo参数值设为off。此字符串中的空格被视为分隔命令行参数,除非用反斜杠(\)转义;写\\表示字面上的反斜杠。有关可用选项的详细讨论,请参阅第 19 章。application_name#指定 application_name 配置参数的值。
fallback_application_name#指定 application_name 配置参数的后备值。如果没有通过连接参数或
PGAPPNAME环境变量为application_name指定值,则将使用此值。在通用实用程序中指定后备名称很有用,该程序希望设置默认应用程序名称,但允许用户覆盖它。keepalives#控制是否使用客户端 TCP keepalive。默认值为 1,表示开启;如果不需要 keepalive,可以将其设为 0,表示关闭。对于通过 Unix 域套接字建立的连接,此参数会被忽略。
keepalives_idle#控制在多久没有活动后,TCP 应向服务器发送 keepalive 消息,以秒为单位。值为零时使用系统默认值。对于通过 Unix 域套接字建立的连接,或禁用 keepalive 时,此参数会被忽略。此参数仅在支持
TCP_KEEPIDLE或等效套接字选项的系统以及 Windows 上受支持;在其他系统上无效。keepalives_interval#控制未被服务器确认收到的 TCP keepalive 消息在多少秒后应被重传。值为零时使用系统默认值。对于通过 Unix 域套接字建立的连接,或禁用 keepalive 时,此参数会被忽略。此参数仅在支持
TCP_KEEPINTVL或等效套接字选项的系统以及 Windows 上受支持;在其他系统上无效。keepalives_count#控制在客户端与服务器之间的连接被视为中断之前,可以丢失多少个 TCP keepalive 消息。值为零时使用系统默认值。对于通过 Unix 域套接字建立的连接,或禁用 keepalive 时,此参数会被忽略。此参数仅在支持
TCP_KEEPCNT或等效套接字选项的系统上受支持;在其他系统上无效。tcp_user_timeout#控制已发送的数据在连接被强制关闭之前最多可以保持未确认状态多长时间,以毫秒为单位。值为零时使用系统默认值。对于通过 Unix 域套接字建立的连接,此参数会被忽略。此参数仅在支持
TCP_USER_TIMEOUT的系统上受支持;在其他系统上无效。replication#这个选项确定连接是否应该使用复制协议而不是正常协议。这就是 PostgreSQL 复制连接以及诸如 pg_basebackup 这样的工具在内部使用的方式,但也可以被第三方应用程序使用。要了解复制协议的描述,请参考第 54.4 节。
支持以下值(不区分大小写):
在物理或逻辑复制模式下,只能使用简单查询协议。
gssencmode#这个选项确定是否以及以何种优先级与服务器协商安全的 GSS TCP/IP 连接。有三种模式:
gssencmode在 Unix 域套接字通信中被忽略。如果 PostgreSQL 没有编译 GSSAPI 支持,使用require选项将导致错误,而prefer将被接受,但 libpq 实际上不会尝试进行 GSSAPI 加密连接。sslmode#这个选项确定是否以及以何种优先级与服务器协商安全的 SSL TCP/IP 连接。有六种模式:
详细了解这些选项如何工作,请参阅第 32.18 节。
在 Unix 域套接字通信中,
sslmode会被忽略。如果 PostgreSQL 编译时未启用 SSL 支持,使用选项require、verify-ca或verify-full会导致错误,而选项allow和prefer将被接受,但 libpq 实际上不会尝试建立 SSL 连接。注意,如果可以使用 GSSAPI 加密,就会优先使用它而不是 SSL 加密,无论
sslmode的值是什么。在具有可用 GSSAPI 基础设施(例如 Kerberos 服务器)的环境中,要强制使用 SSL 加密,还应将gssencmode设为disable。requiressl#此选项已弃用,请改用
sslmode设置。如果设置为 1,则需要与服务器建立 SSL 连接(这相当于
sslmoderequire)。libpq 将拒绝连接,如果服务器不接受 SSL 连接。如果设置为 0(默认值),libpq 将与服务器协商连接类型(相当于sslmodeprefer)。此选项仅在 PostgreSQL 编译时启用了 SSL 支持的情况下可用。sslnegotiation#如果使用 SSL,此选项控制如何与服务器协商 SSL 加密。在默认的
postgres模式下,客户端会先询问服务器是否支持 SSL;在direct模式下,客户端会在建立 TCP/IP 连接后直接开始标准 SSL 握手。传统的 PostgreSQL 协议协商能兼容更多不同的服务器配置;如果已知服务器支持直接 SSL 连接,则后一种方式可以减少一次往返,从而降低连接延迟,也允许使用与协议无关的 SSL 网络工具。直接 SSL 选项是在 PostgreSQL 17 中引入的。postgres执行 PostgreSQL 协议协商。如果未提供该选项,这是默认值。
direct在建立 TCP/IP 连接后直接开始 SSL 握手。仅当
sslmode=require或更高时才允许使用该模式,因为更弱的设置可能在服务器不支持直接 SSL 握手时导致意外回退到明文认证。
sslcompression#如果设置为 1,通过 SSL 连接发送的数据将被压缩。如果设置为 0,将禁用压缩。默认值为 0。如果进行非 SSL 连接,则忽略此参数。
SSL 压缩现在被认为是不安全的,不再建议使用。OpenSSL 1.1.0 默认禁用压缩,许多操作系统发行版也在之前的版本中禁用了压缩,因此如果服务器不接受压缩,将此参数设置为 on 将不会产生任何效果。PostgreSQL 14 在后端完全禁用了压缩。
如果安全性不是主要考虑因素,压缩可以提高吞吐量,如果网络是瓶颈的话。如果 CPU 性能是限制因素,禁用压缩可以缩短响应时间并提高吞吐量。
sslcert#这个参数指定客户端 SSL 证书的文件名,替换默认的
~/.postgresql/postgresql.crt。如果没有建立 SSL 连接,则此参数将被忽略。sslkey#这个参数指定了用于客户端证书的密钥的位置。它可以指定一个文件名,该文件名将被用来替代默认的
~/.postgresql/postgresql.key,或者它可以指定一个从外部“引擎”(引擎是 OpenSSL 可加载模块)获取的密钥。外部引擎的指定形式应包含一个由冒号分隔的引擎名称和一个引擎特定的密钥标识符。如果没有进行 SSL 连接,则此参数将被忽略。sslkeylogfile#这个参数指定 libpq 记录此 SSL 上下文所用密钥的位置。这对于调试 PostgreSQL 协议交互,或者借助 Wireshark 之类的网络检查工具分析客户端连接很有用。如果未建立 SSL 连接,或者使用的是 LibreSSL(其不支持密钥记录),则会忽略此参数。密钥将按 NSS 格式记录。
警告
密钥记录会在 keylog 文件中暴露潜在敏感信息。应当像处理 sslkey 文件一样谨慎处理 keylog 文件。
sslpassword#这个参数指定了在
sslkey中指定的密钥的密码,允许客户端证书私钥在磁盘上以加密形式存储,即使交互式密码输入不可行。当向 libpq 提供加密的客户端证书密钥时,将此参数指定为任意非空值,都将抑制 OpenSSL 默认发出的
Enter PEM pass phrase:提示。如果密钥未加密,则忽略此参数。该参数对由 OpenSSL 引擎指定的密钥没有影响,除非引擎使用 OpenSSL 密码回调机制进行提示。
没有与此选项等效的环境变量,也没有在
.pgpass中查找它的功能。它可以在服务文件连接定义中使用。使用更复杂功能的用户应考虑使用 OpenSSL 引擎和类似 PKCS#11 或 USB 加密卸载设备的工具。sslcertmode#此选项决定是否可以向服务器发送客户端证书,以及服务器是否必须请求客户端证书。共有三种模式:
disable即使客户端有可用证书(默认位置或通过 sslcert 提供),也绝不发送客户端证书。
allow(默认)如果服务器请求证书且客户端有证书可发,则可以发送证书。
require服务器必须请求证书。如果客户端没有发送证书而服务器仍成功认证了客户端,则连接将失败。
注意
sslcertmode=require不会增加额外的安全性,因为无法保证服务器一定正确验证了证书;PostgreSQL 服务器通常无论是否验证,都会向客户端请求 TLS 证书。该选项在排查更复杂的 TLS 配置时可能有用。sslrootcert#此参数指定包含 SSL 证书颁发机构(CA)证书的文件名。如果文件存在,则会验证服务器证书是否由这些机构之一签名。默认值为
~/.postgresql/root.crt。也可以指定特殊值
system,此时会加载 SSL 实现提供的受信任 CA 根证书。这些根证书的确切位置因 SSL 实现和平台而异。对于 OpenSSL,还可以通过SSL_CERT_DIR和SSL_CERT_FILE环境变量进一步修改这些位置。注意
使用
sslrootcert=system时,默认的sslmode会改为verify-full,任何较弱的设置都会引发错误。在大多数情况下,任何人都很容易为其控制的主机名获取受系统信任的证书,因此verify-ca及所有更弱的模式都无法发挥作用。特殊值
system优先于同名的本地证书文件。如果遇到这种情况,请改用其他路径,例如sslrootcert=./system。sslcrl#此参数指定 SSL 服务器证书吊销列表(CRL)的文件名。如果该文件存在,在验证服务器证书时,会拒绝其中列出的证书。如果既未设置 sslcrl,也未设置 sslcrldir,则采用
~/.postgresql/root.crl。sslcrldir#此参数指定 SSL 服务器证书吊销列表(CRL)的目录名。如果该目录存在,在验证服务器证书时,会拒绝该目录下文件中列出的证书。
目录需要使用 OpenSSL 命令
openssl rehash或c_rehash进行准备。详细信息请参阅其文档。sslcrl和sslcrldir可以一起指定。sslsni#如果设置为 1(默认值),libpq 会在启用 SSL 的连接上设置 TLS 扩展“服务器名称指示”(SNI)。通过将此参数设置为 0,可以关闭此功能。
支持 SSL 的代理可以利用服务器名称指示来路由连接,而无需解密 SSL 流。(注意,除非代理能够识别 PostgreSQL 协议握手,否则需要将
sslnegotiation设为direct。)不过,SNI 会使目标主机名以明文形式出现在网络流量中,因此在某些情况下可能不希望使用它。requirepeer#这个参数指定了服务器的操作系统用户名,例如
requirepeer=postgres。在建立 Unix 域套接字连接时,如果设置了这个参数,客户端会在连接开始时检查服务器进程是否在指定的用户下运行;如果不是,则连接会因错误而中止。这个参数可用于提供类似于在 TCP/IP 连接上使用 SSL 证书的服务器认证。(请注意,如果 Unix 域套接字位于/tmp或其他公共可写位置,任何用户都可以在那里启动一个服务器监听。使用这个参数来确保您连接到由受信任用户运行的服务器。)此选项仅在实现了peer认证方法的平台上受支持;请参见第 20.9 节。ssl_min_protocol_version#这个参数指定连接允许的最低 SSL/TLS 协议版本。有效值为
TLSv1、TLSv1.1、TLSv1.2和TLSv1.3。支持的协议取决于所使用的 OpenSSL 版本,旧版本不支持最现代的协议版本。如果未指定,默认值为TLSv1.2,符合本文撰写时的行业最佳实践。ssl_max_protocol_version#这个参数指定连接允许的最大 SSL/TLS 协议版本。有效值为
TLSv1、TLSv1.1、TLSv1.2和TLSv1.3。支持的协议取决于使用的 OpenSSL 版本,旧版本不支持最新的协议版本。如果未设置,则忽略此参数;如果后端定义了最大限制,连接将使用该限制。设置最大协议版本主要用于测试或者某些组件无法使用较新协议时。min_protocol_version#这个参数指定该连接允许的最低协议版本。默认情况下,允许使用 libpq 所支持的任何 PostgreSQL 协议版本,目前即
3.0。如果服务器不支持此协议版本或更高版本,则连接将被关闭。当前支持的值是
3.0、3.2和latest。latest等价于正在使用的 libpq 版本所支持的最新协议版本,目前即3.2。max_protocol_version#这个参数指定要向服务器请求的协议版本。默认会使用 PostgreSQL 协议的
3.0版本;但如果连接字符串指定了依赖更高协议版本的特性,则会使用 libpq 支持的最新版本。如果服务器不支持客户端请求的协议版本,连接会自动降级为服务器支持的较低次版本协议。连接尝试完成后,你可以使用PQfullProtocolVersion来确定最终协商得到的确切协议版本。当前支持的值是
3.0、3.2和latest。latest等价于正在使用的 libpq 版本所支持的最新协议版本,目前即3.2。krbsrvname#使用 GSSAPI 认证时所用的 Kerberos 服务名。这必须与服务器配置中指定的 Kerberos 认证服务名称匹配,才能成功进行认证。(另请参见第 20.6 节。)默认值通常为
postgres,但在构建 PostgreSQL 时,可以通过 configure 的--with-krb-srvnam选项更改。在大多数环境中,通常不需要更改此参数。一些 Kerberos 实现可能需要不同的服务名称,例如 Microsoft Active Directory 需要服务名称为大写(POSTGRES)。gsslib#用于 GSSAPI 认证的 GSS 库。目前,除了包含 GSSAPI 和 SSPI 支持的 Windows 构建之外,这将被忽略。在这种情况下,将其设置为
gssapi,以使 libpq 使用 GSSAPI 库进行认证,而不是默认的 SSPI。gssdelegation#将 GSS 凭据转发(委派)给服务器。默认值为
0,表示不向服务器转发凭据。将其设置为1时,会在可能的情况下转发凭据。scram_client_key#以 Base64 编码的 SCRAM 客户端密钥。外部数据包装器或类似中间件可以利用它启用透传式 SCRAM 认证。一个实现示例见第 F.40.1.10 节。用户或客户端应用不应直接指定它。
scram_server_key#以 Base64 编码的 SCRAM 服务器密钥。外部数据包装器或类似中间件可以利用它启用透传式 SCRAM 认证。一个实现示例见第 F.40.1.10 节。用户或客户端应用不应直接指定它。
service#用于额外参数的服务名称。它指定了
pg_service.conf中保存额外连接参数的服务名称。这允许应用程序只指定一个服务名称,以便可以集中维护连接参数。参见第 32.16 节。servicefile#该选项指定每个用户的连接服务文件名称(参见第 32.16 节)。默认值是
~/.pg_service.conf,在 Microsoft Windows 上则是%APPDATA%\postgresql\.pg_service.conf。target_session_attrs#这个选项确定会话是否必须具有某些属性才能被接受。通常与多个主机名结合使用,以便在多个主机中选择第一个可接受的候选项。有六种模式:
load_balance_hosts#控制客户端尝试连接可用主机和地址的顺序。一旦某次连接尝试成功,就不会再尝试其他主机和地址。该参数通常与多个主机名或返回多个 IP 地址的 DNS 记录一起使用。它还可以与 target_session_attrs 组合使用,例如只在备库之间进行负载均衡。连接一旦成功建立,随后在返回的连接上发出的所有查询都会发送到同一台服务器。目前有两种模式:
disable(默认)不在主机之间执行负载均衡。主机会按提供的顺序进行尝试,地址会按从 DNS 或 hosts 文件获得的顺序进行尝试。
random按随机顺序尝试主机和地址。这个值主要适用于同时打开多个连接的场景,甚至这些连接来自不同机器。这样就可以把连接负载分散到多个 PostgreSQL 服务器上。
虽然随机负载均衡由于其随机性几乎不会得到完全均匀的分布,但统计上会相当接近。这里有一个重要点:该算法使用两级随机选择。首先,主机会按随机顺序解析。其次,在解析下一个主机之前,会按随机顺序尝试当前主机解析得到的全部地址。在某些情况下,这种行为会使各节点获得的连接数量明显倾斜,例如某些主机解析出的地址比其他主机更多时。但这种倾斜也可以被有意利用,例如通过在主机字符串中多次提供某台更大服务器的主机名,来增加它获得的连接数量。
使用这个值时,建议同时为 connect_timeout 配置一个合理的值。这样,如果某个参与负载均衡的节点没有响应,就会继续尝试新的节点。
oauth_issuer#如果服务器为该连接请求 OAuth 令牌,要联系的受信任签发者的 HTTPS URL。所有 OAuth 连接都必须设置此参数;它应当与服务器 HBA 配置中的
issuer设置完全一致。作为标准认证握手的一部分,libpq 会向服务器请求一个发现文档,也就是一个提供一组 OAuth 配置参数的 URL。服务器必须提供一个可由
oauth_issuer的各组成部分直接构造出来的 URL,并且该值必须与发现文档自身声明的签发者标识符完全一致,否则连接会失败。这是为了防止 OAuth 客户端遭受一类“混淆攻击(mix-up attacks)”。你也可以显式把
oauth_issuer设置为 OAuth 发现所使用的/.well-known/URI。在这种情况下,如果服务器要求使用不同的 URL,连接就会失败;不过,自定义 OAuth 流程也许能够通过使用先前缓存的令牌来加速标准握手。(此时也建议设置 oauth_scope,因为客户端将没有机会向服务器询问正确的授权范围设置,而令牌的默认授权范围可能不足以完成连接。)libpq 当前支持以下 well-known 端点:/.well-known/openid-configuration/.well-known/oauth-authorization-server
警告
在 OAuth 连接握手期间,签发者拥有极高的权限。经验法则是:如果你不会信任某个 URL 的运营者来处理你对服务器的访问,或者不会信任其直接冒充你,那么这个 URL 就不应被信任为
oauth_issuer。oauth_client_id#由授权服务器发放的 OAuth 2.0 客户端标识符。如果 PostgreSQL 服务器为该连接请求 OAuth 令牌,并且没有安装自定义 OAuth 钩子来提供该令牌,那么就必须设置此参数;否则连接会失败。
oauth_client_secret#与 OAuth 授权服务器通信时要使用的客户端密码(如果有)。该参数是否必需由 OAuth 提供者决定;公开客户端(public client)通常不使用密钥,而机密客户端(confidential client)通常会使用。
oauth_scope#发送给授权服务器的访问请求的授权范围,以空格分隔的 OAuth 授权范围标识符列表指定(列表可以为空)。该参数是可选的,面向高级用法。
通常客户端会从 PostgreSQL 服务器获得合适的授权范围设置。如果使用这个参数,服务器请求的授权范围列表会被忽略。这可以防止不那么受信任的服务器向最终用户请求不恰当的访问授权范围。不过,如果客户端的授权范围设置不包含服务器所要求的授权范围,服务器很可能会拒绝已经签发的令牌,连接也会失败。
空授权范围列表的含义取决于提供者。OAuth 授权服务器可以选择签发带有“默认授权范围”的令牌,不管那具体是什么;也可以完全拒绝该令牌请求。
oauth_ca_file#包含一个或多个 SSL 证书颁发机构(CA)证书的文件名,用于验证授权服务器及其端点的身份。默认使用 Curl 的系统证书包。
该参数不会影响对 PostgreSQL 服务器证书的验证;参见 sslrootcert。