3030 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
3131 * Portions Copyright (c) 1994, Regents of the University of California
3232 *
33- *$PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.171 2004/08/29 05:06:43 momjian Exp $
33+ *$PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.172 2004/09/26 00:26:19 tgl Exp $
3434 *
3535 *-------------------------------------------------------------------------
3636 */
4444 *StreamClose- Close a client/backend connection
4545 *TouchSocketFile- Protect socket file against /tmp cleaners
4646 *pq_init- initialize libpq at backend startup
47+ *pq_comm_reset- reset libpq during error recovery
4748 *pq_close- shutdown libpq at backend exit
4849 *
4950 * low-level I/O:
8889#include "storage/ipc.h"
8990
9091
91- static void pq_close (int code ,Datum arg );
92-
93- #ifdef HAVE_UNIX_SOCKETS
94- static int Lock_AF_UNIX (unsigned short portNumber ,char * unixSocketName );
95- static int Setup_AF_UNIX (void );
96- #endif /* HAVE_UNIX_SOCKETS */
97-
98-
9992/*
10093 * Configuration options
10194 */
10295int Unix_socket_permissions ;
10396char * Unix_socket_group ;
10497
10598
99+ /* Where the Unix socket file is */
100+ static char sock_path [MAXPGPATH ];
101+
102+
106103/*
107104 * Buffers for low-level I/O
108105 */
@@ -121,9 +118,20 @@ static intPqRecvLength;/* End of data available in PqRecvBuffer */
121118/*
122119 * Message status
123120 */
121+ static bool PqCommBusy ;
124122static bool DoingCopyOut ;
125123
126124
125+ /* Internal functions */
126+ static void pq_close (int code ,Datum arg );
127+ static int internal_putbytes (const char * s ,size_t len );
128+ static int internal_flush (void );
129+ #ifdef HAVE_UNIX_SOCKETS
130+ static int Lock_AF_UNIX (unsigned short portNumber ,char * unixSocketName );
131+ static int Setup_AF_UNIX (void );
132+ #endif /* HAVE_UNIX_SOCKETS */
133+
134+
127135/* --------------------------------
128136 *pq_init - initialize libpq at backend startup
129137 * --------------------------------
@@ -132,10 +140,27 @@ void
132140pq_init (void )
133141{
134142PqSendPointer = PqRecvPointer = PqRecvLength = 0 ;
143+ PqCommBusy = false;
135144DoingCopyOut = false;
136145on_proc_exit (pq_close ,0 );
137146}
138147
148+ /* --------------------------------
149+ *pq_comm_reset - reset libpq during error recovery
150+ *
151+ * This is called from error recovery at the outer idle loop. It's
152+ * just to get us out of trouble if we somehow manage to elog() from
153+ * inside a pqcomm.c routine (which ideally will never happen, but...)
154+ * --------------------------------
155+ */
156+ void
157+ pq_comm_reset (void )
158+ {
159+ /* Do not throw away pending data, but do reset the busy flag */
160+ PqCommBusy = false;
161+ /* We can abort any old-style COPY OUT, too */
162+ pq_endcopyout (true);
163+ }
139164
140165/* --------------------------------
141166 *pq_close - shutdown libpq at backend exit
@@ -174,8 +199,6 @@ pq_close(int code, Datum arg)
174199 *Stream functions are used for vanilla TCP connection protocol.
175200 */
176201
177- static char sock_path [MAXPGPATH ];
178-
179202
180203/* StreamDoUnlink()
181204 * Shutdown routine for backend connection
@@ -885,13 +908,30 @@ pq_getmessage(StringInfo s, int maxlen)
885908 */
886909int
887910pq_putbytes (const char * s ,size_t len )
911+ {
912+ int res ;
913+
914+ /* Should only be called by old-style COPY OUT */
915+ Assert (DoingCopyOut );
916+ /* No-op if reentrant call */
917+ if (PqCommBusy )
918+ return 0 ;
919+ PqCommBusy = true;
920+ res = internal_putbytes (s ,len );
921+ PqCommBusy = false;
922+ return res ;
923+ }
924+
925+ static int
926+ internal_putbytes (const char * s ,size_t len )
888927{
889928size_t amount ;
890929
891930while (len > 0 )
892931{
932+ /* If buffer is full, then flush it out */
893933if (PqSendPointer >=PQ_BUFFER_SIZE )
894- if (pq_flush ())/* If buffer is full, then flush it out */
934+ if (internal_flush ())
895935return EOF ;
896936amount = PQ_BUFFER_SIZE - PqSendPointer ;
897937if (amount > len )
@@ -912,6 +952,20 @@ pq_putbytes(const char *s, size_t len)
912952 */
913953int
914954pq_flush (void )
955+ {
956+ int res ;
957+
958+ /* No-op if reentrant call */
959+ if (PqCommBusy )
960+ return 0 ;
961+ PqCommBusy = true;
962+ res = internal_flush ();
963+ PqCommBusy = false;
964+ return res ;
965+ }
966+
967+ static int
968+ internal_flush (void )
915969{
916970static int last_reported_send_errno = 0 ;
917971
@@ -988,26 +1042,40 @@ pq_flush(void)
9881042 *then; dropping them is annoying, but at least they will still appear
9891043 *in the postmaster log.)
9901044 *
1045+ *We also suppress messages generated while pqcomm.c is busy. This
1046+ *avoids any possibility of messages being inserted within other
1047+ *messages. The only known trouble case arises if SIGQUIT occurs
1048+ *during a pqcomm.c routine --- quickdie() will try to send a warning
1049+ *message, and the most reasonable approach seems to be to drop it.
1050+ *
9911051 *returns 0 if OK, EOF if trouble
9921052 * --------------------------------
9931053 */
9941054int
9951055pq_putmessage (char msgtype ,const char * s ,size_t len )
9961056{
997- if (DoingCopyOut )
1057+ if (DoingCopyOut || PqCommBusy )
9981058return 0 ;
1059+ PqCommBusy = true;
9991060if (msgtype )
1000- if (pq_putbytes (& msgtype ,1 ))
1001- return EOF ;
1061+ if (internal_putbytes (& msgtype ,1 ))
1062+ goto fail ;
10021063if (PG_PROTOCOL_MAJOR (FrontendProtocol ) >=3 )
10031064{
10041065uint32 n32 ;
10051066
10061067n32 = htonl ((uint32 ) (len + 4 ));
1007- if (pq_putbytes ((char * )& n32 ,4 ))
1008- return EOF ;
1068+ if (internal_putbytes ((char * )& n32 ,4 ))
1069+ goto fail ;
10091070}
1010- return pq_putbytes (s ,len );
1071+ if (internal_putbytes (s ,len ))
1072+ gotofail ;
1073+ PqCommBusy = false;
1074+ return 0 ;
1075+
1076+ fail :
1077+ PqCommBusy = false;
1078+ return EOF ;
10111079}
10121080
10131081/* --------------------------------
@@ -1036,8 +1104,8 @@ pq_endcopyout(bool errorAbort)
10361104{
10371105if (!DoingCopyOut )
10381106return ;
1039- DoingCopyOut = false;
10401107if (errorAbort )
10411108pq_putbytes ("\n\n\\.\n" ,5 );
10421109/* in non-error case, copy.c will have emitted the terminator line */
1110+ DoingCopyOut = false;
10431111}