Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit edbd513

Browse files
committed
What I've done:
1. Rewritten libpq to allow asynchronous clients. 2. Implemented client side of cancel protocol in library, and patched psql.c to send a cancel request upon SIGINT. The backend doesn't notice it yet :-( 3. Implemented 'Z' protocol message addition and renaming of copy in/out start messages. These are implemented conditionally, ie, the client protocol version is checked; so the code should still work with 1.0 clients. 4. Revised protocol and libpq sgml documents (don't have an SGML compiler, though, so there may be some markup glitches here). What remains to be done: 1. Implement addition of atttypmod field to RowDescriptor messages. The client-side code is there but ifdef'd out. I have no idea what to change on the backend side. The field should be sent only if protocol >= 2.0, of course. 2. Implement backend response to cancel requests received as OOB messages. (This prolly need not be conditional on protocol version; just do it if you get SIGURG.) 3. Update libpq.3. (I'm hoping this can be generated mechanically from libpq.sgml... if not, will do it by hand.) Is there any other doco to fix? 4. Update non-libpq interfaces as necessary. I patched libpgtcl so that it would compile, but haven't tested it. Dunno what needs to be done with the other interfaces. Have at it! Tom Lane
1 parent 2e12331 commit edbd513

File tree

15 files changed

+2514
-1996
lines changed

15 files changed

+2514
-1996
lines changed

doc/src/sgml/libpq.sgml

+318-71
Large diffs are not rendered by default.

doc/src/sgml/protocol.sgml

+222-49
Large diffs are not rendered by default.

src/backend/commands/async.c

+3-10
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.31 1998/04/27 04:05:08 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.32 1998/05/06 23:49:52 momjian Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -20,8 +20,7 @@
2020
* end of commit),
2121
* 2.a If the process is the same as the backend process that issued
2222
* notification (we are notifying something that we are listening),
23-
* signal the corresponding frontend over the comm channel using the
24-
* out-of-band channel.
23+
* signal the corresponding frontend over the comm channel.
2524
* 2.b For all other listening processes, we send kill(2) to wake up
2625
* the listening backend.
2726
* 3. Upon receiving a kill(2) signal from another backend process notifying
@@ -30,7 +29,7 @@
3029
* 3.a We are sleeping, wake up and signal our frontend.
3130
* 3.b We are in middle of another transaction, wait until the end of
3231
* of the current transaction and signal our frontend.
33-
* 4. Each frontend receives this notification and prcesses accordingly.
32+
* 4. Each frontend receives this notification and processes accordingly.
3433
*
3534
* -- jw, 12/28/93
3635
*
@@ -547,12 +546,6 @@ Async_UnlistenOnExit(int code, /* from exitpg */
547546
* Results:
548547
* XXX
549548
*
550-
* Side effects:
551-
*
552-
* We make use of the out-of-band channel to transmit the
553-
* notification to the front end. The actual data transfer takes
554-
* place at the front end's request.
555-
*
556549
* --------------------------------------------------------------
557550
*/
558551
GlobalMemory notifyContext = NULL;

src/backend/tcop/dest.c

+55-52
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.17 1998/02/26 04:36:24 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.18 1998/05/06 23:49:59 momjian Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
1414
/*
1515
* INTERFACE ROUTINES
1616
* BeginCommand - prepare destination for tuples of the given type
1717
* EndCommand - tell destination that no more tuples will arrive
18-
* NullCommand - tell dest that the last of a query sequence was processed
18+
* NullCommand - tell dest that an empty query string was recognized
19+
* ReadyForQuery - tell dest that we are ready for a new query
1920
*
2021
* NOTES
2122
* These routines do the appropriate work before and after
@@ -115,16 +116,10 @@ EndCommand(char *commandTag, CommandDest dest)
115116
sprintf(buf, "%s%s", commandTag, CommandInfo);
116117
CommandInfo[0] = 0;
117118
pq_putstr(buf);
118-
pq_flush();
119119
break;
120120

121121
case Local:
122122
case Debug:
123-
break;
124-
case CopyEnd:
125-
pq_putnchar("Z", 1);
126-
pq_flush();
127-
break;
128123
case None:
129124
default:
130125
break;
@@ -139,75 +134,84 @@ EndCommand(char *commandTag, CommandDest dest)
139134
*
140135
* COPY rel FROM stdin
141136
*
137+
* NOTE: the message code letters are changed at protocol version 2.0
138+
* to eliminate possible confusion with data tuple messages.
142139
*/
143140
void
144141
SendCopyBegin(void)
145142
{
146-
pq_putnchar("B", 1);
147-
/* pq_putint(0, 4); */
148-
pq_flush();
143+
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
144+
pq_putnchar("H", 1); /* new way */
145+
else
146+
pq_putnchar("B", 1); /* old way */
149147
}
150148

151149
void
152150
ReceiveCopyBegin(void)
153151
{
154-
pq_putnchar("D", 1);
155-
/* pq_putint(0, 4); */
152+
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
153+
pq_putnchar("G", 1); /* new way */
154+
else
155+
pq_putnchar("D", 1); /* old way */
156+
/* We *must* flush here to ensure FE knows it can send. */
156157
pq_flush();
157158
}
158159

159160
/* ----------------
160-
* NullCommand - tell dest that the last of a query sequence was processed
161+
* NullCommand - tell dest that an empty query string was recognized
161162
*
162-
* Necessary to implement the hacky FE/BE interface to handle
163-
* multiple-return queries.
163+
* In FE/BE protocol version 1.0, this hack is necessary to support
164+
* libpq's crufty way of determining whether a multiple-command
165+
* query string is done. In protocol 2.0 it's probably not really
166+
* necessary to distinguish empty queries anymore, but we still do it
167+
* for backwards compatibility with 1.0.
164168
* ----------------
165169
*/
166170
void
167171
NullCommand(CommandDest dest)
168172
{
169173
switch (dest)
170174
{
171-
case RemoteInternal:
172-
case Remote:
175+
case RemoteInternal:
176+
case Remote:
173177
{
174-
#if 0
175-
176-
/*
177-
* Do any asynchronous notification. If front end wants
178-
* to poll, it can send null queries to call this
179-
* function.
180-
*/
181-
PQNotifyList *nPtr;
182-
MemoryContext orig;
183-
184-
if (notifyContext == NULL)
185-
{
186-
notifyContext = CreateGlobalMemory("notify");
187-
}
188-
orig = MemoryContextSwitchTo((MemoryContext) notifyContext);
189-
190-
for (nPtr = PQnotifies();
191-
nPtr != NULL;
192-
nPtr = (PQNotifyList *) SLGetSucc(&nPtr->Node))
193-
{
194-
pq_putnchar("A", 1);
195-
pq_putint(0, sizeof(int4));
196-
pq_putstr(nPtr->relname);
197-
pq_putint(nPtr->be_pid, sizeof(nPtr->be_pid));
198-
PQremoveNotify(nPtr);
199-
}
200-
pq_flush();
201-
PQcleanNotify();/* garbage collect */
202-
MemoryContextSwitchTo(orig);
203-
#endif
204178
/* ----------------
205-
* tell the fe that the last of the queries has finished
179+
* tell the fe that we saw an empty query string
206180
* ----------------
207181
*/
208-
/* pq_putnchar("I", 1); */
209182
pq_putstr("I");
210-
/* pq_putint(0, 4); */
183+
}
184+
break;
185+
186+
case Local:
187+
case Debug:
188+
case None:
189+
default:
190+
break;
191+
}
192+
}
193+
194+
/* ----------------
195+
* ReadyForQuery - tell dest that we are ready for a new query
196+
*
197+
* The ReadyForQuery message is sent in protocol versions 2.0 and up
198+
* so that the FE can tell when we are done processing a query string.
199+
*
200+
* Note that by flushing the stdio buffer here, we can avoid doing it
201+
* most other places and thus reduce the number of separate packets sent.
202+
* ----------------
203+
*/
204+
void
205+
ReadyForQuery(CommandDest dest)
206+
{
207+
switch (dest)
208+
{
209+
case RemoteInternal:
210+
case Remote:
211+
{
212+
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
213+
pq_putnchar("Z", 1);
214+
/* Flush output at end of cycle in any case. */
211215
pq_flush();
212216
}
213217
break;
@@ -264,7 +268,6 @@ BeginCommand(char *pname,
264268
* send fe info on tuples we're about to send
265269
* ----------------
266270
*/
267-
pq_flush();
268271
pq_putnchar("P", 1);/* new portal.. */
269272
pq_putstr(pname); /* portal name */
270273

src/backend/tcop/fastpath.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.16 1998/04/26 04:07:22 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.17 1998/05/06 23:50:10 momjian Exp $
1111
*
1212
* NOTES
1313
* This cruft is the server side of PQfn.
@@ -113,7 +113,6 @@ SendFunctionResult(Oid fid, /* function id */
113113
}
114114

115115
pq_putnchar("0", 1);
116-
pq_flush();
117116
}
118117

119118
/*

src/backend/tcop/postgres.c

+9-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.67 1998/02/26 04:36:31 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.68 1998/05/06 23:50:19 momjian Exp $
1111
*
1212
* NOTES
1313
* this is the "main" module of the postgres backend and
@@ -1302,7 +1302,7 @@ PostgresMain(int argc, char *argv[])
13021302
if (IsUnderPostmaster == false)
13031303
{
13041304
puts("\nPOSTGRES backend interactive interface");
1305-
puts("$Revision: 1.67 $ $Date: 1998/02/26 04:36:31 $");
1305+
puts("$Revision: 1.68 $ $Date: 1998/05/06 23:50:19 $");
13061306
}
13071307

13081308
/* ----------------
@@ -1316,6 +1316,12 @@ PostgresMain(int argc, char *argv[])
13161316

13171317
for (;;)
13181318
{
1319+
/* ----------------
1320+
* (0) tell the frontend we're ready for a new query.
1321+
* ----------------
1322+
*/
1323+
ReadyForQuery(Remote);
1324+
13191325
/* ----------------
13201326
* (1) read a command.
13211327
* ----------------
@@ -1391,8 +1397,8 @@ PostgresMain(int argc, char *argv[])
13911397
* ----------------
13921398
*/
13931399
case 'X':
1394-
IsEmptyQuery = true;
13951400
pq_close();
1401+
exitpg(0);
13961402
break;
13971403

13981404
default:

src/bin/psql/psql.c

+46-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.139 1998/05/04 02:02:01 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.140 1998/05/06 23:50:23 momjian Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -283,6 +283,38 @@ PSQLexec(PsqlSettings *pset, char *query)
283283
return NULL;
284284
}
285285

286+
/*
287+
* Code to support command cancellation.
288+
* If interactive, we enable a SIGINT signal catcher that sends
289+
* a cancel request to the backend.
290+
* Note that sending the cancel directly from the signal handler
291+
* is safe only because the cancel is sent as an OOB message.
292+
* If it were inline data, then we'd risk inserting it into the
293+
* middle of a normal data message by doing this.
294+
* (It's probably not too cool to write on stderr, for that matter...
295+
* but for debugging purposes we'll risk that.)
296+
*/
297+
298+
static PGconn * cancelConn = NULL; /* connection to try cancel on */
299+
300+
static void
301+
handle_sigint (SIGNAL_ARGS)
302+
{
303+
if (cancelConn == NULL)
304+
exit(1); /* accept signal if no connection */
305+
/* Try to send cancel request */
306+
if (PQrequestCancel(cancelConn))
307+
{
308+
fprintf(stderr, "\nCANCEL request sent\n");
309+
}
310+
else
311+
{
312+
fprintf(stderr, "\nCannot send cancel request:\n%s\n",
313+
PQerrorMessage(cancelConn));
314+
}
315+
}
316+
317+
286318
/*
287319
* listAllDbs
288320
*
@@ -1099,8 +1131,7 @@ SendQuery(bool *success_p, PsqlSettings *pset, const char *query,
10991131
exit(2); /* we are out'ta here */
11001132
}
11011133
/* check for asynchronous returns */
1102-
notify = PQnotifies(pset->db);
1103-
if (notify)
1134+
while ((notify = PQnotifies(pset->db)) != NULL)
11041135
{
11051136
fprintf(stderr,
11061137
"ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
@@ -1416,6 +1447,7 @@ do_connect(const char *new_dbname,
14161447
}
14171448
else
14181449
{
1450+
cancelConn = pset->db; /* redirect sigint's loving attentions */
14191451
PQfinish(olddb);
14201452
free(pset->prompt);
14211453
pset->prompt = malloc(strlen(PQdb(pset->db)) + 10);
@@ -2462,11 +2494,18 @@ main(int argc, char **argv)
24622494
settings.opt.fieldSep = strdup(DEFAULT_FIELD_SEP);
24632495
settings.opt.pager = 1;
24642496
if (!isatty(0) || !isatty(1))
2497+
{
2498+
/* Noninteractive defaults */
24652499
settings.notty = 1;
2466-
#ifdef USE_READLINE
2500+
}
24672501
else
2502+
{
2503+
/* Interactive defaults */
2504+
pqsignal(SIGINT, handle_sigint); /* control-C => cancel */
2505+
#ifdef USE_READLINE
24682506
settings.useReadline = 1;
24692507
#endif
2508+
}
24702509
#ifdef PSQL_ALWAYS_GET_PASSWORDS
24712510
settings.getPassword = 1;
24722511
#else
@@ -2580,6 +2619,9 @@ main(int argc, char **argv)
25802619
PQfinish(settings.db);
25812620
exit(1);
25822621
}
2622+
2623+
cancelConn = settings.db; /* enable SIGINT to send cancel */
2624+
25832625
if (listDatabases)
25842626
{
25852627
exit(listAllDbs(&settings));

src/include/libpq/pqcomm.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Id: pqcomm.h,v 1.24 1998/03/02 05:42:15 scrappy Exp $
9+
* $Id: pqcomm.h,v 1.25 1998/05/06 23:50:32 momjian Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -66,7 +66,7 @@ typedef union SockAddr
6666
/* The earliest and latest frontend/backend protocol version supported. */
6767

6868
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(0,0)
69-
#define PG_PROTOCOL_LATEST PG_PROTOCOL(1,0)
69+
#define PG_PROTOCOL_LATEST PG_PROTOCOL(2,0)
7070

7171
/*
7272
* All packets sent to the postmaster start with the length. This is omitted

0 commit comments

Comments
 (0)