diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/compatlib/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f48ac474bfe819cd6c23ff574ab6974486fc9f9a
--- /dev/null
+++ b/src/interfaces/ecpg/compatlib/Makefile
@@ -0,0 +1,43 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for ecpg library
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+# $Header: /cvsroot/pgsql/src/interfaces/ecpg/compatlib/Makefile,v 1.1 2003/03/30 13:26:09 meskes Exp $
+#
+#-------------------------------------------------------------------------
+
+subdir = src/interfaces/ecpg/pgtypeslib
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+
+NAME= ecpg_compat
+SO_MAJOR_VERSION= 1
+SO_MINOR_VERSION= 0.0
+
+override CPPFLAGS := -O1 -g -I$(top_srcdir)/src/interfaces/ecpg/include -I$(top_srcdir)/src/include/utils $(CPPFLAGS)
+
+OBJS= informix.o
+
+all: all-lib
+
+# Shared library stuff
+include $(top_srcdir)/src/Makefile.shlib
+
+install: all installdirs install-lib
+
+installdirs:
+	$(mkinstalldirs) $(DESTDIR)$(libdir)
+
+uninstall: uninstall-lib
+
+clean distclean maintainer-clean: clean-lib
+	rm -f $(OBJS)
+
+depend dep:
+	$(CC) -MM $(CFLAGS) *.c >depend
+
+ifeq (depend,$(wildcard depend))
+include depend
+endif
diff --git a/src/interfaces/ecpg/compatlib/informix.c b/src/interfaces/ecpg/compatlib/informix.c
new file mode 100644
index 0000000000000000000000000000000000000000..b8fd79acde742ddfcdb5fdd1318d21d2b2eacd5c
--- /dev/null
+++ b/src/interfaces/ecpg/compatlib/informix.c
@@ -0,0 +1,361 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <ecpg_informix.h>
+#include <pgtypes_error.h>
+#include <pgtypes_date.h>
+
+/* we start with the numeric functions */
+int
+decadd(Numeric *arg1, Numeric *arg2, Numeric *sum)
+{
+	int i = PGTYPESnumeric_add(arg1, arg2, sum);
+
+	if (i == 0) /* No error */
+		return 0;
+	if (errno == PGTYPES_NUM_OVERFLOW)
+		return -1200;
+
+	return -1201;	
+}
+
+int
+deccmp(Numeric *arg1, Numeric *arg2)
+{
+	int i = PGTYPESnumeric_cmp(arg1, arg2);
+	
+	/* TODO: Need to return DECUNKNOWN instead of PGTYPES_NUM_BAD_NUMERIC */
+	return (i);
+}
+
+void
+deccopy(Numeric *src, Numeric *target)
+{
+	PGTYPESnumeric_copy(src, target);
+}
+
+static char *
+strndup(char *str, int len)
+{
+	int real_len = strlen(str);
+	int use_len = (real_len > len) ? len : real_len;
+	
+	char *new = malloc(use_len + 1);
+
+	if (new)
+	{
+		memcpy(str, new, use_len);
+		new[use_len] = '\0';
+	}
+	else
+		errno = ENOMEM;
+
+	return new;
+}
+
+int
+deccvasc(char *cp, int len, Numeric *np)
+{
+	char *str = strndup(cp, len); /* Numeric_in always converts the complete string */
+	int ret = 0;
+	
+	if (!str)
+		ret = -1201;
+	else
+	{
+		np = PGTYPESnumeric_aton(str, NULL);
+		if (!np)
+		{
+			switch (errno)
+			{
+				case PGTYPES_NUM_OVERFLOW:    ret = -1200;
+						          break;
+				case PGTYPES_NUM_BAD_NUMERIC: ret = -1213;
+							  break;
+				default:		  ret = -1216;
+							  break;
+			}
+		}
+	}
+	
+	return ret;
+}
+
+int
+deccvdbl(double dbl, Numeric *np)
+{
+	return(PGTYPESnumeric_dton(dbl, np));
+}
+
+int
+deccvint(int in, Numeric *np)
+{
+	return(PGTYPESnumeric_iton(in, np));
+}
+
+int
+deccvlong(long lng, Numeric *np)
+{
+	return(PGTYPESnumeric_lton(lng, np));	
+}
+
+int
+decdiv(Numeric *n1, Numeric *n2, Numeric *n3)
+{
+	int i = PGTYPESnumeric_div(n1, n2, n3), ret = 0;
+
+	if (i != 0)
+		switch (errno)
+		{
+			case PGTYPES_NUM_DIVIDE_ZERO: ret = -1202;
+						  break;
+			case PGTYPES_NUM_OVERFLOW:    ret = -1200;
+						  break;
+			default:		  ret = -1201;
+						  break;
+		}
+
+	return ret;
+}
+
+int 
+decmul(Numeric *n1, Numeric *n2, Numeric *n3)
+{
+	int i = PGTYPESnumeric_mul(n1, n2, n3), ret = 0;
+
+	if (i != 0)
+		switch (errno)
+		{
+			case PGTYPES_NUM_OVERFLOW:    ret = -1200;
+						  break;
+			default:		  ret = -1201;
+						  break;
+		}
+
+	return ret;
+}
+
+int
+decsub(Numeric *n1, Numeric *n2, Numeric *n3)
+{
+	int i = PGTYPESnumeric_sub(n1, n2, n3), ret = 0;
+
+	if (i != 0)
+		switch (errno)
+		{
+			case PGTYPES_NUM_OVERFLOW:    ret = -1200;
+						  break;
+			default:		  ret = -1201;
+						  break;
+		}
+
+	return ret;
+}
+
+int
+dectoasc(Numeric *np, char *cp, int len, int right)
+{
+	char *str;
+	
+	if (right >= 0)
+		str = PGTYPESnumeric_ntoa(np, right);
+	else
+		str = PGTYPESnumeric_ntoa(np, 0);
+
+	if (!str)
+		return -1;
+	
+	/* TODO: have to take care of len here and create exponatial notion if necessary */
+	strncpy(cp, str, len);
+	free (str);
+
+	return 0;
+}
+
+int
+dectodbl(Numeric *np, double *dblp)
+{
+	return(PGTYPESnumeric_ntod(np, dblp));
+}
+
+int
+dectoint(Numeric *np, int *ip)
+{
+	int ret = PGTYPESnumeric_ntoi(np, ip);
+
+	if (ret == PGTYPES_NUM_OVERFLOW)
+		ret = -1200;
+	
+	return ret;
+}
+
+int
+dectolong(Numeric *np, long *lngp)	
+{
+	int ret = PGTYPESnumeric_ntol(np, lngp);
+
+	if (ret == PGTYPES_NUM_OVERFLOW)
+		ret = -1200;
+	
+	return ret;
+}
+
+/* Now the date functions */
+int
+rdatestr (Date d, char *str)
+{
+	char *tmp = PGTYPESdate_dtoa(d);
+
+	if (!tmp)
+		return -1210;
+	
+	/* move to user allocated buffer */
+	strcpy(tmp, str);
+	free(str);
+	
+	return 0;
+}
+
+void
+rtoday (Date *d)
+{
+	PGTYPESdate_today(d);
+	return;
+}
+
+int
+rjulmdy (Date d, short mdy[3])
+{
+	PGTYPESdate_julmdy(d, (int *)mdy);
+	return 0;
+}
+
+int
+rdefmtdate (Date *d, char *fmt, char *str)
+{
+	/* TODO: take care of DBCENTURY environment variable */
+	/* PGSQL functions allow all centuries */
+
+	if (PGTYPESdate_defmtdate(d, fmt, str) == 0)
+		return 0;
+	
+	switch (errno)
+	{
+		case PGTYPES_DATE_ERR_ENOSHORTDATE: 	return -1209;
+		case PGTYPES_DATE_ERR_EARGS:
+		case PGTYPES_DATE_ERR_ENOTDMY: 		return -1212;
+		case PGTYPES_DATE_BAD_DAY: 		return -1204;
+		case PGTYPES_DATE_BAD_MONTH:		return -1205;
+		default: 				return -1206; 
+	}
+}
+
+int
+rfmtdate (Date d, char *fmt, char *str)
+{
+	if (PGTYPESdate_fmtdate(d, fmt, str) == 0)
+		return 0;
+		
+	if (errno == ENOMEM)
+		return -1211;
+
+	return -1210;
+}
+
+int
+rmdyjul (short mdy[3], Date *d)
+{
+	PGTYPESdate_mdyjul((int *)mdy, d);
+	return 0;
+}
+
+/* And the datetime stuff */
+
+void
+dtcurrent (Timestamp *ts)
+{
+	return;
+}
+
+int
+dtcvasc (char *str, Timestamp *ts)
+{
+	return 0;
+}
+
+int
+dtsub (Timestamp *ts1, Timestamp *ts2, Interval *iv)
+{
+	return 0;
+}
+
+int
+dttoasc (Timestamp *ts, char *output)
+{
+	return 0;
+}
+
+int
+dttofmtasc (Timestamp *ts, char *output, int str_len, char *fmtstr)
+{
+	return 0;
+}
+
+int
+intoasc(Interval *i, char *str)
+{
+	return 0;
+}
+
+/* And finally some misc functions */
+int
+rstrdate (char *str, Date *d)
+{
+	return 0;
+}
+
+int
+rfmtlong(long lvalue, char *format, char *outbuf)
+{
+	return 0;
+}
+
+int
+rgetmsg(int msgnum, char *s, int maxsize)
+{
+	return 0;
+}
+
+int
+risnull(int vtype, char *pcvar)
+{
+	return 0;
+}
+
+int
+rsetnull(int vtype, char *pcvar)
+{
+	return 0;
+}
+
+int
+rtypalign(int offset, int type)
+{
+	return 0;
+}
+
+int
+rtypmsize(int type, int len)
+{
+	return 0;
+}
+
+void
+rupshift(char *s)
+{
+	return;
+}
+
+
+
diff --git a/src/interfaces/ecpg/pgtypeslib/informix.c b/src/interfaces/ecpg/pgtypeslib/informix.c
deleted file mode 100644
index d5cebe9aa6d32fcae3571f470c5026113fc2aa73..0000000000000000000000000000000000000000
--- a/src/interfaces/ecpg/pgtypeslib/informix.c
+++ /dev/null
@@ -1,44 +0,0 @@
-int
-rfmtlong(long lvalue, char *format, char *outbuf)
-{
-	return 0;
-}
-
-int
-rgetmsg(int msgnum, char *s, int maxsize)
-{
-	return 0;
-}
-
-int
-risnull(int vtype, char *pcvar)
-{
-	return 0;
-}
-
-int
-rsetnull(int vtype, char *pcvar)
-{
-	return 0;
-}
-
-int
-rtypalign(int offset, int type)
-{
-	return 0;
-}
-
-int
-rtypmsize(int type, mint len)
-{
-	return 0;
-}
-
-void
-rupshift(char *s)
-{
-	return;
-}
-
-
-
diff --git a/src/interfaces/ecpg/pgtypeslib/interval.c b/src/interfaces/ecpg/pgtypeslib/interval.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d20bd3db3ed606ed477efada070373b29937445
--- /dev/null
+++ b/src/interfaces/ecpg/pgtypeslib/interval.c
@@ -0,0 +1,834 @@
+#include <math.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <float.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __FAST_MATH__
+#error -ffast-math is known to break this code
+#endif
+
+#include "dt.h"
+#include "extern.h"
+#include "pgtypes_error.h"
+#include "pgtypes_interval.h"
+#include "datetime.h"
+
+/* TrimTrailingZeros()
+ * ... resulting from printing numbers with full precision.
+ */
+static void
+TrimTrailingZeros(char *str)
+{
+	int			len = strlen(str);
+
+	/* chop off trailing zeros... but leave at least 2 fractional digits */
+	while ((*(str + len - 1) == '0')
+		   && (*(str + len - 3) != '.'))
+	{
+		len--;
+		*(str + len) = '\0';
+	}
+}
+
+/* DecodeTime()
+ * Decode time string which includes delimiters.
+ * Only check the lower limit on hours, since this same code
+ *	can be used to represent time spans.
+ */
+static int
+DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec)
+{
+	char	   *cp;
+
+	*tmask = DTK_TIME_M;
+
+	tm->tm_hour = strtol(str, &cp, 10);
+	if (*cp != ':')
+		return -1;
+	str = cp + 1;
+	tm->tm_min = strtol(str, &cp, 10);
+	if (*cp == '\0')
+	{
+		tm->tm_sec = 0;
+		*fsec = 0;
+	}
+	else if (*cp != ':')
+		return -1;
+	else
+	{
+		str = cp + 1;
+		tm->tm_sec = strtol(str, &cp, 10);
+		if (*cp == '\0')
+			*fsec = 0;
+		else if (*cp == '.')
+		{
+#ifdef HAVE_INT64_TIMESTAMP
+			char		fstr[MAXDATELEN + 1];
+
+			/*
+			 * OK, we have at most six digits to work with. Let's
+			 * construct a string and then do the conversion to an
+			 * integer.
+			 */
+			strncpy(fstr, (cp + 1), 7);
+			strcpy((fstr + strlen(fstr)), "000000");
+			*(fstr + 6) = '\0';
+			*fsec = strtol(fstr, &cp, 10);
+#else
+			str = cp;
+			*fsec = strtod(str, &cp);
+#endif
+			if (*cp != '\0')
+				return -1;
+		}
+		else
+			return -1;
+	}
+
+	/* do a sanity check */
+#ifdef HAVE_INT64_TIMESTAMP
+	if ((tm->tm_hour < 0)
+		|| (tm->tm_min < 0) || (tm->tm_min > 59)
+		|| (tm->tm_sec < 0) || (tm->tm_sec > 59)
+		|| (*fsec >= INT64CONST(1000000)))
+		return -1;
+#else
+	if ((tm->tm_hour < 0)
+		|| (tm->tm_min < 0) || (tm->tm_min > 59)
+		|| (tm->tm_sec < 0) || (tm->tm_sec > 59)
+		|| (*fsec >= 1))
+		return -1;
+#endif
+
+	return 0;
+}	/* DecodeTime() */
+
+/* DecodeInterval()
+ * Interpret previously parsed fields for general time interval.
+ * Return 0 if decoded and -1 if problems.
+ *
+ * Allow "date" field DTK_DATE since this could be just
+ *	an unsigned floating point number. - thomas 1997-11-16
+ *
+ * Allow ISO-style time span, with implicit units on number of days
+ *	preceding an hh:mm:ss field. - thomas 1998-04-30
+ */
+int
+DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fsec_t *fsec)
+{
+	int			is_before = FALSE;
+
+	char	   *cp;
+	int			fmask = 0,
+				tmask,
+				type;
+	int			i;
+	int			val;
+	double		fval;
+
+	*dtype = DTK_DELTA;
+
+	type = IGNORE_DTF;
+	tm->tm_year = 0;
+	tm->tm_mon = 0;
+	tm->tm_mday = 0;
+	tm->tm_hour = 0;
+	tm->tm_min = 0;
+	tm->tm_sec = 0;
+	*fsec = 0;
+
+	/* read through list backwards to pick up units before values */
+	for (i = nf - 1; i >= 0; i--)
+	{
+		switch (ftype[i])
+		{
+			case DTK_TIME:
+				if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
+					return -1;
+				type = DTK_DAY;
+				break;
+
+			case DTK_TZ:
+
+				/*
+				 * Timezone is a token with a leading sign character and
+				 * otherwise the same as a non-signed time field
+				 */
+
+				/*
+				 * A single signed number ends up here, but will be
+				 * rejected by DecodeTime(). So, work this out to drop
+				 * through to DTK_NUMBER, which *can* tolerate this.
+				 */
+				cp = field[i] + 1;
+				while ((*cp != '\0') && (*cp != ':') && (*cp != '.'))
+					cp++;
+				if ((*cp == ':')
+					&& (DecodeTime((field[i] + 1), fmask, &tmask, tm, fsec) == 0))
+				{
+					if (*field[i] == '-')
+					{
+						/* flip the sign on all fields */
+						tm->tm_hour = -tm->tm_hour;
+						tm->tm_min = -tm->tm_min;
+						tm->tm_sec = -tm->tm_sec;
+						*fsec = -(*fsec);
+					}
+
+					/*
+					 * Set the next type to be a day, if units are not
+					 * specified. This handles the case of '1 +02:03'
+					 * since we are reading right to left.
+					 */
+					type = DTK_DAY;
+					tmask = DTK_M(TZ);
+					break;
+				}
+				else if (type == IGNORE_DTF)
+				{
+					if (*cp == '.')
+					{
+						/*
+						 * Got a decimal point? Then assume some sort of
+						 * seconds specification
+						 */
+						type = DTK_SECOND;
+					}
+					else if (*cp == '\0')
+					{
+						/*
+						 * Only a signed integer? Then must assume a
+						 * timezone-like usage
+						 */
+						type = DTK_HOUR;
+					}
+				}
+				/* DROP THROUGH */
+
+			case DTK_DATE:
+			case DTK_NUMBER:
+				val = strtol(field[i], &cp, 10);
+
+				if (type == IGNORE_DTF)
+					type = DTK_SECOND;
+
+				if (*cp == '.')
+				{
+					fval = strtod(cp, &cp);
+					if (*cp != '\0')
+						return -1;
+
+					if (val < 0)
+						fval = -(fval);
+				}
+				else if (*cp == '\0')
+					fval = 0;
+				else
+					return -1;
+
+				tmask = 0;		/* DTK_M(type); */
+
+				switch (type)
+				{
+					case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+						*fsec += (val + fval);
+#else
+						*fsec += ((val + fval) * 1e-6);
+#endif
+						break;
+
+					case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+						*fsec += ((val + fval) * 1000);
+#else
+						*fsec += ((val + fval) * 1e-3);
+#endif
+						break;
+
+					case DTK_SECOND:
+						tm->tm_sec += val;
+#ifdef HAVE_INT64_TIMESTAMP
+						*fsec += (fval * 1000000);
+#else
+						*fsec += fval;
+#endif
+						tmask = DTK_M(SECOND);
+						break;
+
+					case DTK_MINUTE:
+						tm->tm_min += val;
+						if (fval != 0)
+						{
+							int			sec;
+
+							fval *= 60;
+							sec = fval;
+							tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+							*fsec += ((fval - sec) * 1000000);
+#else
+							*fsec += (fval - sec);
+#endif
+						}
+						tmask = DTK_M(MINUTE);
+						break;
+
+					case DTK_HOUR:
+						tm->tm_hour += val;
+						if (fval != 0)
+						{
+							int			sec;
+
+							fval *= 3600;
+							sec = fval;
+							tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+							*fsec += ((fval - sec) * 1000000);
+#else
+							*fsec += (fval - sec);
+#endif
+						}
+						tmask = DTK_M(HOUR);
+						break;
+
+					case DTK_DAY:
+						tm->tm_mday += val;
+						if (fval != 0)
+						{
+							int			sec;
+
+							fval *= 86400;
+							sec = fval;
+							tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+							*fsec += ((fval - sec) * 1000000);
+#else
+							*fsec += (fval - sec);
+#endif
+						}
+						tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
+						break;
+
+					case DTK_WEEK:
+						tm->tm_mday += val * 7;
+						if (fval != 0)
+						{
+							int			sec;
+
+							fval *= (7 * 86400);
+							sec = fval;
+							tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+							*fsec += ((fval - sec) * 1000000);
+#else
+							*fsec += (fval - sec);
+#endif
+						}
+						tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
+						break;
+
+					case DTK_MONTH:
+						tm->tm_mon += val;
+						if (fval != 0)
+						{
+							int			sec;
+
+							fval *= (30 * 86400);
+							sec = fval;
+							tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+							*fsec += ((fval - sec) * 1000000);
+#else
+							*fsec += (fval - sec);
+#endif
+						}
+						tmask = DTK_M(MONTH);
+						break;
+
+					case DTK_YEAR:
+						tm->tm_year += val;
+						if (fval != 0)
+							tm->tm_mon += (fval * 12);
+						tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
+						break;
+
+					case DTK_DECADE:
+						tm->tm_year += val * 10;
+						if (fval != 0)
+							tm->tm_mon += (fval * 120);
+						tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
+						break;
+
+					case DTK_CENTURY:
+						tm->tm_year += val * 100;
+						if (fval != 0)
+							tm->tm_mon += (fval * 1200);
+						tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
+						break;
+
+					case DTK_MILLENNIUM:
+						tm->tm_year += val * 1000;
+						if (fval != 0)
+							tm->tm_mon += (fval * 12000);
+						tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
+						break;
+
+					default:
+						return -1;
+				}
+				break;
+
+			case DTK_STRING:
+			case DTK_SPECIAL:
+				type = DecodeUnits(i, field[i], &val);
+				if (type == IGNORE_DTF)
+					continue;
+
+				tmask = 0;		/* DTK_M(type); */
+				switch (type)
+				{
+					case UNITS:
+						type = val;
+						break;
+
+					case AGO:
+						is_before = TRUE;
+						type = val;
+						break;
+
+					case RESERV:
+						tmask = (DTK_DATE_M || DTK_TIME_M);
+						*dtype = val;
+						break;
+
+					default:
+						return -1;
+				}
+				break;
+
+			default:
+				return -1;
+		}
+
+		if (tmask & fmask)
+			return -1;
+		fmask |= tmask;
+	}
+
+	if (*fsec != 0)
+	{
+		int			sec;
+
+#ifdef HAVE_INT64_TIMESTAMP
+		sec = (*fsec / INT64CONST(1000000));
+		*fsec -= (sec * INT64CONST(1000000));
+#else
+		TMODULO(*fsec, sec, 1e0);
+#endif
+		tm->tm_sec += sec;
+	}
+
+	if (is_before)
+	{
+		*fsec = -(*fsec);
+		tm->tm_sec = -(tm->tm_sec);
+		tm->tm_min = -(tm->tm_min);
+		tm->tm_hour = -(tm->tm_hour);
+		tm->tm_mday = -(tm->tm_mday);
+		tm->tm_mon = -(tm->tm_mon);
+		tm->tm_year = -(tm->tm_year);
+	}
+
+	/* ensure that at least one time field has been found */
+	return (fmask != 0) ? 0 : -1;
+}	/* DecodeInterval() */
+
+/* EncodeInterval()
+ * Interpret time structure as a delta time and convert to string.
+ *
+ * Support "traditional Postgres" and ISO-8601 styles.
+ * Actually, afaik ISO does not address time interval formatting,
+ *	but this looks similar to the spec for absolute date/time.
+ * - thomas 1998-04-30
+ */
+int
+EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str)
+{
+	int			is_before = FALSE;
+	int			is_nonzero = FALSE;
+	char	   *cp = str;
+
+	/*
+	 * The sign of year and month are guaranteed to match, since they are
+	 * stored internally as "month". But we'll need to check for is_before
+	 * and is_nonzero when determining the signs of hour/minute/seconds
+	 * fields.
+	 */
+	switch (style)
+	{
+			/* compatible with ISO date formats */
+		case USE_ISO_DATES:
+			if (tm->tm_year != 0)
+			{
+				sprintf(cp, "%d year%s",
+						tm->tm_year, ((tm->tm_year != 1) ? "s" : ""));
+				cp += strlen(cp);
+				is_before = (tm->tm_year < 0);
+				is_nonzero = TRUE;
+			}
+
+			if (tm->tm_mon != 0)
+			{
+				sprintf(cp, "%s%s%d mon%s", (is_nonzero ? " " : ""),
+						((is_before && (tm->tm_mon > 0)) ? "+" : ""),
+						tm->tm_mon, ((tm->tm_mon != 1) ? "s" : ""));
+				cp += strlen(cp);
+				is_before = (tm->tm_mon < 0);
+				is_nonzero = TRUE;
+			}
+
+			if (tm->tm_mday != 0)
+			{
+				sprintf(cp, "%s%s%d day%s", (is_nonzero ? " " : ""),
+						((is_before && (tm->tm_mday > 0)) ? "+" : ""),
+						tm->tm_mday, ((tm->tm_mday != 1) ? "s" : ""));
+				cp += strlen(cp);
+				is_before = (tm->tm_mday < 0);
+				is_nonzero = TRUE;
+			}
+			if ((!is_nonzero) || (tm->tm_hour != 0) || (tm->tm_min != 0)
+				|| (tm->tm_sec != 0) || (fsec != 0))
+			{
+				int			minus = ((tm->tm_hour < 0) || (tm->tm_min < 0)
+									 || (tm->tm_sec < 0) || (fsec < 0));
+
+				sprintf(cp, "%s%s%02d:%02d", (is_nonzero ? " " : ""),
+						(minus ? "-" : (is_before ? "+" : "")),
+						abs(tm->tm_hour), abs(tm->tm_min));
+				cp += strlen(cp);
+				/* Mark as "non-zero" since the fields are now filled in */
+				is_nonzero = TRUE;
+
+				/* fractional seconds? */
+				if (fsec != 0)
+				{
+#ifdef HAVE_INT64_TIMESTAMP
+					sprintf(cp, ":%02d", abs(tm->tm_sec));
+					cp += strlen(cp);
+					sprintf(cp, ".%06d", ((fsec >= 0) ? fsec : -(fsec)));
+#else
+					fsec += tm->tm_sec;
+					sprintf(cp, ":%013.10f", fabs(fsec));
+#endif
+					TrimTrailingZeros(cp);
+					cp += strlen(cp);
+					is_nonzero = TRUE;
+				}
+				/* otherwise, integer seconds only? */
+				else if (tm->tm_sec != 0)
+				{
+					sprintf(cp, ":%02d", abs(tm->tm_sec));
+					cp += strlen(cp);
+					is_nonzero = TRUE;
+				}
+			}
+			break;
+
+		case USE_POSTGRES_DATES:
+		default:
+			strcpy(cp, "@ ");
+			cp += strlen(cp);
+
+			if (tm->tm_year != 0)
+			{
+				int			year = tm->tm_year;
+
+				if (tm->tm_year < 0)
+					year = -year;
+
+				sprintf(cp, "%d year%s", year,
+						((year != 1) ? "s" : ""));
+				cp += strlen(cp);
+				is_before = (tm->tm_year < 0);
+				is_nonzero = TRUE;
+			}
+
+			if (tm->tm_mon != 0)
+			{
+				int			mon = tm->tm_mon;
+
+				if (is_before || ((!is_nonzero) && (tm->tm_mon < 0)))
+					mon = -mon;
+
+				sprintf(cp, "%s%d mon%s", (is_nonzero ? " " : ""), mon,
+						((mon != 1) ? "s" : ""));
+				cp += strlen(cp);
+				if (!is_nonzero)
+					is_before = (tm->tm_mon < 0);
+				is_nonzero = TRUE;
+			}
+
+			if (tm->tm_mday != 0)
+			{
+				int			day = tm->tm_mday;
+
+				if (is_before || ((!is_nonzero) && (tm->tm_mday < 0)))
+					day = -day;
+
+				sprintf(cp, "%s%d day%s", (is_nonzero ? " " : ""), day,
+						((day != 1) ? "s" : ""));
+				cp += strlen(cp);
+				if (!is_nonzero)
+					is_before = (tm->tm_mday < 0);
+				is_nonzero = TRUE;
+			}
+			if (tm->tm_hour != 0)
+			{
+				int			hour = tm->tm_hour;
+
+				if (is_before || ((!is_nonzero) && (tm->tm_hour < 0)))
+					hour = -hour;
+
+				sprintf(cp, "%s%d hour%s", (is_nonzero ? " " : ""), hour,
+						((hour != 1) ? "s" : ""));
+				cp += strlen(cp);
+				if (!is_nonzero)
+					is_before = (tm->tm_hour < 0);
+				is_nonzero = TRUE;
+			}
+
+			if (tm->tm_min != 0)
+			{
+				int			min = tm->tm_min;
+
+				if (is_before || ((!is_nonzero) && (tm->tm_min < 0)))
+					min = -min;
+
+				sprintf(cp, "%s%d min%s", (is_nonzero ? " " : ""), min,
+						((min != 1) ? "s" : ""));
+				cp += strlen(cp);
+				if (!is_nonzero)
+					is_before = (tm->tm_min < 0);
+				is_nonzero = TRUE;
+			}
+
+			/* fractional seconds? */
+			if (fsec != 0)
+			{
+#ifdef HAVE_INT64_TIMESTAMP
+				if (is_before || ((!is_nonzero) && (tm->tm_sec < 0)))
+					tm->tm_sec = -tm->tm_sec;
+				sprintf(cp, "%s%d.%02d secs", (is_nonzero ? " " : ""),
+						tm->tm_sec, (((int) fsec) / 10000));
+				cp += strlen(cp);
+				if (!is_nonzero)
+					is_before = (fsec < 0);
+#else
+				fsec_t		sec;
+
+				fsec += tm->tm_sec;
+				sec = fsec;
+				if (is_before || ((!is_nonzero) && (fsec < 0)))
+					sec = -sec;
+
+				sprintf(cp, "%s%.2f secs", (is_nonzero ? " " : ""), sec);
+				cp += strlen(cp);
+				if (!is_nonzero)
+					is_before = (fsec < 0);
+#endif
+				is_nonzero = TRUE;
+
+				/* otherwise, integer seconds only? */
+			}
+			else if (tm->tm_sec != 0)
+			{
+				int			sec = tm->tm_sec;
+
+				if (is_before || ((!is_nonzero) && (tm->tm_sec < 0)))
+					sec = -sec;
+
+				sprintf(cp, "%s%d sec%s", (is_nonzero ? " " : ""), sec,
+						((sec != 1) ? "s" : ""));
+				cp += strlen(cp);
+				if (!is_nonzero)
+					is_before = (tm->tm_sec < 0);
+				is_nonzero = TRUE;
+			}
+			break;
+	}
+
+	/* identically zero? then put in a unitless zero... */
+	if (!is_nonzero)
+	{
+		strcat(cp, "0");
+		cp += strlen(cp);
+	}
+
+	if (is_before && (style == USE_POSTGRES_DATES))
+	{
+		strcat(cp, " ago");
+		cp += strlen(cp);
+	}
+
+	return 0;
+}	/* EncodeInterval() */
+
+/* interval2tm()
+ * Convert a interval data type to a tm structure.
+ */
+static int
+interval2tm(Interval span, struct tm * tm, fsec_t *fsec)
+{
+#ifdef HAVE_INT64_TIMESTAMP
+	int64		time;
+
+#else
+	double		time;
+#endif
+
+	if (span.month != 0)
+	{
+		tm->tm_year = span.month / 12;
+		tm->tm_mon = span.month % 12;
+
+	}
+	else
+	{
+		tm->tm_year = 0;
+		tm->tm_mon = 0;
+	}
+
+	time = span.time;
+
+#ifdef HAVE_INT64_TIMESTAMP
+	tm->tm_mday = (time / INT64CONST(86400000000));
+	time -= (tm->tm_mday * INT64CONST(86400000000));
+	tm->tm_hour = (time / INT64CONST(3600000000));
+	time -= (tm->tm_hour * INT64CONST(3600000000));
+	tm->tm_min = (time / INT64CONST(60000000));
+	time -= (tm->tm_min * INT64CONST(60000000));
+	tm->tm_sec = (time / INT64CONST(1000000));
+	*fsec = (time - (tm->tm_sec * INT64CONST(1000000)));
+#else
+	TMODULO(time, tm->tm_mday, 86400e0);
+	TMODULO(time, tm->tm_hour, 3600e0);
+	TMODULO(time, tm->tm_min, 60e0);
+	TMODULO(time, tm->tm_sec, 1e0);
+	*fsec = time;
+#endif
+
+	return 0;
+}	/* interval2tm() */
+
+static int
+tm2interval(struct tm * tm, fsec_t fsec, Interval *span)
+{
+	span->month = ((tm->tm_year * 12) + tm->tm_mon);
+#ifdef HAVE_INT64_TIMESTAMP
+	span->time = ((((((((tm->tm_mday * INT64CONST(24))
+						+ tm->tm_hour) * INT64CONST(60))
+					  + tm->tm_min) * INT64CONST(60))
+					+ tm->tm_sec) * INT64CONST(1000000)) + fsec);
+#else
+	span->time = ((((((tm->tm_mday * 24.0)
+					  + tm->tm_hour) * 60.0)
+					+ tm->tm_min) * 60.0)
+				  + tm->tm_sec);
+	span->time = JROUND(span->time + fsec);
+#endif
+
+	return 0;
+}	/* tm2interval() */
+
+Interval *
+PGTYPESinterval_atoi(char *str, char **endptr)
+{
+	Interval	*result = NULL;
+	fsec_t		fsec;
+	struct tm	tt,
+			   *tm = &tt;
+	int			dtype;
+	int			nf;
+	char	   *field[MAXDATEFIELDS];
+	int			ftype[MAXDATEFIELDS];
+	char		lowstr[MAXDATELEN + MAXDATEFIELDS];
+	char            *realptr;
+	char **ptr = (endptr != NULL) ? endptr : &realptr;
+
+	tm->tm_year = 0;
+	tm->tm_mon = 0;
+	tm->tm_mday = 0;
+	tm->tm_hour = 0;
+	tm->tm_min = 0;
+	tm->tm_sec = 0;
+	fsec = 0;
+
+	if (strlen(str) >= sizeof(lowstr))
+	{
+		errno = PGTYPES_INTVL_BAD_INTERVAL;
+		return NULL;
+	}
+
+	if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf, ptr) != 0)
+		|| (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
+	{
+		errno = PGTYPES_INTVL_BAD_INTERVAL;
+		return NULL;
+	}
+
+	result = (Interval *) pgtypes_alloc(sizeof(Interval));
+	if (!result)
+		return NULL;
+
+	if (dtype != DTK_DELTA)
+	{
+		errno = PGTYPES_INTVL_BAD_INTERVAL;
+		return NULL;
+	}
+
+	if (tm2interval(tm, fsec, result) != 0)
+	{
+		errno = PGTYPES_INTVL_BAD_INTERVAL;
+		return NULL;
+	}
+	
+	return result;
+}
+
+char *
+PGTYPESinterval_itoa(Interval *span)
+{
+	struct tm	tt,
+			   *tm = &tt;
+	fsec_t		fsec;
+	char		buf[MAXDATELEN + 1];
+	int DateStyle=0;
+
+	if (interval2tm(*span, tm, &fsec) != 0)
+	{
+		errno = PGTYPES_INTVL_BAD_INTERVAL;
+		return NULL;
+	}
+
+	if (EncodeInterval(tm, fsec, DateStyle, buf) != 0)
+	{
+		errno = PGTYPES_INTVL_BAD_INTERVAL;
+		return NULL;
+	}
+	
+        return pgtypes_strdup(buf);
+}
+
+int 
+PGTYPESinterval_copy(Interval *intvlsrc, Interval *intrcldest)
+{
+	intrcldest->time = intvlsrc->time;
+	intrcldest->month = intvlsrc->month;
+
+	return 0;
+}
+