From: Tom Lane <tgl@sss.pgh.pa.us>

Making PQrequestCancel safe to call in a signal handler turned out to be
much easier than I feared.  So here are the diffs.

Some notes:
  * I modified the postmaster's packet "iodone" callback interface to allow
    the callback routine to return a continue-or-drop-connection return
    code; this was necessary to allow the connection to be closed after
    receiving a Cancel, rather than proceeding to launch a new backend...
    Being a neatnik, I also made the iodone proc have a typechecked
    parameter list.
  * I deleted all code I could find that had to do with OOB.
  * I made some edits to ensure that all signals mentioned in the code
    are referred to symbolically not by numbers ("SIGUSR2" not "2").
    I think Bruce may have already done at least some of the same edits;
    I hope that merging these patches is not too painful.
This commit is contained in:
Marc G. Fournier 1998-07-09 03:29:11 +00:00
parent 8bf61820f0
commit a0659e3e2c
20 changed files with 597 additions and 287 deletions

View File

@ -4,7 +4,7 @@
<FirstName>Phil</FirstName>
<Surname>Thompson</Surname>
</Author>
<Date>1998-05-04</Date>
<Date>1998-07-07</Date>
</DocInfo>
<Title>Frontend/Backend Protocol</Title>
@ -54,8 +54,10 @@ invalid database name).
<Para>
Subsequent communications are query and result packets exchanged between the
frontend and the backend. The postmaster takes no further part in the
communication.
frontend and the backend. The postmaster takes no further part in ordinary
query/result communication. (However, the postmaster is involved when the
frontend wishes to cancel a query currently being executed by its backend.
Further details about that appear below.)
<Para>
When the frontend wishes to disconnect it sends an appropriate packet and
@ -182,6 +184,20 @@ The possible messages from the backend during this phase are:
<Para>
<VariableList>
<VarListEntry>
<Term>
BackendKeyData
</Term>
<ListItem>
<Para>
This message is issued after successful backend startup.
It provides secret-key data that the frontend must save
if it wants to be able to issue cancel requests later.
The frontend should not respond to this message, but should
continue listening for a ReadyForQuery message.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
ReadyForQuery
</Term>
@ -218,6 +234,14 @@ The possible messages from the backend during this phase are:
</VariableList>
</Para>
<Para>
The ReadyForQuery message is the same one that the backend will issue after
each query cycle. Depending on the coding needs of the frontend, it is
reasonable to consider ReadyForQuery as starting a query cycle (and then
BackendKeyData indicates successful conclusion of the startup phase),
or to consider ReadyForQuery as ending the startup phase and each subsequent
query cycle.
<Sect2>
<Title>Query</Title>
@ -453,7 +477,7 @@ NotificationResponse messages at any time; see below.
<Para>
If a frontend issues a listen(l) command, then the backend will send a
NotificationResponse message (not to be confused with NoticeResponse!)
whenever a notify(l) command is executed for the same relation name.
whenever a notify(l) command is executed for the same notification name.
<Para>
Notification responses are permitted at any point in the protocol (after
@ -470,8 +494,8 @@ NotificationResponse messages even when it is not engaged in a query.
</Term>
<ListItem>
<Para>
A notify(l) command has been executed for a relation for
which a previous listen(l) command was executed. Notifications
A notify(l) command has been executed for a name for which
a previous listen(l) command was executed. Notifications
may be sent at any time.
</Para>
</ListItem>
@ -479,29 +503,77 @@ NotificationResponse messages even when it is not engaged in a query.
</VariableList>
</Para>
<Para>
It may be worth pointing out that the names used in listen and notify
commands need not have anything to do with names of relations (tables)
in the SQL database. Notification names are simply arbitrarily chosen
condition names.
<Sect2>
<Title>Cancelling Requests in Progress</Title>
<Para>
During the processing of a query, the frontend may request cancellation of the
query by sending a single byte of OOB (out-of-band) data. The contents of the
data byte should be zero (although the backend does not currently check this).
If the cancellation is effective, it results in the current command being
terminated with an error message. Note that the backend makes no specific
reply to the cancel request itself. If the cancel request is ineffective
(say, because it arrived after processing was complete) then it will have
no visible effect at all. Thus, the frontend must continue with its normal
processing of query cycle responses after issuing a cancel request.
query by sending an appropriate request to the postmaster. The cancel request
is not sent directly to the backend for reasons of implementation efficiency:
we don't want to have the backend constantly checking for new input from
the frontend during query processing. Cancel requests should be relatively
infrequent, so we make them slightly cumbersome in order to avoid a penalty
in the normal case.
<Para>
To issue a cancel request, the frontend opens a new connection to the
postmaster and sends a CancelRequest message, rather than the StartupPacket
message that would ordinarily be sent across a new connection. The postmaster
will process this request and then close the connection. For security
reasons, no direct reply is made to the cancel request message.
<Para>
A CancelRequest message will be ignored unless it contains the same key data
(PID and secret key) passed to the frontend during connection startup. If the
request matches the PID and secret key for a currently executing backend, the
postmaster signals the backend to abort processing of the current query.
<Para>
The cancellation signal may or may not have any effect --- for example, if it
arrives after the backend has finished processing the query, then it will have
no effect. If the cancellation is effective, it results in the current
command being terminated early with an error message.
<Para>
The upshot of all this is that for reasons of both security and efficiency,
the frontend has no direct way to tell whether a cancel request has succeeded.
It must continue to wait for the backend to respond to the query. Issuing a
cancel simply improves the odds that the current query will finish soon,
and improves the odds that it will fail with an error message instead of
succeeding.
<Para>
Since the cancel request is sent to the postmaster and not across the
regular frontend/backend communication link, it is possible for the cancel
request to be issued by any process, not just the frontend whose query is
to be canceled. This may have some benefits of flexibility in building
multiple-process applications. It also introduces a security risk, in that
unauthorized persons might try to cancel queries. The security risk is
addressed by requiring a dynamically generated secret key to be supplied
in cancel requests.
<Sect2>
<Title>Termination</Title>
<Para>
The frontend sends a Terminate message and immediately closes the connection.
On receipt of the message, the backend immediately closes the connection and
terminates.
The normal, graceful termination procedure is that the frontend sends a
Terminate message and immediately closes the connection. On receipt of the
message, the backend immediately closes the connection and terminates.
<Para>
An ungraceful termination may occur due to software failure (i.e., core dump)
at either end. If either frontend or backend sees an unexpected closure of
the connection, it should clean up and terminate. The frontend has the option
of launching a new backend by recontacting the postmaster, if it doesn't want
to terminate itself.
<Sect1>
@ -824,6 +896,52 @@ AuthenticationEncryptedPassword (B)
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
BackendKeyData (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('K')
</Term>
<ListItem>
<Para>
Identifies the message as cancellation key data.
The frontend must save these values if it wishes to be
able to issue CancelRequest messages later.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
The process ID of this backend.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
The secret key of this backend.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
@ -892,6 +1010,63 @@ BinaryRow (B)
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
CancelRequest (F)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Int32(16)
</Term>
<ListItem>
<Para>
The size of the packet in bytes.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32(80877102)
</Term>
<ListItem>
<Para>
The cancel request code. The value is chosen to contain
"1234" in the most significant 16 bits, and "5678" in the
least 16 significant bits. (To avoid confusion, this code
must not be the same as any protocol version number.)
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
The process ID of the target backend.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32
</Term>
<ListItem>
<Para>
The secret key for the target backend.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
@ -1092,31 +1267,6 @@ EncryptedPasswordPacket (F)
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
ReadyForQuery (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('Z')
</Term>
<ListItem>
<Para>
Identifies the message type. ReadyForQuery is sent
whenever the backend is ready for a new query cycle.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
@ -1449,6 +1599,31 @@ Query (F)
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
ReadyForQuery (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('Z')
</Term>
<ListItem>
<Para>
Identifies the message type. ReadyForQuery is sent
whenever the backend is ready for a new query cycle.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.34 1998/06/27 04:53:29 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.35 1998/07/09 03:28:44 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -21,11 +21,11 @@
* 2.a If the process is the same as the backend process that issued
* notification (we are notifying something that we are listening),
* signal the corresponding frontend over the comm channel.
* 2.b For all other listening processes, we send kill(2) to wake up
* 2.b For all other listening processes, we send kill(SIGUSR2) to wake up
* the listening backend.
* 3. Upon receiving a kill(2) signal from another backend process notifying
* that one of the relation that we are listening is being notified,
* we can be in either of two following states:
* 3. Upon receiving a kill(SIGUSR2) signal from another backend process
* notifying that one of the relation that we are listening is being
* notified, we can be in either of two following states:
* 3.a We are sleeping, wake up and signal our frontend.
* 3.b We are in middle of another transaction, wait until the end of
* of the current transaction and signal our frontend.
@ -46,7 +46,7 @@
* (which takes place after commit) to all listeners on this relation.
*
* 3. Async. notification results in all backends listening on relation
* to be woken up, by a process signal kill(2), with name of relation
* to be woken up, by a process signal kill(SIGUSR2), with name of relation
* passed in shared memory.
*
* 4. Each backend notifies its respective frontend over the comm

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.28 1998/06/13 04:27:14 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.29 1998/07/09 03:28:45 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -40,13 +40,13 @@
#include <libpq/crypt.h>
static void sendAuthRequest(Port *port, AuthRequest areq, void (*handler) ());
static void handle_done_auth(Port *port);
static void handle_krb4_auth(Port *port);
static void handle_krb5_auth(Port *port);
static void handle_password_auth(Port *port);
static void readPasswordPacket(char *arg, PacketLen len, char *pkt);
static void pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt);
static void sendAuthRequest(Port *port, AuthRequest areq, PacketDoneProc handler);
static int handle_done_auth(void *arg, PacketLen len, void *pkt);
static int handle_krb4_auth(void *arg, PacketLen len, void *pkt);
static int handle_krb5_auth(void *arg, PacketLen len, void *pkt);
static int handle_password_auth(void *arg, PacketLen len, void *pkt);
static int readPasswordPacket(void *arg, PacketLen len, void *pkt);
static int pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt);
static int checkPassword(Port *port, char *user, char *password);
static int old_be_recvauth(Port *port);
static int map_old_to_new(Port *port, UserAuth old, int status);
@ -327,8 +327,8 @@ pg_krb5_recvauth(Port *port)
* Handle a v0 password packet.
*/
static void
pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt)
static int
pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt)
{
Port *port;
PasswordPacketV0 *pp;
@ -393,6 +393,8 @@ pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt)
if (map_old_to_new(port, uaPassword, status) != STATUS_OK)
auth_failed(port);
}
return (STATUS_OK); /* don't close the connection yet */
}
@ -433,7 +435,7 @@ be_recvauth(Port *port)
else
{
AuthRequest areq;
void (*auth_handler) ();
PacketDoneProc auth_handler;
/* Keep the compiler quiet. */
@ -499,7 +501,7 @@ be_recvauth(Port *port)
*/
static void
sendAuthRequest(Port *port, AuthRequest areq, void (*handler) ())
sendAuthRequest(Port *port, AuthRequest areq, PacketDoneProc handler)
{
char *dp,
*sp;
@ -527,7 +529,7 @@ sendAuthRequest(Port *port, AuthRequest areq, void (*handler) ())
i += 2;
}
PacketSendSetup(&port->pktInfo, i, handler, (char *) port);
PacketSendSetup(&port->pktInfo, i, handler, (void *) port);
}
@ -535,8 +537,8 @@ sendAuthRequest(Port *port, AuthRequest areq, void (*handler) ())
* Called when we have told the front end that it is authorised.
*/
static void
handle_done_auth(Port *port)
static int
handle_done_auth(void *arg, PacketLen len, void *pkt)
{
/*
@ -544,7 +546,7 @@ handle_done_auth(Port *port)
* start.
*/
return;
return STATUS_OK;
}
@ -553,13 +555,17 @@ handle_done_auth(Port *port)
* authentication.
*/
static void
handle_krb4_auth(Port *port)
static int
handle_krb4_auth(void *arg, PacketLen len, void *pkt)
{
Port *port = (Port *) arg;
if (pg_krb4_recvauth(port) != STATUS_OK)
auth_failed(port);
else
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
return STATUS_OK;
}
@ -568,13 +574,17 @@ handle_krb4_auth(Port *port)
* authentication.
*/
static void
handle_krb5_auth(Port *port)
static int
handle_krb5_auth(void *arg, PacketLen len, void *pkt)
{
Port *port = (Port *) arg;
if (pg_krb5_recvauth(port) != STATUS_OK)
auth_failed(port);
else
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
return STATUS_OK;
}
@ -583,12 +593,16 @@ handle_krb5_auth(Port *port)
* authentication.
*/
static void
handle_password_auth(Port *port)
static int
handle_password_auth(void *arg, PacketLen len, void *pkt)
{
Port *port = (Port *) arg;
/* Set up the read of the password packet. */
PacketReceiveSetup(&port->pktInfo, readPasswordPacket, (char *) port);
PacketReceiveSetup(&port->pktInfo, readPasswordPacket, (void *) port);
return STATUS_OK;
}
@ -596,13 +610,11 @@ handle_password_auth(Port *port)
* Called when we have received the password packet.
*/
static void
readPasswordPacket(char *arg, PacketLen len, char *pkt)
static int
readPasswordPacket(void *arg, PacketLen len, void *pkt)
{
char password[sizeof(PasswordPacket) + 1];
Port *port;
port = (Port *) arg;
Port *port = (Port *) arg;
/* Silently truncate a password that is too big. */
@ -615,6 +627,8 @@ readPasswordPacket(char *arg, PacketLen len, char *pkt)
auth_failed(port);
else
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
return (STATUS_OK); /* don't close the connection yet */
}
@ -662,7 +676,7 @@ old_be_recvauth(Port *port)
case STARTUP_PASSWORD_MSG:
PacketReceiveSetup(&port->pktInfo, pg_passwordv0_recvauth,
(char *) port);
(void *) port);
return STATUS_OK;

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.47 1998/06/27 04:53:30 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.48 1998/07/09 03:28:46 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -30,7 +30,6 @@
* pq_getinserv - initialize address from host and service name
* pq_connect - create remote input / output connection
* pq_accept - accept remote input / output connection
* pq_async_notify - receive notification from backend.
*
* NOTES
* These functions are used by both frontend applications and
@ -79,7 +78,6 @@
FILE *Pfout,
*Pfin;
FILE *Pfdebug; /* debugging libpq */
int PQAsyncNotifyWaiting; /* for async. notification */
/* --------------------------------
* pq_init - open portal file descriptors
@ -160,9 +158,7 @@ pq_close()
fclose(Pfout);
Pfout = NULL;
}
PQAsyncNotifyWaiting = 0;
PQnotifies_init();
pq_unregoob();
}
/* --------------------------------
@ -418,29 +414,6 @@ pq_putint(int i, int b)
}
}
/* ---
* pq_sendoob - send a string over the out-of-band channel
* pq_recvoob - receive a string over the oob channel
* NB: Fortunately, the out-of-band channel doesn't conflict with
* buffered I/O because it is separate from regular com. channel.
* ---
*/
int
pq_sendoob(char *msg, int len)
{
int fd = fileno(Pfout);
return send(fd, msg, len, MSG_OOB);
}
int
pq_recvoob(char *msgPtr, int len)
{
int fd = fileno(Pfout);
return recv(fd, msgPtr, len, MSG_OOB);
}
/* --------------------------------
* pq_getinaddr - initialize address from host and port number
* --------------------------------
@ -507,55 +480,6 @@ pq_getinserv(struct sockaddr_in * sin, char *host, char *serv)
return (pq_getinaddr(sin, host, ntohs(ss->s_port)));
}
/*
* register an out-of-band listener proc--at most one allowed.
* This is used for receiving async. notification from the backend.
*/
void
pq_regoob(void (*fptr) ())
{
int fd = fileno(Pfout);
#if defined(hpux)
ioctl(fd, FIOSSAIOOWN, MyProcPid);
#elif defined(sco)
ioctl(fd, SIOCSPGRP, MyProcPid);
#else
fcntl(fd, F_SETOWN, MyProcPid);
#endif /* hpux */
pqsignal(SIGURG, fptr);
}
void
pq_unregoob()
{
pqsignal(SIGURG, SIG_DFL);
}
void
pq_async_notify()
{
char msg[20];
/* int len = sizeof(msg); */
int len = 20;
if (pq_recvoob(msg, len) >= 0)
{
/* debugging */
printf("received notification: %s\n", msg);
PQAsyncNotifyWaiting = 1;
/* PQappendNotify(msg+1); */
}
else
{
extern int errno;
printf("SIGURG but no data: len = %d, err=%d\n", len, errno);
}
}
/*
* Streams -- wrapper around Unix socket system calls
*
@ -620,7 +544,7 @@ StreamServerPort(char *hostName, short portName, int *fdP)
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
bzero(&saddr, sizeof(saddr));
MemSet((char *) &saddr, 0, sizeof(saddr));
saddr.sa.sa_family = family;
if (family == AF_UNIX)
{

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.15 1998/02/26 04:31:56 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.16 1998/07/09 03:28:46 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -33,7 +33,7 @@
* Set up a packet read for the postmaster event loop.
*/
void PacketReceiveSetup(Packet *pkt, void (*iodone) (), char *arg)
void PacketReceiveSetup(Packet *pkt, PacketDoneProc iodone, void *arg)
{
pkt->nrtodo = sizeof(pkt->len);
pkt->ptr = (char *) &pkt->len;
@ -94,8 +94,8 @@ PacketReceiveFragment(Packet *pkt, int sock)
if (pkt->iodone == NULL)
return STATUS_ERROR;
(*pkt->iodone) (pkt->arg, pkt->len - sizeof(pkt->len),
(char *) &pkt->pkt);
return (*pkt->iodone) (pkt->arg, pkt->len - sizeof(pkt->len),
(void *) &pkt->pkt);
}
return STATUS_OK;
@ -107,7 +107,7 @@ PacketReceiveFragment(Packet *pkt, int sock)
if (errno == EINTR)
return STATUS_OK;
fprintf(stderr, "read() system call failed\n");
perror("PacketReceiveFragment: read() failed");
return STATUS_ERROR;
}
@ -117,8 +117,9 @@ PacketReceiveFragment(Packet *pkt, int sock)
* Set up a packet write for the postmaster event loop.
*/
void PacketSendSetup(Packet *pkt, int nbytes, void (*iodone) (), char *arg)
void PacketSendSetup(Packet *pkt, int nbytes, PacketDoneProc iodone, void *arg)
{
pkt->len = (PacketLen) nbytes;
pkt->nrtodo = nbytes;
pkt->ptr = (char *) &pkt->pkt;
pkt->iodone = iodone;
@ -153,7 +154,8 @@ PacketSendFragment(Packet *pkt, int sock)
if (pkt->iodone == NULL)
return STATUS_ERROR;
(*pkt->iodone) (pkt->arg);
return (*pkt->iodone) (pkt->arg, pkt->len,
(void *) &pkt->pkt);
}
return STATUS_OK;
@ -165,7 +167,7 @@ PacketSendFragment(Packet *pkt, int sock)
if (errno == EINTR)
return STATUS_OK;
fprintf(stderr, "write() system call failed\n");
perror("PacketSendFragment: write() failed");
return STATUS_ERROR;
}

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.92 1998/06/27 14:06:40 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.93 1998/07/09 03:28:47 scrappy Exp $
*
* NOTES
*
@ -206,7 +206,6 @@ static int orgsigmask = sigblock(0);
*/
static unsigned int random_seed = 0;
long MyCancelKey = 0;
extern char *optarg;
extern int optind,
@ -228,7 +227,8 @@ static void ExitPostmaster(int status);
static void usage(const char *);
static int ServerLoop(void);
static int BackendStartup(Port *port);
static void readStartupPacket(char *arg, PacketLen len, char *pkt);
static int readStartupPacket(void *arg, PacketLen len, void *pkt);
static int processCancelRequest(Port *port, PacketLen len, void *pkt);
static int initMasks(fd_set *rmask, fd_set *wmask);
static long PostmasterRandom(void);
static void RandomSalt(char *salt);
@ -518,6 +518,10 @@ PostmasterMain(int argc, char *argv[])
if (silentflag)
pmdaemonize();
/*
* Set up signal handlers for the postmaster process.
*/
pqsignal(SIGINT, pmdie);
pqsignal(SIGCHLD, reaper);
pqsignal(SIGTTIN, SIG_IGN);
@ -657,14 +661,14 @@ ServerLoop(void)
(port = ConnCreate(ServerSock_UNIX)) != NULL)
PacketReceiveSetup(&port->pktInfo,
readStartupPacket,
(char *) port);
(void *) port);
if (ServerSock_INET != INVALID_SOCK &&
FD_ISSET(ServerSock_INET, &rmask) &&
(port = ConnCreate(ServerSock_INET)) != NULL)
PacketReceiveSetup(&port->pktInfo,
readStartupPacket,
(char *) port);
(void *) port);
/* Build up new masks for select(). */
@ -790,8 +794,8 @@ initMasks(fd_set *rmask, fd_set *wmask)
* Called when the startup packet has been read.
*/
static void
readStartupPacket(char *arg, PacketLen len, char *pkt)
static int
readStartupPacket(void *arg, PacketLen len, void *pkt)
{
Port *port;
StartupPacket *si;
@ -799,6 +803,28 @@ readStartupPacket(char *arg, PacketLen len, char *pkt)
port = (Port *) arg;
si = (StartupPacket *) pkt;
/* The first field is either a protocol version number or
* a special request code.
*/
port->proto = ntohl(si->protoVersion);
if (port->proto == CANCEL_REQUEST_CODE)
return processCancelRequest(port, len, pkt);
/* Could add additional special packet types here */
/* Check we can handle the protocol the frontend is using. */
if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
PG_PROTOCOL_MAJOR(port->proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
(PG_PROTOCOL_MAJOR(port->proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
PG_PROTOCOL_MINOR(port->proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
{
PacketSendError(&port->pktInfo, "Unsupported frontend protocol.");
return STATUS_OK; /* don't close the connection yet */
}
/*
* Get the parameters from the startup packet as C strings. The
* packet destination was cleared first so a short packet has zeros
@ -815,31 +841,74 @@ readStartupPacket(char *arg, PacketLen len, char *pkt)
if (port->database[0] == '\0')
StrNCpy(port->database, si->user, sizeof(port->database) - 1);
/* Check we can handle the protocol the frontend is using. */
port->proto = ntohl(si->protoVersion);
if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
PG_PROTOCOL_MAJOR(port->proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
(PG_PROTOCOL_MAJOR(port->proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
PG_PROTOCOL_MINOR(port->proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
{
PacketSendError(&port->pktInfo, "Unsupported frontend protocol.");
return;
}
/* Check a user name was given. */
if (port->user[0] == '\0')
{
PacketSendError(&port->pktInfo,
"No Postgres username specified in startup packet.");
return;
return STATUS_OK; /* don't close the connection yet */
}
/* Start the authentication itself. */
be_recvauth(port);
return STATUS_OK; /* don't close the connection yet */
}
/*
* The client has sent a cancel request packet, not a normal
* start-a-new-backend packet. Perform the necessary processing.
* Note that in any case, we return STATUS_ERROR to close the
* connection immediately. Nothing is sent back to the client.
*/
static int
processCancelRequest(Port *port, PacketLen len, void *pkt)
{
CancelRequestPacket *canc = (CancelRequestPacket *) pkt;
int backendPID;
long cancelAuthCode;
Dlelem *curr;
Backend *bp;
backendPID = (int) ntohl(canc->backendPID);
cancelAuthCode = (long) ntohl(canc->cancelAuthCode);
/* See if we have a matching backend */
for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
{
bp = (Backend *) DLE_VAL(curr);
if (bp->pid == backendPID)
{
if (bp->cancel_key == cancelAuthCode)
{
/* Found a match; signal that backend to cancel current op */
if (DebugLvl)
fprintf(stderr, "%s: processCancelRequest: sending SIGINT to process %d\n",
progname, bp->pid);
kill(bp->pid, SIGINT);
}
else
{
/* Right PID, wrong key: no way, Jose */
if (DebugLvl)
fprintf(stderr, "%s: processCancelRequest: bad key in cancel request for process %d\n",
progname, bp->pid);
}
return STATUS_ERROR;
}
}
/* No matching backend */
if (DebugLvl)
fprintf(stderr, "%s: processCancelRequest: bad PID in cancel request for process %d\n",
progname, backendPID);
return STATUS_ERROR;
}
@ -1221,6 +1290,8 @@ DoBackend(Port *port)
char dbbuf[ARGV_SIZE + 1];
int ac = 0;
int i;
struct timeval now;
struct timezone tz;
/*
* Let's clean up ourselves as the postmaster child
@ -1254,7 +1325,16 @@ DoBackend(Port *port)
if (NetServer)
StreamClose(ServerSock_INET);
StreamClose(ServerSock_UNIX);
/*
* Don't want backend to be able to see the postmaster random number
* generator state. We have to clobber the static random_seed *and*
* start a new random sequence in the random() library function.
*/
random_seed = 0;
gettimeofday(&now, &tz);
srandom(now.tv_usec);
/* Now, on to standard postgres stuff */
MyProcPid = getpid();

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.78 1998/06/27 04:53:43 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.79 1998/07/09 03:28:48 scrappy Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -724,7 +724,7 @@ pg_exec_query_dest(char *query_string, /* string to execute */
/* --------------------------------
* signal handler routines used in PostgresMain()
*
* handle_warn() is used to catch kill(getpid(),1) which
* handle_warn() is used to catch kill(getpid(), SIGHUP) which
* occurs when elog(ERROR) is called.
*
* quickdie() occurs when signalled by the postmaster.
@ -777,7 +777,7 @@ FloatExceptionHandler(SIGNAL_ARGS)
}
/* signal handler for query cancel */
/* signal handler for query cancel signal from postmaster */
static void
QueryCancelHandler(SIGNAL_ARGS)
{
@ -787,12 +787,9 @@ QueryCancelHandler(SIGNAL_ARGS)
void
CancelQuery(void)
{
char dummy;
/* throw it away */
while (pq_recvoob(&dummy, 1) > 0)
;
/* QueryCancel reset in longjump after elog() call */
/* QueryCancel flag will be reset in main loop, which we reach by
* longjmp from elog().
*/
elog(ERROR, "Query was cancelled.");
}
@ -1261,7 +1258,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
}
pq_init(Portfd);
whereToSendOutput = Remote;
pq_regoob(QueryCancelHandler); /* we do it here so the backend it connected */
}
else
whereToSendOutput = Debug;
@ -1287,6 +1283,24 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
}
#endif
/* ----------------
* Set up handler for cancel-request signal, and
* send this backend's cancellation info to the frontend.
* This should not be done until we are sure startup is successful.
* ----------------
*/
pqsignal(SIGINT, QueryCancelHandler);
if (whereToSendOutput == Remote &&
PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
{
pq_putnchar("K", 1);
pq_putint((int32) MyProcPid, sizeof(int32));
pq_putint((int32) MyCancelKey, sizeof(int32));
/* Need not flush since ReadyForQuery will do it. */
}
/* ----------------
* if an exception is encountered, processing resumes here
* so we abort the current transaction and start a new one.
@ -1294,7 +1308,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
* so that the slaves signal the master to abort the transaction
* rather than calling AbortCurrentTransaction() themselves.
*
* Note: elog(ERROR) causes a kill(getpid(),1) to occur sending
* Note: elog(ERROR) causes a kill(getpid(), SIGHUP) to occur sending
* us back here.
* ----------------
*/
@ -1325,7 +1339,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface");
puts("$Revision: 1.78 $ $Date: 1998/06/27 04:53:43 $");
puts("$Revision: 1.79 $ $Date: 1998/07/09 03:28:48 $");
}
/* ----------------
@ -1431,7 +1445,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
break;
default:
elog(ERROR, "unknown frontend message was recieved");
elog(ERROR, "unknown frontend message was received");
}
/* ----------------

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.23 1998/05/29 17:00:18 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.24 1998/07/09 03:28:51 scrappy Exp $
*
* NOTES
* Globals used all over the place should be declared here and not
@ -44,6 +44,8 @@ bool QueryCancel = false;
int MyProcPid;
long MyCancelKey;
char *DataDir;
/*

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.146 1998/06/16 07:29:38 momjian Exp $
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.147 1998/07/09 03:28:53 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -291,15 +291,27 @@ PSQLexec(PsqlSettings *pset, char *query)
* If interactive, we enable a SIGINT signal catcher that sends
* a cancel request to the backend.
* Note that sending the cancel directly from the signal handler
* is safe only because the cancel is sent as an OOB message.
* If it were inline data, then we'd risk inserting it into the
* middle of a normal data message by doing this.
* (It's probably not too cool to write on stderr, for that matter...
* but for debugging purposes we'll risk that.)
* is safe only because PQrequestCancel is carefully written to
* make it so. We have to be very careful what else we do in the
* signal handler.
* Writing on stderr is potentially dangerous, if the signal interrupted
* some stdio operation on stderr. On Unix we can avoid trouble by using
* write() instead; on Windows that's probably not workable, but we can
* at least avoid trusting printf by using the more primitive fputs.
*/
static PGconn * cancelConn = NULL; /* connection to try cancel on */
static void
safe_write_stderr (const char * s)
{
#ifdef WIN32
fputs(s, stderr);
#else
write(fileno(stderr), s, strlen(s));
#endif
}
static void
handle_sigint (SIGNAL_ARGS)
{
@ -307,11 +319,13 @@ handle_sigint (SIGNAL_ARGS)
exit(1); /* accept signal if no connection */
/* Try to send cancel request */
if (PQrequestCancel(cancelConn))
fprintf(stderr, "\nCANCEL request sent\n");
{
safe_write_stderr("\nCANCEL request sent\n");
}
else
{
fprintf(stderr, "\nCannot send cancel request:\n%s\n",
PQerrorMessage(cancelConn));
safe_write_stderr("\nCannot send cancel request:\n");
safe_write_stderr(PQerrorMessage(cancelConn));
}
}

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: dbcommands.h,v 1.1 1997/11/24 05:32:51 momjian Exp $
* $Id: dbcommands.h,v 1.2 1998/07/09 03:28:56 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -17,8 +17,7 @@
* Originally from tmp/daemon.h. The functions declared in daemon.h does not
* exist; hence removed. -- AY 7/29/94
*/
#define SIGKILLDAEMON1 SIGINT
#define SIGKILLDAEMON2 SIGTERM
#define SIGKILLDAEMON1 SIGTERM
extern void createdb(char *dbname, char *dbpath);
extern void destroydb(char *dbname);

View File

@ -7,7 +7,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: libpq-be.h,v 1.10 1998/02/26 04:41:49 momjian Exp $
* $Id: libpq-be.h,v 1.11 1998/07/09 03:29:00 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -68,16 +68,20 @@ typedef enum
WritingPacket
} PacketState;
typedef int (*PacketDoneProc) (void * arg, PacketLen pktlen, void * pktdata);
typedef struct Packet
{
PacketState state; /* What's in progress. */
PacketLen len; /* Actual length */
int nrtodo; /* Bytes still to transfer */
char *ptr; /* Buffer pointer */
void (*iodone) (); /* I/O complete callback */
char *arg; /* Argument to callback */
PacketDoneProc iodone; /* I/O complete callback */
void *arg; /* Argument to callback */
/* A union of all the different packets. */
/* We declare the data buffer as a union of the allowed packet types,
* mainly to ensure that enough space is allocated for the largest one.
*/
union
{
@ -89,6 +93,7 @@ typedef struct Packet
/* These are incoming and have a packet length prepended. */
StartupPacket si;
CancelRequestPacket canc;
PasswordPacketV0 pwv0;
PasswordPacket pw;
} pkt;
@ -126,16 +131,15 @@ typedef struct Port
extern FILE *Pfout,
*Pfin;
extern int PQAsyncNotifyWaiting;
extern ProtocolVersion FrontendProtocol;
/*
* prototypes for functions in pqpacket.c
*/
void PacketReceiveSetup(Packet *pkt, void (*iodone) (), char *arg);
void PacketReceiveSetup(Packet *pkt, PacketDoneProc iodone, void *arg);
int PacketReceiveFragment(Packet *pkt, int sock);
void PacketSendSetup(Packet *pkt, int nbytes, void (*iodone) (), char *arg);
void PacketSendSetup(Packet *pkt, int nbytes, PacketDoneProc iodone, void *arg);
int PacketSendFragment(Packet *pkt, int sock);
void PacketSendError(Packet *pkt, char *errormsg);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: libpq.h,v 1.16 1998/06/16 07:29:41 momjian Exp $
* $Id: libpq.h,v 1.17 1998/07/09 03:29:01 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -126,8 +126,7 @@ extern size_t portals_array_size;
*/
typedef struct PQNotifyList
{
char relname[NAMEDATALEN]; /* name of relation containing
* data */
char relname[NAMEDATALEN]; /* listen/notify name */
int be_pid; /* process id of backend */
int valid; /* has this already been handled by user. */
/* SLNode Node; */
@ -268,8 +267,6 @@ extern int pq_getint(int b);
extern void pq_putstr(char *s);
extern void pq_putnchar(char *s, int n);
extern void pq_putint(int i, int b);
extern int pq_sendoob(char *msg, int len);
extern int pq_recvoob(char *msgPtr, int len);
extern int pq_getinaddr(struct sockaddr_in * sin, char *host, int port);
extern int pq_getinserv(struct sockaddr_in * sin, char *host, char *serv);
@ -281,10 +278,7 @@ extern int
pq_connect(char *dbname, char *user, char *args, char *hostName,
char *debugTty, char *execFile, short portName);
extern int StreamOpen(char *hostName, short portName, Port *port);
extern void pq_regoob(void (*fptr) ());
extern void pq_unregoob(void);
extern void pq_async_notify(void);
extern void StreamDoUnlink();
extern void StreamDoUnlink(void);
extern int StreamServerPort(char *hostName, short portName, int *fdP);
extern int StreamConnection(int server_fd, Port *port);
extern void StreamClose(int sock);

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: pqcomm.h,v 1.25 1998/05/06 23:50:32 momjian Exp $
* $Id: pqcomm.h,v 1.26 1998/07/09 03:29:01 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -122,6 +122,25 @@ typedef uint32 AuthRequest;
typedef ProtocolVersion MsgType;
/* A client can also send a cancel-current-operation request to the postmaster.
* This is uglier than sending it directly to the client's backend, but it
* avoids depending on out-of-band communication facilities.
*/
/* The cancel request code must not match any protocol version number
* we're ever likely to use. This random choice should do.
*/
#define CANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678)
typedef struct CancelRequestPacket
{
/* Note that each field is stored in network byte order! */
MsgType cancelRequestCode; /* code to identify a cancel request */
uint32 backendPID; /* PID of client's backend */
uint32 cancelAuthCode; /* secret key to authorize cancel */
} CancelRequestPacket;
/* in pqcompriv.c */
int pqGetShort(int *, FILE *);
int pqGetLong(int *, FILE *);

View File

@ -11,7 +11,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: miscadmin.h,v 1.26 1998/06/09 17:13:06 momjian Exp $
* $Id: miscadmin.h,v 1.27 1998/07/09 03:28:55 scrappy Exp $
*
* NOTES
* some of the information in this file will be moved to
@ -42,6 +42,8 @@ extern char *DataDir;
extern int MyProcPid;
extern long MyCancelKey;
extern char OutputFileName[];
/*

View File

@ -1,6 +1,5 @@
#include <limits.h> /* For _POSIX_PATH_MAX */
#define MAXPATHLEN _POSIX_PATH_MAX
#define SIGURG SIGUSR1
#define NOFILE NOFILES_MIN

View File

@ -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

View File

@ -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;
@ -761,44 +771,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.

View File

@ -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);

View File

@ -1,6 +1,6 @@
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" $Header: /cvsroot/pgsql/src/man/Attic/listen.l,v 1.6 1998/06/24 13:21:27 momjian Exp $
.\" $Header: /cvsroot/pgsql/src/man/Attic/listen.l,v 1.7 1998/07/09 03:29:09 scrappy Exp $
.TH "LISTEN" SQL 03/12/94 PostgreSQL PostgreSQL
.SH NAME
listen - listen for notification on a relation
@ -21,9 +21,7 @@ is cleared.
.PP
This event notification is performed through the Libpq protocol
and frontend application interface. The application program
must explicitly poll a Libpq global variable,
.IR PQAsyncNotifyWaiting ,
and call the routine
must call the routine
.IR PQnotifies
in order to find out the name of the class to which a given
notification corresponds. If this code is not included in

View File

@ -1,6 +1,6 @@
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" $Header: /cvsroot/pgsql/src/man/Attic/notify.l,v 1.4 1998/06/24 13:21:27 momjian Exp $
.\" $Header: /cvsroot/pgsql/src/man/Attic/notify.l,v 1.5 1998/07/09 03:29:11 scrappy Exp $
.TH "NOTIFY" SQL 11/05/95 PostgreSQL PostgreSQL
.SH NAME
notify - signal all frontends and backends listening on a class
@ -32,11 +32,14 @@ does is indicate that some backend wishes its peers to examine
.IR class_name
in some application-specific way.
.PP
In fact,
.IR class_name
need not be the name of an SQL class at all. It is best thought of
as a condition name that the application programmer selects.
.PP
This event notification is performed through the Libpq protocol
and frontend application interface. The application program
must explicitly poll a Libpq global variable,
.IR PQAsyncNotifyWaiting ,
and call the routine
must call the routine
.IR PQnotifies
in order to find out the name of the class to which a given
notification corresponds. If this code is not included in