On Fri, May 16, 2008 at 2:34 PM, Andrew Chernow <[EMAIL PROTECTED]> wrote:
> Tom Lane wrote:
>> typedef void (*PGeventProc) (PGeventId eventId, const void *eventInfo,
>>                             void *passthrough);
>> int PQregisterEventProc(PGconn *conn, PGeventProc proc, void
>> *passthrough);

> The above prototypes will work and we will add our 'event instance pointer'
> to the event info structures.  Should have a patch shortly.

Right.  I actually overlooked the 'passthrough' in
PQregisterEventProc.  It turns out that we are still not quite on the
same page and this needs to be clarified before we move on.  The
passthrough cannot exist...the correct prototypes (reasoning will
follow) are:

typedef void (*PGeventProc) (PGeventId eventId, const void *eventInfo);
int PQregisterEventProc(PGconn *conn, PGeventProc proc);
PQhookData(const PGconn* conn, PGeventProc proc);

The purpose of the callbacks is to allow a hooking library to
establish private data that is associated with a PGconn or a PGresult.
 Invoking PQregisterEventProc tells libpq 'I am interested in doing
this', for the supplied PGconn, future results created with that
connection, and (if PGconn is passed as null), all future connections.

Once that is established, libpq begins telling the hooking library
when and what needs to be allocated or deleted.  This is done for both
connections and results at the appropriate times and the management
always occurs inside a callback function.  Thus, while the hooking
library controls what is in the state data, _it does not control when
it is created or destroyed_.  Passing a void* into PQregisterEventProc
suggests that is the wrapper's purvue to establish the private
information.  It isn't, and it can't be..it's as simple as that.

For example, consider that 'hooked' PGconn then produces a result.  If
a passthrough as Tom suggested were passed around, what would you do
to it when the connection was freed (which throws a connection closing
event)?  What exactly is passthrough pointing to in a result copy
event?  If passed around as a single poitner, they are not
defined.These are pointers to different structures who are created at
particular times that only libpq knows.

All of the callbacks (except for possibly conn reset) are basically
allocation and deletion events.  For example, result create is libpq
telling the hooking library: 'a result is coming, please initialize
your result extensions now'.  At that point, a very particular
structure is passed back to the hooking library:

  const PGconn* conn;   // the source conn the result
  const void *conn_state; // the conn's private state (it might be
interesting, and we don't want to look it up later)
  const PGresult* res; // the new result's poiter
  void *out_res_state; // we are going to allocate something and set
this in the callback

As you can see, there is more going on here than a single passthrough
pointer can handle.  We are in fact doing what a passthrough provides
in principle.  I can certainly understand why our original 'lookup by
name' concept threw up a smokescreen (it did obfuscate the passing
requirements), but hooking can't be serviced by a single pointer set
at callback registration.

With the above prototypes and carefully designed structures,
everything feels natural.  libpq is defining exactly what is supposed
to happen, and the structure parameters define what is coming in and
out.  Things are being 'passed through'...but in a more discrete way.


Sent via pgsql-patches mailing list (pgsql-patches@postgresql.org)
To make changes to your subscription:

Reply via email to