????
Current Path : C:/opt/pgsql/doc/postgresql/html/ |
Current File : C:/opt/pgsql/doc/postgresql/html/libpq-events.html |
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>34.14. Event System</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="libpq-notice-processing.html" title="34.13. Notice Processing" /><link rel="next" href="libpq-envars.html" title="34.15. Environment Variables" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">34.14. Event System</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="libpq-notice-processing.html" title="34.13. Notice Processing">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="libpq.html" title="Chapter 34. libpq — C Library">Up</a></td><th width="60%" align="center">Chapter 34. <span class="application">libpq</span> — C Library</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 16.3 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="libpq-envars.html" title="34.15. Environment Variables">Next</a></td></tr></table><hr /></div><div class="sect1" id="LIBPQ-EVENTS"><div class="titlepage"><div><div><h2 class="title" style="clear: both">34.14. Event System <a href="#LIBPQ-EVENTS" class="id_link">#</a></h2></div></div></div><div class="toc"><dl class="toc"><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-TYPES">34.14.1. Event Types</a></span></dt><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-PROC">34.14.2. Event Callback Procedure</a></span></dt><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-FUNCS">34.14.3. Event Support Functions</a></span></dt><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-EXAMPLE">34.14.4. Event Example</a></span></dt></dl></div><p> <span class="application">libpq</span>'s event system is designed to notify registered event handlers about interesting <span class="application">libpq</span> events, such as the creation or destruction of <code class="structname">PGconn</code> and <code class="structname">PGresult</code> objects. A principal use case is that this allows applications to associate their own data with a <code class="structname">PGconn</code> or <code class="structname">PGresult</code> and ensure that that data is freed at an appropriate time. </p><p> Each registered event handler is associated with two pieces of data, known to <span class="application">libpq</span> only as opaque <code class="literal">void *</code> pointers. There is a <em class="firstterm">pass-through</em> pointer that is provided by the application when the event handler is registered with a <code class="structname">PGconn</code>. The pass-through pointer never changes for the life of the <code class="structname">PGconn</code> and all <code class="structname">PGresult</code>s generated from it; so if used, it must point to long-lived data. In addition there is an <em class="firstterm">instance data</em> pointer, which starts out <code class="symbol">NULL</code> in every <code class="structname">PGconn</code> and <code class="structname">PGresult</code>. This pointer can be manipulated using the <a class="xref" href="libpq-events.html#LIBPQ-PQINSTANCEDATA"><code class="function">PQinstanceData</code></a>, <a class="xref" href="libpq-events.html#LIBPQ-PQSETINSTANCEDATA"><code class="function">PQsetInstanceData</code></a>, <a class="xref" href="libpq-events.html#LIBPQ-PQRESULTINSTANCEDATA"><code class="function">PQresultInstanceData</code></a> and <a class="xref" href="libpq-events.html#LIBPQ-PQRESULTSETINSTANCEDATA"><code class="function">PQresultSetInstanceData</code></a> functions. Note that unlike the pass-through pointer, instance data of a <code class="structname">PGconn</code> is not automatically inherited by <code class="structname">PGresult</code>s created from it. <span class="application">libpq</span> does not know what pass-through and instance data pointers point to (if anything) and will never attempt to free them — that is the responsibility of the event handler. </p><div class="sect2" id="LIBPQ-EVENTS-TYPES"><div class="titlepage"><div><div><h3 class="title">34.14.1. Event Types <a href="#LIBPQ-EVENTS-TYPES" class="id_link">#</a></h3></div></div></div><p> The enum <code class="literal">PGEventId</code> names the types of events handled by the event system. All its values have names beginning with <code class="literal">PGEVT</code>. For each event type, there is a corresponding event info structure that carries the parameters passed to the event handlers. The event types are: </p><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PGEVT-REGISTER"><span class="term"><code class="literal">PGEVT_REGISTER</code></span> <a href="#LIBPQ-PGEVT-REGISTER" class="id_link">#</a></dt><dd><p> The register event occurs when <a class="xref" href="libpq-events.html#LIBPQ-PQREGISTEREVENTPROC"><code class="function">PQregisterEventProc</code></a> is called. It is the ideal time to initialize any <code class="literal">instanceData</code> an event procedure may need. Only one register event will be fired per event handler per connection. If the event procedure fails (returns zero), the registration is cancelled. </p><pre class="synopsis"> typedef struct { PGconn *conn; } PGEventRegister; </pre><p> When a <code class="literal">PGEVT_REGISTER</code> event is received, the <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a <code class="structname">PGEventRegister *</code>. This structure contains a <code class="structname">PGconn</code> that should be in the <code class="literal">CONNECTION_OK</code> status; guaranteed if one calls <a class="xref" href="libpq-events.html#LIBPQ-PQREGISTEREVENTPROC"><code class="function">PQregisterEventProc</code></a> right after obtaining a good <code class="structname">PGconn</code>. When returning a failure code, all cleanup must be performed as no <code class="literal">PGEVT_CONNDESTROY</code> event will be sent. </p></dd><dt id="LIBPQ-PGEVT-CONNRESET"><span class="term"><code class="literal">PGEVT_CONNRESET</code></span> <a href="#LIBPQ-PGEVT-CONNRESET" class="id_link">#</a></dt><dd><p> The connection reset event is fired on completion of <a class="xref" href="libpq-connect.html#LIBPQ-PQRESET"><code class="function">PQreset</code></a> or <code class="function">PQresetPoll</code>. In both cases, the event is only fired if the reset was successful. The return value of the event procedure is ignored in <span class="productname">PostgreSQL</span> v15 and later. With earlier versions, however, it's important to return success (nonzero) or the connection will be aborted. </p><pre class="synopsis"> typedef struct { PGconn *conn; } PGEventConnReset; </pre><p> When a <code class="literal">PGEVT_CONNRESET</code> event is received, the <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a <code class="structname">PGEventConnReset *</code>. Although the contained <code class="structname">PGconn</code> was just reset, all event data remains unchanged. This event should be used to reset/reload/requery any associated <code class="literal">instanceData</code>. Note that even if the event procedure fails to process <code class="literal">PGEVT_CONNRESET</code>, it will still receive a <code class="literal">PGEVT_CONNDESTROY</code> event when the connection is closed. </p></dd><dt id="LIBPQ-PGEVT-CONNDESTROY"><span class="term"><code class="literal">PGEVT_CONNDESTROY</code></span> <a href="#LIBPQ-PGEVT-CONNDESTROY" class="id_link">#</a></dt><dd><p> The connection destroy event is fired in response to <a class="xref" href="libpq-connect.html#LIBPQ-PQFINISH"><code class="function">PQfinish</code></a>. It is the event procedure's responsibility to properly clean up its event data as libpq has no ability to manage this memory. Failure to clean up will lead to memory leaks. </p><pre class="synopsis"> typedef struct { PGconn *conn; } PGEventConnDestroy; </pre><p> When a <code class="literal">PGEVT_CONNDESTROY</code> event is received, the <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a <code class="structname">PGEventConnDestroy *</code>. This event is fired prior to <a class="xref" href="libpq-connect.html#LIBPQ-PQFINISH"><code class="function">PQfinish</code></a> performing any other cleanup. The return value of the event procedure is ignored since there is no way of indicating a failure from <a class="xref" href="libpq-connect.html#LIBPQ-PQFINISH"><code class="function">PQfinish</code></a>. Also, an event procedure failure should not abort the process of cleaning up unwanted memory. </p></dd><dt id="LIBPQ-PGEVT-RESULTCREATE"><span class="term"><code class="literal">PGEVT_RESULTCREATE</code></span> <a href="#LIBPQ-PGEVT-RESULTCREATE" class="id_link">#</a></dt><dd><p> The result creation event is fired in response to any query execution function that generates a result, including <a class="xref" href="libpq-async.html#LIBPQ-PQGETRESULT"><code class="function">PQgetResult</code></a>. This event will only be fired after the result has been created successfully. </p><pre class="synopsis"> typedef struct { PGconn *conn; PGresult *result; } PGEventResultCreate; </pre><p> When a <code class="literal">PGEVT_RESULTCREATE</code> event is received, the <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a <code class="structname">PGEventResultCreate *</code>. The <em class="parameter"><code>conn</code></em> is the connection used to generate the result. This is the ideal place to initialize any <code class="literal">instanceData</code> that needs to be associated with the result. If an event procedure fails (returns zero), that event procedure will be ignored for the remaining lifetime of the result; that is, it will not receive <code class="literal">PGEVT_RESULTCOPY</code> or <code class="literal">PGEVT_RESULTDESTROY</code> events for this result or results copied from it. </p></dd><dt id="LIBPQ-PGEVT-RESULTCOPY"><span class="term"><code class="literal">PGEVT_RESULTCOPY</code></span> <a href="#LIBPQ-PGEVT-RESULTCOPY" class="id_link">#</a></dt><dd><p> The result copy event is fired in response to <a class="xref" href="libpq-misc.html#LIBPQ-PQCOPYRESULT"><code class="function">PQcopyResult</code></a>. This event will only be fired after the copy is complete. Only event procedures that have successfully handled the <code class="literal">PGEVT_RESULTCREATE</code> or <code class="literal">PGEVT_RESULTCOPY</code> event for the source result will receive <code class="literal">PGEVT_RESULTCOPY</code> events. </p><pre class="synopsis"> typedef struct { const PGresult *src; PGresult *dest; } PGEventResultCopy; </pre><p> When a <code class="literal">PGEVT_RESULTCOPY</code> event is received, the <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a <code class="structname">PGEventResultCopy *</code>. The <em class="parameter"><code>src</code></em> result is what was copied while the <em class="parameter"><code>dest</code></em> result is the copy destination. This event can be used to provide a deep copy of <code class="literal">instanceData</code>, since <code class="literal">PQcopyResult</code> cannot do that. If an event procedure fails (returns zero), that event procedure will be ignored for the remaining lifetime of the new result; that is, it will not receive <code class="literal">PGEVT_RESULTCOPY</code> or <code class="literal">PGEVT_RESULTDESTROY</code> events for that result or results copied from it. </p></dd><dt id="LIBPQ-PGEVT-RESULTDESTROY"><span class="term"><code class="literal">PGEVT_RESULTDESTROY</code></span> <a href="#LIBPQ-PGEVT-RESULTDESTROY" class="id_link">#</a></dt><dd><p> The result destroy event is fired in response to a <a class="xref" href="libpq-exec.html#LIBPQ-PQCLEAR"><code class="function">PQclear</code></a>. It is the event procedure's responsibility to properly clean up its event data as libpq has no ability to manage this memory. Failure to clean up will lead to memory leaks. </p><pre class="synopsis"> typedef struct { PGresult *result; } PGEventResultDestroy; </pre><p> When a <code class="literal">PGEVT_RESULTDESTROY</code> event is received, the <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a <code class="structname">PGEventResultDestroy *</code>. This event is fired prior to <a class="xref" href="libpq-exec.html#LIBPQ-PQCLEAR"><code class="function">PQclear</code></a> performing any other cleanup. The return value of the event procedure is ignored since there is no way of indicating a failure from <a class="xref" href="libpq-exec.html#LIBPQ-PQCLEAR"><code class="function">PQclear</code></a>. Also, an event procedure failure should not abort the process of cleaning up unwanted memory. </p></dd></dl></div></div><div class="sect2" id="LIBPQ-EVENTS-PROC"><div class="titlepage"><div><div><h3 class="title">34.14.2. Event Callback Procedure <a href="#LIBPQ-EVENTS-PROC" class="id_link">#</a></h3></div></div></div><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PGEVENTPROC"><span class="term"><code class="literal">PGEventProc</code><a id="id-1.7.3.21.5.2.1.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PGEVENTPROC" class="id_link">#</a></dt><dd><p> <code class="literal">PGEventProc</code> is a typedef for a pointer to an event procedure, that is, the user callback function that receives events from libpq. The signature of an event procedure must be </p><pre class="synopsis"> int eventproc(PGEventId evtId, void *evtInfo, void *passThrough) </pre><p> The <em class="parameter"><code>evtId</code></em> parameter indicates which <code class="literal">PGEVT</code> event occurred. The <em class="parameter"><code>evtInfo</code></em> pointer must be cast to the appropriate structure type to obtain further information about the event. The <em class="parameter"><code>passThrough</code></em> parameter is the pointer provided to <a class="xref" href="libpq-events.html#LIBPQ-PQREGISTEREVENTPROC"><code class="function">PQregisterEventProc</code></a> when the event procedure was registered. The function should return a non-zero value if it succeeds and zero if it fails. </p><p> A particular event procedure can be registered only once in any <code class="structname">PGconn</code>. This is because the address of the procedure is used as a lookup key to identify the associated instance data. </p><div class="caution"><h3 class="title">Caution</h3><p> On Windows, functions can have two different addresses: one visible from outside a DLL and another visible from inside the DLL. One should be careful that only one of these addresses is used with <span class="application">libpq</span>'s event-procedure functions, else confusion will result. The simplest rule for writing code that will work is to ensure that event procedures are declared <code class="literal">static</code>. If the procedure's address must be available outside its own source file, expose a separate function to return the address. </p></div></dd></dl></div></div><div class="sect2" id="LIBPQ-EVENTS-FUNCS"><div class="titlepage"><div><div><h3 class="title">34.14.3. Event Support Functions <a href="#LIBPQ-EVENTS-FUNCS" class="id_link">#</a></h3></div></div></div><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PQREGISTEREVENTPROC"><span class="term"><code class="function">PQregisterEventProc</code><a id="id-1.7.3.21.6.2.1.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQREGISTEREVENTPROC" class="id_link">#</a></dt><dd><p> Registers an event callback procedure with libpq. </p><pre class="synopsis"> int PQregisterEventProc(PGconn *conn, PGEventProc proc, const char *name, void *passThrough); </pre><p> </p><p> An event procedure must be registered once on each <code class="structname">PGconn</code> you want to receive events about. There is no limit, other than memory, on the number of event procedures that can be registered with a connection. The function returns a non-zero value if it succeeds and zero if it fails. </p><p> The <em class="parameter"><code>proc</code></em> argument will be called when a libpq event is fired. Its memory address is also used to lookup <code class="literal">instanceData</code>. The <em class="parameter"><code>name</code></em> argument is used to refer to the event procedure in error messages. This value cannot be <code class="symbol">NULL</code> or a zero-length string. The name string is copied into the <code class="structname">PGconn</code>, so what is passed need not be long-lived. The <em class="parameter"><code>passThrough</code></em> pointer is passed to the <em class="parameter"><code>proc</code></em> whenever an event occurs. This argument can be <code class="symbol">NULL</code>. </p></dd><dt id="LIBPQ-PQSETINSTANCEDATA"><span class="term"><code class="function">PQsetInstanceData</code><a id="id-1.7.3.21.6.2.2.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQSETINSTANCEDATA" class="id_link">#</a></dt><dd><p> Sets the connection <em class="parameter"><code>conn</code></em>'s <code class="literal">instanceData</code> for procedure <em class="parameter"><code>proc</code></em> to <em class="parameter"><code>data</code></em>. This returns non-zero for success and zero for failure. (Failure is only possible if <em class="parameter"><code>proc</code></em> has not been properly registered in <em class="parameter"><code>conn</code></em>.) </p><pre class="synopsis"> int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data); </pre><p> </p></dd><dt id="LIBPQ-PQINSTANCEDATA"><span class="term"><code class="function">PQinstanceData</code><a id="id-1.7.3.21.6.2.3.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQINSTANCEDATA" class="id_link">#</a></dt><dd><p> Returns the connection <em class="parameter"><code>conn</code></em>'s <code class="literal">instanceData</code> associated with procedure <em class="parameter"><code>proc</code></em>, or <code class="symbol">NULL</code> if there is none. </p><pre class="synopsis"> void *PQinstanceData(const PGconn *conn, PGEventProc proc); </pre><p> </p></dd><dt id="LIBPQ-PQRESULTSETINSTANCEDATA"><span class="term"><code class="function">PQresultSetInstanceData</code><a id="id-1.7.3.21.6.2.4.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQRESULTSETINSTANCEDATA" class="id_link">#</a></dt><dd><p> Sets the result's <code class="literal">instanceData</code> for <em class="parameter"><code>proc</code></em> to <em class="parameter"><code>data</code></em>. This returns non-zero for success and zero for failure. (Failure is only possible if <em class="parameter"><code>proc</code></em> has not been properly registered in the result.) </p><pre class="synopsis"> int PQresultSetInstanceData(PGresult *res, PGEventProc proc, void *data); </pre><p> </p><p> Beware that any storage represented by <em class="parameter"><code>data</code></em> will not be accounted for by <a class="xref" href="libpq-misc.html#LIBPQ-PQRESULTMEMORYSIZE"><code class="function">PQresultMemorySize</code></a>, unless it is allocated using <a class="xref" href="libpq-misc.html#LIBPQ-PQRESULTALLOC"><code class="function">PQresultAlloc</code></a>. (Doing so is recommendable because it eliminates the need to free such storage explicitly when the result is destroyed.) </p></dd><dt id="LIBPQ-PQRESULTINSTANCEDATA"><span class="term"><code class="function">PQresultInstanceData</code><a id="id-1.7.3.21.6.2.5.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQRESULTINSTANCEDATA" class="id_link">#</a></dt><dd><p> Returns the result's <code class="literal">instanceData</code> associated with <em class="parameter"><code>proc</code></em>, or <code class="symbol">NULL</code> if there is none. </p><pre class="synopsis"> void *PQresultInstanceData(const PGresult *res, PGEventProc proc); </pre><p> </p></dd></dl></div></div><div class="sect2" id="LIBPQ-EVENTS-EXAMPLE"><div class="titlepage"><div><div><h3 class="title">34.14.4. Event Example <a href="#LIBPQ-EVENTS-EXAMPLE" class="id_link">#</a></h3></div></div></div><p> Here is a skeleton example of managing private data associated with libpq connections and results. </p><pre class="programlisting"> /* required header for libpq events (note: includes libpq-fe.h) */ #include <libpq-events.h> /* The instanceData */ typedef struct { int n; char *str; } mydata; /* PGEventProc */ static int myEventProc(PGEventId evtId, void *evtInfo, void *passThrough); int main(void) { mydata *data; PGresult *res; PGconn *conn = PQconnectdb("dbname=postgres options=-csearch_path="); if (PQstatus(conn) != CONNECTION_OK) { /* PQerrorMessage's result includes a trailing newline */ fprintf(stderr, "%s", PQerrorMessage(conn)); PQfinish(conn); return 1; } /* called once on any connection that should receive events. * Sends a PGEVT_REGISTER to myEventProc. */ if (!PQregisterEventProc(conn, myEventProc, "mydata_proc", NULL)) { fprintf(stderr, "Cannot register PGEventProc\n"); PQfinish(conn); return 1; } /* conn instanceData is available */ data = PQinstanceData(conn, myEventProc); /* Sends a PGEVT_RESULTCREATE to myEventProc */ res = PQexec(conn, "SELECT 1 + 1"); /* result instanceData is available */ data = PQresultInstanceData(res, myEventProc); /* If PG_COPYRES_EVENTS is used, sends a PGEVT_RESULTCOPY to myEventProc */ res_copy = PQcopyResult(res, PG_COPYRES_TUPLES | PG_COPYRES_EVENTS); /* result instanceData is available if PG_COPYRES_EVENTS was * used during the PQcopyResult call. */ data = PQresultInstanceData(res_copy, myEventProc); /* Both clears send a PGEVT_RESULTDESTROY to myEventProc */ PQclear(res); PQclear(res_copy); /* Sends a PGEVT_CONNDESTROY to myEventProc */ PQfinish(conn); return 0; } static int myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) { switch (evtId) { case PGEVT_REGISTER: { PGEventRegister *e = (PGEventRegister *)evtInfo; mydata *data = get_mydata(e->conn); /* associate app specific data with connection */ PQsetInstanceData(e->conn, myEventProc, data); break; } case PGEVT_CONNRESET: { PGEventConnReset *e = (PGEventConnReset *)evtInfo; mydata *data = PQinstanceData(e->conn, myEventProc); if (data) memset(data, 0, sizeof(mydata)); break; } case PGEVT_CONNDESTROY: { PGEventConnDestroy *e = (PGEventConnDestroy *)evtInfo; mydata *data = PQinstanceData(e->conn, myEventProc); /* free instance data because the conn is being destroyed */ if (data) free_mydata(data); break; } case PGEVT_RESULTCREATE: { PGEventResultCreate *e = (PGEventResultCreate *)evtInfo; mydata *conn_data = PQinstanceData(e->conn, myEventProc); mydata *res_data = dup_mydata(conn_data); /* associate app specific data with result (copy it from conn) */ PQresultSetInstanceData(e->result, myEventProc, res_data); break; } case PGEVT_RESULTCOPY: { PGEventResultCopy *e = (PGEventResultCopy *)evtInfo; mydata *src_data = PQresultInstanceData(e->src, myEventProc); mydata *dest_data = dup_mydata(src_data); /* associate app specific data with result (copy it from a result) */ PQresultSetInstanceData(e->dest, myEventProc, dest_data); break; } case PGEVT_RESULTDESTROY: { PGEventResultDestroy *e = (PGEventResultDestroy *)evtInfo; mydata *data = PQresultInstanceData(e->result, myEventProc); /* free instance data because the result is being destroyed */ if (data) free_mydata(data); break; } /* unknown event ID, just return true. */ default: break; } return true; /* event processing succeeded */ } </pre></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="libpq-notice-processing.html" title="34.13. Notice Processing">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="libpq.html" title="Chapter 34. libpq — C Library">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="libpq-envars.html" title="34.15. Environment Variables">Next</a></td></tr><tr><td width="40%" align="left" valign="top">34.13. Notice Processing </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 16.3 Documentation">Home</a></td><td width="40%" align="right" valign="top"> 34.15. Environment Variables</td></tr></table></div></body></html>