Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit42b1480

Browse files
committed
libpq: Complain about missing BackendKeyData later with PGgetCancel()
PostgreSQL always sends the BackendKeyData message at connectionstartup, but there are some third party backend implementations outthere that don't support cancellation, and don't send the message[1]. While the protocol docs left it up for interpretation if that isvalid behavior, libpq in PostgreSQL 17 and below accepted it. It doesnot seem like the libpq behavior was intentional though, since it didso by sending CancelRequest messages with all zeros to such servers(instead of returning an error or making the cancel a no-op).In version 18 the behavior was changed to return an error when tryingto create the cancel object with PGgetCancel() or PGcancelCreate().This was done without any discussion, as part of supporting differentlengths of cancel packets for the new 3.2 version of the protocol.This commit changes the behavior of PGgetCancel() / PGcancel() oncemore to only return an error when the cancel object is actually usedto send a cancellation, instead of when merely creating the object.The reason to do so is that some clients [2] create a cancel object aspart of their connection creation logic (thus having the cancel objectready for later when they need it), so if creating the cancel objectreturns an error, the whole connection attempt fails. By delaying theerror, such clients will still be able to connect to the third partybackend implementations in question, but when actually trying tocancel a query, the user will be notified that that is not possiblefor the server that they are connected to.This commit only changes the behavior of the older PGgetCancel() /PQcancel() functions, not the more modern PQcancelCreate() family offunctions. I.e. PQcancelCreate() returns a failed connection object(CONNECTION_BAD) if the server didn't send a cancellation key. Unlikethe old PQgetCancel() function, we're not aware of any clients in thefield that use PQcancelCreate() during connection startup in a waythat would prevent connecting to such servers.[1] AWS RDS Proxy is definitely one of them, and CockroachDB might beanother.[2] psycopg2 (but not psycopg3).Author: Jelte Fennema-Nio <postgres@jeltef.nl>Reviewed-by: Jacob Champion <jacob.champion@enterprisedb.com>Backpatch-through: 18Discussion:https://www.postgresql.org/message-id/20250617.101056.1437027795118961504.ishii%40postgresql.org
1 parentd9f01a2 commit42b1480

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

‎doc/src/sgml/protocol.sgml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,11 @@
537537
The frontend should not respond to this message, but should
538538
continue listening for a ReadyForQuery message.
539539
</para>
540+
<para>
541+
The <productname>PostgreSQL</productname> server will always send this
542+
message, but some third party backend implementations of the protocol
543+
that don't support query cancellation are known not to.
544+
</para>
540545
</listitem>
541546
</varlistentry>
542547

‎src/interfaces/libpq/fe-cancel.c‎

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,24 @@ PQgetCancel(PGconn *conn)
379379

380380
/* Check that we have received a cancellation key */
381381
if (conn->be_cancel_key_len==0)
382-
returnNULL;
382+
{
383+
/*
384+
* In case there is no cancel key, return an all-zero PGcancel object.
385+
* Actually calling PQcancel on this will fail, but we allow creating
386+
* the PGcancel object anyway. Arguably it would be better return NULL
387+
* to indicate that cancellation is not possible, but there'd be no
388+
* way for the caller to distinguish "out of memory" from "server did
389+
* not send a cancel key". Also, this is how PGgetCancel() has always
390+
* behaved, and if we changed it, some clients would stop working
391+
* altogether with servers that don't support cancellation. (The
392+
* modern PQcancelCreate() function returns a failed connection object
393+
* instead.)
394+
*
395+
* The returned dummy object has cancel_pkt_len == 0; we check for
396+
* that in PQcancel() to identify it as a dummy.
397+
*/
398+
returncalloc(1,sizeof(PGcancel));
399+
}
383400

384401
cancel_req_len= offsetof(CancelRequestPacket,cancelAuthCode)+conn->be_cancel_key_len;
385402
cancel=malloc(offsetof(PGcancel,cancel_req)+cancel_req_len);
@@ -544,6 +561,15 @@ PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
544561
return false;
545562
}
546563

564+
if (cancel->cancel_pkt_len==0)
565+
{
566+
/* This is a dummy PGcancel object, see PQgetCancel */
567+
strlcpy(errbuf,"PQcancel() -- no cancellation key received",errbufsize);
568+
/* strlcpy probably doesn't change errno, but be paranoid */
569+
SOCK_ERRNO_SET(save_errno);
570+
return false;
571+
}
572+
547573
/*
548574
* We need to open a temporary connection to the postmaster. Do this with
549575
* only kernel calls.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp