packages feed

hpqtypes-1.2.2: libpqtypes/src/libpqtypes-int.h

/*
 * libpqtypes-int.h
 *   Private header file for libpqtypes.  All source files include
 *   this header.
 *
 * 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.
 */

#ifndef LIBPQTYPES_INT_H
#define LIBPQTYPES_INT_H

#define PLN do{ \
	printf("%s:%d\n", __FUNCTION__, __LINE__); \
	fflush(stdout); \
}while(0)

#ifdef HAVE_CONFIG_H
#	include "pqt_config.h"
#endif

/* Using the windows compiler */
#ifdef _MSC_VER
#	define PQT_MSVC _MSC_VER
#endif

/* We can/should use the Windows API */
#if defined(PQT_MSVC) || defined(__MINGW32__)
#	define PQT_WINAPI
#endif

/* Compiling on a windows platform */
#if defined(PQT_WINAPI) || defined(__CYGWIN__)
#	define PQT_WIN32
#endif

/* WINAPI is available, include needed winsock headers */
#ifdef PQT_WINAPI
#	ifdef PQT_MSVC
# 	pragma warning (disable : 4706 4100 4711 4127 4702)
#		pragma warning (disable: 4706 4100 4514 4710 4201 4206)
#	endif
# include <winsock2.h>
# include <ws2tcpip.h>
#	include <Wspiapi.h> /* need for getaddrinfo (2000 and below */
#	include <windows.h>
#else
#	if defined(__CYGWIN__) || defined(HAVE_SYS_TYPES_H)
#		include <sys/types.h>
#	endif
#	if defined(__CYGWIN__) || defined(HAVE_SYS_SOCKET_H)
#		include <sys/socket.h>
#	endif
#	if defined(__CYGWIN__) || defined(HAVE_NETDB_H)
#		include <netdb.h>
#	endif
#	if defined(__CYGWIN__) || defined(HAVE_NETINET_IN_H)
#		include <netinet/in.h>
#	endif
#	if defined(__CYGWIN__) || defined(HAVE_ARPA_INET_H)
#		include <arpa/inet.h>
#	endif
#endif

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>

/* string*.h, windows platforms just include string.h */
#ifdef PQT_WIN32
#	include <string.h>
#else
#	ifdef HAVE_STRING_H
#		include <string.h>
#	endif
#	ifdef HAVE_STRINGS_H
#		include <strings.h>
#	endif
#endif

/* Include stddef.h if on windows or if we have it */
#if defined(PQT_WIN32) || defined(HAVE_STDDEF_H)
#	include <stddef.h>
#endif

/* Include limits.h if on windows or if we have it */
#if defined(PQT_WIN32) || defined(HAVE_LIMITS_H)
#	include <limits.h>
#endif

/* Include linux/limits.h if available */
#if defined(HAVE_CONFIG_H) && defined(HAVE_LINUX_LIMITS_H)
#	include <linux/limits.h>
#endif

/* Include math.h if on windows or if we have it */
#if defined(PQT_WIN32) || defined(HAVE_MATH_H)
#	include <math.h>
#endif

/* Include the public API, pulls in libpq-fe.h for us. */
#include "libpqtypes.h"
#include "libpq-events.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifndef TRUE
#	define TRUE 1
#endif

#ifndef FALSE
#	define FALSE 0
#endif

#ifndef NULL_LEN
#	define NULL_LEN (-1)
#endif

/* Win32 builds use _timezone and _tzname: manually define HAVE_TZNAME. */
#ifdef PQT_WIN32
#	define HAVE_TZNAME
#	define pqt_timezone _timezone
#	define pqt_tzname   _tzname
#else
#	define pqt_timezone timezone
#	define pqt_tzname   tzname
#endif

#define PQT_OUTOFMEMORY "Out of memory error"
#define PQT_MAXIDLEN 64

#define TEXTFMT 0
#define BINARYFMT 1
#define TYPFLAG_CASEFOLD 0x01
#define TYPFLAG_ARRAY    0x02
#define TYPFLAG_POINTER  0x04
#define TYPFLAG_INVALID  0x08
#define TYPFLAG_BYNAME   0x10

/* Avoid passing NULL to realloc, some systems don't support it */
#define pqt_realloc(ptr, size) (ptr) ? realloc(ptr, size) : malloc(size)

#define countof(array) (int) (sizeof(array) / sizeof(array[0]))

/* MSVC 8 deprecated quite a few POSIX names */
#if defined(PQT_MSVC) && PQT_MSVC >= 1400
#	undef strdup
#	undef sscanf
#	define strdup _strdup
#	define sscanf sscanf_s
#endif

/* define va_copy */
#ifndef va_copy
#	ifdef __va_copy
#		define va_copy(dest, src) __va_copy(dest, src)
#	else
#		define va_copy(dest, src) (dest) = (src)
#	endif
#endif

#define pqt_hex_to_dec(v) \
	(unsigned char) (((v) > '9') ? ((v) - 'a') + 10 : (v) - '0')

/* --------------------------------
 * Macros used by built-in handlers
 */

/* used by get handlers */
#define DECLLENGTH(args) \
	int valuel = PQgetlength((args)->get.result, (args)->get.tup_num, \
		(args)->get.field_num)

/* used by get handlers */
#define DECLVALUE(getargs) \
	char *value = PQgetvalue((getargs)->get.result, (getargs)->get.tup_num, \
		(getargs)->get.field_num)

/* used by put handlers */
#define PUTNULLCHK(args, valp) do{ \
	if (!(valp)) \
		return pqt_put_null(args); \
}while (0)

/* used by get handlers, checks for NULL pointers and PQgetisnull */
#define CHKGETVALS(args, outp) do{ \
	if (!(outp)) \
		RERR(args, "output pointer is NULL"); \
	memset(outp, 0, sizeof(*(outp))); \
	if (PQgetisnull((args)->get.result, (args)->get.tup_num, \
			(args)->get.field_num)) \
		return 0; \
}while (0)

/* RERR for return error: errorf always returns -1 */
#define RERR(_args, msg) return (_args)->errorf(_args, msg)
#define RERR_STR2INT(args) RERR(args, "String to integer conversion failed")
#define RERR_MEM(args) RERR(args, PQT_OUTOFMEMORY)

#ifdef STRICT_MEMORY_ALIGNMENT
#	define pqt_buf_putint2(_buffer, _val) do{ \
		short _v = (short) htons((short) (_val)); \
		memcpy(_buffer, &_v, sizeof(short)); \
	} while (0)

#	define pqt_buf_putint4(_buffer, _val) do{ \
		int _v = (int) htonl((int) (_val)); \
		memcpy(_buffer, &_v, sizeof(int)); \
	} while (0)

	short pqt_buf_getint2(char *buffer);
	int pqt_buf_getint4(char *buffer);
#else
#	define pqt_buf_putint2(_out, _val) \
	*(short *) (_out) = (short) htons((short) (_val))
#	define pqt_buf_getint2(_buffer) (short) ntohs(*(short *) (_buffer))
#	define pqt_buf_putint4(_out, _val) \
	*(int *) (_out) = (int) htonl((int) (_val))
#	define pqt_buf_getint4(_buffer) (int) ntohl(*(int *) (_buffer))
#endif

/* ----------------------------------
 * See: src/include/catalog/pg_type.h
 * Used by built-in type handlers
 */

/* numerics types */
#define INT2OID            21
#define INT4OID            23
#define INT8OID            20
#define FLOAT4OID         700
#define FLOAT8OID         701
#define NUMERICOID       1700
/* geo types */
#define POINTOID          600
#define LSEGOID           601
#define PATHOID           602
#define BOXOID            603
#define POLYGONOID        604
#define LINEOID           628 /* not supported yet */
#define CIRCLEOID         718
/* network types */
#define INETOID           869
#define CIDROID           650
#define MACADDROID        829
/* variable length types */
#define BPCHAROID        1042
#define VARCHAROID       1043
#define NAMEOID            19
#define TEXTOID            25
#define ZPBITOID         1560 /* not supported yet */
#define VARBITOID        1562 /* not supported yet */
#define BYTEAOID           17
/* date and time types */
#define DATEOID          1082
#define TIMEOID          1083
#define TIMETZOID        1266
#define TIMESTAMPOID     1114
#define TIMESTAMPTZOID   1184
#define INTERVALOID      1186
/* misc types */
#define CHAROID            18
#define BOOLOID            16
#define OIDOID             26
#define CASHOID           790
#define RECORDOID        2249
#define UUIDOID          2950

/* --------------------------------
 * Private Structures
 */

/* Represents a param value.  An array of PGvalues was choosen over
 * allocating 4 separate arrays: oids, values, lengths, formats.  Instead
 * of 4 allocations you only have one.  The PGvalue array can easily be
 * converted to 4 arrays for execution.
 */
typedef struct
{
	int ptrl;   /* Length of value's pointer */
	void *ptr;  /* value pointer, data member uses this for non-NULL values */
	int datal;  /* Length of current value: always <= ptrl */
	char *data; /* current value data, can be NULL ... thus the ptr member. */
	int format; /* format: 0=text, 1=binary */
	Oid oid;    /* Oid of the data */
} PGvalue;

/* performance driven structure.  Instead of parsing and looking up
 * type specs each put or get, PQspecPrepare can be used to compile
 * a spec format string into a PGtypeSpec object.  The biggest wins are
 * large results sets and arrays.
 */
typedef struct
{
	char *name;           /* name for the prepared spec, used for lookup. */
	char *stmt;           /* parameterized version of stmt, if supplied */
	int idcnt;            /* number of handler ids */
	int *idlist;          /* handler ids */
	unsigned char *flags; /* handler flags */
} PGtypeSpec;

/* PGparam structure */
struct pg_param
{
	int vcnt;         /* current number of param values */
	int vmax;         /* number of PGvalue structs in 'vals' array. */
	PGvalue *vals;    /* array of param values, grown when needed */

	/* assigned during PQparamCreate */
	PGtypeFormatInfo fmtinfo;
	int typhcnt;
	PGtypeHandler *typhandlers;

	int typspeccnt;
	PGtypeSpec *typspecs;
};

typedef struct
{
	PGtypeFormatInfo fmtinfo;
	int typhcnt;
	int typhmax;
	PGtypeHandler *typhandlers;

	int typspeccnt;
	int typspecmax;
	PGtypeSpec *typspecs;
} PGtypeData;

/* --------------------------------
 * Internal API functions (not exported)
 */

/* === in events.c === */

/* The libpq PGEventProc */
int pqt_eventproc(PGEventId id, void *info, void *passThrough);

void pqt_cleartypes(PGtypeData *typeData);

/* === in param.c === */

int pqt_putparam(PGparam *param, PGerror *err, const void *data, int datal,
	int flags, int format, Oid typoid);

/* === in spec.c === */

PGtypeSpec *pqt_getspec(PGtypeSpec *specs, int count, const char *name);
PGtypeSpec *pqt_dupspecs(PGtypeSpec *specs, int count);
void pqt_clearspec(PGtypeSpec *cache);
void pqt_freespecs(PGtypeSpec *specs, int count);

char *pqt_parse(PGerror *err, const char *format, PGtypeHandler *h, int hcnt,
	char *stmtBuf, size_t stmtBufLen, PGtypeHandler **out, size_t *stmtPos,
	int *typpos, int *flags);

char *pqt_parsetype(PGerror *err, const char *spec, char *schema, char *typname,
	int *flags, int typpos);

/* === in handler.c === */

int pqt_allowsptr(PGtypeHandler *h);
void pqt_getfmtinfo(const PGconn *conn, PGtypeFormatInfo *info);
PGtypeHandler *pqt_duphandlers(PGtypeHandler *handlers, int hcnt);
void pqt_freehandlers(PGtypeHandler *handlers, int hcnt);
int pqt_argssuper(PGtypeArgs *args, ...);
int pqt_argserrorf(PGtypeArgs *args, const char *format, ...);

PGtypeHandler *pqt_gethandler(PGtypeHandler *handlers, int hcnt,
	const char *schema, const char *typname);

PGtypeHandler *pqt_gethandlerbyid(PGtypeHandler *handlers,
	int hcnt, int id);

PGtypeHandler *pqt_gethandlerbyoid(PGtypeHandler *handlers,
	int hcnt, Oid oid);

/* FQTN standards for Fully Qualified Type Name.  Returns a pointer to out.
 * Only returns NULL if out is NULL or outl <= 0.
 */
char *pqt_fqtn(char *out, size_t outl,
	const char *schema, const char *typname);

/* == in utils.c == */

PGresult *pqt_copyresult(PGtypeArgs *args, int nattrs);
void pqt_swap8(void *outp, void *inp, int tonet);
int pqt_text_to_int8(char *val, void *out);
int pqt_text_to_float8(double *f8, char *text, char **endptr);

/* Checks buffer and truncates 'src' if 'dest' is too small. */
char *pqt_strcpy(char *dest, size_t size, const char *src);

/* Taken from postgres project (named pg_xxx) */
unsigned char pqt_tolower(unsigned char ch);
int pqt_strcasecmp(const char *s1, const char *s2);
int pqt_strncasecmp(const char *s1, const char *s2, size_t n);

/* == in port.c == */

/* Define a strtoll macro for windows, except for MinGW & Cygwin
 * which always have it.  MSVC has _strtoi64, but MSVC 6 and under
 * require that we declare the prototype.
 */
#ifdef PQT_MSVC
#	if PQT_MSVC <= 1200
		__int64 __cdecl _strtoi64(const char *, char **, int);
#	endif
# define strtoll _strtoi64
#endif

/* In rare cases these could be absent (older platforms).  We implement
 * drop-in replacements in port.c for those cases.  strtod handled by
 * configure, which adds a replacement for us.
 *
 * NOTE: only unixes use configure so sections wrapped around
 * HAVE_CONFIG_H exclude windows.
 */
#ifdef HAVE_CONFIG_H
#	ifndef HAVE_STRTOL
		long strtol(const char *nptr, char **endptr, int base);
#	endif
#	ifndef HAVE_STRTOUL
		unsigned long strtoul(const char *nptr, char **endptr, int base);
#	endif
#	ifndef HAVE_STRTOLL
		long long int strtoll(const char *nptr, char **endptr, int base);
#	endif
#endif

/* Handles platform differences and always returns -1 for failure.
 * On windows: MSVC 8 uses _snprintf_s, otherwise _snprintf.
 */
int pqt_snprintf(char *buf, size_t size, const char *format, ...);
int pqt_vsnprintf(char *buf, size_t size, const char *format, va_list ap);

/* --------------------------------
 * Built-in Type Handlers
 */

/* === in array.c === */

int pqt_put_array(PGtypeArgs *args);
int pqt_get_array(PGtypeArgs *args);

/* == in datetime.c == */

int pqt_put_date(PGtypeArgs *args);
int pqt_get_date(PGtypeArgs *args);
int pqt_put_time(PGtypeArgs *args);
int pqt_get_time(PGtypeArgs *args);
int pqt_put_timetz(PGtypeArgs *args);
int pqt_get_timetz(PGtypeArgs *args);
int pqt_put_timestamp(PGtypeArgs *args);
int pqt_get_timestamp(PGtypeArgs *args);
int pqt_put_timestamptz(PGtypeArgs *args);
int pqt_get_timestamptz(PGtypeArgs *args);
int pqt_put_interval(PGtypeArgs *args);
int pqt_get_interval(PGtypeArgs *args);

/* == in geo.c == */

int pqt_put_point(PGtypeArgs *args);
int pqt_get_point(PGtypeArgs *args);
int pqt_put_lseg(PGtypeArgs *args);
int pqt_get_lseg(PGtypeArgs *args);
int pqt_put_box(PGtypeArgs *args);
int pqt_get_box(PGtypeArgs *args);
int pqt_put_circle(PGtypeArgs *args);
int pqt_get_circle(PGtypeArgs *args);
int pqt_put_path(PGtypeArgs *args);
int pqt_get_path(PGtypeArgs *args);
int pqt_put_polygon(PGtypeArgs *args);
int pqt_get_polygon(PGtypeArgs *args);

/* == in misc.c == */

int pqt_put_char(PGtypeArgs *args); /* "char" type, not char(N) */
int pqt_get_char(PGtypeArgs *args);
int pqt_put_bool(PGtypeArgs *args);
int pqt_get_bool(PGtypeArgs *args);
int pqt_put_money(PGtypeArgs *args);
int pqt_get_money(PGtypeArgs *args);
int pqt_put_uuid(PGtypeArgs *args);
int pqt_get_uuid(PGtypeArgs *args);
int pqt_put_null(PGtypeArgs *args); /* no get for null */

/* == in network.c == */

int pqt_put_inet(PGtypeArgs *args); /* handles cidr */
int pqt_get_inet(PGtypeArgs *args);
int pqt_get_cidr(PGtypeArgs *args);
int pqt_put_macaddr(PGtypeArgs *args);
int pqt_get_macaddr(PGtypeArgs *args);

/* == in numerics.c == */

int pqt_put_int2(PGtypeArgs *args);
int pqt_get_int2(PGtypeArgs *args);
int pqt_put_int4(PGtypeArgs *args); /* handles oid */
int pqt_get_int4(PGtypeArgs *args); /* handles oid */
int pqt_put_int8(PGtypeArgs *args);
int pqt_get_int8(PGtypeArgs *args);
int pqt_put_float4(PGtypeArgs *args);
int pqt_get_float4(PGtypeArgs *args);
int pqt_put_float8(PGtypeArgs *args);
int pqt_get_float8(PGtypeArgs *args);
int pqt_put_numeric(PGtypeArgs *args);
int pqt_get_numeric(PGtypeArgs *args);

/* == record.c (composites) == */

int pqt_put_record(PGtypeArgs *args);
int pqt_get_record(PGtypeArgs *args);

/* == in varlena.c == */

int pqt_put_str(PGtypeArgs *args);  /* no get for str - use PQgetvalue */
int pqt_put_text(PGtypeArgs *args); /* handles varchar, bpchar and name */
int pqt_get_text(PGtypeArgs *args); /* handles varchar, bpchar and name */
int pqt_put_bytea(PGtypeArgs *args);
int pqt_get_bytea(PGtypeArgs *args);

#ifdef __cplusplus
}
#endif
#endif