大约 7 分钟
34.11. 杂项函数
一如往常,总有一些函数不适合放在任何其他地方。
PQfreemem : 释放libpq分配的内存。
```synopsis
void PQfreemem(void *ptr);
```
释放libpq分配的内存,尤其是`PQescapeByteaConn`、`PQescapeBytea`、`PQunescapeBytea`和`PQnotifies`分配的内存。特别重要的是,在微软 Windows 上使用这个函数,而不是`free()`。这是因为只有 DLL 和应用的当多线程/单线程、发布/调试以及静态/动态标志相同时,才能在一个 DLL 中分配内存并且在应用中释放它。在非微软 Windows 平台上,这个函数与标准库函数`free()`相同。
PQconninfoFree : 释放PQconndefaults或PQconninfoParse分配的数据结构。
```synopsis
void PQconninfoFree(PQconninfoOption *connOptions);
```
一个简单的`PQfreemem`不会做这些,因为数组包含对子字符串的引用。
PQencryptPasswordConn : 准备一个PostgreSQL口令的加密形式。
```synopsis
char *PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, const char *algorithm);
```
这个函数旨在用于那些希望发送类似于`ALTER USER joe PASSWORD 'pwd'`命令的客户端应用。不在这样一个命令中发送原始的明文密码是一个好习惯,因为它可能被暴露在命令日志、活动显示等等中。相反,在发送之前使用这个函数可以将口令转换为加密的形式。
**`passwd`**和**`user`**参数是明文口令以及用户的SQL名称。**`algorithm`**指定用来加密口令的加密算法。当前支持的算法是`md5`和`scram-sha-256`(`on`和`off`也被接受作为`md5`的别名,用于与较老的服务器版本兼容)。注意,对`scram-sha-256`支持是在PostgreSQL版本10中引入的,并且在老的服务器版本上无法工作。如果**`algorithm`**是`NULL`,这个函数将向服务器查询[password_encryption](runtime-config-connection.md#GUC-PASSWORD-ENCRYPTION)设置的当前值。这种行为可能会阻塞当前事务,并且当前事务被中止或者连接正忙于执行另一个查询时会失败。如果希望为服务器使用默认的算法但避免阻塞,应在调用`PQencryptPasswordConn`之前查询你自己的`password_encryption`,并且将该值作为**`algorithm`**传入。
返回值是一个由`malloc`分配的字符串。调用者可以假设该字符串不含有需要转义的任何特殊字符。在处理完它之后,用`PQfreemem`释放结果。发生错误时,返回的是`NULL`,并且适当的消息会被存储在连接对象中。
PQencryptPassword : 准备一个PostgreSQL口令的md5加密形式。
```synopsis
char *PQencryptPassword(const char *passwd, const char *user);
```
`PQencryptPassword`是`PQencryptPasswodConn`的一个较老的已经被废弃的版本。其差别是`PQencryptPassword`不要求一个连接对象,并且总是用`md5`作为加密算法。
PQmakeEmptyPGresult : 用给定的状态,构造一个空PGresult对象。
```synopsis
PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
```
这是libpq内部用于分配并初始化一个空`PGresult`对象的函数。如果不能分配内存,那么这个函数返回`NULL`。它也是可以对外使用的,因为一些应用认为它可以用于产生结果对象(特别是带有错误状态的对象)本身。如果**`conn`**非空,并且**`status`**表示一个错误,那么指定连接的当前错误消息会被复制到`PGresult`中。如果**`conn`**非空,那么连接中的任何已注册事件过程也会被复制到`PGresult`中(它们不会获得`PGEVT_RESULTCREATE`调用,但会看到`PQfireResultCreateEvents`)。注意在该对象上最终应该调用`PQclear`,正如对libpq本身返回的`PGresult`对象所作的那样。
PQfireResultCreateEvents : 为每一个在PGresult对象中注册的事件过程触发一个PGEVT_RESULTCREATE事件(见第 34.13 节)。成功时返回非 0,如果任何事件过程失败则返回 0。
```synopsis
int PQfireResultCreateEvents(PGconn *conn, PGresult *res);
```
`conn`参数被传送给事件过程,但不会被直接使用。如果事件过程不使用它,则会返回`NULL`。
已经接收到这个对象的`PGEVT_RESULTCREATE`或`PGEVT_RESULTCOPY`事件的事件过程不会被再次触发。
这个函数与`PQmakeEmptyPGresult`分开的主要原因是在调用事件过程之前创建一个`PGresult`并且填充它常常是合适的。
PQcopyResult : 为一个PGresult对象创建一个拷贝。这个拷贝不会以任何方式链接到源结果,并且当该拷贝不再需要时,必须调用PQclear进行清理。如果函数失败,返回NULL。
```synopsis
PGresult *PQcopyResult(const PGresult *src, int flags);
```
这个函数的意图并非是制作一个准确的拷贝。返回的结果总是会被放入`PGRES_TUPLES_OK`状态,并且不会拷贝来源中的任何错误消息(不过它确实会拷贝命令状态字符串)。**`flags`**参数决定还要拷贝些什么。它通常是几个标志的按位 OR。`PG_COPYRES_ATTRS`指定复制源结果的属性(列定义)。`PG_COPYRES_TUPLES`指定复制源结果的元组(这也意味着复制属性)。`PG_COPYRES_NOTICEHOOKS`指定复制源结果的提醒钩子。`PG_COPYRES_EVENTS`指定复制源结果的事件(但是不会复制与源结果相关的实例数据)。
PQsetResultAttrs : 设置PGresult对象的属性。
```synopsis
int PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs);
```
提供的**`attDescs`**被复制到结果中。如果**`attDescs`**指针为`NULL`或**`numAttributes`**小于1,那么请求将被忽略并且函数成功。如果**`res`**已经包含属性,那么函数会失败。如果函数失败,返回值是 0。如果函数成功,返回值是非 0。
PQsetvalue : 设置一个PGresult对象的一个元组域值。
```synopsis
int PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len);
```
这个函数将自动按需增加结果的内置元组数组。但是,**`tup_num`**参数必须小于等于`PQntuples`,意味着这个函数对元组数组一次只能增加一个元组。但已存在的任意元组中的任意域可以以任意顺序进行调整。如果**`field_num`**的一个值已经存在,它会被覆盖。如果**`len`**是 -1,或**`value`**是`NULL`, 该域值会被设置为一个 SQL 空值。**`value`**会被复制到结果的私有存储中,因此函数返回后就不再需要了。如果函数失败,返回值是 0。如果函数成功,返回值会是非 0。
PQresultAlloc : 为一个PGresult对象分配附属存储。
```synopsis
void *PQresultAlloc(PGresult *res, size_t nBytes);
```
当**`res`**被清除时,这个函数分配的内存也会被释放掉。如果函数失败,返回值是`NULL`。结果被保证为按照数据的任意类型充分地对齐,正如`malloc`所作的。
PQlibVersion : 返回所使用的libpq版本。
```synopsis
int PQlibVersion(void);
```
在运行时,这个函数的结果可以被用来决定在当前已载入的 libpq 版本中特定的功能是否可用。例如,这个函数可以被用来决定哪些选项可以被用于`PQconnectdb`。
结果通过将库的主版本号乘以10000再加上次版本号形成。例如,版本10.1将被返回为100001,而版本11.0将被返回为110000。
在主版本10之前,PostgreSQL采用一种由三个部分组成的版本号,其中前两部分共同表示主版本。对于那些版本,`PQlibVersion`为每个部分使用两个数字,例如版本9.1.5将被返回为90105,而版本9.2.0将被返回为90200。
因此,出于判断特性兼容性的目的,应用应该将`PQlibVersion`的结果除以100而不是10000来判断逻辑的主版本号。在所有的发行序列中,只有最后两个数字在次发行(问题修正发行)之间不同。
### 注意
这个函数出现于PostgreSQL版本 9.1,因此它不能被用来在早期的版本中检测所需的功能,因为调用它将会创建一个对版本9.1及其后版本的链接依赖。
