packages feed

hpqtypes-1.2.2: libpqtypes/src/events.c

/*
 * events.c
 *   The libpq PGEventProc implementation.
 *
 * Copyright (c) 2011 eSilo, LLC. All rights reserved.
 * This is free software; see the source for copying conditions.  There is
 * NO warranty; not even for MERCHANTABILITY or  FITNESS FOR A  PARTICULAR
 * PURPOSE.
 */

#include "libpqtypes-int.h"

static PGtypeData *
allocTypeData(PGconn *conn);

static void
freeTypeData(PGtypeData *typeData);

/* Deprecated, use PQinitTypes instead */
int
PQtypesRegister(PGconn *conn)
{
	return PQinitTypes(conn);
}

int
pqt_eventproc(PGEventId id, void *info, void *passThrough)
{
	/* supress warning about this variable being unused */
	(void)passThrough;
	switch (id)
	{
		case PGEVT_REGISTER:
		{
			PGEventRegister *e = (PGEventRegister *) info;
			void *data = allocTypeData(e->conn);
			if (!data)
				return FALSE;
			PQsetInstanceData((PGconn *) e->conn, pqt_eventproc, data);
			break;
		}

		case PGEVT_CONNRESET:
		{
			/* No special handling for PGEVT_CONNRESET.  Previously, types were
			 * automatically re-registered but this idea fails miserably during
			 * asynchronous resets.  Yanked in favor of using the following
			 * call sequence: PQresetXXX, PQclearTypes, PQregisterTypes.
			 */
			break;
		}

		case PGEVT_CONNDESTROY:
		{
			PGEventConnDestroy *e = (PGEventConnDestroy *) info;
			freeTypeData((PGtypeData *) PQinstanceData(e->conn, pqt_eventproc));
			break;
		}

		case PGEVT_RESULTCREATE:
		{
			PGtypeData *resData;
			PGEventResultCreate *e = (PGEventResultCreate *) info;
			PGtypeData *connData = (PGtypeData *) PQinstanceData(
				e->conn, pqt_eventproc);

			if (!connData || !(resData = allocTypeData(e->conn)))
				return FALSE;

			/* copy type handlers from PGconn's typeData */
			if (connData->typhcnt > 0)
			{
				resData->typhandlers = pqt_duphandlers(
					connData->typhandlers, connData->typhcnt);

				if (resData->typhandlers)
					resData->typhcnt = connData->typhcnt;
			}

			/* copy type specs from PGconn's typeData */
			if (connData->typspeccnt > 0)
			{
				resData->typspecs = pqt_dupspecs(
					connData->typspecs, connData->typspeccnt);

				if (resData->typspecs)
					resData->typspeccnt = connData->typspeccnt;
			}

			PQresultSetInstanceData((PGresult *) e->result, pqt_eventproc, resData);
			break;
		}

		case PGEVT_RESULTCOPY:
		{
			PGtypeData *destData;
			PGEventResultCopy *e = (PGEventResultCopy *) info;
			PGtypeData *srcData = (PGtypeData *) PQresultInstanceData(
				e->src, pqt_eventproc);

			if (!srcData || !(destData = allocTypeData(NULL)))
				return FALSE;

			memcpy(&destData->fmtinfo, &srcData->fmtinfo, sizeof(PGtypeFormatInfo));

			/* copy type handlers from PGresult's typeData */
			if (srcData->typhcnt > 0)
			{
				destData->typhandlers = pqt_duphandlers(
					srcData->typhandlers, srcData->typhcnt);

				if (destData->typhandlers)
					destData->typhcnt = srcData->typhcnt;
			}

			/* copy type specs from PGresult's typeData */
			if (srcData->typspeccnt > 0)
			{
				destData->typspecs = pqt_dupspecs(
					srcData->typspecs, srcData->typspeccnt);

				if (destData->typspecs)
					destData->typspeccnt = srcData->typspeccnt;
			}

			PQresultSetInstanceData(e->dest, pqt_eventproc, destData);
			break;
		}

		case PGEVT_RESULTDESTROY:
		{
			PGEventResultDestroy *e = (PGEventResultDestroy *) info;
			freeTypeData((PGtypeData *) PQresultInstanceData(
				e->result, pqt_eventproc));
			break;
		}
	}

	return TRUE;
}

static PGtypeData *
allocTypeData(PGconn *conn)
{
	PGtypeData *typeData = (PGtypeData *) malloc(sizeof(PGtypeData));

	if (typeData)
	{
		memset(typeData, 0, sizeof(PGtypeData));

		/* get type formatting info from conn */
		if (conn)
			pqt_getfmtinfo(conn, &typeData->fmtinfo);
	}

	return typeData;
}

static void
freeTypeData(PGtypeData *typeData)
{
	if (typeData)
	{
		pqt_cleartypes(typeData);

		pqt_freespecs(typeData->typspecs, typeData->typspeccnt);
		typeData->typspecs = NULL;
		typeData->typspeccnt = 0;
		typeData->typspecmax = 0;

		free(typeData);
	}
}