]> granicus.if.org Git - postgresql/commitdiff
Forgot two new files and one that was moved.
authorMichael Meskes <meskes@postgresql.org>
Sun, 30 Mar 2003 13:26:09 +0000 (13:26 +0000)
committerMichael Meskes <meskes@postgresql.org>
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 <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 (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 <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;
+}
+