postgresql/src/interfaces/libpq/libpq-events.c

210 lines
4.4 KiB
C

/*-------------------------------------------------------------------------
*
* libpq-events.c
* functions for supporting the libpq "events" API
*
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/interfaces/libpq/libpq-events.c
*
*-------------------------------------------------------------------------
*/
#include "postgres_fe.h"
#include "libpq-fe.h"
#include "libpq-int.h"
/*
* Registers an event proc with the given PGconn.
*
* The same proc can't be registered more than once in a PGconn. This
* restriction is required because we use the proc address to identify
* the event for purposes such as PQinstanceData().
*
* The name argument is used within error messages to aid in debugging.
* A name must be supplied, but it needn't be unique. The string is
* copied, so the passed value needn't be long-lived.
*
* The passThrough argument is an application specific pointer and can be set
* to NULL if not required. It is passed through to the event proc whenever
* the event proc is called, and is not otherwise touched by libpq.
*
* The function returns a non-zero if successful. If the function fails,
* zero is returned.
*/
int
PQregisterEventProc(PGconn *conn, PGEventProc proc,
const char *name, void *passThrough)
{
int i;
PGEventRegister regevt;
if (!proc || !conn || !name || !*name)
return FALSE; /* bad arguments */
for (i = 0; i < conn->nEvents; i++)
{
if (conn->events[i].proc == proc)
return FALSE; /* already registered */
}
if (conn->nEvents >= conn->eventArraySize)
{
PGEvent *e;
int newSize;
newSize = conn->eventArraySize ? conn->eventArraySize * 2 : 8;
if (conn->events)
e = (PGEvent *) realloc(conn->events, newSize * sizeof(PGEvent));
else
e = (PGEvent *) malloc(newSize * sizeof(PGEvent));
if (!e)
return FALSE;
conn->eventArraySize = newSize;
conn->events = e;
}
conn->events[conn->nEvents].proc = proc;
conn->events[conn->nEvents].name = strdup(name);
if (!conn->events[conn->nEvents].name)
return FALSE;
conn->events[conn->nEvents].passThrough = passThrough;
conn->events[conn->nEvents].data = NULL;
conn->events[conn->nEvents].resultInitialized = FALSE;
conn->nEvents++;
regevt.conn = conn;
if (!proc(PGEVT_REGISTER, &regevt, passThrough))
{
conn->nEvents--;
free(conn->events[conn->nEvents].name);
return FALSE;
}
return TRUE;
}
/*
* Set some "instance data" for an event within a PGconn.
* Returns nonzero on success, zero on failure.
*/
int
PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data)
{
int i;
if (!conn || !proc)
return FALSE;
for (i = 0; i < conn->nEvents; i++)
{
if (conn->events[i].proc == proc)
{
conn->events[i].data = data;
return TRUE;
}
}
return FALSE;
}
/*
* Obtain the "instance data", if any, for the event.
*/
void *
PQinstanceData(const PGconn *conn, PGEventProc proc)
{
int i;
if (!conn || !proc)
return NULL;
for (i = 0; i < conn->nEvents; i++)
{
if (conn->events[i].proc == proc)
return conn->events[i].data;
}
return NULL;
}
/*
* Set some "instance data" for an event within a PGresult.
* Returns nonzero on success, zero on failure.
*/
int
PQresultSetInstanceData(PGresult *result, PGEventProc proc, void *data)
{
int i;
if (!result || !proc)
return FALSE;
for (i = 0; i < result->nEvents; i++)
{
if (result->events[i].proc == proc)
{
result->events[i].data = data;
return TRUE;
}
}
return FALSE;
}
/*
* Obtain the "instance data", if any, for the event.
*/
void *
PQresultInstanceData(const PGresult *result, PGEventProc proc)
{
int i;
if (!result || !proc)
return NULL;
for (i = 0; i < result->nEvents; i++)
if (result->events[i].proc == proc)
return result->events[i].data;
return NULL;
}
/*
* Fire RESULTCREATE events for an application-created PGresult.
*
* The conn argument can be NULL if event procedures won't use it.
*/
int
PQfireResultCreateEvents(PGconn *conn, PGresult *res)
{
int i;
if (!res)
return FALSE;
for (i = 0; i < res->nEvents; i++)
{
if (!res->events[i].resultInitialized)
{
PGEventResultCreate evt;
evt.conn = conn;
evt.result = res;
if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt,
res->events[i].passThrough))
return FALSE;
res->events[i].resultInitialized = TRUE;
}
}
return TRUE;
}