Applied patch by Ron Mayer to merge the new
authorMichael Meskes
Wed, 26 Nov 2008 16:31:02 +0000 (16:31 +0000)
committerMichael Meskes
Wed, 26 Nov 2008 16:31:02 +0000 (16:31 +0000)
interval style into ecpg.

src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/pgtypeslib/dt.h
src/interfaces/ecpg/pgtypeslib/interval.c
src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr
src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc

index 939b2e5914b8b1babc1c235be356df7597fd34d8..c6064cd0afb4103779033ec17c8a69b8f4afd2c5 100644 (file)
@@ -2394,6 +2394,8 @@ Sat, 25 Oct 2008 16:34:28 +0200
 Wed, 26 Nov 2008 14:09:08 +0100
 
    - When creating a varchar struct name braces must be discarded.
+   - Applied patch by Ron Mayer  to merge
+     the new interval style into ecpg.
    - Set pgtypes library version to 3.1.
    - Set compat library version to 3.1.
    - Set ecpg library version to 6.2.
index 47905dedfe769b028512dd60f296344b23ed7db9..0008211fad0049568c33abddf4fb1bafe20f3350 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/dt.h,v 1.39 2007/11/15 21:14:45 momjian Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/dt.h,v 1.40 2008/11/26 16:31:02 meskes Exp $ */
 
 #ifndef DT_H
 #define DT_H
@@ -25,6 +25,22 @@ typedef double fsec_t;
 #define USE_SQL_DATES                  2
 #define USE_GERMAN_DATES               3
 
+#define INTSTYLE_POSTGRES             0
+#define INTSTYLE_POSTGRES_VERBOSE     1
+#define INTSTYLE_SQL_STANDARD         2
+#define INTSTYLE_ISO_8601             3
+
+#define INTERVAL_FULL_RANGE (0x7FFF)
+#define INTERVAL_MASK(b) (1 << (b))
+#define MAX_INTERVAL_PRECISION 6
+
+#define DTERR_BAD_FORMAT       (-1)
+#define DTERR_FIELD_OVERFLOW   (-2)
+#define DTERR_MD_FIELD_OVERFLOW (-3)   /* triggers hint about DateStyle */
+#define DTERR_INTERVAL_OVERFLOW (-4)
+#define DTERR_TZDISP_OVERFLOW  (-5)
+
+
 #define DAGO           "ago"
 #define EPOCH          "epoch"
 #define INVALID            "invalid"
@@ -77,6 +93,9 @@ typedef double fsec_t;
  * Furthermore, the values for YEAR, MONTH, DAY, HOUR, MINUTE, SECOND
  * must be in the range 0..14 so that the associated bitmasks can fit
  * into the left half of an INTERVAL's typmod value.
+ *
+ * Copy&pasted these values from src/include/utils/datetime.h
+ * 2008-11-20, changing a number of their values.
  */
 
 #define RESERV 0
@@ -92,20 +111,23 @@ typedef double fsec_t;
 #define HOUR   10
 #define MINUTE 11
 #define SECOND 12
-#define DOY        13
-#define DOW        14
-#define UNITS  15
-#define ADBC   16
+#define MILLISECOND 13
+#define MICROSECOND 14
+#define DOY        15
+#define DOW        16
+#define UNITS  17
+#define ADBC   18
 /* these are only for relative dates */
-#define AGO        17
-#define ABS_BEFORE     18
-#define ABS_AFTER      19
+#define AGO        19
+#define ABS_BEFORE     20
+#define ABS_AFTER      21
 /* generic fields to help with parsing */
-#define ISODATE 20
-#define ISOTIME 21
+#define ISODATE 22
+#define ISOTIME 23
 /* reserved for unrecognized string values */
 #define UNKNOWN_FIELD  31
 
+
 /*
  * Token field definitions for time parsing and decoding.
  * These need to fit into the datetkn table type.
@@ -164,13 +186,13 @@ typedef double fsec_t;
 /*
  * Bit mask definitions for time parsing.
  */
-
+/* Copy&pasted these values from src/include/utils/datetime.h */
 #define DTK_M(t)       (0x01 << (t))
-
+#define DTK_ALL_SECS_M     (DTK_M(SECOND) | DTK_M(MILLISECOND) | DTK_M(MICROSECOND))
 #define DTK_DATE_M     (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
 #define DTK_TIME_M     (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND))
 
-#define MAXDATELEN     51      /* maximum possible length of an input date
+#define MAXDATELEN     63      /* maximum possible length of an input date
                                 * string (not counting tr. null) */
 #define MAXDATEFIELDS  25      /* maximum possible number of fields in a date
                                 * string */
index a8f1899fdb3c08bd6280a790dcb3814ac6ee6a1e..58b5fefff6d4875efec58cb8e5a2c32a43cb5b46 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/interval.c,v 1.37 2007/08/22 08:20:58 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/interval.c,v 1.38 2008/11/26 16:31:02 meskes Exp $ */
 
 #include "postgres_fe.h"
 #include 
 #include "pgtypes_error.h"
 #include "pgtypes_interval.h"
 
-/* DecodeInterval()
- * Interpret previously parsed fields for general time interval.
- * Return 0 if decoded and -1 if problems.
+/* copy&pasted from .../src/backend/utils/adt/datetime.c */
+static int
+strtoi(const char *nptr, char **endptr, int base)
+{
+   long    val;
+
+   val = strtol(nptr, endptr, base);
+#ifdef HAVE_LONG_INT_64
+   if (val != (long) ((int32) val))
+       errno = ERANGE;
+#endif
+   return (int) val;
+}
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c 
+ * and changesd struct pg_tm to struct tm
+ */
+static void
+AdjustFractSeconds(double frac, struct /*pg_*/tm * tm, fsec_t *fsec, int scale)
+{
+   int sec;
+
+   if (frac == 0)
+       return;
+   frac       *= scale;
+   sec         = (int) frac;
+   tm->tm_sec += sec;
+   frac       -= sec;
+#ifdef HAVE_INT64_TIMESTAMP
+   *fsec      += rint(frac * 1000000);
+#else
+   *fsec      += frac;
+#endif
+}
+
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c 
+ * and changesd struct pg_tm to struct tm
+ */
+static void
+AdjustFractDays(double frac, struct /*pg_*/tm * tm, fsec_t *fsec, int scale)
+{
+   int extra_days;
+
+   if (frac == 0)
+       return;
+   frac        *= scale;
+   extra_days   = (int) frac;
+   tm->tm_mday += extra_days;
+   frac        -= extra_days;
+   AdjustFractSeconds(frac, tm, fsec, SECS_PER_DAY);
+}
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c */
+static int
+ParseISO8601Number(char *str, char **endptr, int *ipart, double *fpart)
+{
+   double      val;
+
+   if (!(isdigit((unsigned char) *str) || *str == '-' || *str == '.'))
+       return DTERR_BAD_FORMAT;
+   errno = 0;
+   val = strtod(str, endptr);
+   /* did we not see anything that looks like a double? */
+   if (*endptr == str || errno != 0)
+       return DTERR_BAD_FORMAT;
+   /* watch out for overflow */
+   if (val < INT_MIN || val > INT_MAX)
+       return DTERR_FIELD_OVERFLOW;
+   /* be very sure we truncate towards zero (cf dtrunc()) */
+   if (val >= 0)
+       *ipart = (int) floor(val);
+   else
+       *ipart = (int) -floor(-val);
+   *fpart = val - *ipart;
+   return 0;
+}
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c */
+static int
+ISO8601IntegerWidth(char *fieldstart)
+{
+   /* We might have had a leading '-' */
+   if (*fieldstart == '-')
+       fieldstart++;
+   return strspn(fieldstart, "0123456789");
+}
+
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c 
+ * and changesd struct pg_tm to struct tm
+ */
+static inline void 
+ClearPgTm(struct /*pg_*/tm *tm, fsec_t *fsec)
+{
+   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;
+}
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c 
+ * 
+ * * changesd struct pg_tm to struct tm
+ * 
+ * * Made the function static
+ */
+static int
+DecodeISO8601Interval(char *str,
+                     int *dtype, struct /*pg_*/tm * tm, fsec_t *fsec)
+{
+   bool    datepart = true;
+   bool    havefield = false;
+
+   *dtype = DTK_DELTA;
+   ClearPgTm(tm, fsec);
+
+   if (strlen(str) < 2 || str[0] != 'P')
+       return DTERR_BAD_FORMAT;
+
+   str++;
+   while (*str)
+   {
+       char   *fieldstart;
+       int     val;
+       double  fval;
+       char    unit;
+       int     dterr;
+
+       if (*str == 'T') /* T indicates the beginning of the time part */
+       {
+           datepart = false;
+           havefield = false;
+           str++;
+           continue;
+       }
+
+       fieldstart = str;
+       dterr = ParseISO8601Number(str, &str, &val, &fval);
+       if (dterr)
+           return dterr;
+
+       /*
+        * Note: we could step off the end of the string here.  Code below
+        * *must* exit the loop if unit == '\0'.
+        */
+       unit = *str++;
+
+       if (datepart)
+       {
+           switch (unit) /* before T: Y M W D */
+           {
+               case 'Y':
+                   tm->tm_year += val;
+                   tm->tm_mon += (fval * 12);
+                   break;
+               case 'M':
+                   tm->tm_mon += val;
+                   AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
+                   break;
+               case 'W':
+                   tm->tm_mday += val * 7;
+                   AdjustFractDays(fval, tm, fsec, 7);
+                   break;
+               case 'D':
+                   tm->tm_mday += val;
+                   AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
+                   break;
+               case 'T': /* ISO 8601 4.4.3.3 Alternative Format / Basic */
+               case '\0':
+                   if (ISO8601IntegerWidth(fieldstart) == 8 && !havefield)
+                   {
+                       tm->tm_year += val / 10000;
+                       tm->tm_mon  += (val / 100) % 100;
+                       tm->tm_mday += val % 100;
+                       AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
+                       if (unit == '\0')
+                           return 0;
+                       datepart = false;
+                       havefield = false;
+                       continue;
+                   }
+                   /* Else fall through to extended alternative format */
+               case '-': /* ISO 8601 4.4.3.3 Alternative Format, Extended */
+                   if (havefield)
+                       return DTERR_BAD_FORMAT;
+
+                   tm->tm_year += val;
+                   tm->tm_mon  += (fval * 12);
+                   if (unit == '\0')
+                       return 0;
+                   if (unit == 'T')
+                   {
+                       datepart = false;
+                       havefield = false;
+                       continue;
+                   }
+
+                   dterr = ParseISO8601Number(str, &str, &val, &fval);
+                   if (dterr)
+                       return dterr;
+                   tm->tm_mon  += val;
+                   AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
+                   if (*str == '\0')
+                       return 0;
+                   if (*str == 'T')
+                   {
+                       datepart = false;
+                       havefield = false;
+                       continue;
+                   }
+                   if (*str != '-')
+                       return DTERR_BAD_FORMAT;
+                   str++;
+                   
+                   dterr = ParseISO8601Number(str, &str, &val, &fval);
+                   if (dterr)
+                       return dterr;
+                   tm->tm_mday += val;
+                   AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
+                   if (*str == '\0')
+                       return 0;
+                   if (*str == 'T')
+                   {
+                       datepart = false;
+                       havefield = false;
+                       continue;
+                   }
+                   return DTERR_BAD_FORMAT;
+               default:
+                   /* not a valid date unit suffix */
+                   return DTERR_BAD_FORMAT;
+           }
+       }
+       else
+       {
+           switch (unit) /* after T: H M S */
+           {
+               case 'H':
+                   tm->tm_hour += val;
+                   AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
+                   break;
+               case 'M':
+                   tm->tm_min += val;
+                   AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
+                   break;
+               case 'S':
+                   tm->tm_sec += val;
+                   AdjustFractSeconds(fval, tm, fsec, 1);
+                   break;
+               case '\0': /* ISO 8601 4.4.3.3 Alternative Format */
+                   if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
+                   {
+                       tm->tm_hour += val / 10000;
+                       tm->tm_min  += (val / 100) % 100;
+                       tm->tm_sec  += val % 100;
+                       AdjustFractSeconds(fval, tm, fsec, 1);
+                       return 0;
+                   }
+                   /* Else fall through to extended alternative format */
+               case ':': /* ISO 8601 4.4.3.3 Alternative Format, Extended */
+                   if (havefield)
+                       return DTERR_BAD_FORMAT;
+
+                   tm->tm_hour += val;
+                   AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
+                   if (unit == '\0')
+                       return 0;
+                   
+                   dterr = ParseISO8601Number(str, &str, &val, &fval);
+                   if (dterr)
+                       return dterr;
+                   tm->tm_min  += val;
+                   AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
+                   if (*str == '\0')
+                       return 0;
+                   if (*str != ':')
+                       return DTERR_BAD_FORMAT;
+                   str++;
+                   
+                   dterr = ParseISO8601Number(str, &str, &val, &fval);
+                   if (dterr)
+                       return dterr;
+                   tm->tm_sec  += val;
+                   AdjustFractSeconds(fval, tm, fsec, 1);
+                   if (*str == '\0')
+                       return 0;
+                   return DTERR_BAD_FORMAT;
+
+               default:
+                   /* not a valid time unit suffix */
+                   return DTERR_BAD_FORMAT;
+           }
+       }
+
+       havefield = true;
+   }
+
+   return 0;
+}
+
+
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c
+ * with 3 exceptions
+ *
+ *  * changesd struct pg_tm to struct tm
+ *
+ *  * ECPG code called this without a 'range' parameter
+ *    removed 'int range' from the argument list and
+ *    places where DecodeTime is called; and added
+ *       int range = INTERVAL_FULL_RANGE;
  *
- * Allow "date" field DTK_DATE since this could be just
- * an unsigned floating point number. - thomas 1997-11-16
+ *  * ECPG semes not to have a global IntervalStyle
+ *    so added
+ *     int IntervalStyle = INTSTYLE_POSTGRES;
  *
- * Allow ISO-style time span, with implicit units on number of days
- * preceding an hh:mm:ss field. - thomas 1998-04-30
+ *  * Assert wasn't available so removed it.
  */
 int
-DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fsec_t *fsec)
+DecodeInterval(char **field, int *ftype, int nf, /*int range,*/
+              int *dtype, struct /*pg_*/tm * tm, fsec_t *fsec)
 {
-   int         is_before = FALSE;
-
+    int IntervalStyle = INTSTYLE_POSTGRES_VERBOSE;
+    int range = INTERVAL_FULL_RANGE;
+   bool        is_before = FALSE;
    char       *cp;
    int         fmask = 0,
                tmask,
                type;
    int         i;
+   int         dterr;
    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;
+   ClearPgTm(tm,fsec);
 
    /* read through list backwards to pick up units before values */
    for (i = nf - 1; i >= 0; i--)
@@ -53,8 +361,10 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
        switch (ftype[i])
        {
            case DTK_TIME:
-               if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
-                   return -1;
+               dterr = DecodeTime(field[i], fmask, /* range, */
+                                  &tmask, tm, fsec);
+               if (dterr)
+                   return dterr;
                type = DTK_DAY;
                break;
 
@@ -62,18 +372,19 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
 
                /*
                 * Timezone is a token with a leading sign character and
-                * otherwise the same as a non-signed time field
+                * at least one digit; there could be ':', '.', '-'
+                * embedded in it as well.
                 */
+               /* Assert(*field[i] == '-' || *field[i] == '+'); */
 
                /*
-                * 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.
+                * Try for hh:mm or hh:mm:ss.  If not, fall through to
+                * DTK_NUMBER case, which can handle signed float numbers
+                * and signed year-month values.
                 */
-               cp = field[i] + 1;
-               while (*cp != '\0' && *cp != ':' && *cp != '.')
-                   cp++;
-               if (*cp == ':' && DecodeTime((field[i] + 1), fmask, &tmask, tm, fsec) == 0)
+               if (strchr(field[i] + 1, ':') != NULL &&
+                   DecodeTime(field[i] + 1, fmask, /* INTERVAL_FULL_RANGE, */
+                              &tmask, tm, fsec) == 0)
                {
                    if (*field[i] == '-')
                    {
@@ -93,47 +404,81 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
                    tmask = DTK_M(TZ);
                    break;
                }
-               else if (type == IGNORE_DTF)
+               /* FALL THROUGH */
+
+           case DTK_DATE:
+           case DTK_NUMBER:
+               if (type == IGNORE_DTF)
                {
-                   if (*cp == '.')
+                   /* use typmod to decide what rightmost field is */
+                   switch (range)
                    {
-                       /*
-                        * 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;
+                       case INTERVAL_MASK(YEAR):
+                           type = DTK_YEAR;
+                           break;
+                       case INTERVAL_MASK(MONTH):
+                       case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
+                           type = DTK_MONTH;
+                           break;
+                       case INTERVAL_MASK(DAY):
+                           type = DTK_DAY;
+                           break;
+                       case INTERVAL_MASK(HOUR):
+                       case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
+                       case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
+                       case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
+                           type = DTK_HOUR;
+                           break;
+                       case INTERVAL_MASK(MINUTE):
+                       case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
+                           type = DTK_MINUTE;
+                           break;
+                       case INTERVAL_MASK(SECOND):
+                       case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
+                       case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
+                           type = DTK_SECOND;
+                           break;
+                       default:
+                           type = DTK_SECOND;
+                           break;
                    }
                }
-               /* DROP THROUGH */
 
-           case DTK_DATE:
-           case DTK_NUMBER:
-               val = strtol(field[i], &cp, 10);
+               errno = 0;
+               val = strtoi(field[i], &cp, 10);
+               if (errno == ERANGE)
+                   return DTERR_FIELD_OVERFLOW;
 
-               if (type == IGNORE_DTF)
-                   type = DTK_SECOND;
+               if (*cp == '-')
+               {
+                   /* SQL "years-months" syntax */
+                   int     val2;
 
-               if (*cp == '.')
+                   val2 = strtoi(cp + 1, &cp, 10);
+                   if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR)
+                       return DTERR_FIELD_OVERFLOW;
+                   if (*cp != '\0')
+                       return DTERR_BAD_FORMAT;
+                   type = DTK_MONTH;
+                   if (*field[i] == '-')
+                       val2 = -val2;
+                   val = val * MONTHS_PER_YEAR + val2;
+                   fval = 0;
+               }
+               else if (*cp == '.')
                {
+                   errno = 0;
                    fval = strtod(cp, &cp);
-                   if (*cp != '\0')
-                       return -1;
+                   if (*cp != '\0' || errno != 0)
+                       return DTERR_BAD_FORMAT;
 
-                   if (val < 0)
+                   if (*field[i] == '-')
                        fval = -fval;
                }
                else if (*cp == '\0')
                    fval = 0;
                else
-                   return -1;
+                   return DTERR_BAD_FORMAT;
 
                tmask = 0;      /* DTK_M(type); */
 
@@ -141,135 +486,68 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
                {
                    case DTK_MICROSEC:
 #ifdef HAVE_INT64_TIMESTAMP
-                       *fsec += val + fval;
+                       *fsec += rint(val + fval);
 #else
                        *fsec += (val + fval) * 1e-6;
 #endif
+                       tmask = DTK_M(MICROSECOND);
                        break;
 
                    case DTK_MILLISEC:
 #ifdef HAVE_INT64_TIMESTAMP
-                       *fsec += (val + fval) * 1000;
+                       *fsec += rint((val + fval) * 1000);
 #else
                        *fsec += (val + fval) * 1e-3;
 #endif
+                       tmask = DTK_M(MILLISECOND);
                        break;
 
                    case DTK_SECOND:
                        tm->tm_sec += val;
 #ifdef HAVE_INT64_TIMESTAMP
-                       *fsec += fval * 1000000;
+                       *fsec += rint(fval * 1000000);
 #else
                        *fsec += fval;
 #endif
-                       tmask = DTK_M(SECOND);
+
+                       /*
+                        * If any subseconds were specified, consider this
+                        * microsecond and millisecond input as well.
+                        */
+                       if (fval == 0)
+                           tmask = DTK_M(SECOND);
+                       else
+                           tmask = DTK_ALL_SECS_M;
                        break;
 
                    case DTK_MINUTE:
                        tm->tm_min += val;
-                       if (fval != 0)
-                       {
-                           int         sec;
-
-                           fval *= SECS_PER_MINUTE;
-                           sec = fval;
-                           tm->tm_sec += sec;
-#ifdef HAVE_INT64_TIMESTAMP
-                           *fsec += ((fval - sec) * 1000000);
-#else
-                           *fsec += fval - sec;
-#endif
-                       }
+                       AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
                        tmask = DTK_M(MINUTE);
                        break;
 
                    case DTK_HOUR:
                        tm->tm_hour += val;
-                       if (fval != 0)
-                       {
-                           int         sec;
-
-                           fval *= SECS_PER_HOUR;
-                           sec = fval;
-                           tm->tm_sec += sec;
-#ifdef HAVE_INT64_TIMESTAMP
-                           *fsec += (fval - sec) * 1000000;
-#else
-                           *fsec += fval - sec;
-#endif
-                       }
+                       AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
                        tmask = DTK_M(HOUR);
+                       type = DTK_DAY;
                        break;
 
                    case DTK_DAY:
                        tm->tm_mday += val;
-                       if (fval != 0)
-                       {
-                           int         sec;
-
-                           fval *= SECS_PER_DAY;
-                           sec = fval;
-                           tm->tm_sec += sec;
-#ifdef HAVE_INT64_TIMESTAMP
-                           *fsec += (fval - sec) * 1000000;
-#else
-                           *fsec += fval - sec;
-#endif
-                       }
+                       AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
                        tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
                        break;
 
                    case DTK_WEEK:
                        tm->tm_mday += val * 7;
-                       if (fval != 0)
-                       {
-                           int         extra_days;
-
-                           fval *= 7;
-                           extra_days = (int32) fval;
-                           tm->tm_mday += extra_days;
-                           fval -= extra_days;
-                           if (fval != 0)
-                           {
-                               int         sec;
-
-                               fval *= SECS_PER_DAY;
-                               sec = fval;
-                               tm->tm_sec += sec;
-#ifdef HAVE_INT64_TIMESTAMP
-                               *fsec += (fval - sec) * 1000000;
-#else
-                               *fsec += fval - sec;
-#endif
-                           }
-                       }
+                       AdjustFractDays(fval, tm, fsec, 7);
                        tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
                        break;
 
                    case DTK_MONTH:
                        tm->tm_mon += val;
-                       if (fval != 0)
-                       {
-                           int         day;
-
-                           fval *= DAYS_PER_MONTH;
-                           day = fval;
-                           tm->tm_mday += day;
-                           fval -= day;
-                           if (fval != 0)
-                           {
-                               int         sec;
-
-                               fval *= SECS_PER_DAY;
-                               sec = fval;
-                               tm->tm_sec += sec;
-#ifdef HAVE_INT64_TIMESTAMP
-                               *fsec += (fval - sec) * 1000000;
-#else
-                               *fsec += fval - sec;
-#endif
-                           }
-                       }
+                       AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
                        tmask = DTK_M(MONTH);
                        break;
 
@@ -302,7 +580,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
                        break;
 
                    default:
-                       return -1;
+                       return DTERR_BAD_FORMAT;
                }
                break;
 
@@ -330,19 +608,24 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
                        break;
 
                    default:
-                       return -1;
+                       return DTERR_BAD_FORMAT;
                }
                break;
 
            default:
-               return -1;
+               return DTERR_BAD_FORMAT;
        }
 
        if (tmask & fmask)
-           return -1;
+           return DTERR_BAD_FORMAT;
        fmask |= tmask;
    }
 
+   /* ensure that at least one time field has been found */
+   if (fmask == 0)
+       return DTERR_BAD_FORMAT;
+
+   /* ensure fractional seconds are fractional */
    if (*fsec != 0)
    {
        int         sec;
@@ -356,250 +639,344 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
        tm->tm_sec += sec;
    }
 
+   /*----------
+    * The SQL standard defines the interval literal
+    *   '-1 1:00:00'
+    * to mean "negative 1 days and negative 1 hours", while Postgres
+    * traditionally treats this as meaning "negative 1 days and positive
+    * 1 hours".  In SQL_STANDARD intervalstyle, we apply the leading sign
+    * to all fields if there are no other explicit signs.
+    *
+    * We leave the signs alone if there are additional explicit signs.
+    * This protects us against misinterpreting postgres-style dump output,
+    * since the postgres-style output code has always put an explicit sign on
+    * all fields following a negative field.  But note that SQL-spec output
+    * is ambiguous and can be misinterpreted on load!  (So it's best practice
+    * to dump in postgres style, not SQL style.)
+    *----------
+    */
+   if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
+   {
+       /* Check for additional explicit signs */
+       bool    more_signs = false;
+
+       for (i = 1; i < nf; i++)
+       {
+           if (*field[i] == '-' || *field[i] == '+')
+           {
+               more_signs = true;
+               break;
+           }
+       }
+
+       if (!more_signs)
+       {
+           /*
+            * Rather than re-determining which field was field[0], just
+            * force 'em all negative.
+            */
+           if (*fsec > 0)
+               *fsec = -(*fsec);
+           if (tm->tm_sec > 0)
+               tm->tm_sec = -tm->tm_sec;
+           if (tm->tm_min > 0)
+               tm->tm_min = -tm->tm_min;
+           if (tm->tm_hour > 0)
+               tm->tm_hour = -tm->tm_hour;
+           if (tm->tm_mday > 0)
+               tm->tm_mday = -tm->tm_mday;
+           if (tm->tm_mon > 0)
+               tm->tm_mon = -tm->tm_mon;
+           if (tm->tm_year > 0)
+               tm->tm_year = -tm->tm_year;
+       }
+   }
+
+   /* finally, AGO negates everything */
    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);
+       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() */
+   return 0;
+}
 
-/* 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
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c */
+static char *
+AddVerboseIntPart(char *cp, int value, const char *units,
+                 bool *is_zero, bool *is_before)
+{
+   if (value == 0)
+       return cp;
+   /* first nonzero value sets is_before */
+   if (*is_zero)
+   {
+       *is_before = (value < 0);
+       value = abs(value);
+   }
+   else if (*is_before)
+       value = -value;
+   sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
+   *is_zero = FALSE;
+   return cp + strlen(cp);
+}
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c */
+static char *
+AddPostgresIntPart(char *cp, int value, const char *units,
+                  bool *is_zero, bool *is_before)
+{
+   if (value == 0)
+       return cp;
+   sprintf(cp, "%s%s%d %s%s",
+           (!*is_zero) ? " " : "",
+           (*is_before && value > 0) ? "+" : "",
+           value,
+           units,
+           (value != 1) ? "s" : "");
+   /*
+    * Each nonzero field sets is_before for (only) the next one.  This is
+    * a tad bizarre but it's how it worked before...
+    */
+   *is_before = (value < 0);
+   *is_zero = FALSE;
+   return cp + strlen(cp);
+}
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c */
+static char *
+AddISO8601IntPart(char *cp, int value, char units)
+{
+   if (value == 0)
+       return cp;
+   sprintf(cp, "%d%c", value, units);
+   return cp + strlen(cp);
+}
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c */
+static void
+AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
+{
+   if (fsec == 0)
+   {
+       if (fillzeros)
+           sprintf(cp, "%02d", abs(sec));
+       else
+           sprintf(cp, "%d", abs(sec));
+   }
+   else
+   {
+#ifdef HAVE_INT64_TIMESTAMP
+       if (fillzeros)
+           sprintf(cp, "%02d.%0*d", abs(sec), precision, (int) Abs(fsec));
+       else
+           sprintf(cp, "%d.%0*d", abs(sec), precision, (int) Abs(fsec));
+#else
+       if (fillzeros)
+           sprintf(cp, "%0*.*f", precision + 3, precision, fabs(sec + fsec));
+       else
+           sprintf(cp, "%.*f", precision, fabs(sec + fsec));
+#endif
+       TrimTrailingZeros(cp);
+   }
+}
+
+
+/* copy&pasted from .../src/backend/utils/adt/datetime.c
+ * 
+ * Change pg_tm to tm
  */
+
 int
-EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str)
+EncodeInterval(struct /*pg_*/tm * tm, fsec_t fsec, int style, char *str)
 {
-   int         is_before = FALSE;
-   int         is_nonzero = FALSE;
+
    char       *cp = str;
+   int         year = tm->tm_year;
+   int         mon  = tm->tm_mon;
+   int         mday = tm->tm_mday;
+   int         hour = tm->tm_hour;
+   int         min  = tm->tm_min;
+   int         sec  = tm->tm_sec;
+   bool        is_before = FALSE;
+   bool        is_zero = TRUE;
 
    /*
     * 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.
+    * is_zero when determining the signs of day and 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)
+       /* SQL Standard interval format */
+       case INTSTYLE_SQL_STANDARD:
            {
-               int         minus = tm->tm_hour < 0 || tm->tm_min < 0 ||
-               tm->tm_sec < 0 || fsec < 0;
+               bool has_negative = year < 0 || mon  < 0 ||
+                                   mday < 0 || hour < 0 ||
+                                   min  < 0 || sec  < 0 || fsec < 0;
+               bool has_positive = year > 0 || mon  > 0 ||
+                                   mday > 0 || hour > 0 ||
+                                   min  > 0 || sec  > 0 || fsec > 0;
+               bool has_year_month = year != 0 || mon  != 0;
+               bool has_day_time   = mday != 0 || hour != 0 ||
+                                     min  != 0 || sec  != 0 || fsec != 0;
+               bool has_day        = mday != 0;
+               bool sql_standard_value = !(has_negative && has_positive) &&
+                                         !(has_year_month && has_day_time);
 
-               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;
+               /*
+                * SQL Standard wants only 1 "" preceding the whole
+                * interval ... but can't do that if mixed signs.
+                */
+               if (has_negative && sql_standard_value)
+               {
+                   *cp++ = '-';
+                   year = -year;
+                   mon  = -mon;
+                   mday = -mday;
+                   hour = -hour;
+                   min  = -min;
+                   sec  = -sec;
+                   fsec = -fsec;
+               }
 
-               /* fractional seconds? */
-               if (fsec != 0)
+               if (!has_negative && !has_positive)
                {
-#ifdef HAVE_INT64_TIMESTAMP
-                   sprintf(cp, ":%02d", abs(tm->tm_sec));
+                   sprintf(cp, "0");
+               }
+               else if (!sql_standard_value)
+               {
+                   /*
+                    * For non sql-standard interval values,
+                    * force outputting the signs to avoid
+                    * ambiguities with intervals with mixed
+                    * sign components.
+                    */
+                   char year_sign = (year < 0 || mon < 0) ? '-' : '+';
+                   char day_sign = (mday < 0) ? '-' : '+';
+                   char sec_sign = (hour < 0 || min < 0 ||
+                                    sec < 0 || fsec < 0) ? '-' : '+';
+
+                   sprintf(cp, "%c%d-%d %c%d %c%d:%02d:",
+                           year_sign, abs(year), abs(mon),
+                           day_sign, abs(mday),
+                           sec_sign, abs(hour), abs(min));
                    cp += strlen(cp);
-                   sprintf(cp, ".%06d", Abs(fsec));
-#else
-                   fsec += tm->tm_sec;
-                   sprintf(cp, ":%012.9f", fabs(fsec));
-#endif
-                   TrimTrailingZeros(cp);
+                   AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
+               }
+               else if (has_year_month)
+               {
+                   sprintf(cp, "%d-%d", year, mon);
+               }
+               else if (has_day)
+               {
+                   sprintf(cp, "%d %d:%02d:", mday, hour, min);
                    cp += strlen(cp);
-                   is_nonzero = TRUE;
+                   AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
                }
-               /* otherwise, integer seconds only? */
-               else if (tm->tm_sec != 0)
+               else
                {
-                   sprintf(cp, ":%02d", abs(tm->tm_sec));
+                   sprintf(cp, "%d:%02d:", hour, min);
                    cp += strlen(cp);
-                   is_nonzero = TRUE;
+                   AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
                }
            }
            break;
 
-       case USE_POSTGRES_DATES:
-       default:
-           strcpy(cp, "@ ");
-           cp += strlen(cp);
-
-           if (tm->tm_year != 0)
+       /* ISO 8601 "time-intervals by duration only" */
+       case INTSTYLE_ISO_8601:
+           /* special-case zero to avoid printing nothing */
+           if (year == 0 && mon == 0 && mday == 0 &&
+               hour == 0 && min == 0 && sec  == 0 && fsec == 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;
+               sprintf(cp, "PT0S");
+               break;
            }
-           if (tm->tm_hour != 0)
+           *cp++ = 'P';
+           cp = AddISO8601IntPart(cp, year, 'Y');
+           cp = AddISO8601IntPart(cp, mon , 'M');
+           cp = AddISO8601IntPart(cp, mday, 'D');
+           if (hour != 0 || min != 0 || sec != 0 || fsec != 0)
+               *cp++ = 'T';
+           cp = AddISO8601IntPart(cp, hour, 'H');
+           cp = AddISO8601IntPart(cp, min , 'M');
+           if (sec != 0 || fsec != 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" : "");
+               if (sec < 0 || fsec < 0)
+                   *cp++ = '-';
+               AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
                cp += strlen(cp);
-               if (!is_nonzero)
-                   is_before = (tm->tm_hour < 0);
-               is_nonzero = TRUE;
+               *cp++ = 'S';
+               *cp++ = '\0';
            }
+           break;
 
-           if (tm->tm_min != 0)
+       /* Compatible with postgresql < 8.4 when DateStyle = 'iso' */
+       case INTSTYLE_POSTGRES:
+           cp = AddPostgresIntPart(cp, year, "year", &is_zero, &is_before);
+           cp = AddPostgresIntPart(cp, mon, "mon", &is_zero, &is_before);
+           cp = AddPostgresIntPart(cp, mday, "day", &is_zero, &is_before);
+           if (is_zero || hour != 0 || min != 0 || sec != 0 || fsec != 0)
            {
-               int         min = tm->tm_min;
+               bool    minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0);
 
-               if (is_before || (!is_nonzero && tm->tm_min < 0))
-                   min = -min;
-
-               sprintf(cp, "%s%d min%s", is_nonzero ? " " : "", min,
-                       (min != 1) ? "s" : "");
+               sprintf(cp, "%s%s%02d:%02d:",
+                       is_zero ? "" : " ",
+                       (minus ? "-" : (is_before ? "+" : "")),
+                       abs(hour), abs(min));
                cp += strlen(cp);
-               if (!is_nonzero)
-                   is_before = (tm->tm_min < 0);
-               is_nonzero = TRUE;
+               AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
            }
+           break;
 
-           /* 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)
+       /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */
+       case INTSTYLE_POSTGRES_VERBOSE:
+       default:
+           strcpy(cp, "@");
+           cp++;
+           cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before);
+           cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before);
+           cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before);
+           cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before);
+           cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before);
+           if (sec != 0 || fsec != 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++ = ' ';
+               if (sec < 0 || (sec == 0 && fsec < 0))
+               {
+                   if (is_zero)
+                       is_before = TRUE;
+                   else if (!is_before)
+                       *cp++ = '-';
+               }
+               else if (is_before)
+                   *cp++ = '-';
+               AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
                cp += strlen(cp);
-               if (!is_nonzero)
-                   is_before = (tm->tm_sec < 0);
-               is_nonzero = TRUE;
+               sprintf(cp, " sec%s",
+                       (abs(sec) != 1 || fsec != 0) ? "s" : "");
+               is_zero = FALSE;
            }
+           /* identically zero? then put in a unitless zero... */
+           if (is_zero)
+               strcat(cp, " 0");
+           if (is_before)
+               strcat(cp, " ago");
            break;
    }
 
-   /* identically zero? then put in a unitless zero... */
-   if (!is_nonzero)
-   {
-       strcat(cp, "0");
-       cp += strlen(cp);
-   }
-
-   if (is_before && (style != USE_ISO_DATES))
-   {
-       strcat(cp, " ago");
-       cp += strlen(cp);
-   }
-
    return 0;
 }  /* EncodeInterval() */
 
+
 /* interval2tm()
  * Convert a interval data type to a tm structure.
  */
@@ -719,7 +1096,8 @@ PGTYPESinterval_from_asc(char *str, char **endptr)
    }
 
    if (ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf, ptr) != 0 ||
-       DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0)
+       (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0 &&
+        DecodeISO8601Interval(str, &dtype, tm, &fsec) != 0))
    {
        errno = PGTYPES_INTVL_BAD_INTERVAL;
        return NULL;
@@ -754,7 +1132,7 @@ PGTYPESinterval_to_asc(interval * span)
               *tm = &tt;
    fsec_t      fsec;
    char        buf[MAXDATELEN + 1];
-   int         DateStyle = 0;
+   int         IntervalStyle = INTSTYLE_POSTGRES_VERBOSE;
 
    if (interval2tm(*span, tm, &fsec) != 0)
    {
@@ -762,7 +1140,7 @@ PGTYPESinterval_to_asc(interval * span)
        return NULL;
    }
 
-   if (EncodeInterval(tm, fsec, DateStyle, buf) != 0)
+   if (EncodeInterval(tm, fsec, IntervalStyle, buf) != 0)
    {
        errno = PGTYPES_INTVL_BAD_INTERVAL;
        return NULL;
index 2dd263267d6fd23672576d38532573abadb5eaf2..f71d3ab98d25662533cdb743a73381cfed07ecaf 100644 (file)
@@ -77,6 +77,12 @@ if (sqlca.sqlcode < 0) sqlprint (  );}
 if (sqlca.sqlcode < 0) sqlprint (  );}
 #line 30 "dt_test.pgc"
 
+   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "set intervalstyle to postgres_verbose", ECPGt_EOIT, ECPGt_EORT);
+#line 31 "dt_test.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint (  );}
+#line 31 "dt_test.pgc"
+
 
    date1 = PGTYPESdate_from_asc(d1, NULL); 
    ts1 = PGTYPEStimestamp_from_asc(t1, NULL); 
@@ -86,10 +92,10 @@ if (sqlca.sqlcode < 0) sqlprint (  );}
    ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
    ECPGt_timestamp,&(ts1),(long)1,(long)1,sizeof(timestamp), 
    ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
-#line 35 "dt_test.pgc"
+#line 36 "dt_test.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint (  );}
-#line 35 "dt_test.pgc"
+#line 36 "dt_test.pgc"
 
 
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select  *  from date_test where d =  $1   ", 
@@ -99,10 +105,10 @@ if (sqlca.sqlcode < 0) sqlprint (  );}
    ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
    ECPGt_timestamp,&(ts1),(long)1,(long)1,sizeof(timestamp), 
    ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
-#line 37 "dt_test.pgc"
+#line 38 "dt_test.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint (  );}
-#line 37 "dt_test.pgc"
+#line 38 "dt_test.pgc"
 
 
    text = PGTYPESdate_to_asc(date1);
@@ -417,16 +423,16 @@ if (sqlca.sqlcode < 0) sqlprint (  );}
    free(text);
 
    { ECPGtrans(__LINE__, NULL, "rollback ");
-#line 350 "dt_test.pgc"
+#line 351 "dt_test.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint (  );}
-#line 350 "dt_test.pgc"
+#line 351 "dt_test.pgc"
 
         { ECPGdisconnect(__LINE__, "CURRENT");
-#line 351 "dt_test.pgc"
+#line 352 "dt_test.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint (  );}
-#line 351 "dt_test.pgc"
+#line 352 "dt_test.pgc"
 
 
    return (0);
index 7dced6a746196dd5f5f077a3aab29d51430f9070..3aaee055cee6b06f3a50b7dc8708de5295baeb77 100644 (file)
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_execute on line 30: OK: SET
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 35: query: insert into date_test ( d  , ts  ) values (  $1  ,  $2  ) ; with 2 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 31: query: set intervalstyle to postgres_verbose; with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 35: using PQexecParams
+[NO_PID]: ecpg_execute on line 31: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: free_params on line 35: parameter 1 = 1966-01-17
+[NO_PID]: ecpg_execute on line 31: OK: SET
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: free_params on line 35: parameter 2 = 2000-07-12 17:34:29
+[NO_PID]: ecpg_execute on line 36: query: insert into date_test ( d  , ts  ) values (  $1  ,  $2  ) ; with 2 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 35: OK: INSERT 0 1
+[NO_PID]: ecpg_execute on line 36: using PQexecParams
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 37: query: select  *  from date_test where d =  $1   ; with 1 parameter(s) on connection regress1
+[NO_PID]: free_params on line 36: parameter 1 = 1966-01-17
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 37: using PQexecParams
+[NO_PID]: free_params on line 36: parameter 2 = 2000-07-12 17:34:29
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: free_params on line 37: parameter 1 = 1966-01-17
+[NO_PID]: ecpg_execute on line 36: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 37: correctly got 1 tuples with 2 fields
+[NO_PID]: ecpg_execute on line 38: query: select  *  from date_test where d =  $1   ; with 1 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 37: RESULT: 1966-01-17 offset: -1; array: yes
+[NO_PID]: ecpg_execute on line 38: using PQexecParams
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 37: RESULT: 2000-07-12 17:34:29 offset: -1; array: yes
+[NO_PID]: free_params on line 38: parameter 1 = 1966-01-17
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ECPGtrans on line 350: action "rollback "; connection "regress1"
+[NO_PID]: ecpg_execute on line 38: correctly got 1 tuples with 2 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 38: RESULT: 1966-01-17 offset: -1; array: yes
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 38: RESULT: 2000-07-12 17:34:29 offset: -1; array: yes
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 351: action "rollback "; connection "regress1"
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_finish: connection regress1 closed
 [NO_PID]: sqlca: code: 0, state: 00000
index d6c166477fc56cc14e46f15f495a53fd649bbee9..fcf39cecc7c07bcb478f41480399fef228fd58bb 100644 (file)
@@ -28,6 +28,7 @@ main(void)
         exec sql connect to REGRESSDB1;
         exec sql create table date_test (d date, ts timestamp);
    exec sql set datestyle to iso;
+   exec sql set intervalstyle to postgres_verbose;
 
    date1 = PGTYPESdate_from_asc(d1, NULL); 
    ts1 = PGTYPEStimestamp_from_asc(t1, NULL);