Re: [PATCHES] libpq events patch (with sgml docs) - Mailing list pgsql-hackers

From Andrew Chernow
Subject Re: [PATCHES] libpq events patch (with sgml docs)
Date
Msg-id 48D3EBEC.1040503@esilo.com
Whole thread Raw
In response to Re: [PATCHES] libpq events patch (with sgml docs)  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: [PATCHES] libpq events patch (with sgml docs)  ("Merlin Moncure" <mmoncure@gmail.com>)
Re: [PATCHES] libpq events patch (with sgml docs)  (Tom Lane <tgl@sss.pgh.pa.us>)
Re: [PATCHES] libpq events patch (with sgml docs)  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-hackers
Tom Lane wrote:
>
> I'll go ahead and apply this patch in a little bit, but if you concur
> with the above reasoning, please put together a followon patch to add
> such a function.
>
>             regards, tom lane
>
>

I attached a patch.  You have to copy the events in PQmakeEmptyPGResult
because there is no where else to do this, other than copyresult but
that is different because it copies from a result not a conn.

PQmakeEmptyPGResult - must copy events here
PQsetResultAttrs - set attributes
PQsetvalue - set tuple values
PQfireResultCreateEvents(conn,res) - now fire resultcreate event

PQgetResult now calls PQfireResultCreateEvents.

BTW, the event system might be an alternative solution for PGNoticeHooks
(PGEVT_NOTICE).

--
Andrew Chernow
eSilo, LLC
every bit counts
http://www.esilo.com/
Index: doc/src/sgml/libpq.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/libpq.sgml,v
retrieving revision 1.262
diff -C6 -r1.262 libpq.sgml
*** doc/src/sgml/libpq.sgml    19 Sep 2008 16:40:40 -0000    1.262
--- doc/src/sgml/libpq.sgml    19 Sep 2008 18:05:55 -0000
***************
*** 4592,4604 ****
        <parameter>conn</parameter> is not null and <parameter>status</>
        indicates an error, the current error message of the specified
        connection is copied into the <structname>PGresult</structname>.
        Also, if <parameter>conn</parameter> is not null, any event handlers
        registered in the connection are copied into the
        <structname>PGresult</structname> (but they don't get
!       <literal>PGEVT_RESULTCREATE</> calls).
        Note that <function>PQclear</function> should eventually be called
        on the object, just as with a <structname>PGresult</structname>
        returned by <application>libpq</application> itself.
       </para>
      </listitem>
     </varlistentry>
--- 4592,4606 ----
        <parameter>conn</parameter> is not null and <parameter>status</>
        indicates an error, the current error message of the specified
        connection is copied into the <structname>PGresult</structname>.
        Also, if <parameter>conn</parameter> is not null, any event handlers
        registered in the connection are copied into the
        <structname>PGresult</structname> (but they don't get
!       <literal>PGEVT_RESULTCREATE</> calls).  Although,
!       <function>PQfireResultCreateEvents</function> can be used to fire
!       <literal>PGEVT_RESULTCREATE</> events.
        Note that <function>PQclear</function> should eventually be called
        on the object, just as with a <structname>PGresult</structname>
        returned by <application>libpq</application> itself.
       </para>
      </listitem>
     </varlistentry>
***************
*** 5242,5253 ****
--- 5244,5279 ----
          void *PQresultInstanceData(const PGresult *res, PGEventProc proc);
         </synopsis>
        </para>
       </listitem>
      </varlistentry>
     </variablelist>
+
+     <varlistentry>
+      <term>
+       <function>PQfireResultCreateEvents</function>
+       <indexterm>
+        <primary>PQfireResultCreateEvents</primary>
+       </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Manually fires a <literal>PGEVT_RESULTCREATE</literal> event.  This is
+        useful for applications that create a result using
+        <function>PQmakeEmptyPGResult</function>, which does not fire a
+        <literal>PGEVT_RESULTCREATE</literal> event.  It allows an application
+        to create the result, fill it and then fire the creation event.  This
+        returns non-zero for success and zero for failure.
+
+        <synopsis>
+         int PQfireResultCreateEvents(const PGconn conn, PGresult *res);
+        </synopsis>
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
    </sect2>

    <sect2 id="libpq-events-example">
     <title>Event Example</title>

     <para>
Index: src/interfaces/libpq/exports.txt
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/exports.txt,v
retrieving revision 1.20
diff -C6 -r1.20 exports.txt
*** src/interfaces/libpq/exports.txt    17 Sep 2008 04:31:08 -0000    1.20
--- src/interfaces/libpq/exports.txt    19 Sep 2008 18:05:55 -0000
***************
*** 147,152 ****
--- 147,153 ----
  PQresultAlloc             145
  PQregisterEventProc       146
  PQinstanceData            147
  PQsetInstanceData         148
  PQresultInstanceData      149
  PQresultSetInstanceData   150
+ PQfireResultCreateEvents  151
Index: src/interfaces/libpq/fe-exec.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v
retrieving revision 1.199
diff -C6 -r1.199 fe-exec.c
*** src/interfaces/libpq/fe-exec.c    19 Sep 2008 16:40:40 -0000    1.199
--- src/interfaces/libpq/fe-exec.c    19 Sep 2008 18:05:55 -0000
***************
*** 1595,1630 ****
                                libpq_gettext("unexpected asyncStatus: %d\n"),
                                (int) conn->asyncStatus);
              res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
              break;
      }

!     if (res)
!     {
!         int i;
!
!         for (i = 0; i < res->nEvents; i++)
!         {
!             PGEventResultCreate evt;
!
!             evt.conn = conn;
!             evt.result = res;
!             if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt,
!                                      res->events[i].passThrough))
!             {
!                 printfPQExpBuffer(&conn->errorMessage,
!                                   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;
  }


  /*
   * PQexec
--- 1595,1608 ----
                                libpq_gettext("unexpected asyncStatus: %d\n"),
                                (int) conn->asyncStatus);
              res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);
              break;
      }

!     /* Function performs error handling: message and resultStatus. */
!     (void) PQfireResultCreateEvents(conn, res);
      return res;
  }


  /*
   * PQexec
Index: src/interfaces/libpq/libpq-events.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/libpq-events.c,v
retrieving revision 1.2
diff -C6 -r1.2 libpq-events.c
*** src/interfaces/libpq/libpq-events.c    19 Sep 2008 16:40:40 -0000    1.2
--- src/interfaces/libpq/libpq-events.c    19 Sep 2008 18:05:55 -0000
***************
*** 172,177 ****
--- 172,209 ----
      for (i = 0; i < result->nEvents; i++)
          if (result->events[i].proc == proc)
              return result->events[i].data;

      return NULL;
  }
+
+ int
+ PQfireResultCreateEvents(const PGconn *conn, PGresult *res)
+ {
+     int i;
+
+     if (!conn || !res)
+         return FALSE;
+
+     for (i = 0; i < res->nEvents; i++)
+     {
+         PGEventResultCreate evt;
+
+         evt.conn = conn;
+         evt.result = res;
+         if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt,
+                                  res->events[i].passThrough))
+         {
+             printfPQExpBuffer(&conn->errorMessage,
+                               libpq_gettext("PGEventProc \"%s\" failed during PGEVT_RESULTCREATE event\n"),
+                               res->events[i].name);
+             pqSetResultError(res, conn->errorMessage.data);
+             res->resultStatus = PGRES_FATAL_ERROR;
+             return FALSE;
+         }
+
+         res->events[i].resultInitialized = TRUE;
+     }
+
+     return TRUE;
+ }
+
Index: src/interfaces/libpq/libpq-events.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/libpq-events.h,v
retrieving revision 1.1
diff -C6 -r1.1 libpq-events.h
*** src/interfaces/libpq/libpq-events.h    17 Sep 2008 04:31:08 -0000    1.1
--- src/interfaces/libpq/libpq-events.h    19 Sep 2008 18:05:55 -0000
***************
*** 81,91 ****
--- 81,93 ----
  /* Sets the PGresult instance data for the provided proc to data. */
  extern int    PQresultSetInstanceData(PGresult *result, PGEventProc proc, void *data);

  /* Gets the PGresult instance data for the provided proc. */
  extern void *PQresultInstanceData(const PGresult *result, PGEventProc proc);

+ extern int PQfireResultCreateEvents(const PGconn *conn, PGresult *res);
+
  #ifdef __cplusplus
  }
  #endif

  #endif /* LIBPQ_EVENTS_H */

pgsql-hackers by date:

Previous
From: Joshua Drake
Date:
Subject: Re: Where to Host Project
Next
From: Robert Treat
Date:
Subject: Re: Where to Host Project