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

Commit e2b7d0c

Browse files
committed
Improve the recently-added libpq events code to provide more consistent
guarantees about whether event procedures will receive DESTROY events. They no longer need to defend themselves against getting a DESTROY without a successful prior CREATE. Andrew Chernow
1 parent 7626f2a commit e2b7d0c

File tree

4 files changed

+53
-31
lines changed

4 files changed

+53
-31
lines changed

doc/src/sgml/libpq.sgml

+19-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.261 2008/09/17 04:31:08 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.262 2008/09/19 16:40:40 tgl Exp $ -->
22

33
<chapter id="libpq">
44
<title><application>libpq</application> - C Library</title>
@@ -4914,7 +4914,9 @@ typedef struct
49144914
<structname>PGconn</structname> that should be in the
49154915
<literal>CONNECTION_OK</literal> status; guaranteed if one calls
49164916
<function>PQregisterEventProc</function> right after obtaining a good
4917-
<structname>PGconn</structname>.
4917+
<structname>PGconn</structname>. When returning a failure code, all
4918+
cleanup must be performed as no <literal>PGEVT_CONNDESTROY</literal>
4919+
event will be sent.
49184920
</para>
49194921
</listitem>
49204922
</varlistentry>
@@ -4944,7 +4946,10 @@ typedef struct
49444946
<structname>PGEventConnReset *</structname>. Although the contained
49454947
<structname>PGconn</structname> was just reset, all event data remains
49464948
unchanged. This event should be used to reset/reload/requery any
4947-
associated <literal>instanceData</literal>.
4949+
associated <literal>instanceData</literal>. Note that even if the
4950+
event procedure fails to process <literal>PGEVT_CONNRESET</>, it will
4951+
still receive a <literal>PGEVT_CONNDESTROY</> event when the connection
4952+
is closed.
49484953
</para>
49494954
</listitem>
49504955
</varlistentry>
@@ -5003,7 +5008,9 @@ typedef struct
50035008
<literal>instanceData</literal> that needs to be associated with the
50045009
result. If the event procedure fails, the result will be cleared and
50055010
the failure will be propagated. The event procedure must not try to
5006-
<function>PQclear</> the result object for itself.
5011+
<function>PQclear</> the result object for itself. When returning a
5012+
failure code, all cleanup must be performed as no
5013+
<literal>PGEVT_RESULTDESTROY</literal> event will be sent.
50075014
</para>
50085015
</listitem>
50095016
</varlistentry>
@@ -5014,7 +5021,10 @@ typedef struct
50145021
<para>
50155022
The result copy event is fired in response to
50165023
<function>PQcopyResult</function>. This event will only be fired after
5017-
the copy is complete.
5024+
the copy is complete. Only event procedures that have
5025+
successfully handled the <literal>PGEVT_RESULTCREATE</literal>
5026+
or <literal>PGEVT_RESULTCOPY</literal> event for the source result
5027+
will receive <literal>PGEVT_RESULTCOPY</literal> events.
50185028

50195029
<synopsis>
50205030
typedef struct
@@ -5032,7 +5042,10 @@ typedef struct
50325042
can be used to provide a deep copy of <literal>instanceData</literal>,
50335043
since <literal>PQcopyResult</literal> cannot do that. If the event
50345044
procedure fails, the entire copy operation will fail and the
5035-
<parameter>dest</parameter> result will be cleared.
5045+
<parameter>dest</parameter> result will be cleared. When returning a
5046+
failure code, all cleanup must be performed as no
5047+
<literal>PGEVT_RESULTDESTROY</literal> event will be sent for the
5048+
destination result.
50365049
</para>
50375050
</listitem>
50385051
</varlistentry>

src/interfaces/libpq/fe-exec.c

+30-23
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.198 2008/09/17 04:31:08 tgl Exp $
11+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.199 2008/09/19 16:40:40 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -331,10 +331,7 @@ PQcopyResult(const PGresult *src, int flags)
331331
if (flags & PG_COPYRES_NOTICEHOOKS)
332332
dest->noticeHooks = src->noticeHooks;
333333

334-
/*
335-
* Wants to copy PGEvents? NB: this should be last, as we don't want
336-
* to trigger RESULTDESTROY events on a useless PGresult.
337-
*/
334+
/* Wants to copy PGEvents? */
338335
if ((flags & PG_COPYRES_EVENTS) && src->nEvents > 0)
339336
{
340337
dest->events = dupEvents(src->events, src->nEvents);
@@ -349,24 +346,29 @@ PQcopyResult(const PGresult *src, int flags)
349346
/* Okay, trigger PGEVT_RESULTCOPY event */
350347
for (i = 0; i < dest->nEvents; i++)
351348
{
352-
PGEventResultCopy evt;
353-
354-
evt.src = src;
355-
evt.dest = dest;
356-
if (!dest->events[i].proc(PGEVT_RESULTCOPY, &evt,
357-
dest->events[i].passThrough))
349+
if (src->events[i].resultInitialized)
358350
{
359-
PQclear(dest);
360-
return NULL;
351+
PGEventResultCopy evt;
352+
353+
evt.src = src;
354+
evt.dest = dest;
355+
if (!dest->events[i].proc(PGEVT_RESULTCOPY, &evt,
356+
dest->events[i].passThrough))
357+
{
358+
PQclear(dest);
359+
return NULL;
360+
}
361+
dest->events[i].resultInitialized = TRUE;
361362
}
362363
}
363364

364365
return dest;
365366
}
366367

367368
/*
368-
* Copy an array of PGEvents (with no extra space for more)
369-
* Does not duplicate the event instance data, sets this to NULL
369+
* Copy an array of PGEvents (with no extra space for more).
370+
* Does not duplicate the event instance data, sets this to NULL.
371+
* Also, the resultInitialized flags are all cleared.
370372
*/
371373
static PGEvent *
372374
dupEvents(PGEvent *events, int count)
@@ -381,13 +383,13 @@ dupEvents(PGEvent *events, int count)
381383
if (!newEvents)
382384
return NULL;
383385

384-
memcpy(newEvents, events, count * sizeof(PGEvent));
385-
386-
/* NULL out the data pointers and deep copy names */
387386
for (i = 0; i < count; i++)
388387
{
388+
newEvents[i].proc = events[i].proc;
389+
newEvents[i].passThrough = events[i].passThrough;
389390
newEvents[i].data = NULL;
390-
newEvents[i].name = strdup(newEvents[i].name);
391+
newEvents[i].resultInitialized = FALSE;
392+
newEvents[i].name = strdup(events[i].name);
391393
if (!newEvents[i].name)
392394
{
393395
while (--i >= 0)
@@ -666,11 +668,15 @@ PQclear(PGresult *res)
666668

667669
for (i = 0; i < res->nEvents; i++)
668670
{
669-
PGEventResultDestroy evt;
671+
/* only send DESTROY to successfully-initialized event procs */
672+
if (res->events[i].resultInitialized)
673+
{
674+
PGEventResultDestroy evt;
670675

671-
evt.result = res;
672-
(void) res->events[i].proc(PGEVT_RESULTDESTROY, &evt,
673-
res->events[i].passThrough);
676+
evt.result = res;
677+
(void) res->events[i].proc(PGEVT_RESULTDESTROY, &evt,
678+
res->events[i].passThrough);
679+
}
674680
free(res->events[i].name);
675681
}
676682

@@ -1612,6 +1618,7 @@ PQgetResult(PGconn *conn)
16121618
res->resultStatus = PGRES_FATAL_ERROR;
16131619
break;
16141620
}
1621+
res->events[i].resultInitialized = TRUE;
16151622
}
16161623
}
16171624

src/interfaces/libpq/libpq-events.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-events.c,v 1.1 2008/09/17 04:31:08 tgl Exp $
11+
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-events.c,v 1.2 2008/09/19 16:40:40 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -76,6 +76,7 @@ PQregisterEventProc(PGconn *conn, PGEventProc proc,
7676
return FALSE;
7777
conn->events[conn->nEvents].passThrough = passThrough;
7878
conn->events[conn->nEvents].data = NULL;
79+
conn->events[conn->nEvents].resultInitialized = FALSE;
7980
conn->nEvents++;
8081

8182
regevt.conn = conn;

src/interfaces/libpq/libpq-int.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
15-
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.132 2008/09/17 04:31:08 tgl Exp $
15+
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.133 2008/09/19 16:40:40 tgl Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -156,6 +156,7 @@ typedef struct PGEvent
156156
char *name; /* used only for error messages */
157157
void *passThrough; /* pointer supplied at registration time */
158158
void *data; /* optional state (instance) data */
159+
bool resultInitialized; /* T if RESULTCREATE/COPY succeeded */
159160
} PGEvent;
160161

161162
struct pg_result

0 commit comments

Comments
 (0)