mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
Add an "events" system to libpq, whereby applications can get callbacks that
enable them to manage private data associated with PGconns and PGresults. Andrew Chernow and Merlin Moncure
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.260 2008/06/27 02:44:31 momjian Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.261 2008/09/17 04:31:08 tgl Exp $ -->
|
||||
|
||||
<chapter id="libpq">
|
||||
<title><application>libpq</application> - C Library</title>
|
||||
@ -2063,38 +2063,6 @@ PGresult *PQdescribePortal(PGconn *conn, const char *portalName);
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>PQmakeEmptyPGresult</function>
|
||||
<indexterm>
|
||||
<primary>PQmakeEmptyPGresult</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Constructs an empty <structname>PGresult</structname> object with the given status.
|
||||
<synopsis>
|
||||
PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
|
||||
</synopsis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This is <application>libpq</>'s internal function to allocate and
|
||||
initialize an empty <structname>PGresult</structname> object. This
|
||||
function returns NULL if memory could not be allocated. It is
|
||||
exported because some applications find it useful to generate result
|
||||
objects (particularly objects with error status) themselves. If
|
||||
<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>.
|
||||
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>
|
||||
</variablelist>
|
||||
</para>
|
||||
</sect2>
|
||||
@ -4598,6 +4566,170 @@ char *pg_encoding_to_char(int <replaceable>encoding_id</replaceable>);
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>PQmakeEmptyPGresult</function>
|
||||
<indexterm>
|
||||
<primary>PQmakeEmptyPGresult</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Constructs an empty <structname>PGresult</structname> object with the given status.
|
||||
<synopsis>
|
||||
PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
|
||||
</synopsis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This is <application>libpq</>'s internal function to allocate and
|
||||
initialize an empty <structname>PGresult</structname> object. This
|
||||
function returns NULL if memory could not be allocated. It is
|
||||
exported because some applications find it useful to generate result
|
||||
objects (particularly objects with error status) themselves. If
|
||||
<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>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>PQcopyResult</function>
|
||||
<indexterm>
|
||||
<primary>PQcopyResult</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Makes a copy of a <structname>PGresult</structname> object. The copy is
|
||||
not linked to the source result in any way and
|
||||
<function>PQclear</function> must be called when the copy is no longer
|
||||
needed. If the function fails, NULL is returned.
|
||||
|
||||
<synopsis>
|
||||
PGresult *PQcopyResult(const PGresult *src, int flags);
|
||||
</synopsis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This is not intended to make an exact copy. The returned result is
|
||||
always put into <literal>PGRES_TUPLES_OK</literal> status, and does not
|
||||
copy any error message in the source. (It does copy the command status
|
||||
string, however.) The <parameter>flags</parameter> argument determines
|
||||
what else is copied. It is a bitwise OR of several flags.
|
||||
<literal>PG_COPYRES_ATTRS</literal> specifies copying the source
|
||||
result's attributes (column definitions).
|
||||
<literal>PG_COPYRES_TUPLES</literal> specifies copying the source
|
||||
result's tuples. (This implies copying the attributes, too.)
|
||||
<literal>PG_COPYRES_NOTICEHOOKS</literal> specifies
|
||||
copying the source result's notify hooks.
|
||||
<literal>PG_COPYRES_EVENTS</literal> specifies copying the source
|
||||
result's events. (But any instance data associated with the source
|
||||
is not copied.)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>PQsetResultAttrs</function>
|
||||
<indexterm>
|
||||
<primary>PQsetResultAttrs</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Sets the attributes of a <structname>PGresult</structname> object.
|
||||
<synopsis>
|
||||
int PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs);
|
||||
</synopsis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The provided <parameter>attDescs</parameter> are copied into the result.
|
||||
If the <parameter>attDescs</parameter> pointer is NULL or
|
||||
<parameter>numAttributes</parameter> is less than one, the request is
|
||||
ignored and the function succeeds. If <parameter>res</parameter>
|
||||
already contains attributes, the function will fail. If the function
|
||||
fails, the return value is zero. If the function succeeds, the return
|
||||
value is non-zero.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>PQsetvalue</function>
|
||||
<indexterm>
|
||||
<primary>PQsetvalue</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Sets a tuple field value of a <structname>PGresult</structname> object.
|
||||
<synopsis>
|
||||
int PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len);
|
||||
</synopsis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The function will automatically grow the result's internal tuples array
|
||||
as needed. However, the <parameter>tup_num</parameter> argument must be
|
||||
less than or equal to <function>PQntuples</function>, meaning this
|
||||
function can only grow the tuples array one tuple at a time. But any
|
||||
field of any existing tuple can be modified in any order. If a value at
|
||||
<parameter>field_num</parameter> already exists, it will be overwritten.
|
||||
If <parameter>len</parameter> is <literal>-1</literal> or
|
||||
<parameter>value</parameter> is <literal>NULL</literal>, the field value
|
||||
will be set to an SQL <literal>NULL</literal>. The
|
||||
<parameter>value</parameter> is copied into the result's private storage,
|
||||
thus is no longer needed after the function
|
||||
returns. If the function fails, the return value is zero. If the
|
||||
function succeeds, the return value is non-zero.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>PQresultAlloc</function>
|
||||
<indexterm>
|
||||
<primary>PQresultAlloc</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Allocate subsidiary storage for a <structname>PGresult</structname> object.
|
||||
<synopsis>
|
||||
void *PQresultAlloc(PGresult *res, size_t nBytes);
|
||||
</synopsis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Any memory allocated with this function will be freed when
|
||||
<parameter>res</parameter> is cleared. If the function fails,
|
||||
the return value is <literal>NULL</literal>. The result is
|
||||
guaranteed to be adequately aligned for any type of data,
|
||||
just as for <function>malloc</>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</sect1>
|
||||
@ -4711,6 +4843,551 @@ defaultNoticeProcessor(void *arg, const char *message)
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="libpq-events">
|
||||
<title>Event System</title>
|
||||
|
||||
<para>
|
||||
<application>libpq</application>'s event system is designed to notify
|
||||
registered event handlers about interesting
|
||||
<application>libpq</application> events, such as the creation or
|
||||
destruction of <structname>PGconn</structname> and
|
||||
<structname>PGresult</structname> objects. A principal use case is that
|
||||
this allows applications to associate their own data with a
|
||||
<structname>PGconn</structname> or <structname>PGresult</structname>
|
||||
and ensure that that data is freed at an appropriate time.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Each registered event handler is associated with two pieces of data,
|
||||
known to <application>libpq</application> only as opaque <literal>void *</>
|
||||
pointers. There is a <firstterm>passthrough</> pointer that is provided
|
||||
by the application when the event handler is registered with a
|
||||
<structname>PGconn</>. The passthrough pointer never changes for the
|
||||
life of the <structname>PGconn</> and all <structname>PGresult</>s
|
||||
generated from it; so if used, it must point to long-lived data.
|
||||
In addition there is an <firstterm>instance data</> pointer, which starts
|
||||
out NULL in every <structname>PGconn</> and <structname>PGresult</>.
|
||||
This pointer can be manipulated using the
|
||||
<function>PQinstanceData</function>,
|
||||
<function>PQsetInstanceData</function>,
|
||||
<function>PQresultInstanceData</function> and
|
||||
<function>PQsetResultInstanceData</function> functions. Note that
|
||||
unlike the passthrough pointer, instance data of a <structname>PGconn</>
|
||||
is not automatically inherited by <structname>PGresult</>s created from
|
||||
it. <application>libpq</application> does not know what passthrough
|
||||
and instance data pointers point to (if anything) and will never attempt
|
||||
to free them — that is the responsibility of the event handler.
|
||||
</para>
|
||||
|
||||
<sect2 id="libpq-events-types">
|
||||
<title>Event Types</title>
|
||||
|
||||
<para>
|
||||
The enum <literal>PGEventId</> names the types of events handled by
|
||||
the event system. All its values have names beginning with
|
||||
<literal>PGEVT</literal>. For each event type, there is a corresponding
|
||||
event info structure that carries the parameters passed to the event
|
||||
handlers. The event types are:
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><literal>PGEVT_REGISTER</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The register event occurs when <function>PQregisterEventProc</function>
|
||||
is called. It is the ideal time to initialize any
|
||||
<literal>instanceData</literal> an event procedure may need. Only one
|
||||
register event will be fired per event handler per connection. If the
|
||||
event procedure fails, the registration is aborted.
|
||||
|
||||
<synopsis>
|
||||
typedef struct
|
||||
{
|
||||
const PGconn *conn;
|
||||
} PGEventRegister;
|
||||
</synopsis>
|
||||
|
||||
When a <literal>PGEVT_REGISTER</literal> event is received, the
|
||||
<parameter>evtInfo</parameter> pointer should be cast to a
|
||||
<structname>PGEventRegister *</structname>. This structure contains a
|
||||
<structname>PGconn</structname> that should be in the
|
||||
<literal>CONNECTION_OK</literal> status; guaranteed if one calls
|
||||
<function>PQregisterEventProc</function> right after obtaining a good
|
||||
<structname>PGconn</structname>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>PGEVT_CONNRESET</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The connection reset event is fired on completion of
|
||||
<function>PQreset</function> or <function>PQresetPoll</function>. In
|
||||
both cases, the event is only fired if the reset was successful. If
|
||||
the event procedure fails, the entire connection reset will fail; the
|
||||
<structname>PGconn</structname> is put into
|
||||
<literal>CONNECTION_BAD</literal> status and
|
||||
<function>PQresetPoll</function> will return
|
||||
<literal>PGRES_POLLING_FAILED</literal>.
|
||||
|
||||
<synopsis>
|
||||
typedef struct
|
||||
{
|
||||
const PGconn *conn;
|
||||
} PGEventConnReset;
|
||||
</synopsis>
|
||||
|
||||
When a <literal>PGEVT_CONNRESET</literal> event is received, the
|
||||
<parameter>evtInfo</parameter> pointer should be cast to a
|
||||
<structname>PGEventConnReset *</structname>. Although the contained
|
||||
<structname>PGconn</structname> was just reset, all event data remains
|
||||
unchanged. This event should be used to reset/reload/requery any
|
||||
associated <literal>instanceData</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>PGEVT_CONNDESTROY</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The connection destroy event is fired in response to
|
||||
<function>PQfinish</function>. 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.
|
||||
|
||||
<synopsis>
|
||||
typedef struct
|
||||
{
|
||||
const PGconn *conn;
|
||||
} PGEventConnDestroy;
|
||||
</synopsis>
|
||||
|
||||
When a <literal>PGEVT_CONNDESTROY</literal> event is received, the
|
||||
<parameter>evtInfo</parameter> pointer should be cast to a
|
||||
<structname>PGEventConnDestroy *</structname>. This event is fired
|
||||
prior to <function>PQfinish</function> performing any other cleanup.
|
||||
The return value of the event procedure is ignored since there is no
|
||||
way of indicating a failure from <function>PQfinish</function>. Also,
|
||||
an event procedure failure should not abort the process of cleaning up
|
||||
unwanted memory.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>PGEVT_RESULTCREATE</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The result creation event is fired in response to any query execution
|
||||
function that generates a result, including
|
||||
<function>PQgetResult</function>. This event will only be fired after
|
||||
the result has been created successfully.
|
||||
|
||||
<synopsis>
|
||||
typedef struct
|
||||
{
|
||||
const PGconn *conn;
|
||||
PGresult *result;
|
||||
} PGEventResultCreate;
|
||||
</synopsis>
|
||||
|
||||
When a <literal>PGEVT_RESULTCREATE</literal> event is received, the
|
||||
<parameter>evtInfo</parameter> pointer should be cast to a
|
||||
<structname>PGEventResultCreate *</structname>. The
|
||||
<parameter>conn</parameter> is the connection used to generate the
|
||||
result. This is the ideal place to initialize any
|
||||
<literal>instanceData</literal> 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
|
||||
<function>PQclear</> the result object for itself.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>PGEVT_RESULTCOPY</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The result copy event is fired in response to
|
||||
<function>PQcopyResult</function>. This event will only be fired after
|
||||
the copy is complete.
|
||||
|
||||
<synopsis>
|
||||
typedef struct
|
||||
{
|
||||
const PGresult *src;
|
||||
PGresult *dest;
|
||||
} PGEventResultCopy;
|
||||
</synopsis>
|
||||
|
||||
When a <literal>PGEVT_RESULTCOPY</literal> event is received, the
|
||||
<parameter>evtInfo</parameter> pointer should be cast to a
|
||||
<structname>PGEventResultCopy *</structname>. The
|
||||
<parameter>src</parameter> result is what was copied while the
|
||||
<parameter>dest</parameter> result is the copy destination. This event
|
||||
can be used to provide a deep copy of <literal>instanceData</literal>,
|
||||
since <literal>PQcopyResult</literal> cannot do that. If the event
|
||||
procedure fails, the entire copy operation will fail and the
|
||||
<parameter>dest</parameter> result will be cleared.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>PGEVT_RESULTDESTROY</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The result destroy event is fired in response to a
|
||||
<function>PQclear</function>. 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.
|
||||
|
||||
<synopsis>
|
||||
typedef struct
|
||||
{
|
||||
const PGresult *result;
|
||||
} PGEventResultDestroy;
|
||||
</synopsis>
|
||||
|
||||
When a <literal>PGEVT_RESULTDESTROY</literal> event is received, the
|
||||
<parameter>evtInfo</parameter> pointer should be cast to a
|
||||
<structname>PGEventResultDestroy *</structname>. This event is fired
|
||||
prior to <function>PQclear</function> performing any other cleanup.
|
||||
The return value of the event procedure is ignored since there is no
|
||||
way of indicating a failure from <function>PQclear</function>. Also,
|
||||
an event procedure failure should not abort the process of cleaning up
|
||||
unwanted memory.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="libpq-events-proc">
|
||||
<title>Event Callback Procedure</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>PGEventProc</literal>
|
||||
<indexterm>
|
||||
<primary>PGEventProc</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>PGEventProc</literal> 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
|
||||
|
||||
<synopsis>
|
||||
int eventproc(PGEventId evtId, void *evtInfo, void *passThrough)
|
||||
</synopsis>
|
||||
|
||||
The <parameter>evtId</parameter> parameter indicates which
|
||||
<literal>PGEVT</literal> event occurred. The
|
||||
<parameter>evtInfo</parameter> pointer must be cast to the appropriate
|
||||
structure type to obtain further information about the event.
|
||||
The <parameter>passThrough</parameter> parameter is the pointer
|
||||
provided to <function>PQregisterEventProc</function> when the event
|
||||
procedure was registered. The function should return a non-zero value
|
||||
if it succeeds and zero if it fails.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A particular event procedure can be registered only once in any
|
||||
<structname>PGconn</>. This is because the address of the procedure
|
||||
is used as a lookup key to identify the associated instance data.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="libpq-events-funcs">
|
||||
<title>Event Support Functions</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>PQregisterEventProc</function>
|
||||
<indexterm>
|
||||
<primary>PQregisterEventProc</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Registers an event callback procedure with libpq.
|
||||
|
||||
<synopsis>
|
||||
int PQregisterEventProc(PGconn *conn, PGEventProc proc,
|
||||
const char *name, void *passThrough);
|
||||
</synopsis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An event procedure must be registered once on each
|
||||
<structname>PGconn</> 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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <parameter>proc</parameter> argument will be called when a libpq
|
||||
event is fired. Its memory address is also used to lookup
|
||||
<literal>instanceData</literal>. The <parameter>name</parameter>
|
||||
argument is used to refer to the event procedure in error messages.
|
||||
This value cannot be NULL or a zero-length string. The name string is
|
||||
copied into the <structname>PGconn</>, so what is passed need not be
|
||||
long-lived. The <parameter>passThrough</parameter> pointer is passed
|
||||
to the <parameter>proc</parameter> whenever an event occurs. This
|
||||
argument can be NULL.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>PQsetInstanceData</function>
|
||||
<indexterm>
|
||||
<primary>PQsetInstanceData</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Sets the conn's instanceData for proc to data. This returns non-zero
|
||||
for success and zero for failure. (Failure is only possible if
|
||||
the proc has not been properly registered in the conn.)
|
||||
|
||||
<synopsis>
|
||||
int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data);
|
||||
</synopsis>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>PQinstanceData</function>
|
||||
<indexterm>
|
||||
<primary>PQinstanceData</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Returns the conn's instanceData associated with proc, or NULL
|
||||
if there is none.
|
||||
|
||||
<synopsis>
|
||||
void *PQinstanceData(const PGconn *conn, PGEventProc proc);
|
||||
</synopsis>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>PQresultSetInstanceData</function>
|
||||
<indexterm>
|
||||
<primary>PQresultSetInstanceData</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Sets the result's instanceData for proc to data. This returns non-zero
|
||||
for success and zero for failure. (Failure is only possible if the
|
||||
proc has not been properly registered in the result.)
|
||||
|
||||
<synopsis>
|
||||
int PQresultSetInstanceData(PGresult *res, PGEventProc proc, void *data);
|
||||
</synopsis>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>PQresultInstanceData</function>
|
||||
<indexterm>
|
||||
<primary>PQresultInstanceData</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Returns the result's instanceData associated with proc, or NULL
|
||||
if there is none.
|
||||
|
||||
<synopsis>
|
||||
void *PQresultInstanceData(const PGresult *res, PGEventProc proc);
|
||||
</synopsis>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="libpq-events-example">
|
||||
<title>Event Example</title>
|
||||
|
||||
<para>
|
||||
Here is a skeleton example of managing private data associated with
|
||||
libpq connections and results.
|
||||
</para>
|
||||
|
||||
<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");
|
||||
|
||||
if (PQstatus(conn) != CONNECTION_OK)
|
||||
{
|
||||
fprintf(stderr, "Connection to database failed: %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) */
|
||||
PQsetResultInstanceData(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) */
|
||||
PQsetResultInstanceData(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 */
|
||||
}
|
||||
</programlisting>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="libpq-envars">
|
||||
<title>Environment Variables</title>
|
||||
|
||||
@ -5263,7 +5940,7 @@ defaultNoticeProcessor(void *arg, const char *message)
|
||||
to inside <application>libpq</application>), you can use
|
||||
<function>PQinitSSL(int)</> to tell <application>libpq</application>
|
||||
that the <acronym>SSL</> library has already been initialized by your
|
||||
application.
|
||||
application.
|
||||
<!-- If this URL changes replace it with a URL to www.archive.org. -->
|
||||
See <ulink
|
||||
url="http://h71000.www7.hp.com/doc/83final/BA554_90007/ch04.html"></ulink>
|
||||
|
Reference in New Issue
Block a user