PostgreSQL Source Code: src/interfaces/libpq/fe-cancel.c Source File

PostgreSQL Source Code git master
fe-cancel.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * fe-cancel.c
4 * functions related to query cancellation
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/interfaces/libpq/fe-cancel.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16#include "postgres_fe.h"
17
18#include <unistd.h>
19
20#include "libpq-fe.h"
21#include "libpq-int.h"
22#include "port/pg_bswap.h"
23
24
25/*
26 * pg_cancel_conn (backing struct for PGcancelConn) is a wrapper around a
27 * PGconn to send cancellations using PQcancelBlocking and PQcancelStart.
28 * This isn't just a typedef because we want the compiler to complain when a
29 * PGconn is passed to a function that expects a PGcancelConn, and vice versa.
30 */
31 struct pg_cancel_conn
32{
33 PGconn conn;
34};
35
36/*
37 * pg_cancel (backing struct for PGcancel) stores all data necessary to send a
38 * cancel request.
39 */
40 struct pg_cancel
41{
42 SockAddr raddr; /* Remote address */
43 int be_pid; /* PID of to-be-canceled backend */
44 int pgtcp_user_timeout; /* tcp user timeout */
45 int keepalives; /* use TCP keepalives? */
46 int keepalives_idle; /* time between TCP keepalives */
47 int keepalives_interval; /* time between TCP keepalive
48 * retransmits */
49 int keepalives_count; /* maximum number of TCP keepalive
50 * retransmits */
51
52 /* Pre-constructed cancel request packet starts here */
53 int32 cancel_pkt_len; /* in network byte order */
54 char cancel_req[FLEXIBLE_ARRAY_MEMBER]; /* CancelRequestPacket */
55};
56
57
58/*
59 * PQcancelCreate
60 *
61 * Create and return a PGcancelConn, which can be used to securely cancel a
62 * query on the given connection.
63 *
64 * This requires either following the non-blocking flow through
65 * PQcancelStart() and PQcancelPoll(), or the blocking PQcancelBlocking().
66 */
67PGcancelConn *
68 PQcancelCreate(PGconn *conn)
69{
70 PGconn *cancelConn = pqMakeEmptyPGconn();
71 pg_conn_host originalHost;
72
73 if (cancelConn == NULL)
74 return NULL;
75
76 /* Check we have an open connection */
77 if (!conn)
78 {
79 libpq_append_conn_error(cancelConn, "connection pointer is NULL");
80 return (PGcancelConn *) cancelConn;
81 }
82
83 if (conn->sock == PGINVALID_SOCKET)
84 {
85 libpq_append_conn_error(cancelConn, "connection not open");
86 return (PGcancelConn *) cancelConn;
87 }
88
89 /* Check that we have received a cancellation key */
90 if (conn->be_cancel_key_len == 0)
91 {
92 libpq_append_conn_error(cancelConn, "no cancellation key received");
93 return (PGcancelConn *) cancelConn;
94 }
95
96 /*
97 * Indicate that this connection is used to send a cancellation
98 */
99 cancelConn->cancelRequest = true;
100
101 if (!pqCopyPGconn(conn, cancelConn))
102 return (PGcancelConn *) cancelConn;
103
104 /*
105 * Compute derived options
106 */
107 if (!pqConnectOptions2(cancelConn))
108 return (PGcancelConn *) cancelConn;
109
110 /*
111 * Copy cancellation token data from the original connection
112 */
113 cancelConn->be_pid = conn->be_pid;
114 if (conn->be_cancel_key != NULL)
115 {
116 cancelConn->be_cancel_key = malloc(conn->be_cancel_key_len);
117 if (cancelConn->be_cancel_key == NULL)
118 goto oom_error;
119 memcpy(cancelConn->be_cancel_key, conn->be_cancel_key, conn->be_cancel_key_len);
120 }
121 cancelConn->be_cancel_key_len = conn->be_cancel_key_len;
122 cancelConn->pversion = conn->pversion;
123
124 /*
125 * Cancel requests should not iterate over all possible hosts. The request
126 * needs to be sent to the exact host and address that the original
127 * connection used. So we manually create the host and address arrays with
128 * a single element after freeing the host array that we generated from
129 * the connection options.
130 */
131 pqReleaseConnHosts(cancelConn);
132 cancelConn->nconnhost = 1;
133 cancelConn->naddr = 1;
134
135 cancelConn->connhost = calloc(cancelConn->nconnhost, sizeof(pg_conn_host));
136 if (!cancelConn->connhost)
137 goto oom_error;
138
139 originalHost = conn->connhost[conn->whichhost];
140 cancelConn->connhost[0].type = originalHost.type;
141 if (originalHost.host)
142 {
143 cancelConn->connhost[0].host = strdup(originalHost.host);
144 if (!cancelConn->connhost[0].host)
145 goto oom_error;
146 }
147 if (originalHost.hostaddr)
148 {
149 cancelConn->connhost[0].hostaddr = strdup(originalHost.hostaddr);
150 if (!cancelConn->connhost[0].hostaddr)
151 goto oom_error;
152 }
153 if (originalHost.port)
154 {
155 cancelConn->connhost[0].port = strdup(originalHost.port);
156 if (!cancelConn->connhost[0].port)
157 goto oom_error;
158 }
159 if (originalHost.password)
160 {
161 cancelConn->connhost[0].password = strdup(originalHost.password);
162 if (!cancelConn->connhost[0].password)
163 goto oom_error;
164 }
165
166 cancelConn->addr = calloc(cancelConn->naddr, sizeof(AddrInfo));
167 if (!cancelConn->addr)
168 goto oom_error;
169
170 cancelConn->addr[0].addr = conn->raddr;
171 cancelConn->addr[0].family = conn->raddr.addr.ss_family;
172
173 cancelConn->status = CONNECTION_ALLOCATED;
174 return (PGcancelConn *) cancelConn;
175
176oom_error:
177 cancelConn->status = CONNECTION_BAD;
178 libpq_append_conn_error(cancelConn, "out of memory");
179 return (PGcancelConn *) cancelConn;
180}
181
182
183/*
184 * PQcancelBlocking
185 *
186 * Send a cancellation request in a blocking fashion.
187 * Returns 1 if successful 0 if not.
188 */
189int
190 PQcancelBlocking(PGcancelConn *cancelConn)
191{
192 if (!PQcancelStart(cancelConn))
193 return 0;
194 return pqConnectDBComplete(&cancelConn->conn);
195}
196
197/*
198 * PQcancelStart
199 *
200 * Starts sending a cancellation request in a non-blocking fashion. Returns
201 * 1 if successful 0 if not.
202 */
203int
204 PQcancelStart(PGcancelConn *cancelConn)
205{
206 if (!cancelConn || cancelConn->conn.status == CONNECTION_BAD)
207 return 0;
208
209 if (cancelConn->conn.status != CONNECTION_ALLOCATED)
210 {
211 libpq_append_conn_error(&cancelConn->conn,
212 "cancel request is already being sent on this connection");
213 cancelConn->conn.status = CONNECTION_BAD;
214 return 0;
215 }
216
217 return pqConnectDBStart(&cancelConn->conn);
218}
219
220/*
221 * PQcancelPoll
222 *
223 * Poll a cancel connection. For usage details see PQconnectPoll.
224 */
225PostgresPollingStatusType
226 PQcancelPoll(PGcancelConn *cancelConn)
227{
228 PGconn *conn = &cancelConn->conn;
229 int n;
230
231 /*
232 * We leave most of the connection establishment to PQconnectPoll, since
233 * it's very similar to normal connection establishment. But once we get
234 * to the CONNECTION_AWAITING_RESPONSE we need to start doing our own
235 * thing.
236 */
237 if (conn->status != CONNECTION_AWAITING_RESPONSE)
238 {
239 return PQconnectPoll(conn);
240 }
241
242 /*
243 * At this point we are waiting on the server to close the connection,
244 * which is its way of communicating that the cancel has been handled.
245 */
246
247 n = pqReadData(conn);
248
249 if (n == 0)
250 return PGRES_POLLING_READING;
251
252#ifndef WIN32
253
254 /*
255 * If we receive an error report it, but only if errno is non-zero.
256 * Otherwise we assume it's an EOF, which is what we expect from the
257 * server.
258 *
259 * We skip this for Windows, because Windows is a bit special in its EOF
260 * behaviour for TCP. Sometimes it will error with an ECONNRESET when
261 * there is a clean connection closure. See these threads for details:
262 * https://www.postgresql.org/message-id/flat/90b34057-4176-7bb0-0dbb-9822a5f6425b%40greiz-reinsdorf.de
263 *
264 * https://www.postgresql.org/message-id/flat/CA%2BhUKG%2BOeoETZQ%3DQw5Ub5h3tmwQhBmDA%3DnuNO3KG%3DzWfUypFAw%40mail.gmail.com
265 *
266 * PQcancel ignores such errors and reports success for the cancellation
267 * anyway, so even if this is not always correct we do the same here.
268 */
269 if (n < 0 && errno != 0)
270 {
271 conn->status = CONNECTION_BAD;
272 return PGRES_POLLING_FAILED;
273 }
274#endif
275
276 /*
277 * We don't expect any data, only connection closure. So if we strangely
278 * do receive some data we consider that an error.
279 */
280 if (n > 0)
281 {
282 libpq_append_conn_error(conn, "unexpected response from server");
283 conn->status = CONNECTION_BAD;
284 return PGRES_POLLING_FAILED;
285 }
286
287 /*
288 * Getting here means that we received an EOF, which is what we were
289 * expecting -- the cancel request has completed.
290 */
291 cancelConn->conn.status = CONNECTION_OK;
292 resetPQExpBuffer(&conn->errorMessage);
293 return PGRES_POLLING_OK;
294}
295
296/*
297 * PQcancelStatus
298 *
299 * Get the status of a cancel connection.
300 */
301ConnStatusType
302 PQcancelStatus(const PGcancelConn *cancelConn)
303{
304 return PQstatus(&cancelConn->conn);
305}
306
307/*
308 * PQcancelSocket
309 *
310 * Get the socket of the cancel connection.
311 */
312int
313 PQcancelSocket(const PGcancelConn *cancelConn)
314{
315 return PQsocket(&cancelConn->conn);
316}
317
318/*
319 * PQcancelErrorMessage
320 *
321 * Returns the error message most recently generated by an operation on the
322 * cancel connection.
323 */
324char *
325 PQcancelErrorMessage(const PGcancelConn *cancelConn)
326{
327 return PQerrorMessage(&cancelConn->conn);
328}
329
330/*
331 * PQcancelReset
332 *
333 * Resets the cancel connection, so it can be reused to send a new cancel
334 * request.
335 */
336void
337 PQcancelReset(PGcancelConn *cancelConn)
338{
339 pqClosePGconn(&cancelConn->conn);
340 cancelConn->conn.status = CONNECTION_ALLOCATED;
341 cancelConn->conn.whichhost = 0;
342 cancelConn->conn.whichaddr = 0;
343 cancelConn->conn.try_next_host = false;
344 cancelConn->conn.try_next_addr = false;
345}
346
347/*
348 * PQcancelFinish
349 *
350 * Closes and frees the cancel connection.
351 */
352void
353 PQcancelFinish(PGcancelConn *cancelConn)
354{
355 PQfinish(&cancelConn->conn);
356}
357
358/*
359 * PQgetCancel: get a PGcancel structure corresponding to a connection.
360 *
361 * A copy is needed to be able to cancel a running query from a different
362 * thread. If the same structure is used all structure members would have
363 * to be individually locked (if the entire structure was locked, it would
364 * be impossible to cancel a synchronous query because the structure would
365 * have to stay locked for the duration of the query).
366 */
367PGcancel *
368 PQgetCancel(PGconn *conn)
369{
370 PGcancel *cancel;
371 int cancel_req_len;
372 CancelRequestPacket *req;
373
374 if (!conn)
375 return NULL;
376
377 if (conn->sock == PGINVALID_SOCKET)
378 return NULL;
379
380 /* Check that we have received a cancellation key */
381 if (conn->be_cancel_key_len == 0)
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 return calloc(1, sizeof(PGcancel));
399 }
400
401 cancel_req_len = offsetof(CancelRequestPacket, cancelAuthCode) + conn->be_cancel_key_len;
402 cancel = malloc(offsetof(PGcancel, cancel_req) + cancel_req_len);
403 if (cancel == NULL)
404 return NULL;
405
406 memcpy(&cancel->raddr, &conn->raddr, sizeof(SockAddr));
407
408 /* We use -1 to indicate an unset connection option */
409 cancel->pgtcp_user_timeout = -1;
410 cancel->keepalives = -1;
411 cancel->keepalives_idle = -1;
412 cancel->keepalives_interval = -1;
413 cancel->keepalives_count = -1;
414 if (conn->pgtcp_user_timeout != NULL)
415 {
416 if (!pqParseIntParam(conn->pgtcp_user_timeout,
417 &cancel->pgtcp_user_timeout,
418 conn, "tcp_user_timeout"))
419 goto fail;
420 }
421 if (conn->keepalives != NULL)
422 {
423 if (!pqParseIntParam(conn->keepalives,
424 &cancel->keepalives,
425 conn, "keepalives"))
426 goto fail;
427 }
428 if (conn->keepalives_idle != NULL)
429 {
430 if (!pqParseIntParam(conn->keepalives_idle,
431 &cancel->keepalives_idle,
432 conn, "keepalives_idle"))
433 goto fail;
434 }
435 if (conn->keepalives_interval != NULL)
436 {
437 if (!pqParseIntParam(conn->keepalives_interval,
438 &cancel->keepalives_interval,
439 conn, "keepalives_interval"))
440 goto fail;
441 }
442 if (conn->keepalives_count != NULL)
443 {
444 if (!pqParseIntParam(conn->keepalives_count,
445 &cancel->keepalives_count,
446 conn, "keepalives_count"))
447 goto fail;
448 }
449
450 req = (CancelRequestPacket *) &cancel->cancel_req;
451 req->cancelRequestCode = (MsgType) pg_hton32(CANCEL_REQUEST_CODE);
452 req->backendPID = pg_hton32(conn->be_pid);
453 memcpy(req->cancelAuthCode, conn->be_cancel_key, conn->be_cancel_key_len);
454 /* include the length field itself in the length */
455 cancel->cancel_pkt_len = pg_hton32(cancel_req_len + 4);
456
457 return cancel;
458
459fail:
460 free(cancel);
461 return NULL;
462}
463
464/*
465 * PQsendCancelRequest
466 * Submit a CancelRequest message, but don't wait for it to finish
467 *
468 * Returns: 1 if successfully submitted
469 * 0 if error (conn->errorMessage is set)
470 */
471int
472 PQsendCancelRequest(PGconn *cancelConn)
473{
474 CancelRequestPacket req;
475
476 /* Start the message. */
477 if (pqPutMsgStart(0, cancelConn))
478 return STATUS_ERROR;
479
480 /* Send the message body. */
481 memset(&req, 0, offsetof(CancelRequestPacket, cancelAuthCode));
482 req.cancelRequestCode = (MsgType) pg_hton32(CANCEL_REQUEST_CODE);
483 req.backendPID = pg_hton32(cancelConn->be_pid);
484 if (pqPutnchar(&req, offsetof(CancelRequestPacket, cancelAuthCode), cancelConn))
485 return STATUS_ERROR;
486 if (pqPutnchar(cancelConn->be_cancel_key, cancelConn->be_cancel_key_len, cancelConn))
487 return STATUS_ERROR;
488
489 /* Finish the message. */
490 if (pqPutMsgEnd(cancelConn))
491 return STATUS_ERROR;
492
493 /* Flush to ensure backend gets it. */
494 if (pqFlush(cancelConn))
495 return STATUS_ERROR;
496
497 return STATUS_OK;
498}
499
500/* PQfreeCancel: free a cancel structure */
501void
502 PQfreeCancel(PGcancel *cancel)
503{
504 free(cancel);
505}
506
507
508/*
509 * Sets an integer socket option on a TCP socket, if the provided value is
510 * not negative. Returns false if setsockopt fails for some reason.
511 *
512 * CAUTION: This needs to be signal safe, since it's used by PQcancel.
513 */
514#if defined(TCP_USER_TIMEOUT) || !defined(WIN32)
515static bool
516 optional_setsockopt(int fd, int protoid, int optid, int value)
517{
518 if (value < 0)
519 return true;
520 if (setsockopt(fd, protoid, optid, (char *) &value, sizeof(value)) < 0)
521 return false;
522 return true;
523}
524#endif
525
526
527/*
528 * PQcancel: old, non-encrypted, but signal-safe way of requesting query cancel
529 *
530 * The return value is true if the cancel request was successfully
531 * dispatched, false if not (in which case an error message is available).
532 * Note: successful dispatch is no guarantee that there will be any effect at
533 * the backend. The application must read the operation result as usual.
534 *
535 * On failure, an error message is stored in *errbuf, which must be of size
536 * errbufsize (recommended size is 256 bytes). *errbuf is not changed on
537 * success return.
538 *
539 * CAUTION: we want this routine to be safely callable from a signal handler
540 * (for example, an application might want to call it in a SIGINT handler).
541 * This means we cannot use any C library routine that might be non-reentrant.
542 * malloc/free are often non-reentrant, and anything that might call them is
543 * just as dangerous. We avoid sprintf here for that reason. Building up
544 * error messages with strcpy/strcat is tedious but should be quite safe.
545 * We also save/restore errno in case the signal handler support doesn't.
546 */
547int
548 PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
549{
550 int save_errno = SOCK_ERRNO;
551 pgsocket tmpsock = PGINVALID_SOCKET;
552 int maxlen;
553 char recvbuf;
554 int cancel_pkt_len;
555
556 if (!cancel)
557 {
558 strlcpy(errbuf, "PQcancel() -- no cancel object supplied", errbufsize);
559 /* strlcpy probably doesn't change errno, but be paranoid */
560 SOCK_ERRNO_SET(save_errno);
561 return false;
562 }
563
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
573 /*
574 * We need to open a temporary connection to the postmaster. Do this with
575 * only kernel calls.
576 */
577 if ((tmpsock = socket(cancel->raddr.addr.ss_family, SOCK_STREAM, 0)) == PGINVALID_SOCKET)
578 {
579 strlcpy(errbuf, "PQcancel() -- socket() failed: ", errbufsize);
580 goto cancel_errReturn;
581 }
582
583 /*
584 * Since this connection will only be used to send a single packet of
585 * data, we don't need NODELAY. We also don't set the socket to
586 * nonblocking mode, because the API definition of PQcancel requires the
587 * cancel to be sent in a blocking way.
588 *
589 * We do set socket options related to keepalives and other TCP timeouts.
590 * This ensures that this function does not block indefinitely when
591 * reasonable keepalive and timeout settings have been provided.
592 */
593 if (cancel->raddr.addr.ss_family != AF_UNIX &&
594 cancel->keepalives != 0)
595 {
596#ifndef WIN32
597 if (!optional_setsockopt(tmpsock, SOL_SOCKET, SO_KEEPALIVE, 1))
598 {
599 strlcpy(errbuf, "PQcancel() -- setsockopt(SO_KEEPALIVE) failed: ", errbufsize);
600 goto cancel_errReturn;
601 }
602
603#ifdef PG_TCP_KEEPALIVE_IDLE
604 if (!optional_setsockopt(tmpsock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE,
605 cancel->keepalives_idle))
606 {
607 strlcpy(errbuf, "PQcancel() -- setsockopt(" PG_TCP_KEEPALIVE_IDLE_STR ") failed: ", errbufsize);
608 goto cancel_errReturn;
609 }
610#endif
611
612#ifdef TCP_KEEPINTVL
613 if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_KEEPINTVL,
614 cancel->keepalives_interval))
615 {
616 strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_KEEPINTVL) failed: ", errbufsize);
617 goto cancel_errReturn;
618 }
619#endif
620
621#ifdef TCP_KEEPCNT
622 if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_KEEPCNT,
623 cancel->keepalives_count))
624 {
625 strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_KEEPCNT) failed: ", errbufsize);
626 goto cancel_errReturn;
627 }
628#endif
629
630#else /* WIN32 */
631
632#ifdef SIO_KEEPALIVE_VALS
633 if (!pqSetKeepalivesWin32(tmpsock,
634 cancel->keepalives_idle,
635 cancel->keepalives_interval))
636 {
637 strlcpy(errbuf, "PQcancel() -- WSAIoctl(SIO_KEEPALIVE_VALS) failed: ", errbufsize);
638 goto cancel_errReturn;
639 }
640#endif /* SIO_KEEPALIVE_VALS */
641#endif /* WIN32 */
642
643 /* TCP_USER_TIMEOUT works the same way on Unix and Windows */
644#ifdef TCP_USER_TIMEOUT
645 if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_USER_TIMEOUT,
646 cancel->pgtcp_user_timeout))
647 {
648 strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_USER_TIMEOUT) failed: ", errbufsize);
649 goto cancel_errReturn;
650 }
651#endif
652 }
653
654retry3:
655 if (connect(tmpsock, (struct sockaddr *) &cancel->raddr.addr,
656 cancel->raddr.salen) < 0)
657 {
658 if (SOCK_ERRNO == EINTR)
659 /* Interrupted system call - we'll just try again */
660 goto retry3;
661 strlcpy(errbuf, "PQcancel() -- connect() failed: ", errbufsize);
662 goto cancel_errReturn;
663 }
664
665 cancel_pkt_len = pg_ntoh32(cancel->cancel_pkt_len);
666
667retry4:
668
669 /*
670 * Send the cancel request packet. It starts with the message length at
671 * cancel_pkt_len, followed by the actual packet.
672 */
673 if (send(tmpsock, (char *) &cancel->cancel_pkt_len, cancel_pkt_len, 0) != cancel_pkt_len)
674 {
675 if (SOCK_ERRNO == EINTR)
676 /* Interrupted system call - we'll just try again */
677 goto retry4;
678 strlcpy(errbuf, "PQcancel() -- send() failed: ", errbufsize);
679 goto cancel_errReturn;
680 }
681
682 /*
683 * Wait for the postmaster to close the connection, which indicates that
684 * it's processed the request. Without this delay, we might issue another
685 * command only to find that our cancel zaps that command instead of the
686 * one we thought we were canceling. Note we don't actually expect this
687 * read to obtain any data, we are just waiting for EOF to be signaled.
688 */
689retry5:
690 if (recv(tmpsock, &recvbuf, 1, 0) < 0)
691 {
692 if (SOCK_ERRNO == EINTR)
693 /* Interrupted system call - we'll just try again */
694 goto retry5;
695 /* we ignore other error conditions */
696 }
697
698 /* All done */
699 closesocket(tmpsock);
700 SOCK_ERRNO_SET(save_errno);
701 return true;
702
703cancel_errReturn:
704
705 /*
706 * Make sure we don't overflow the error buffer. Leave space for the \n at
707 * the end, and for the terminating zero.
708 */
709 maxlen = errbufsize - strlen(errbuf) - 2;
710 if (maxlen >= 0)
711 {
712 /*
713 * We can't invoke strerror here, since it's not signal-safe. Settle
714 * for printing the decimal value of errno. Even that has to be done
715 * the hard way.
716 */
717 int val = SOCK_ERRNO;
718 char buf[32];
719 char *bufp;
720
721 bufp = buf + sizeof(buf) - 1;
722 *bufp = '0円';
723 do
724 {
725 *(--bufp) = (val % 10) + '0';
726 val /= 10;
727 } while (val > 0);
728 bufp -= 6;
729 memcpy(bufp, "error ", 6);
730 strncat(errbuf, bufp, maxlen);
731 strcat(errbuf, "\n");
732 }
733 if (tmpsock != PGINVALID_SOCKET)
734 closesocket(tmpsock);
735 SOCK_ERRNO_SET(save_errno);
736 return false;
737}
738
739/*
740 * PQrequestCancel: old, not thread-safe function for requesting query cancel
741 *
742 * Returns true if able to send the cancel request, false if not.
743 *
744 * On failure, the error message is saved in conn->errorMessage; this means
745 * that this can't be used when there might be other active operations on
746 * the connection object.
747 *
748 * NOTE: error messages will be cut off at the current size of the
749 * error message buffer, since we dare not try to expand conn->errorMessage!
750 */
751int
752 PQrequestCancel(PGconn *conn)
753{
754 int r;
755 PGcancel *cancel;
756
757 /* Check we have an open connection */
758 if (!conn)
759 return false;
760
761 if (conn->sock == PGINVALID_SOCKET)
762 {
763 strlcpy(conn->errorMessage.data,
764 "PQrequestCancel() -- connection is not open\n",
765 conn->errorMessage.maxlen);
766 conn->errorMessage.len = strlen(conn->errorMessage.data);
767 conn->errorReported = 0;
768
769 return false;
770 }
771
772 cancel = PQgetCancel(conn);
773 if (cancel)
774 {
775 r = PQcancel(cancel, conn->errorMessage.data,
776 conn->errorMessage.maxlen);
777 PQfreeCancel(cancel);
778 }
779 else
780 {
781 strlcpy(conn->errorMessage.data, "out of memory",
782 conn->errorMessage.maxlen);
783 r = false;
784 }
785
786 if (!r)
787 {
788 conn->errorMessage.len = strlen(conn->errorMessage.data);
789 conn->errorReported = 0;
790 }
791
792 return r;
793}
#define STATUS_OK
Definition: c.h:1168
#define FLEXIBLE_ARRAY_MEMBER
Definition: c.h:470
int32_t int32
Definition: c.h:534
#define STATUS_ERROR
Definition: c.h:1169
static PGcancel *volatile cancelConn
Definition: cancel.c:43
PGcancel * PQgetCancel(PGconn *conn)
Definition: fe-cancel.c:368
void PQcancelReset(PGcancelConn *cancelConn)
Definition: fe-cancel.c:337
int PQsendCancelRequest(PGconn *cancelConn)
Definition: fe-cancel.c:472
PGcancelConn * PQcancelCreate(PGconn *conn)
Definition: fe-cancel.c:68
ConnStatusType PQcancelStatus(const PGcancelConn *cancelConn)
Definition: fe-cancel.c:302
static bool optional_setsockopt(int fd, int protoid, int optid, int value)
Definition: fe-cancel.c:516
int PQcancelBlocking(PGcancelConn *cancelConn)
Definition: fe-cancel.c:190
int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
Definition: fe-cancel.c:548
PostgresPollingStatusType PQcancelPoll(PGcancelConn *cancelConn)
Definition: fe-cancel.c:226
void PQcancelFinish(PGcancelConn *cancelConn)
Definition: fe-cancel.c:353
int PQrequestCancel(PGconn *conn)
Definition: fe-cancel.c:752
void PQfreeCancel(PGcancel *cancel)
Definition: fe-cancel.c:502
int PQcancelSocket(const PGcancelConn *cancelConn)
Definition: fe-cancel.c:313
char * PQcancelErrorMessage(const PGcancelConn *cancelConn)
Definition: fe-cancel.c:325
int PQcancelStart(PGcancelConn *cancelConn)
Definition: fe-cancel.c:204
bool pqConnectOptions2(PGconn *conn)
Definition: fe-connect.c:1250
void pqClosePGconn(PGconn *conn)
Definition: fe-connect.c:5258
PostgresPollingStatusType PQconnectPoll(PGconn *conn)
Definition: fe-connect.c:2911
bool pqParseIntParam(const char *value, int *result, PGconn *conn, const char *context)
Definition: fe-connect.c:8237
void pqReleaseConnHosts(PGconn *conn)
Definition: fe-connect.c:5141
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:7616
void PQfinish(PGconn *conn)
Definition: fe-connect.c:5305
PGconn * pqMakeEmptyPGconn(void)
Definition: fe-connect.c:4943
int pqConnectDBStart(PGconn *conn)
Definition: fe-connect.c:2707
bool pqCopyPGconn(PGconn *srcConn, PGconn *dstConn)
Definition: fe-connect.c:1035
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7679
int PQsocket(const PGconn *conn)
Definition: fe-connect.c:7705
int pqConnectDBComplete(PGconn *conn)
Definition: fe-connect.c:2785
int pqReadData(PGconn *conn)
Definition: fe-misc.c:606
int pqFlush(PGconn *conn)
Definition: fe-misc.c:994
int pqPutMsgStart(char msg_type, PGconn *conn)
Definition: fe-misc.c:473
int pqPutnchar(const void *s, size_t len, PGconn *conn)
Definition: fe-misc.c:202
int pqPutMsgEnd(PGconn *conn)
Definition: fe-misc.c:532
#define calloc(a, b)
Definition: header.h:55
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
static struct @169 value
long val
Definition: informix.c:689
ConnStatusType
Definition: libpq-fe.h:83
@ CONNECTION_AWAITING_RESPONSE
Definition: libpq-fe.h:94
@ CONNECTION_BAD
Definition: libpq-fe.h:85
@ CONNECTION_OK
Definition: libpq-fe.h:84
@ CONNECTION_ALLOCATED
Definition: libpq-fe.h:107
PostgresPollingStatusType
Definition: libpq-fe.h:114
@ PGRES_POLLING_OK
Definition: libpq-fe.h:118
@ PGRES_POLLING_READING
Definition: libpq-fe.h:116
@ PGRES_POLLING_FAILED
Definition: libpq-fe.h:115
#define SOCK_ERRNO
Definition: oauth-utils.c:164
#define SOCK_ERRNO_SET(e)
Definition: oauth-utils.c:165
void libpq_append_conn_error(PGconn *conn, const char *fmt,...)
Definition: oauth-utils.c:95
#define pg_ntoh32(x)
Definition: pg_bswap.h:125
#define pg_hton32(x)
Definition: pg_bswap.h:121
static char * buf
Definition: pg_test_fsync.c:72
int pgsocket
Definition: port.h:29
#define PGINVALID_SOCKET
Definition: port.h:31
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define closesocket
Definition: port.h:377
#define CANCEL_REQUEST_CODE
Definition: pqcomm.h:137
ProtocolVersion MsgType
Definition: pqcomm.h:101
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:146
static int fd(const char *x, int i)
Definition: preproc-init.c:105
PGconn * conn
Definition: streamutil.c:52
Definition: pqcomm.h:37
MsgType cancelRequestCode
Definition: pqcomm.h:142
uint32 backendPID
Definition: pqcomm.h:143
uint8 cancelAuthCode[FLEXIBLE_ARRAY_MEMBER]
Definition: pqcomm.h:144
size_t maxlen
Definition: pqexpbuffer.h:48
char * data
Definition: pqexpbuffer.h:46
size_t len
Definition: pqexpbuffer.h:47
Definition: pqcomm.h:31
struct sockaddr_storage addr
Definition: pqcomm.h:32
socklen_t salen
Definition: pqcomm.h:33
PGconn conn
Definition: fe-cancel.c:33
int pgtcp_user_timeout
Definition: fe-cancel.c:44
int32 cancel_pkt_len
Definition: fe-cancel.c:53
int keepalives_interval
Definition: fe-cancel.c:47
int keepalives_idle
Definition: fe-cancel.c:46
char cancel_req[FLEXIBLE_ARRAY_MEMBER]
Definition: fe-cancel.c:54
int keepalives_count
Definition: fe-cancel.c:49
SockAddr raddr
Definition: fe-cancel.c:42
int be_pid
Definition: fe-cancel.c:43
int keepalives
Definition: fe-cancel.c:45
char * host
Definition: libpq-int.h:358
char * password
Definition: libpq-int.h:362
char * port
Definition: libpq-int.h:360
char * hostaddr
Definition: libpq-int.h:359
pg_conn_host_type type
Definition: libpq-int.h:357
uint8 * be_cancel_key
Definition: libpq-int.h:554
pgsocket sock
Definition: libpq-int.h:499
ProtocolVersion pversion
Definition: libpq-int.h:503
int errorReported
Definition: libpq-int.h:675
int be_pid
Definition: libpq-int.h:552
char * keepalives_idle
Definition: libpq-int.h:401
char * keepalives
Definition: libpq-int.h:400
char * keepalives_interval
Definition: libpq-int.h:402
char * pgtcp_user_timeout
Definition: libpq-int.h:385
PQExpBufferData errorMessage
Definition: libpq-int.h:674
SockAddr raddr
Definition: libpq-int.h:502
int be_cancel_key_len
Definition: libpq-int.h:553
int whichhost
Definition: libpq-int.h:481
char * keepalives_count
Definition: libpq-int.h:404
pg_conn_host * connhost
Definition: libpq-int.h:482
ConnStatusType status
Definition: libpq-int.h:462
#define EINTR
Definition: win32_port.h:364
#define recv(s, buf, len, flags)
Definition: win32_port.h:504
#define send(s, buf, len, flags)
Definition: win32_port.h:505
#define socket(af, type, protocol)
Definition: win32_port.h:498
#define connect(s, name, namelen)
Definition: win32_port.h:502

AltStyle によって変換されたページ (->オリジナル) /