Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/contrib/btree_gin/sql/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 778 B image not shown  

Quelle  fe-cancel.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * fe-cancel.c
 *   functions related to query cancellation
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *   src/interfaces/libpq/fe-cancel.c
 *
 *-------------------------------------------------------------------------
 */


#include "postgres_fe.h"

#include <unistd.h>

#include "libpq-fe.h"
#include "libpq-int.h"
#include "port/pg_bswap.h"


/*
 * pg_cancel_conn (backing struct for PGcancelConn) is a wrapper around a
 * PGconn to send cancellations using PQcancelBlocking and PQcancelStart.
 * This isn't just a typedef because we want the compiler to complain when a
 * PGconn is passed to a function that expects a PGcancelConn, and vice versa.
 */

struct pg_cancel_conn
{
 PGconn  conn;
};

/*
 * pg_cancel (backing struct for PGcancel) stores all data necessary to send a
 * cancel request.
 */

struct pg_cancel
{
 SockAddr raddr;   /* Remote address */
 int   be_pid;   /* PID of to-be-canceled backend */
 int   pgtcp_user_timeout; /* tcp user timeout */
 int   keepalives;  /* use TCP keepalives? */
 int   keepalives_idle; /* time between TCP keepalives */
 int   keepalives_interval; /* time between TCP keepalive
 * retransmits */

 int   keepalives_count; /* maximum number of TCP keepalive
 * retransmits */


 /* Pre-constructed cancel request packet starts here */
 int32  cancel_pkt_len; /* in network byte order */
 char  cancel_req[FLEXIBLE_ARRAY_MEMBER]; /* CancelRequestPacket */
};


/*
 *  PQcancelCreate
 *
 * Create and return a PGcancelConn, which can be used to securely cancel a
 * query on the given connection.
 *
 * This requires either following the non-blocking flow through
 * PQcancelStart() and PQcancelPoll(), or the blocking PQcancelBlocking().
 */

PGcancelConn *
PQcancelCreate(PGconn *conn)
{
 PGconn    *cancelConn = pqMakeEmptyPGconn();
 pg_conn_host originalHost;

 if (cancelConn == NULL)
  return NULL;

 /* Check we have an open connection */
 if (!conn)
 {
  libpq_append_conn_error(cancelConn, "connection pointer is NULL");
  return (PGcancelConn *) cancelConn;
 }

 if (conn->sock == PGINVALID_SOCKET)
 {
  libpq_append_conn_error(cancelConn, "connection not open");
  return (PGcancelConn *) cancelConn;
 }

 /* Check that we have received a cancellation key */
 if (conn->be_cancel_key_len == 0)
 {
  libpq_append_conn_error(cancelConn, "no cancellation key received");
  return (PGcancelConn *) cancelConn;
 }

 /*
  * Indicate that this connection is used to send a cancellation
 */

 cancelConn->cancelRequest = true;

 if (!pqCopyPGconn(conn, cancelConn))
  return (PGcancelConn *) cancelConn;

 /*
  * Compute derived options
 */

 if (!pqConnectOptions2(cancelConn))
  return (PGcancelConn *) cancelConn;

 /*
  * Copy cancellation token data from the original connection
 */

 cancelConn->be_pid = conn->be_pid;
 if (conn->be_cancel_key != NULL)
 {
  cancelConn->be_cancel_key = malloc(conn->be_cancel_key_len);
  if (cancelConn->be_cancel_key == NULL)
   goto oom_error;
  memcpy(cancelConn->be_cancel_key, conn->be_cancel_key, conn->be_cancel_key_len);
 }
 cancelConn->be_cancel_key_len = conn->be_cancel_key_len;
 cancelConn->pversion = conn->pversion;

 /*
  * Cancel requests should not iterate over all possible hosts. The request
  * needs to be sent to the exact host and address that the original
  * connection used. So we manually create the host and address arrays with
  * a single element after freeing the host array that we generated from
  * the connection options.
 */

 pqReleaseConnHosts(cancelConn);
 cancelConn->nconnhost = 1;
 cancelConn->naddr = 1;

 cancelConn->connhost = calloc(cancelConn->nconnhost, sizeof(pg_conn_host));
 if (!cancelConn->connhost)
  goto oom_error;

 originalHost = conn->connhost[conn->whichhost];
 cancelConn->connhost[0].type = originalHost.type;
 if (originalHost.host)
 {
  cancelConn->connhost[0].host = strdup(originalHost.host);
  if (!cancelConn->connhost[0].host)
   goto oom_error;
 }
 if (originalHost.hostaddr)
 {
  cancelConn->connhost[0].hostaddr = strdup(originalHost.hostaddr);
  if (!cancelConn->connhost[0].hostaddr)
   goto oom_error;
 }
 if (originalHost.port)
 {
  cancelConn->connhost[0].port = strdup(originalHost.port);
  if (!cancelConn->connhost[0].port)
   goto oom_error;
 }
 if (originalHost.password)
 {
  cancelConn->connhost[0].password = strdup(originalHost.password);
  if (!cancelConn->connhost[0].password)
   goto oom_error;
 }

 cancelConn->addr = calloc(cancelConn->naddr, sizeof(AddrInfo));
 if (!cancelConn->addr)
  goto oom_error;

 cancelConn->addr[0].addr = conn->raddr;
 cancelConn->addr[0].family = conn->raddr.addr.ss_family;

 cancelConn->status = CONNECTION_ALLOCATED;
 return (PGcancelConn *) cancelConn;

oom_error:
 cancelConn->status = CONNECTION_BAD;
 libpq_append_conn_error(cancelConn, "out of memory");
 return (PGcancelConn *) cancelConn;
}


/*
 *  PQcancelBlocking
 *
 * Send a cancellation request in a blocking fashion.
 * Returns 1 if successful 0 if not.
 */

int
PQcancelBlocking(PGcancelConn *cancelConn)
{
 if (!PQcancelStart(cancelConn))
  return 0;
 return pqConnectDBComplete(&cancelConn->conn);
}

/*
 *  PQcancelStart
 *
 * Starts sending a cancellation request in a non-blocking fashion. Returns
 * 1 if successful 0 if not.
 */

int
PQcancelStart(PGcancelConn *cancelConn)
{
 if (!cancelConn || cancelConn->conn.status == CONNECTION_BAD)
  return 0;

 if (cancelConn->conn.status != CONNECTION_ALLOCATED)
 {
  libpq_append_conn_error(&cancelConn->conn,
        "cancel request is already being sent on this connection");
  cancelConn->conn.status = CONNECTION_BAD;
  return 0;
 }

 return pqConnectDBStart(&cancelConn->conn);
}

/*
 *  PQcancelPoll
 *
 * Poll a cancel connection. For usage details see PQconnectPoll.
 */

PostgresPollingStatusType
PQcancelPoll(PGcancelConn *cancelConn)
{
 PGconn    *conn = &cancelConn->conn;
 int   n;

 /*
  * We leave most of the connection establishment to PQconnectPoll, since
  * it's very similar to normal connection establishment. But once we get
  * to the CONNECTION_AWAITING_RESPONSE we need to start doing our own
  * thing.
 */

 if (conn->status != CONNECTION_AWAITING_RESPONSE)
 {
  return PQconnectPoll(conn);
 }

 /*
  * At this point we are waiting on the server to close the connection,
  * which is its way of communicating that the cancel has been handled.
 */


 n = pqReadData(conn);

 if (n == 0)
  return PGRES_POLLING_READING;

#ifndef WIN32

 /*
  * If we receive an error report it, but only if errno is non-zero.
  * Otherwise we assume it's an EOF, which is what we expect from the
  * server.
  *
  * We skip this for Windows, because Windows is a bit special in its EOF
  * behaviour for TCP. Sometimes it will error with an ECONNRESET when
  * there is a clean connection closure. See these threads for details:
  * https://www.postgresql.org/message-id/flat/90b34057-4176-7bb0-0dbb-9822a5f6425b%40greiz-reinsdorf.de
  *
  * https://www.postgresql.org/message-id/flat/CA%2BhUKG%2BOeoETZQ%3DQw5Ub5h3tmwQhBmDA%3DnuNO3KG%3DzWfUypFAw%40mail.gmail.com
  *
  * PQcancel ignores such errors and reports success for the cancellation
  * anyway, so even if this is not always correct we do the same here.
 */

 if (n < 0 && errno != 0)
 {
  conn->status = CONNECTION_BAD;
  return PGRES_POLLING_FAILED;
 }
#endif

 /*
  * We don't expect any data, only connection closure. So if we strangely
  * do receive some data we consider that an error.
 */

 if (n > 0)
 {
  libpq_append_conn_error(conn, "unexpected response from server");
  conn->status = CONNECTION_BAD;
  return PGRES_POLLING_FAILED;
 }

 /*
  * Getting here means that we received an EOF, which is what we were
  * expecting -- the cancel request has completed.
 */

 cancelConn->conn.status = CONNECTION_OK;
 resetPQExpBuffer(&conn->errorMessage);
 return PGRES_POLLING_OK;
}

/*
 *  PQcancelStatus
 *
 * Get the status of a cancel connection.
 */

ConnStatusType
PQcancelStatus(const PGcancelConn *cancelConn)
{
 return PQstatus(&cancelConn->conn);
}

/*
 *  PQcancelSocket
 *
 * Get the socket of the cancel connection.
 */

int
PQcancelSocket(const PGcancelConn *cancelConn)
{
 return PQsocket(&cancelConn->conn);
}

/*
 *  PQcancelErrorMessage
 *
 * Returns the error message most recently generated by an operation on the
 * cancel connection.
 */

char *
PQcancelErrorMessage(const PGcancelConn *cancelConn)
{
 return PQerrorMessage(&cancelConn->conn);
}

/*
 *  PQcancelReset
 *
 * Resets the cancel connection, so it can be reused to send a new cancel
 * request.
 */

void
PQcancelReset(PGcancelConn *cancelConn)
{
 pqClosePGconn(&cancelConn->conn);
 cancelConn->conn.status = CONNECTION_ALLOCATED;
 cancelConn->conn.whichhost = 0;
 cancelConn->conn.whichaddr = 0;
 cancelConn->conn.try_next_host = false;
 cancelConn->conn.try_next_addr = false;
}

/*
 *  PQcancelFinish
 *
 * Closes and frees the cancel connection.
 */

void
PQcancelFinish(PGcancelConn *cancelConn)
{
 PQfinish(&cancelConn->conn);
}

/*
 * PQgetCancel: get a PGcancel structure corresponding to a connection.
 *
 * A copy is needed to be able to cancel a running query from a different
 * thread. If the same structure is used all structure members would have
 * to be individually locked (if the entire structure was locked, it would
 * be impossible to cancel a synchronous query because the structure would
 * have to stay locked for the duration of the query).
 */

PGcancel *
PQgetCancel(PGconn *conn)
{
 PGcancel   *cancel;
 int   cancel_req_len;
 CancelRequestPacket *req;

 if (!conn)
  return NULL;

 if (conn->sock == PGINVALID_SOCKET)
  return NULL;

 /* Check that we have received a cancellation key */
 if (conn->be_cancel_key_len == 0)
 {
  /*
   * In case there is no cancel key, return an all-zero PGcancel object.
   * Actually calling PQcancel on this will fail, but we allow creating
   * the PGcancel object anyway. Arguably it would be better return NULL
   * to indicate that cancellation is not possible, but there'd be no
   * way for the caller to distinguish "out of memory" from "server did
   * not send a cancel key". Also, this is how PGgetCancel() has always
   * behaved, and if we changed it, some clients would stop working
   * altogether with servers that don't support cancellation. (The
   * modern PQcancelCreate() function returns a failed connection object
   * instead.)
   *
   * The returned dummy object has cancel_pkt_len == 0; we check for
   * that in PQcancel() to identify it as a dummy.
 */

  return calloc(1sizeof(PGcancel));
 }

 cancel_req_len = offsetof(CancelRequestPacket, cancelAuthCode) + conn->be_cancel_key_len;
 cancel = malloc(offsetof(PGcancel, cancel_req) + cancel_req_len);
 if (cancel == NULL)
  return NULL;

 memcpy(&cancel->raddr, &conn->raddr, sizeof(SockAddr));

 /* We use -1 to indicate an unset connection option */
 cancel->pgtcp_user_timeout = -1;
 cancel->keepalives = -1;
 cancel->keepalives_idle = -1;
 cancel->keepalives_interval = -1;
 cancel->keepalives_count = -1;
 if (conn->pgtcp_user_timeout != NULL)
 {
  if (!pqParseIntParam(conn->pgtcp_user_timeout,
        &cancel->pgtcp_user_timeout,
        conn, "tcp_user_timeout"))
   goto fail;
 }
 if (conn->keepalives != NULL)
 {
  if (!pqParseIntParam(conn->keepalives,
        &cancel->keepalives,
        conn, "keepalives"))
   goto fail;
 }
 if (conn->keepalives_idle != NULL)
 {
  if (!pqParseIntParam(conn->keepalives_idle,
        &cancel->keepalives_idle,
        conn, "keepalives_idle"))
   goto fail;
 }
 if (conn->keepalives_interval != NULL)
 {
  if (!pqParseIntParam(conn->keepalives_interval,
        &cancel->keepalives_interval,
        conn, "keepalives_interval"))
   goto fail;
 }
 if (conn->keepalives_count != NULL)
 {
  if (!pqParseIntParam(conn->keepalives_count,
        &cancel->keepalives_count,
        conn, "keepalives_count"))
   goto fail;
 }

 req = (CancelRequestPacket *) &cancel->cancel_req;
 req->cancelRequestCode = (MsgType) pg_hton32(CANCEL_REQUEST_CODE);
 req->backendPID = pg_hton32(conn->be_pid);
 memcpy(req->cancelAuthCode, conn->be_cancel_key, conn->be_cancel_key_len);
 /* include the length field itself in the length */
 cancel->cancel_pkt_len = pg_hton32(cancel_req_len + 4);

 return cancel;

fail:
 free(cancel);
 return NULL;
}

/*
 * PQsendCancelRequest
 *  Submit a CancelRequest message, but don't wait for it to finish
 *
 * Returns: 1 if successfully submitted
 *   0 if error (conn->errorMessage is set)
 */

int
PQsendCancelRequest(PGconn *cancelConn)
{
 CancelRequestPacket req;

 /* Start the message. */
 if (pqPutMsgStart(0, cancelConn))
  return STATUS_ERROR;

 /* Send the message body. */
 memset(&req, 0, offsetof(CancelRequestPacket, cancelAuthCode));
 req.cancelRequestCode = (MsgType) pg_hton32(CANCEL_REQUEST_CODE);
 req.backendPID = pg_hton32(cancelConn->be_pid);
 if (pqPutnchar(&req, offsetof(CancelRequestPacket, cancelAuthCode), cancelConn))
  return STATUS_ERROR;
 if (pqPutnchar(cancelConn->be_cancel_key, cancelConn->be_cancel_key_len, cancelConn))
  return STATUS_ERROR;

 /* Finish the message. */
 if (pqPutMsgEnd(cancelConn))
  return STATUS_ERROR;

 /* Flush to ensure backend gets it. */
 if (pqFlush(cancelConn))
  return STATUS_ERROR;

 return STATUS_OK;
}

/* PQfreeCancel: free a cancel structure */
void
PQfreeCancel(PGcancel *cancel)
{
 free(cancel);
}


/*
 * Sets an integer socket option on a TCP socket, if the provided value is
 * not negative.  Returns false if setsockopt fails for some reason.
 *
 * CAUTION: This needs to be signal safe, since it's used by PQcancel.
 */

#if defined(TCP_USER_TIMEOUT) || !defined(WIN32)
static bool
optional_setsockopt(int fd, int protoid, int optid, int value)
{
 if (value < 0)
  return true;
 if (setsockopt(fd, protoid, optid, (char *) &value, sizeof(value)) < 0)
  return false;
 return true;
}
#endif


/*
 * PQcancel: old, non-encrypted, but signal-safe way of requesting query cancel
 *
 * The return value is true if the cancel request was successfully
 * dispatched, false if not (in which case an error message is available).
 * Note: successful dispatch is no guarantee that there will be any effect at
 * the backend.  The application must read the operation result as usual.
 *
 * On failure, an error message is stored in *errbuf, which must be of size
 * errbufsize (recommended size is 256 bytes).  *errbuf is not changed on
 * success return.
 *
 * CAUTION: we want this routine to be safely callable from a signal handler
 * (for example, an application might want to call it in a SIGINT handler).
 * This means we cannot use any C library routine that might be non-reentrant.
 * malloc/free are often non-reentrant, and anything that might call them is
 * just as dangerous.  We avoid sprintf here for that reason.  Building up
 * error messages with strcpy/strcat is tedious but should be quite safe.
 * We also save/restore errno in case the signal handler support doesn't.
 */

int
PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
{
 int   save_errno = SOCK_ERRNO;
 pgsocket tmpsock = PGINVALID_SOCKET;
 int   maxlen;
 char  recvbuf;
 int   cancel_pkt_len;

 if (!cancel)
 {
  strlcpy(errbuf, "PQcancel() -- no cancel object supplied", errbufsize);
  /* strlcpy probably doesn't change errno, but be paranoid */
  SOCK_ERRNO_SET(save_errno);
  return false;
 }

 if (cancel->cancel_pkt_len == 0)
 {
  /* This is a dummy PGcancel object, see PQgetCancel */
  strlcpy(errbuf, "PQcancel() -- no cancellation key received", errbufsize);
  /* strlcpy probably doesn't change errno, but be paranoid */
  SOCK_ERRNO_SET(save_errno);
  return false;
 }

 /*
  * We need to open a temporary connection to the postmaster. Do this with
  * only kernel calls.
 */

 if ((tmpsock = socket(cancel->raddr.addr.ss_family, SOCK_STREAM, 0)) == PGINVALID_SOCKET)
 {
  strlcpy(errbuf, "PQcancel() -- socket() failed: ", errbufsize);
  goto cancel_errReturn;
 }

 /*
  * Since this connection will only be used to send a single packet of
  * data, we don't need NODELAY.  We also don't set the socket to
  * nonblocking mode, because the API definition of PQcancel requires the
  * cancel to be sent in a blocking way.
  *
  * We do set socket options related to keepalives and other TCP timeouts.
  * This ensures that this function does not block indefinitely when
  * reasonable keepalive and timeout settings have been provided.
 */

 if (cancel->raddr.addr.ss_family != AF_UNIX &&
  cancel->keepalives != 0)
 {
#ifndef WIN32
  if (!optional_setsockopt(tmpsock, SOL_SOCKET, SO_KEEPALIVE, 1))
  {
   strlcpy(errbuf, "PQcancel() -- setsockopt(SO_KEEPALIVE) failed: ", errbufsize);
   goto cancel_errReturn;
  }

#ifdef PG_TCP_KEEPALIVE_IDLE
  if (!optional_setsockopt(tmpsock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE,
         cancel->keepalives_idle))
  {
   strlcpy(errbuf, "PQcancel() -- setsockopt(" PG_TCP_KEEPALIVE_IDLE_STR ") failed: ", errbufsize);
   goto cancel_errReturn;
  }
#endif

#ifdef TCP_KEEPINTVL
  if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_KEEPINTVL,
         cancel->keepalives_interval))
  {
   strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_KEEPINTVL) failed: ", errbufsize);
   goto cancel_errReturn;
  }
#endif

#ifdef TCP_KEEPCNT
  if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_KEEPCNT,
         cancel->keepalives_count))
  {
   strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_KEEPCNT) failed: ", errbufsize);
   goto cancel_errReturn;
  }
#endif

#else       /* WIN32 */

#ifdef SIO_KEEPALIVE_VALS
  if (!pqSetKeepalivesWin32(tmpsock,
          cancel->keepalives_idle,
          cancel->keepalives_interval))
  {
   strlcpy(errbuf, "PQcancel() -- WSAIoctl(SIO_KEEPALIVE_VALS) failed: ", errbufsize);
   goto cancel_errReturn;
  }
#endif       /* SIO_KEEPALIVE_VALS */
#endif       /* WIN32 */

  /* TCP_USER_TIMEOUT works the same way on Unix and Windows */
#ifdef TCP_USER_TIMEOUT
  if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_USER_TIMEOUT,
         cancel->pgtcp_user_timeout))
  {
   strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_USER_TIMEOUT) failed: ", errbufsize);
   goto cancel_errReturn;
  }
#endif
 }

retry3:
 if (connect(tmpsock, (struct sockaddr *) &cancel->raddr.addr,
    cancel->raddr.salen) < 0)
 {
  if (SOCK_ERRNO == EINTR)
   /* Interrupted system call - we'll just try again */
   goto retry3;
  strlcpy(errbuf, "PQcancel() -- connect() failed: ", errbufsize);
  goto cancel_errReturn;
 }

 cancel_pkt_len = pg_ntoh32(cancel->cancel_pkt_len);

retry4:

 /*
  * Send the cancel request packet. It starts with the message length at
  * cancel_pkt_len, followed by the actual packet.
 */

 if (send(tmpsock, (char *) &cancel->cancel_pkt_len, cancel_pkt_len, 0) != cancel_pkt_len)
 {
  if (SOCK_ERRNO == EINTR)
   /* Interrupted system call - we'll just try again */
   goto retry4;
  strlcpy(errbuf, "PQcancel() -- send() failed: ", errbufsize);
  goto cancel_errReturn;
 }

 /*
  * Wait for the postmaster to close the connection, which indicates that
  * it's processed the request.  Without this delay, we might issue another
  * command only to find that our cancel zaps that command instead of the
  * one we thought we were canceling.  Note we don't actually expect this
  * read to obtain any data, we are just waiting for EOF to be signaled.
 */

retry5:
 if (recv(tmpsock, &recvbuf, 10) < 0)
 {
  if (SOCK_ERRNO == EINTR)
   /* Interrupted system call - we'll just try again */
   goto retry5;
  /* we ignore other error conditions */
 }

 /* All done */
 closesocket(tmpsock);
 SOCK_ERRNO_SET(save_errno);
 return true;

cancel_errReturn:

 /*
  * Make sure we don't overflow the error buffer. Leave space for the \n at
  * the end, and for the terminating zero.
 */

 maxlen = errbufsize - strlen(errbuf) - 2;
 if (maxlen >= 0)
 {
  /*
   * We can't invoke strerror here, since it's not signal-safe.  Settle
   * for printing the decimal value of errno.  Even that has to be done
   * the hard way.
 */

  int   val = SOCK_ERRNO;
  char  buf[32];
  char    *bufp;

  bufp = buf + sizeof(buf) - 1;
  *bufp = '\0';
  do
  {
   *(--bufp) = (val % 10) + '0';
   val /= 10;
  } while (val > 0);
  bufp -= 6;
  memcpy(bufp, "error "6);
  strncat(errbuf, bufp, maxlen);
  strcat(errbuf, "\n");
 }
 if (tmpsock != PGINVALID_SOCKET)
  closesocket(tmpsock);
 SOCK_ERRNO_SET(save_errno);
 return false;
}

/*
 * PQrequestCancel: old, not thread-safe function for requesting query cancel
 *
 * Returns true if able to send the cancel request, false if not.
 *
 * On failure, the error message is saved in conn->errorMessage; this means
 * that this can't be used when there might be other active operations on
 * the connection object.
 *
 * NOTE: error messages will be cut off at the current size of the
 * error message buffer, since we dare not try to expand conn->errorMessage!
 */

int
PQrequestCancel(PGconn *conn)
{
 int   r;
 PGcancel   *cancel;

 /* Check we have an open connection */
 if (!conn)
  return false;

 if (conn->sock == PGINVALID_SOCKET)
 {
  strlcpy(conn->errorMessage.data,
    "PQrequestCancel() -- connection is not open\n",
    conn->errorMessage.maxlen);
  conn->errorMessage.len = strlen(conn->errorMessage.data);
  conn->errorReported = 0;

  return false;
 }

 cancel = PQgetCancel(conn);
 if (cancel)
 {
  r = PQcancel(cancel, conn->errorMessage.data,
      conn->errorMessage.maxlen);
  PQfreeCancel(cancel);
 }
 else
 {
  strlcpy(conn->errorMessage.data, "out of memory",
    conn->errorMessage.maxlen);
  r = false;
 }

 if (!r)
 {
  conn->errorMessage.len = strlen(conn->errorMessage.data);
  conn->errorReported = 0;
 }

 return r;
}

Messung V0.5 in Prozent
C=92 H=75 G=83

¤ Dauer der Verarbeitung: 0.6 Sekunden  (vorverarbeitet am  2026-08-06) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.