↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0
预发布版本文档。 PostgreSQL 19beta4 为测试版本,最终发布内容可能有所不同。

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 获取错误信息。

取消请求成功分派并不保证一定会产生效果。如果取消成功,被取消的命令会提前终止并返回一个错误结果;如果取消失败(例如服务器已经处理完该命令),则不会有任何可见结果。

PQcancelStart
PQcancelPoll #

以非阻塞方式请求服务器放弃处理当前命令。

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 中的错误消息,从而破坏当前连接上正在进行的操作。

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.