/*------------------------------------------------------------------------- * * libpq-events.c * functions for supporting the libpq "events" API * * Portions Copyright (c) 1996-2016, 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, ®evt, 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; }