2008-09-17 06:31:08 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* libpq-events.c
|
|
|
|
* functions for supporting the libpq "events" API
|
|
|
|
*
|
2017-01-03 19:48:53 +01:00
|
|
|
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
|
2008-09-17 06:31:08 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/interfaces/libpq/libpq-events.c
|
2008-09-17 06:31:08 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#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)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
int i;
|
2008-09-17 06:31:08 +02:00
|
|
|
PGEventRegister regevt;
|
|
|
|
|
|
|
|
if (!proc || !conn || !name || !*name)
|
2017-08-16 06:22:32 +02:00
|
|
|
return false; /* bad arguments */
|
2008-09-17 06:31:08 +02:00
|
|
|
|
|
|
|
for (i = 0; i < conn->nEvents; i++)
|
|
|
|
{
|
|
|
|
if (conn->events[i].proc == proc)
|
2017-08-16 06:22:32 +02:00
|
|
|
return false; /* already registered */
|
2008-09-17 06:31:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->nEvents >= conn->eventArraySize)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
PGEvent *e;
|
|
|
|
int newSize;
|
2008-09-17 06:31:08 +02:00
|
|
|
|
|
|
|
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)
|
2017-08-16 06:22:32 +02:00
|
|
|
return false;
|
2008-09-17 06:31:08 +02:00
|
|
|
|
|
|
|
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)
|
2017-08-16 06:22:32 +02:00
|
|
|
return false;
|
2008-09-17 06:31:08 +02:00
|
|
|
conn->events[conn->nEvents].passThrough = passThrough;
|
|
|
|
conn->events[conn->nEvents].data = NULL;
|
2017-08-16 06:22:32 +02:00
|
|
|
conn->events[conn->nEvents].resultInitialized = false;
|
2008-09-17 06:31:08 +02:00
|
|
|
conn->nEvents++;
|
|
|
|
|
|
|
|
regevt.conn = conn;
|
|
|
|
if (!proc(PGEVT_REGISTER, ®evt, passThrough))
|
|
|
|
{
|
|
|
|
conn->nEvents--;
|
|
|
|
free(conn->events[conn->nEvents].name);
|
2017-08-16 06:22:32 +02:00
|
|
|
return false;
|
2008-09-17 06:31:08 +02:00
|
|
|
}
|
|
|
|
|
2017-08-16 06:22:32 +02:00
|
|
|
return true;
|
2008-09-17 06:31:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
int i;
|
2008-09-17 06:31:08 +02:00
|
|
|
|
|
|
|
if (!conn || !proc)
|
2017-08-16 06:22:32 +02:00
|
|
|
return false;
|
2008-09-17 06:31:08 +02:00
|
|
|
|
|
|
|
for (i = 0; i < conn->nEvents; i++)
|
|
|
|
{
|
|
|
|
if (conn->events[i].proc == proc)
|
|
|
|
{
|
|
|
|
conn->events[i].data = data;
|
2017-08-16 06:22:32 +02:00
|
|
|
return true;
|
2008-09-17 06:31:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-16 06:22:32 +02:00
|
|
|
return false;
|
2008-09-17 06:31:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Obtain the "instance data", if any, for the event.
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
PQinstanceData(const PGconn *conn, PGEventProc proc)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
int i;
|
2008-09-17 06:31:08 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
int i;
|
2008-09-17 06:31:08 +02:00
|
|
|
|
|
|
|
if (!result || !proc)
|
2017-08-16 06:22:32 +02:00
|
|
|
return false;
|
2008-09-17 06:31:08 +02:00
|
|
|
|
|
|
|
for (i = 0; i < result->nEvents; i++)
|
|
|
|
{
|
|
|
|
if (result->events[i].proc == proc)
|
|
|
|
{
|
|
|
|
result->events[i].data = data;
|
2017-08-16 06:22:32 +02:00
|
|
|
return true;
|
2008-09-17 06:31:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-16 06:22:32 +02:00
|
|
|
return false;
|
2008-09-17 06:31:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Obtain the "instance data", if any, for the event.
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
PQresultInstanceData(const PGresult *result, PGEventProc proc)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
int i;
|
2008-09-17 06:31:08 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2008-09-19 22:06:13 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
int i;
|
2008-09-19 22:06:13 +02:00
|
|
|
|
|
|
|
if (!res)
|
2017-08-16 06:22:32 +02:00
|
|
|
return false;
|
2008-09-19 22:06:13 +02:00
|
|
|
|
|
|
|
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))
|
2017-08-16 06:22:32 +02:00
|
|
|
return false;
|
2008-09-19 22:06:13 +02:00
|
|
|
|
2017-08-16 06:22:32 +02:00
|
|
|
res->events[i].resultInitialized = true;
|
2008-09-19 22:06:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-16 06:22:32 +02:00
|
|
|
return true;
|
2008-09-19 22:06:13 +02:00
|
|
|
}
|