Index: doc/src/sgml/libpq.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/libpq.sgml,v
retrieving revision 1.261
diff -C6 -r1.261 libpq.sgml
*** doc/src/sgml/libpq.sgml 17 Sep 2008 04:31:08 -0000 1.261
--- doc/src/sgml/libpq.sgml 17 Sep 2008 14:19:29 -0000
***************
*** 4911,4923 ****
When a PGEVT_REGISTER event is received, the
evtInfo pointer should be cast to a
PGEventRegister *. This structure contains a
PGconn that should be in the
CONNECTION_OK status; guaranteed if one calls
PQregisterEventProc right after obtaining a good
! PGconn.
PGEVT_CONNRESET
--- 4911,4925 ----
When a PGEVT_REGISTER event is received, the
evtInfo pointer should be cast to a
PGEventRegister *. This structure contains a
PGconn that should be in the
CONNECTION_OK status; guaranteed if one calls
PQregisterEventProc right after obtaining a good
! PGconn. When returning a failure code, all
! cleanup must be performed as no PGEVT_CONNDESTROY
! event will be sent.
PGEVT_CONNRESET
***************
*** 4941,4953 ****
When a PGEVT_CONNRESET event is received, the
evtInfo pointer should be cast to a
PGEventConnReset *. Although the contained
PGconn was just reset, all event data remains
unchanged. This event should be used to reset/reload/requery any
! associated instanceData.
PGEVT_CONNDESTROY
--- 4943,4956 ----
When a PGEVT_CONNRESET event is received, the
evtInfo pointer should be cast to a
PGEventConnReset *. Although the contained
PGconn was just reset, all event data remains
unchanged. This event should be used to reset/reload/requery any
! associated instanceData. A PGEVT_CONNDESTROY event
! is always sent, regardless of the event procedure's return value.
PGEVT_CONNDESTROY
***************
*** 5000,5023 ****
PGEventResultCreate *. The
conn is the connection used to generate the
result. This is the ideal place to initialize any
instanceData that needs to be associated with the
result. If the event procedure fails, the result will be cleared and
the failure will be propagated. The event procedure must not try to
! PQclear> the result object for itself.
PGEVT_RESULTCOPY
The result copy event is fired in response to
PQcopyResult. This event will only be fired after
! the copy is complete.
typedef struct
{
const PGresult *src;
PGresult *dest;
--- 5003,5030 ----
PGEventResultCreate *. The
conn is the connection used to generate the
result. This is the ideal place to initialize any
instanceData that needs to be associated with the
result. If the event procedure fails, the result will be cleared and
the failure will be propagated. The event procedure must not try to
! PQclear> the result object for itself. When returning a
! failure code, all cleanup must be performed as no
! PGEVT_RESULTDESTROY event will be sent.
PGEVT_RESULTCOPY
The result copy event is fired in response to
PQcopyResult. This event will only be fired after
! the copy is complete. Only source result event procedures that have
! successfully handled the PGEVT_RESULTCREATE event,
! will be copied to the destination result.
typedef struct
{
const PGresult *src;
PGresult *dest;
***************
*** 5029,5041 ****
PGEventResultCopy *. The
src result is what was copied while the
dest result is the copy destination. This event
can be used to provide a deep copy of instanceData,
since PQcopyResult cannot do that. If the event
procedure fails, the entire copy operation will fail and the
! dest result will be cleared.
PGEVT_RESULTDESTROY
--- 5036,5050 ----
PGEventResultCopy *. The
src result is what was copied while the
dest result is the copy destination. This event
can be used to provide a deep copy of instanceData,
since PQcopyResult cannot do that. If the event
procedure fails, the entire copy operation will fail and the
! dest result will be cleared. When returning a
! failure code, all cleanup must be performed as no
! PGEVT_RESULTDESTROY event will be sent.
PGEVT_RESULTDESTROY
Index: src/interfaces/libpq/fe-exec.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v
retrieving revision 1.198
diff -C6 -r1.198 fe-exec.c
*** src/interfaces/libpq/fe-exec.c 17 Sep 2008 04:31:08 -0000 1.198
--- src/interfaces/libpq/fe-exec.c 17 Sep 2008 14:19:29 -0000
***************
*** 346,366 ****
dest->nEvents = src->nEvents;
}
/* Okay, trigger PGEVT_RESULTCOPY event */
for (i = 0; i < dest->nEvents; i++)
{
! PGEventResultCopy evt;
!
! evt.src = src;
! evt.dest = dest;
! if (!dest->events[i].proc(PGEVT_RESULTCOPY, &evt,
! dest->events[i].passThrough))
{
! PQclear(dest);
! return NULL;
}
}
return dest;
}
--- 346,371 ----
dest->nEvents = src->nEvents;
}
/* Okay, trigger PGEVT_RESULTCOPY event */
for (i = 0; i < dest->nEvents; i++)
{
! if(src->events[i].resultInitialized)
{
! PGEventResultCopy evt;
!
! evt.src = src;
! evt.dest = dest;
! if (!dest->events[i].proc(PGEVT_RESULTCOPY, &evt,
! dest->events[i].passThrough))
! {
! PQclear(dest);
! return NULL;
! }
!
! dest->events[i].resultInitialized = TRUE;
}
}
return dest;
}
***************
*** 378,396 ****
return NULL;
newEvents = (PGEvent *) malloc(count * sizeof(PGEvent));
if (!newEvents)
return NULL;
- memcpy(newEvents, events, count * sizeof(PGEvent));
-
- /* NULL out the data pointers and deep copy names */
for (i = 0; i < count; i++)
{
newEvents[i].data = NULL;
! newEvents[i].name = strdup(newEvents[i].name);
if (!newEvents[i].name)
{
while (--i >= 0)
free(newEvents[i].name);
free(newEvents);
return NULL;
--- 383,401 ----
return NULL;
newEvents = (PGEvent *) malloc(count * sizeof(PGEvent));
if (!newEvents)
return NULL;
for (i = 0; i < count; i++)
{
+ newEvents[i].proc = events[i].proc;
+ newEvents[i].passThrough = events[i].passThrough;
+ newEvents[i].resultInitialized = FALSE;
newEvents[i].data = NULL;
! newEvents[i].name = strdup(events[i].name);
if (!newEvents[i].name)
{
while (--i >= 0)
free(newEvents[i].name);
free(newEvents);
return NULL;
***************
*** 663,679 ****
if (!res)
return;
for (i = 0; i < res->nEvents; i++)
{
! PGEventResultDestroy evt;
- evt.result = res;
- (void) res->events[i].proc(PGEVT_RESULTDESTROY, &evt,
- res->events[i].passThrough);
free(res->events[i].name);
}
if (res->events)
free(res->events);
--- 668,688 ----
if (!res)
return;
for (i = 0; i < res->nEvents; i++)
{
! if(res->events[i].resultInitialized)
! {
! PGEventResultDestroy evt;
!
! evt.result = res;
! (void) res->events[i].proc(PGEVT_RESULTDESTROY, &evt,
! res->events[i].passThrough);
! }
free(res->events[i].name);
}
if (res->events)
free(res->events);
***************
*** 1609,1620 ****
--- 1618,1631 ----
libpq_gettext("PGEventProc \"%s\" failed during PGEVT_RESULTCREATE event\n"),
res->events[i].name);
pqSetResultError(res, conn->errorMessage.data);
res->resultStatus = PGRES_FATAL_ERROR;
break;
}
+
+ res->events[i].resultInitialized = TRUE;
}
}
return res;
}
Index: src/interfaces/libpq/libpq-events.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/libpq-events.c,v
retrieving revision 1.1
diff -C6 -r1.1 libpq-events.c
*** src/interfaces/libpq/libpq-events.c 17 Sep 2008 04:31:08 -0000 1.1
--- src/interfaces/libpq/libpq-events.c 17 Sep 2008 14:19:29 -0000
***************
*** 73,84 ****
--- 73,85 ----
conn->events[conn->nEvents].proc = proc;
conn->events[conn->nEvents].name = strdup(name);
if (!conn->events[conn->nEvents].name)
return FALSE;
conn->events[conn->nEvents].passThrough = passThrough;
conn->events[conn->nEvents].data = NULL;
+ conn->events[conn->nEvents].resultInitialized = FALSE;
conn->nEvents++;
regevt.conn = conn;
if (!proc(PGEVT_REGISTER, ®evt, passThrough))
{
conn->nEvents--;
Index: src/interfaces/libpq/libpq-int.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/libpq-int.h,v
retrieving revision 1.132
diff -C6 -r1.132 libpq-int.h
*** src/interfaces/libpq/libpq-int.h 17 Sep 2008 04:31:08 -0000 1.132
--- src/interfaces/libpq/libpq-int.h 17 Sep 2008 14:19:29 -0000
***************
*** 153,164 ****
--- 153,165 ----
typedef struct PGEvent
{
PGEventProc proc; /* the function to call on events */
char *name; /* used only for error messages */
void *passThrough; /* pointer supplied at registration time */
void *data; /* optional state (instance) data */
+ int resultInitialized; /* indicates a PGEVT_RESULTCREATE succeeded. */
} PGEvent;
struct pg_result
{
int ntups;
int numAttributes;