summaryrefslogtreecommitdiff
path: root/src/interfaces/libpq
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/libpq')
-rw-r--r--src/interfaces/libpq/fe-connect.c107
-rw-r--r--src/interfaces/libpq/fe-exec.c50
-rw-r--r--src/interfaces/libpq/libpq-fe.h8
3 files changed, 116 insertions, 49 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 672948a287..47aa2b9bca 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.72 1998/07/07 18:00:09 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.73 1998/07/09 03:29:07 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -499,13 +499,11 @@ connectDB(PGconn *conn)
{
PGresult *res;
struct hostent *hp;
-
StartupPacket sp;
AuthRequest areq;
int laddrlen = sizeof(SockAddr);
int portno,
- family,
- len;
+ family;
char beresp;
int on = 1;
@@ -561,11 +559,11 @@ connectDB(PGconn *conn)
(char *) hp->h_addr,
hp->h_length);
conn->raddr.in.sin_port = htons((unsigned short) (portno));
- len = sizeof(struct sockaddr_in);
+ conn->raddr_len = sizeof(struct sockaddr_in);
}
#ifndef WIN32
else
- len = UNIXSOCK_PATH(conn->raddr.un, portno);
+ conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
#endif
@@ -577,7 +575,7 @@ connectDB(PGconn *conn)
errno, strerror(errno));
goto connect_errReturn;
}
- if (connect(conn->sock, &conn->raddr.sa, len) < 0)
+ if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
{
(void) sprintf(conn->errorMessage,
"connectDB() failed: Is the postmaster running and accepting%s connections at '%s' on port '%s'?\n",
@@ -724,7 +722,7 @@ connectDB(PGconn *conn)
* A ReadyForQuery message indicates that startup is successful,
* but we might also get an Error message indicating failure.
* (Notice messages indicating nonfatal warnings are also allowed
- * by the protocol.)
+ * by the protocol, as is a BackendKeyData message.)
* Easiest way to handle this is to let PQgetResult() read the messages.
* We just have to fake it out about the state of the connection.
*/
@@ -994,6 +992,99 @@ PQreset(PGconn *conn)
}
}
+
+/*
+ * PQrequestCancel: attempt to request cancellation of the current operation.
+ *
+ * The return value is TRUE if the cancel request was successfully
+ * dispatched, FALSE if not (in which case errorMessage is set).
+ * Note: successful dispatch is no guarantee that there will be any effect at
+ * the backend. The application must read the operation result as usual.
+ *
+ * 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.
+ */
+
+int
+PQrequestCancel(PGconn *conn)
+{
+ int tmpsock = -1;
+ struct {
+ uint32 packetlen;
+ CancelRequestPacket cp;
+ } crp;
+
+ /* Check we have an open connection */
+ if (!conn)
+ return FALSE;
+
+ if (conn->sock < 0)
+ {
+ strcpy(conn->errorMessage,
+ "PQrequestCancel() -- connection is not open\n");
+ return FALSE;
+ }
+
+ /*
+ * We need to open a temporary connection to the postmaster.
+ * Use the information saved by connectDB to do this with
+ * only kernel calls.
+ */
+ if ((tmpsock = socket(conn->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0)
+ {
+ strcpy(conn->errorMessage, "PQrequestCancel() -- socket() failed: ");
+ goto cancel_errReturn;
+ }
+ if (connect(tmpsock, &conn->raddr.sa, conn->raddr_len) < 0)
+ {
+ strcpy(conn->errorMessage, "PQrequestCancel() -- connect() failed: ");
+ goto cancel_errReturn;
+ }
+ /*
+ * We needn't set nonblocking I/O or NODELAY options here.
+ */
+
+ /* Create and send the cancel request packet. */
+
+ crp.packetlen = htonl((uint32) sizeof(crp));
+ crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE);
+ crp.cp.backendPID = htonl(conn->be_pid);
+ crp.cp.cancelAuthCode = htonl(conn->be_key);
+
+ if (send(tmpsock, (char*) &crp, sizeof(crp), 0) != (int) sizeof(crp))
+ {
+ strcpy(conn->errorMessage, "PQrequestCancel() -- send() failed: ");
+ goto cancel_errReturn;
+ }
+
+ /* Sent it, done */
+#ifdef WIN32
+ closesocket(tmpsock);
+#else
+ close(tmpsock);
+#endif
+
+ return TRUE;
+
+cancel_errReturn:
+ strcat(conn->errorMessage, strerror(errno));
+ strcat(conn->errorMessage, "\n");
+ if (tmpsock >= 0)
+ {
+#ifdef WIN32
+ closesocket(tmpsock);
+#else
+ close(tmpsock);
+#endif
+ }
+ return FALSE;
+}
+
+
/*
* PacketSend() -- send a single-packet message.
* this is like PacketSend(), defined in backend/libpq/pqpacket.c
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 49bd6d07e5..6a68af49d3 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.55 1998/07/03 04:24:13 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.56 1998/07/09 03:29:08 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -361,6 +361,16 @@ parseInput(PGconn *conn)
PGRES_EMPTY_QUERY);
conn->asyncStatus = PGASYNC_READY;
break;
+ case 'K': /* secret key data from the backend */
+ /* This is expected only during backend startup,
+ * but it's just as easy to handle it as part of the
+ * main loop. Save the data and continue processing.
+ */
+ if (pqGetInt(&(conn->be_pid), 4, conn))
+ return;
+ if (pqGetInt(&(conn->be_key), 4, conn))
+ return;
+ break;
case 'N': /* notices from the backend */
if (getNotice(conn))
return;
@@ -762,44 +772,6 @@ PQexec(PGconn *conn, const char *query)
/*
- * Attempt to request cancellation of the current operation.
- *
- * The return value is TRUE if the cancel request was successfully
- * dispatched, FALSE if not (in which case errorMessage is set).
- * Note: successful dispatch is no guarantee that there will be any effect at
- * the backend. The application must read the operation result as usual.
- */
-
-int
-PQrequestCancel(PGconn *conn)
-{
- char msg[1];
-
- if (!conn)
- return FALSE;
-
- if (conn->sock < 0)
- {
- sprintf(conn->errorMessage,
- "PQrequestCancel() -- connection is not open\n");
- return FALSE;
- }
-
- msg[0] = '\0';
-
- if (send(conn->sock, msg, 1, MSG_OOB) < 0)
- {
- sprintf(conn->errorMessage,
- "PQrequestCancel() -- couldn't send OOB data: errno=%d\n%s\n",
- errno, strerror(errno));
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
* Attempt to read a Notice response message.
* This is possible in several places, so we break it out as a subroutine.
* Entry: 'N' flag character has already been consumed.
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 1bfd0f5a3e..a4fad81a37 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: libpq-fe.h,v 1.30 1998/06/16 07:29:49 momjian Exp $
+ * $Id: libpq-fe.h,v 1.31 1998/07/09 03:29:09 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -174,8 +174,11 @@ extern "C"
int sock; /* Unix FD for socket, -1 if not connected */
SockAddr laddr; /* Local address */
SockAddr raddr; /* Remote address */
+ int raddr_len; /* Length of remote address */
/* Miscellaneous stuff */
+ int be_pid; /* PID of backend --- needed for cancels */
+ int be_key; /* key of backend --- needed for cancels */
char salt[2]; /* password salt received from backend */
PGlobjfuncs *lobjfuncs; /* private state for large-object access fns */
@@ -273,6 +276,8 @@ extern "C"
#define PQsetdb(M_PGHOST,M_PGPORT,M_PGOPT,M_PGTTY,M_DBNAME) PQsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, NULL, NULL)
/* close the current connection and free the PGconn data structure */
extern void PQfinish(PGconn *conn);
+ /* issue a cancel request */
+ extern int PQrequestCancel(PGconn *conn);
/*
* close the current connection and restablish a new one with the same
@@ -305,7 +310,6 @@ extern "C"
/* Routines for managing an asychronous query */
extern int PQisBusy(PGconn *conn);
extern void PQconsumeInput(PGconn *conn);
- extern int PQrequestCancel(PGconn *conn);
/* Routines for copy in/out */
extern int PQgetline(PGconn *conn, char *string, int length);
extern void PQputline(PGconn *conn, const char *string);