32.7. 取消进行中的查询 #
32.7.1. 发送取消请求的函数 #
PQcancelCreate#准备用于发送取消请求的连接。
PGcancelConn *PQcancelCreate(PGconn *conn);
PQcancelCreate创建一个PGcancelConn对象,但不会立即通过这条连接发送取消请求。可以使用PQcancelBlocking以阻塞方式发送取消请求,或者使用PQcancelStart以非阻塞方式发送。返回值可以传给PQcancelStatus,以检查该PGcancelConn对象是否成功创建。PGcancelConn是不透明结构体,不应由应用程序直接访问。这个PGcancelConn对象可用于以线程安全的方式取消原始连接上正在执行的查询。在为取消请求建立连接时,会重用原始客户端连接的许多连接参数。特别是,如果原始连接要求对连接进行加密和/或验证目标主机(通过
sslmode或gssencmode),则取消请求连接也会使用同样的要求。不过,仅在客户端认证期间或认证后才会用到的连接选项会被忽略,因为取消请求不需要认证,并且提交取消请求后该连接就会立即关闭。请注意,当
PQcancelCreate返回非空指针时,你必须在使用完毕后调用PQcancelFinish,以释放该结构体及其关联内存块。即使取消请求失败或被放弃,也必须这样做。PQcancelBlocking#以阻塞方式请求服务器放弃处理当前命令。
int PQcancelBlocking(PGcancelConn *cancelConn);
请求通过给定的
PGcancelConn发送,该对象必须由PQcancelCreate创建。PQcancelBlocking成功分派取消请求时返回 1,否则返回 0。若失败,可通过PQcancelErrorMessage获取错误信息。取消请求成功分派并不保证一定会产生效果。如果取消成功,被取消的命令会提前终止并返回一个错误结果;如果取消失败(例如服务器已经处理完该命令),则不会有任何可见结果。
PQcancelStartPQcancelPoll#以非阻塞方式请求服务器放弃处理当前命令。
int PQcancelStart(PGcancelConn *cancelConn); PostgresPollingStatusType PQcancelPoll(PGcancelConn *cancelConn);
请求通过给定的
PGcancelConn发送,该对象必须由PQcancelCreate创建。PQcancelStart能够启动取消请求时返回 1,否则返回 0。若失败,可通过PQcancelErrorMessage获取错误信息。如果
PQcancelStart成功,下一阶段就是轮询 libpq,使其继续进行取消连接的建立过程。使用PQcancelSocket获取数据库连接底层套接字的描述符。(注意:不要假定该套接字在多次调用PQcancelPoll之间保持不变。)循环规则如下:如果PQcancelPoll(cancelConn)上一次返回PGRES_POLLING_READING,就等待该套接字准备好可读(由select()、poll()或类似系统函数指示),然后再次调用PQcancelPoll(cancelConn)。反之,如果PQcancelPoll(cancelConn)上一次返回PGRES_POLLING_WRITING,就等待套接字准备好可写,然后再次调用PQcancelPoll(cancelConn)。第一次迭代时,也就是尚未调用过PQcancelPoll(cancelConn)时,按其上次返回PGRES_POLLING_WRITING来处理。持续这一循环,直到PQcancelPoll(cancelConn)返回PGRES_POLLING_FAILED,表示连接过程失败,或者返回PGRES_POLLING_OK,表示取消请求已成功分派。取消请求成功分派并不保证一定会产生效果。如果取消成功,被取消的命令会提前终止并返回一个错误结果;如果取消失败(例如服务器已经处理完该命令),则不会有任何可见结果。
在连接期间的任意时刻,都可以通过调用
PQcancelStatus检查取消连接的状态。如果返回CONNECTION_BAD,则取消过程失败;如果返回CONNECTION_OK,则取消请求已成功分派。这两种状态同样可以从前面描述的PQcancelPoll返回值中检测到。其他状态也可能仅在异步取消过程中出现,它们表示连接过程的当前阶段,并可能有助于向用户提供反馈。这些状态如下:CONNECTION_ALLOCATED#等待调用
PQcancelStart或PQcancelBlocking以真正打开套接字。这是刚调用PQcancelCreate或PQcancelReset之后的连接状态。此时尚未开始与服务器建立连接。要真正开始发送取消请求,请使用PQcancelStart或PQcancelBlocking。CONNECTION_STARTED#等待连接建立。
CONNECTION_MADE#连接正常,等待发送。
CONNECTION_AWAITING_RESPONSE#等待服务器响应。
CONNECTION_SSL_STARTUP#协商 SSL 加密。
CONNECTION_GSS_STARTUP#协商 GSS 加密。
请注意,尽管这些常量会继续保留(为了保持兼容性),应用程序也绝不应依赖它们按某个特定顺序出现,甚至不应依赖它们一定会出现,或者依赖状态值始终属于本节列出的取值之一。应用程序可以这样写:
switch(PQcancelStatus(conn)) { case CONNECTION_STARTED: feedback = "Connecting..."; break; case CONNECTION_MADE: feedback = "Connected to server..."; break; . . . default: feedback = "Connecting..."; }在使用
PQcancelPoll时,连接参数connect_timeout会被忽略;是否已经过去过长时间应由应用程序自行判断。除此之外,PQcancelStart后接PQcancelPoll循环,等效于PQcancelBlocking。PQcancelStatus#返回取消连接的状态。
ConnStatusType PQcancelStatus(const PGcancelConn *cancelConn);
该状态可以是多种取值之一。不过,在异步取消过程之外只能看到三种:
CONNECTION_ALLOCATED、CONNECTION_OK和CONNECTION_BAD。使用PQcancelCreate成功创建的PGcancelConn初始状态为CONNECTION_ALLOCATED。成功分派取消请求后状态为CONNECTION_OK;取消失败则表现为CONNECTION_BAD。处于 OK 状态时,会一直保持到调用PQcancelFinish或PQcancelReset。其他可能返回的状态代码,请参见
PQcancelStart条目。取消请求成功分派并不保证一定会产生效果。如果取消成功,被取消的命令会提前终止并返回一个错误结果;如果取消失败(例如服务器已经处理完该命令),则不会有任何可见结果。
PQcancelSocket#获取到服务器的取消连接套接字的文件描述符编号。
int PQcancelSocket(const PGcancelConn *cancelConn);
有效描述符将大于等于 0;结果为 -1 表示当前没有打开到服务器的连接。对该
PGcancelConn调用本节中的任意函数(PQcancelErrorMessage和PQcancelSocket自身除外)都可能改变这一状态。-
PQcancelErrorMessage# 返回最近一次针对取消连接执行操作时生成的错误消息。
char *PQcancelErrorMessage(const PGcancelConn *cancelconn);
几乎所有接受
PGcancelConn参数的 libpq 函数在失败时都会为PQcancelErrorMessage设置消息。按照 libpq 的约定,非空的PQcancelErrorMessage结果可能包含多行,并带有结尾换行符。调用者不应直接释放该结果;当关联的PGcancelConn句柄传给PQcancelFinish时,它会被释放。也不应假定该结果字符串在多次对PGcancelConn结构体执行操作之间保持不变。PQcancelFinish#关闭取消连接(如果它尚未完成发送取消请求),同时释放
PGcancelConn对象使用的内存。void PQcancelFinish(PGcancelConn *cancelConn);
请注意,即使取消尝试失败(由
PQcancelStatus指示),应用程序也应调用PQcancelFinish来释放PGcancelConn对象使用的内存。在调用PQcancelFinish后,不得再次使用该PGcancelConn指针。PQcancelReset#重置
PGcancelConn,以便将其重新用于新的取消连接。void PQcancelReset(PGcancelConn *cancelConn);
如果
PGcancelConn当前正用于发送取消请求,则会关闭该连接。随后它会将PGcancelConn对象重新准备好,使其能够用于发送新的取消请求。这使得可以为一个
PGconn创建一个PGcancelConn,并在原始PGconn的整个生命周期中重复使用它。
32.7.2. 发送取消请求的过时函数 #
这些函数使用较旧的方式发送取消请求。即使原始连接通过 sslmode 或 gssencmode 要求加密,它们也不会加密取消请求,因此虽然仍可使用,却已被弃用。强烈不建议在新代码中使用这些旧方法,也建议将现有代码改为使用新函数。
PQgetCancel#创建一个数据结构,其中包含使用
PQcancel取消命令所需的信息。PGcancel *PQgetCancel(PGconn *conn);
PQgetCancel基于一个PGconn连接对象创建PGcancel对象。如果给定的conn为NULL或无效连接,则返回NULL。PGcancel是不透明结构体,不应由应用程序直接访问;它只能传给PQcancel或PQfreeCancel。PQfreeCancel#释放由
PQgetCancel创建的数据结构。void PQfreeCancel(PGcancel *cancel);
PQfreeCancel释放先前由PQgetCancel创建的数据对象。PQcancel#PQcancel是PQcancelBlocking的一个已弃用且不安全的变体,但可以在信号处理程序中安全调用。int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize);
PQcancel仅因向后兼容而保留,应改用PQcancelBlocking。PQcancel唯一的优势在于:当errbuf是信号处理程序中的局部变量时,可以在信号处理程序中安全调用它。不过,通常认为这一优势不足以抵消该函数的安全问题。对于
PQcancel而言,PGcancel对象是只读的,因此也可以从与操作PGconn对象的线程不同的线程中调用它。PQcancel的返回值为 1 表示取消请求成功发送,为 0 表示未成功发送。如果未成功发送,errbuf将填充解释性错误消息。errbuf必须是大小为errbufsize的字符数组(推荐大小为 256 字节)。
PQrequestCancel#PQrequestCancel是PQcancelBlocking的一个已弃用且不安全的变体。int PQrequestCancel(PGconn *conn);
PQrequestCancel仅因向后兼容而保留,应改用PQcancelBlocking。与PQcancelBlocking相比,使用PQrequestCancel没有任何优势。请求服务器放弃当前命令的处理。它直接作用于
PGconn对象,失败时会把错误消息存储到PGconn对象中(可通过PQerrorMessage获取)。虽然功能相同,但这种方法在多线程程序或信号处理程序中并不安全,因为它可能覆盖PGconn中的错误消息,从而破坏当前连接上正在进行的操作。
报告文档问题
阅读 上游文档. 通过 PostgreSQL 文档反馈表单.