From: Alvaro Herrera <alvherre@commandprompt.com>
To: Andrew Chernow <ac@esilo.com>
Cc: Merlin Moncure <mmoncure@gmail.com>
Cc: Pg Hackers <pgsql-hackers@postgresql.org>
Subject: Re: libpq object hooks (libpq events)
Date: Tue, 2 Sep 2008 20:19:20 -0400
Message-ID: <20080903001920.GT12610@alvh.no-ip.org> (raw)
In-Reply-To: <48325386.2010506@esilo.com>
References: <19342.1210776271@sss.pgh.pa.us>
<b42b73150805140921v30d24b75m6c230932c61ffdd2@mail.gmail.com>
<482B1480.1070705@esilo.com>
<482B2AC5.7000503@esilo.com>
<482ECF62.7010901@esilo.com>
<12200.1211242959@sss.pgh.pa.us>
<48323593.4060302@esilo.com>
<13642.1211251078@sss.pgh.pa.us>
<48323F94.6010201@esilo.com>
<48325386.2010506@esilo.com>
Andrew Chernow escribió:
> Attached is the latest patch. It has addressed the requested changes
> found here:
> http://archives.postgresql.org/pgsql-patches/2008-05/msg00389.php
>
> Its a tarball because there are two new files, libpq-events.c and
> libpq-events.h. The patch is in the tarball as well as attached to the
> email.
I modified this patch slightly. I was about to try libpqtypes on it,
but then I noticed that libpqtypes as published on pgfoundry is based on
a very old version of this patch, so I punted. So, for now, the only
guarantee is that it compiles with no warnings.
However, the only change of any significance that I introduced was that
a "name" is attached to every event proc, so that it can be reported in
error messages, as reporting only %p seems very useless. (I also
removed PQresultAlloc.)
The API seems reasonable to me.
There's one thing that seems a bit baroque, which is the
PG_COPYRES_USE_ATTRS stuff in PQcopyResult. I think that flag
introduces different enough behavior that it should be a routine of its
own, say PQcopyResultAttrs. That way you would leave out the two extra
params in PQcopyResult.
Oh -- one last thing. I am not really sure about the flags to
PQcopyResult. Should there really be flags to _remove_ behavior,
instead of flags that add? i.e. instead of having "0" copy everything,
and have to pass flags for things not to copy, wouldn't it be cleaner to
have 0 copy only base stuff, and require flags to copy extra things?
The main missing thing from this patch is SGML docs for the new libpq
functions.
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Attachments:pqevents.patch (text/x-diff, 21.3K) download
Index: src/interfaces/libpq/Makefile
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/interfaces/libpq/Makefile,v
retrieving revision 1.166
diff -c -p -r1.166 Makefile
*** src/interfaces/libpq/Makefile 16 Apr 2008 14:19:56 -0000 1.166
--- src/interfaces/libpq/Makefile 2 Sep 2008 21:54:47 -0000
*************** LIBS := $(LIBS:-lpgport=)
*** 32,38 ****
OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
! md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o \
$(filter crypt.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
ifeq ($(PORTNAME), cygwin)
--- 32,38 ----
OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
! md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o libpq-events.o \
$(filter crypt.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
ifeq ($(PORTNAME), cygwin)
*************** $(top_builddir)/src/port/pg_config_paths
*** 106,111 ****
--- 106,112 ----
install: all installdirs install-lib
$(INSTALL_DATA) $(srcdir)/libpq-fe.h '$(DESTDIR)$(includedir)'
+ $(INSTALL_DATA) $(srcdir)/libpq-events.h '$(DESTDIR)$(includedir)'
$(INSTALL_DATA) $(srcdir)/libpq-int.h '$(DESTDIR)$(includedir_internal)'
$(INSTALL_DATA) $(srcdir)/pqexpbuffer.h '$(DESTDIR)$(includedir_internal)'
$(INSTALL_DATA) $(srcdir)/pg_service.conf.sample '$(DESTDIR)$(datadir)/pg_service.conf.sample'
*************** installdirs: installdirs-lib
*** 114,120 ****
$(mkinstalldirs) '$(DESTDIR)$(includedir)' '$(DESTDIR)$(includedir_internal)'
uninstall: uninstall-lib
! rm -f '$(DESTDIR)$(includedir)/libpq-fe.h' '$(DESTDIR)$(includedir_internal)/libpq-int.h' '$(DESTDIR)$(includedir_internal)/pqexpbuffer.h' '$(DESTDIR)$(datadir)/pg_service.conf.sample'
clean distclean: clean-lib
rm -f $(OBJS) pg_config_paths.h crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
--- 115,121 ----
$(mkinstalldirs) '$(DESTDIR)$(includedir)' '$(DESTDIR)$(includedir_internal)'
uninstall: uninstall-lib
! rm -f '$(DESTDIR)$(includedir)/libpq-fe.h' '$(DESTDIR)$(includedir)/libpq-events.h' '$(DESTDIR)$(includedir_internal)/libpq-int.h' '$(DESTDIR)$(includedir_internal)/pqexpbuffer.h' '$(DESTDIR)$(datadir)/pg_service.conf.sample'
clean distclean: clean-lib
rm -f $(OBJS) pg_config_paths.h crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
Index: src/interfaces/libpq/exports.txt
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/interfaces/libpq/exports.txt,v
retrieving revision 1.19
diff -c -p -r1.19 exports.txt
*** src/interfaces/libpq/exports.txt 19 Mar 2008 00:39:33 -0000 1.19
--- src/interfaces/libpq/exports.txt 2 Sep 2008 22:41:17 -0000
*************** PQconnectionUsedPassword 138
*** 141,143 ****
--- 141,152 ----
pg_valid_server_encoding_id 139
PQconnectionNeedsPassword 140
lo_import_with_oid 141
+ PQcopyResult 142+ PQsetvalue 143+ PQregisterEventProc 144+ PQinstanceData 145+ PQsetInstanceData 146+ PQresultInstanceData 147+ PQresultSetInstanceData 148+ PQpassThroughData 149+ PQresultPassThroughData 150
Index: src/interfaces/libpq/fe-connect.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/interfaces/libpq/fe-connect.c,v
retrieving revision 1.359
diff -c -p -r1.359 fe-connect.c
*** src/interfaces/libpq/fe-connect.c 29 May 2008 22:02:44 -0000 1.359
--- src/interfaces/libpq/fe-connect.c 2 Sep 2008 23:22:02 -0000
*************** makeEmptyPGconn(void)
*** 1974,1979 ****
--- 1974,1998 ----
static void
freePGconn(PGconn *conn)
{
+ int i;+ PGEventConnDestroy evt;+ + /* Let the event procs cleanup their state data */+ for (i = 0; i < conn->nEvents; i++)+ {+ evt.conn = conn;+ (void)conn->events[i].proc(PGEVT_CONNDESTROY, &evt);+ free(conn->events[i].name);+ }+ + /* free the PGEvent array */+ if (conn->events)+ {+ free(conn->events);+ conn->events = NULL;+ conn->nEvents = conn->eventArrSize = 0;+ }+
if (conn->pghost)
free(conn->pghost);
if (conn->pghostaddr)
*************** PQreset(PGconn *conn)
*** 2155,2162 ****
{
closePGconn(conn);
! if (connectDBStart(conn))
! (void) connectDBComplete(conn);
}
}
--- 2174,2198 ----
{
closePGconn(conn);
! if (connectDBStart(conn) && connectDBComplete(conn))
! {
! int i;
! PGEventConnReset evt;
!
! for (i = 0; i < conn->nEvents; i++)
! {
! evt.conn = conn;
!
! if(!conn->events[i].proc(PGEVT_CONNRESET, &evt))
! {
! conn->status = CONNECTION_BAD;
! printfPQExpBuffer(&conn->errorMessage,
! libpq_gettext("PGEvent \"%s\" failed during PGEVT_CONNRESET event\n"),
! conn->events[i].name);
! break;
! }
! }
! }
}
}
*************** PostgresPollingStatusType
*** 2190,2196 ****
PQresetPoll(PGconn *conn)
{
if (conn)
! return PQconnectPoll(conn);
return PGRES_POLLING_FAILED;
}
--- 2226,2256 ----
PQresetPoll(PGconn *conn)
{
if (conn)
! {
! PostgresPollingStatusType status = PQconnectPoll(conn);
!
! if (status == PGRES_POLLING_OK)
! {
! int i;
! PGEventConnReset evt;
!
! for (i = 0; i < conn->nEvents; i++)
! {
! evt.conn = conn;
!
! if (!conn->events[i].proc(PGEVT_CONNRESET, &evt))
! {
! conn->status = CONNECTION_BAD;
! printfPQExpBuffer(&conn->errorMessage,
! libpq_gettext("PGEvent \"%s\" failed during PGEVT_CONNRESET event\n"),
! conn->events[i].name);
! return PGRES_POLLING_FAILED;
! }
! }
! }
!
! return status;
! }
return PGRES_POLLING_FAILED;
}
Index: src/interfaces/libpq/fe-exec.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/interfaces/libpq/fe-exec.c,v
retrieving revision 1.196
diff -c -p -r1.196 fe-exec.c
*** src/interfaces/libpq/fe-exec.c 23 Jun 2008 21:10:49 -0000 1.196
--- src/interfaces/libpq/fe-exec.c 2 Sep 2008 23:21:12 -0000
*************** static bool PQexecStart(PGconn *conn);
*** 63,68 ****
--- 63,69 ----
static PGresult *PQexecFinish(PGconn *conn);
static int PQsendDescribe(PGconn *conn, char desc_type,
const char *desc_target);
+ static int check_field_number(const PGresult *res, int field_num);
/* ----------------
*************** static int PQsendDescribe(PGconn *conn,
*** 125,134 ****
/*
* PQmakeEmptyPGresult
* returns a newly allocated, initialized PGresult with given status.
* If conn is not NULL and status indicates an error, the conn's
! * errorMessage is copied.
*
* Note this is exported --- you wouldn't think an application would need
* to build its own PGresults, but this has proven useful in both libpgtcl
--- 126,163 ----
/*
+ * Creates a copy of a PGEvent array. The event proc name is not allocated+ * separately.+ *+ * Note that it doesn't duplicate the event instance data; it is left NULL.+ */+ static PGEvent *+ dupEvents(PGEvent *events, int count)+ {+ int i;+ PGEvent *newEvents;+ + if (!events || count <= 0)+ return NULL;+ + newEvents = (PGEvent *) malloc(count * sizeof(PGEvent));+ if (!newEvents)+ return NULL;+ + memcpy(newEvents, events, count * sizeof(PGEvent));+ + /* NULL out the data pointer */+ for (i = 0; i < count; i++)+ newEvents[i].data = NULL;+ + return newEvents;+ }+ + /*
* PQmakeEmptyPGresult
* returns a newly allocated, initialized PGresult with given status.
* If conn is not NULL and status indicates an error, the conn's
! * errorMessage and events state are copied.
*
* Note this is exported --- you wouldn't think an application would need
* to build its own PGresults, but this has proven useful in both libpgtcl
*************** PQmakeEmptyPGresult(PGconn *conn, ExecSt
*** 160,165 ****
--- 189,196 ----
result->curBlock = NULL;
result->curOffset = 0;
result->spaceLeft = 0;
+ result->nEvents = 0;+ result->events = NULL;
if (conn)
{
*************** PQmakeEmptyPGresult(PGconn *conn, ExecSt
*** 167,172 ****
--- 198,216 ----
result->noticeHooks = conn->noticeHooks;
result->client_encoding = conn->client_encoding;
+ /* copy events from connection */+ if (conn->nEvents > 0)+ {+ result->events = dupEvents(conn->events, conn->nEvents);+ if (!result->events)+ {+ PQclear(result);+ return NULL;+ }+ + result->nEvents = conn->nEvents;+ }+
/* consider copying conn's errorMessage */
switch (status)
{
*************** PQmakeEmptyPGresult(PGconn *conn, ExecSt
*** 196,201 ****
--- 240,477 ----
}
/*
+ * PQcopyResult+ * Returns a deep copy of the provided 'src' PGresult, which cannot be NULL.+ * The 'options' argument controls which portions of the result will or will+ * NOT be copied. If this value is 0, the entire result is deep copied.+ * The created result is always put into the PGRES_TUPLES_OK status. The+ * source result error message is not copied, although cmdStatus is.+ *+ * Options:+ * PG_COPYRES_NO_TUPLES - Do not copy the tuples. This option is+ * automatically enabled when PG_COPYRES_USE_ATTRS is set.+ *+ * PG_COPYRES_USE_ATTRS - Indicates that the 'numAttributes' and 'attDescs'+ * arguments should be used as the fields for the created result, rather+ * than copying them from the source result. When this option is set,+ * the tuples will NOT be copied, behaving identically to setting the+ * PG_COPYRES_NO_TUPLES option. One must use PQsetvalue to manually+ * add tuples to the returned result. NOTE: numAttributes and attDescs+ * arguments are ignored unless this option is set!+ *+ * PG_COPYRES_NO_EVENTS - Indicates that the source result's+ * events should NOT be copied to the created result.+ *+ * PG_COPYRES_NO_NOTICEHOOKS - Indicates that the source result's+ * NoticeHooks should NOT be copied to the created result.+ */+ PGresult *+ PQcopyResult(const PGresult *src, int numAttributes,+ PGresAttDesc *attDescs, int options)+ {+ int i;+ PGresult *dest;+ PGEventResultCopy evt;+ + if (!src)+ return NULL;+ + /* Automatically turn on no_tuples since use_attrs is set. It makes+ * no sense to copy tuples into an unknown set of columns.+ */+ if (options & PG_COPYRES_USE_ATTRS)+ options |= PG_COPYRES_NO_TUPLES;+ + /* If use_attrs is set, verify attr arguments. */+ if ((options & PG_COPYRES_USE_ATTRS) && (numAttributes <= 0 || !attDescs))+ return NULL;+ + dest = PQmakeEmptyPGresult((PGconn *)NULL, PGRES_TUPLES_OK);+ if (!dest)+ return NULL;+ + /* always copy these over. Is cmdStatus useful here? */+ dest->client_encoding = src->client_encoding;+ strcpy(dest->cmdStatus, src->cmdStatus);+ + /* Wants to copy notice hooks */+ if (!(options & PG_COPYRES_NO_NOTICEHOOKS))+ dest->noticeHooks = src->noticeHooks;+ + /* Copy from src result when not supplying attrs */+ if (!(options & PG_COPYRES_USE_ATTRS) && src->numAttributes > 0)+ {+ numAttributes = src->numAttributes;+ attDescs = src->attDescs;+ }+ + /* copy attrs */+ if (numAttributes > 0)+ {+ dest->attDescs = (PGresAttDesc *) pqResultAlloc(dest,+ numAttributes * sizeof(PGresAttDesc), TRUE);+ + if (!dest->attDescs)+ {+ PQclear(dest);+ return NULL;+ }+ + dest->numAttributes = numAttributes;+ memcpy(dest->attDescs, attDescs, numAttributes * sizeof(PGresAttDesc));+ + /* resultalloc the attribute names. The above memcpy has the attr+ * names pointing at the source result's private memory (or at the+ * callers provided attDescs memory).+ */+ dest->binary = 1;+ for (i = 0; i < numAttributes; i++)+ {+ if (attDescs[i].name)+ dest->attDescs[i].name = pqResultStrdup(dest, attDescs[i].name);+ else+ dest->attDescs[i].name = dest->null_field;+ + if (!dest->attDescs[i].name)+ {+ PQclear(dest);+ return NULL;+ }+ + /* Although deprecated, because results can have text+binary columns,+ * its easy enough to deduce so set it for completeness.+ */+ if (dest->attDescs[i].format == 0)+ dest->binary = 0;+ }+ }+ + /* Wants to copy result tuples: use PQsetvalue(). */+ if (!(options & PG_COPYRES_NO_TUPLES) && src->ntups > 0)+ {+ int tup, field;+ for (tup = 0; tup < src->ntups; tup++)+ for (field = 0; field < src->numAttributes; field++)+ PQsetvalue(dest, tup, field, src->tuples[tup][field].value,+ src->tuples[tup][field].len);+ }+ + /* Wants to copy PGEvents. */+ if (!(options & PG_COPYRES_NO_EVENTS) && src->nEvents > 0)+ {+ dest->events = dupEvents(src->events, src->nEvents);+ if (!dest->events)+ {+ PQclear(dest);+ return NULL;+ }+ + dest->nEvents = src->nEvents;+ }+ + /* Trigger PGEVT_RESULTCOPY event */+ for (i = 0; i < dest->nEvents; i++)+ {+ evt.src = src;+ evt.dest = dest;+ if (!dest->events[i].proc(PGEVT_RESULTCOPY, &evt))+ {+ PQclear(dest);+ return NULL;+ }+ }+ + return dest;+ }+ + int+ PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)+ {+ PGresAttValue *attval;+ + if (!check_field_number(res, field_num))+ return FALSE;+ + /* Invalid tup_num, must be <= ntups */+ if (tup_num > res->ntups)+ return FALSE;+ + /* need to grow the tuple table */+ if (res->ntups >= res->tupArrSize)+ {+ int n = res->tupArrSize ? res->tupArrSize * 2 : 128;+ PGresAttValue **tups;+ + if (res->tuples)+ tups = realloc(res->tuples, n * sizeof(PGresAttValue *));+ else+ tups = malloc(n * sizeof(PGresAttValue *));+ + if (!tups)+ return FALSE;+ + memset(tups + res->tupArrSize, 0,+ (n - res->tupArrSize) * sizeof(PGresAttValue *));+ res->tuples = tups;+ res->tupArrSize = n;+ }+ + /* need to allocate a new tuple */+ if (tup_num == res->ntups && !res->tuples[tup_num])+ {+ int i;+ PGresAttValue *tup;+ + tup = (PGresAttValue *) pqResultAlloc(res, res->numAttributes * sizeof(PGresAttValue), TRUE);+ + if (!tup)+ return FALSE;+ + /* initialize each column to NULL */+ for (i = 0; i < res->numAttributes; i++)+ {+ tup[i].len = NULL_LEN;+ tup[i].value = res->null_field;+ }+ + res->tuples[tup_num] = tup;+ res->ntups++;+ }+ + attval = &res->tuples[tup_num][field_num];+ + /* On top of NULL_LEN, treat a NULL value as a NULL field */+ if (len == NULL_LEN || value == NULL)+ {+ attval->len = NULL_LEN;+ attval->value = res->null_field;+ }+ else+ {+ if (len < 0)+ len = 0;+ + if (len == 0)+ {+ attval->len = 0;+ attval->value = res->null_field;+ }+ else+ {+ attval->value = (char *) pqResultAlloc(res, len + 1, TRUE);+ if (!attval->value)+ return FALSE;+ + attval->len = len;+ memcpy(attval->value, value, len);+ attval->value[len] = '\0';+ }+ }+ + return TRUE;+ }+ + /*
* pqResultAlloc -
* Allocate subsidiary storage for a PGresult.
*
*************** pqCatenateResultError(PGresult *res, con
*** 352,362 ****
--- 628,655 ----
void
PQclear(PGresult *res)
{
+ int i;
PGresult_data *block;
+ PGEventResultDestroy evt;
if (!res)
return;
+ /* invoke each event's destroy routine */+ for (i = 0; i < res->nEvents; i++)+ {+ evt.result = res;+ (void) res->events[i].proc(PGEVT_RESULTDESTROY, &evt);+ }+ + /* free the event array */+ if (res->events)+ {+ free(res->events);+ res->events = NULL;+ res->nEvents = 0;+ }+
/* Free all the subsidiary blocks */
while ((block = res->curBlock) != NULL)
{
*************** PQgetResult(PGconn *conn)
*** 1270,1275 ****
--- 1563,1594 ----
break;
}
+ if (res && res->nEvents > 0 &&+ (res->resultStatus == PGRES_COMMAND_OK ||+ res->resultStatus == PGRES_TUPLES_OK ||+ res->resultStatus == PGRES_EMPTY_QUERY))+ {+ int i;+ PGEventResultCreate evt;+ + for (i = 0; i < res->nEvents; i++)+ {+ evt.conn = conn;+ evt.result = res;+ + if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt))+ {+ char msg[256];+ sprintf(msg,+ "PGEvent \"%s\" failed during PGEVT_RESULTCREATE event",+ res->events[i].name);+ pqSetResultError(res, msg);+ res->resultStatus = PGRES_FATAL_ERROR;+ break;+ }+ }+ }+
return res;
}
Index: src/interfaces/libpq/libpq-fe.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/interfaces/libpq/libpq-fe.h,v
retrieving revision 1.142
diff -c -p -r1.142 libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h 19 Mar 2008 00:39:33 -0000 1.142
--- src/interfaces/libpq/libpq-fe.h 2 Sep 2008 23:23:48 -0000
*************** extern "C"
*** 28,33 ****
--- 28,42 ----
*/
#include "postgres_ext.h"
+ /* -----------------------+ * Options for PQcopyResult+ */+ + #define PG_COPYRES_NO_TUPLES 0x01+ #define PG_COPYRES_USE_ATTRS 0x02+ #define PG_COPYRES_NO_EVENTS 0x04+ #define PG_COPYRES_NO_NOTICEHOOKS 0x08+
/* Application-visible enum types */
typedef enum
*************** typedef struct
*** 193,198 ****
--- 202,222 ----
} PQArgBlock;
/* ----------------
+ * PGresAttDesc -- Data about a single attribute (column) of a query result+ * ----------------+ */+ typedef struct pgresAttDesc+ {+ char *name; /* column name */+ Oid tableid; /* source table, if known */+ int columnid; /* source column, if known */+ int format; /* format code for value (text/binary) */+ Oid typid; /* type id */+ int typlen; /* type size */+ int atttypmod; /* type-specific modifier info */+ } PGresAttDesc;+ + /* ----------------
* Exported functions of libpq
* ----------------
*/
*************** extern void PQfreemem(void *ptr);
*** 437,442 ****
--- 461,481 ----
*/
extern PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
+ extern PGresult *+ PQcopyResult(const PGresult *src, int numAttributes,+ PGresAttDesc *attDescs, int options);+ + /*+ * Sets the value for a tuple field. The tup_num must be less than or+ * equal to PQntuples(res). This function will generate tuples as needed.+ * A new tuple is generated when tup_num equals PQntuples(res) and there+ * are no fields defined for that tuple.+ *+ * Returns a non-zero value for success and zero for failure.+ */+ extern int+ PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len);+
/* Quoting strings before inclusion in queries. */
extern size_t PQescapeStringConn(PGconn *conn,
Index: src/interfaces/libpq/libpq-int.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/interfaces/libpq/libpq-int.h,v
retrieving revision 1.131
diff -c -p -r1.131 libpq-int.h
*** src/interfaces/libpq/libpq-int.h 29 May 2008 22:02:44 -0000 1.131
--- src/interfaces/libpq/libpq-int.h 2 Sep 2008 23:24:39 -0000
***************
*** 22,27 ****
--- 22,28 ----
/* We assume libpq-fe.h has already been included. */
#include "postgres_fe.h"
+ #include "libpq-events.h"
#include <time.h>
#include <sys/types.h>
*************** union pgresult_data
*** 100,118 ****
char space[1]; /* dummy for accessing block as bytes */
};
- /* Data about a single attribute (column) of a query result */- - typedef struct pgresAttDesc- {- char *name; /* column name */- Oid tableid; /* source table, if known */- int columnid; /* source column, if known */- int format; /* format code for value (text/binary) */- Oid typid; /* type id */- int typlen; /* type size */- int atttypmod; /* type-specific modifier info */- } PGresAttDesc;-
/* Data about a single parameter of a prepared statement */
typedef struct pgresParamDesc
{
--- 101,106 ----
*************** typedef struct
*** 162,167 ****
--- 150,164 ----
void *noticeProcArg;
} PGNoticeHooks;
+ /* Fields needed for PGEvent processing */+ typedef struct+ {+ char *name; /* for error messages */+ void *passThrough; /* pointer supplied by user */+ void *data; /* state data, optionally generated by event proc */+ PGEventProc proc; /* the function to call on events */+ } PGEvent;+
struct pg_result
{
int ntups;
*************** struct pg_result
*** 184,189 ****
--- 181,190 ----
PGNoticeHooks noticeHooks;
int client_encoding; /* encoding id */
+ /* registered events, copied from conn */+ int nEvents;+ PGEvent *events;+
/*
* Error information (all NULL if not an error result). errMsg is the
* "overall" error message returned by PQresultErrorMessage. If we have
*************** struct pg_conn
*** 303,308 ****
--- 304,314 ----
/* Callback procedures for notice message processing */
PGNoticeHooks noticeHooks;
+ /* registered events via PQregisterEventProc */+ int nEvents;+ int eventArrSize;+ PGEvent *events;+
/* Status indicators */
ConnStatusType status;
PGAsyncStatusType asyncStatus;
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-patches@postgresql.org
Cc: alvherre@commandprompt.com, ac@esilo.com, mmoncure@gmail.com, pgsql-hackers@postgresql.org
Subject: Re: libpq object hooks (libpq events)
In-Reply-To: <20080903001920.GT12610@alvh.no-ip.org>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox