Forgot two new files and one that was moved.
authorMichael Meskes
Sun, 30 Mar 2003 13:26:09 +0000 (13:26 +0000)
committerMichael Meskes
Sun, 30 Mar 2003 13:26:09 +0000 (13:26 +0000)
src/interfaces/ecpg/compatlib/Makefile [new file with mode: 0644]
src/interfaces/ecpg/compatlib/informix.c [new file with mode: 0644]
src/interfaces/ecpg/pgtypeslib/informix.c [deleted file]
src/interfaces/ecpg/pgtypeslib/interval.c [new file with mode: 0644]

diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/compatlib/Makefile
new file mode 100644 (file)
index 0000000..f48ac47
--- /dev/null
@@ -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 (file)
index 0000000..b8fd79a
--- /dev/null
@@ -0,0 +1,361 @@
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+/* 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 (file)
index d5cebe9..0000000
+++ /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 (file)
index 0000000..3d20bd3
--- /dev/null
@@ -0,0 +1,834 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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;
+}
+