diff options
Diffstat (limited to 'src/interfaces/libpq')
| -rw-r--r-- | src/interfaces/libpq/fe-connect.c | 107 | ||||
| -rw-r--r-- | src/interfaces/libpq/fe-exec.c | 50 | ||||
| -rw-r--r-- | src/interfaces/libpq/libpq-fe.h | 8 |
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); |
