Michael Meskes wrote:
On Wed, Nov 12, 2008 at 02:28:56PM -0800, Ron Mayer wrote:
Merging of the interval style into ecpg attached.
Thanks for caring about the ecpg changes too.
Thanks for the comments. Updated the patch.
I know little enough about ecpg that I can't really tell if these changes
are for the better or worse.
The closer pgtypeslib is to the backend the better.
One thing in the patch that's probably a bug is that the
constants in src/include/utils/dt.h and src/include/utils/datetime.h
under the section "Fields for time decoding" seem not to match, so
Assuming you mean src/interfaces/ecpg/pgtypeslib/dt.h. The numbers should match
IMO.
Ok. I copy&pasted them from datetime.h to dt.h.
This changes a number of values that were like
#define DOY 13
#define DOW 14
to
#define DOY 15
#define DOW 16
and I'm not quite sure what the consequences of that might be,
but the regression tests still pass.
Also one files seems to be missing, there are no changes to
test/expected/pgtypeslib-dt_test.c in the patch, but when changing dt_test.pgc
this file should be changed too.
Could you add this to your work too?
Got it.
Patch attached.
*** a/src/interfaces/ecpg/pgtypeslib/dt.h
--- b/src/interfaces/ecpg/pgtypeslib/dt.h
***************
*** 25,30 **** typedef double fsec_t;
--- 25,46 ----
#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,82 **** typedef double fsec_t;
--- 93,101 ----
* 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,111 **** 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
/* these are only for relative dates */
! #define AGO 17
! #define ABS_BEFORE 18
! #define ABS_AFTER 19
/* generic fields to help with parsing */
! #define ISODATE 20
! #define ISOTIME 21
/* 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.
--- 111,133 ----
#define HOUR 10
#define MINUTE 11
#define SECOND 12
! #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 19
! #define ABS_BEFORE 20
! #define ABS_AFTER 21
/* generic fields to help with parsing */
! #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,176 **** typedef double fsec_t;
/*
* Bit mask definitions for time parsing.
*/
!
#define DTK_M(t) (0x01 << (t))
!
#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
* string (not
counting tr. null) */
#define MAXDATEFIELDS 25 /* maximum possible number of fields in
a date
* string */
--- 186,198 ----
/*
* 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 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 */
*** a/src/interfaces/ecpg/pgtypeslib/interval.c
--- b/src/interfaces/ecpg/pgtypeslib/interval.c
***************
*** 13,51 ****
#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.
*
! * 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--)
--- 13,359 ----
#include "pgtypes_error.h"
#include "pgtypes_interval.h"
! /* 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;
*
! * * ECPG semes not to have a global IntervalStyle
! * so added
! * int IntervalStyle = INTSTYLE_POSTGRES;
*
! * * Assert wasn't available so removed it.
*/
int
! DecodeInterval(char **field, int *ftype, int nf, /*int range,*/
! int *dtype, struct /*pg_*/tm * tm, fsec_t *fsec)
{
! 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;
! ClearPgTm(tm,fsec);
/* read through list backwards to pick up units before values */
for (i = nf - 1; i >= 0; i--)
***************
*** 53,60 **** 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;
type = DTK_DAY;
break;
--- 361,370 ----
switch (ftype[i])
{
case DTK_TIME:
! dterr = DecodeTime(field[i], fmask, /* range, */
! &tmask, tm,
fsec);
! if (dterr)
! return dterr;
type = DTK_DAY;
break;
***************
*** 62,79 **** 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
*/
/*
! * 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] == '-')
{
--- 372,390 ----
/*
* Timezone is a token with a leading sign
character and
! * at least one digit; there could be ':', '.',
'-'
! * embedded in it as well.
*/
+ /* Assert(*field[i] == '-' || *field[i] ==
'+'); */
/*
! * 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.
*/
! if (strchr(field[i] + 1, ':') != NULL &&
! DecodeTime(field[i] + 1, fmask, /*
INTERVAL_FULL_RANGE, */
! &tmask, tm, fsec) ==
0)
{
if (*field[i] == '-')
{
***************
*** 93,139 **** DecodeInterval(char **field, int *ftype, int nf, int *dtype,
struct tm * tm, fse
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); */
--- 404,484 ----
tmask = DTK_M(TZ);
break;
}
! /* FALL THROUGH */
!
! case DTK_DATE:
! case DTK_NUMBER:
! if (type == IGNORE_DTF)
{
! /* use typmod to decide what rightmost
field is */
! switch (range)
{
! 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;
}
}
! errno = 0;
! val = strtoi(field[i], &cp, 10);
! if (errno == ERANGE)
! return DTERR_FIELD_OVERFLOW;
! if (*cp == '-')
! {
! /* SQL "years-months" syntax */
! int val2;
! 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' || errno != 0)
! return DTERR_BAD_FORMAT;
! if (*field[i] == '-')
fval = -fval;
}
else if (*cp == '\0')
fval = 0;
else
! return DTERR_BAD_FORMAT;
tmask = 0; /* DTK_M(type); */
***************
*** 141,275 **** DecodeInterval(char **field, int *ftype, int nf, int *dtype,
struct tm * tm, fse
{
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 *= SECS_PER_MINUTE;
! 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 *= SECS_PER_HOUR;
! 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 *= SECS_PER_DAY;
! 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
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
! }
! }
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
! }
! }
tmask = DTK_M(MONTH);
break;
--- 486,553 ----
{
case DTK_MICROSEC:
#ifdef HAVE_INT64_TIMESTAMP
! *fsec += rint(val + fval);
#else
*fsec += (val + fval) * 1e-6;
#endif
+ tmask = DTK_M(MICROSECOND);
break;
case DTK_MILLISEC:
#ifdef HAVE_INT64_TIMESTAMP
! *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 += rint(fval * 1000000);
#else
*fsec += fval;
#endif
!
! /*
! * 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;
! AdjustFractSeconds(fval, tm,
fsec, SECS_PER_MINUTE);
tmask = DTK_M(MINUTE);
break;
case DTK_HOUR:
tm->tm_hour += val;
! AdjustFractSeconds(fval, tm,
fsec, SECS_PER_HOUR);
tmask = DTK_M(HOUR);
+ type = DTK_DAY;
break;
case DTK_DAY:
tm->tm_mday += val;
! 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;
! AdjustFractDays(fval, tm, fsec,
7);
tmask = (fmask & DTK_M(DAY)) ?
0 : DTK_M(DAY);
break;
case DTK_MONTH:
tm->tm_mon += val;
! AdjustFractDays(fval, tm, fsec,
DAYS_PER_MONTH);
tmask = DTK_M(MONTH);
break;
***************
*** 302,308 **** DecodeInterval(char **field, int *ftype, int nf, int *dtype,
struct tm * tm, fse
break;
default:
! return -1;
}
break;
--- 580,586 ----
break;
default:
! return DTERR_BAD_FORMAT;
}
break;
***************
*** 330,348 **** DecodeInterval(char **field, int *ftype, int nf, int *dtype,
struct tm * tm, fse
break;
default:
! return -1;
}
break;
default:
! return -1;
}
if (tmask & fmask)
! return -1;
fmask |= tmask;
}
if (*fsec != 0)
{
int sec;
--- 608,631 ----
break;
default:
! return DTERR_BAD_FORMAT;
}
break;
default:
! return DTERR_BAD_FORMAT;
}
if (tmask & fmask)
! 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,605 **** DecodeInterval(char **field, int *ftype, int nf, int *dtype,
struct tm * tm, fse
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", Abs(fsec));
! #else
! fsec += tm->tm_sec;
! sprintf(cp, ":%012.9f", 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_ISO_DATES))
- {
- strcat(cp, " ago");
- cp += strlen(cp);
- }
-
return 0;
} /* EncodeInterval() */
/* interval2tm()
* Convert a interval data type to a tm structure.
*/
--- 639,982 ----
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;
}
! return 0;
! }
!
! /* 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 /*pg_*/tm * tm, fsec_t fsec, int style, char *str)
{
!
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_zero when determining the signs of day and hour/minute/seconds
! * fields.
*/
switch (style)
{
! /* SQL Standard interval format */
! case INTSTYLE_SQL_STANDARD:
{
! 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);
! /*
! * SQL Standard wants only 1 "<sign>" 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;
! }
! if (!has_negative && !has_positive)
{
! 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);
! 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);
! AppendSeconds(cp, sec, fsec,
MAX_INTERVAL_PRECISION, true);
}
! else
{
! sprintf(cp, "%d:%02d:", hour, min);
cp += strlen(cp);
! AppendSeconds(cp, sec, fsec,
MAX_INTERVAL_PRECISION, true);
}
}
break;
! /* 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)
{
! sprintf(cp, "PT0S");
! break;
}
! *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)
{
! if (sec < 0 || fsec < 0)
! *cp++ = '-';
! AppendSeconds(cp, sec, fsec,
MAX_INTERVAL_PRECISION, false);
cp += strlen(cp);
! *cp++ = 'S';
! *cp++ = '\0';
}
+ break;
! /* 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)
{
! bool minus = (hour < 0 || min < 0 || sec < 0
|| fsec < 0);
! sprintf(cp, "%s%s%02d:%02d:",
! is_zero ? "" : " ",
! (minus ? "-" : (is_before ? "+"
: "")),
! abs(hour), abs(min));
cp += strlen(cp);
! AppendSeconds(cp, sec, fsec,
MAX_INTERVAL_PRECISION, true);
}
+ break;
! /* 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)
{
! *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);
! 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;
}
return 0;
} /* EncodeInterval() */
+
/* interval2tm()
* Convert a interval data type to a tm structure.
*/
***************
*** 719,725 **** 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)
{
errno = PGTYPES_INTVL_BAD_INTERVAL;
return NULL;
--- 1096,1103 ----
}
if (ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf, ptr)
!= 0 ||
! (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0 &&
! DecodeISO8601Interval(str, &dtype, tm, &fsec) != 0))
{
errno = PGTYPES_INTVL_BAD_INTERVAL;
return NULL;
***************
*** 754,760 **** PGTYPESinterval_to_asc(interval * span)
*tm = &tt;
fsec_t fsec;
char buf[MAXDATELEN + 1];
! int DateStyle = 0;
if (interval2tm(*span, tm, &fsec) != 0)
{
--- 1132,1138 ----
*tm = &tt;
fsec_t fsec;
char buf[MAXDATELEN + 1];
! int IntervalStyle = INTSTYLE_POSTGRES_VERBOSE;
if (interval2tm(*span, tm, &fsec) != 0)
{
***************
*** 762,768 **** PGTYPESinterval_to_asc(interval * span)
return NULL;
}
! if (EncodeInterval(tm, fsec, DateStyle, buf) != 0)
{
errno = PGTYPES_INTVL_BAD_INTERVAL;
return NULL;
--- 1140,1146 ----
return NULL;
}
! if (EncodeInterval(tm, fsec, IntervalStyle, buf) != 0)
{
errno = PGTYPES_INTVL_BAD_INTERVAL;
return NULL;
*** a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
--- b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
***************
*** 77,82 **** if (sqlca.sqlcode < 0) sqlprint ( );}
--- 77,88 ----
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,95 **** 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"
if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 35 "dt_test.pgc"
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select * from
date_test where d = $1 ",
--- 92,101 ----
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 36 "dt_test.pgc"
if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 36 "dt_test.pgc"
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select * from
date_test where d = $1 ",
***************
*** 99,108 **** 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"
if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 37 "dt_test.pgc"
text = PGTYPESdate_to_asc(date1);
--- 105,114 ----
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 38 "dt_test.pgc"
if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 38 "dt_test.pgc"
text = PGTYPESdate_to_asc(date1);
***************
*** 417,432 **** if (sqlca.sqlcode < 0) sqlprint ( );}
free(text);
{ ECPGtrans(__LINE__, NULL, "rollback ");
! #line 350 "dt_test.pgc"
if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 350 "dt_test.pgc"
{ ECPGdisconnect(__LINE__, "CURRENT");
! #line 351 "dt_test.pgc"
if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 351 "dt_test.pgc"
return (0);
--- 423,438 ----
free(text);
{ ECPGtrans(__LINE__, NULL, "rollback ");
! #line 351 "dt_test.pgc"
if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 351 "dt_test.pgc"
{ ECPGdisconnect(__LINE__, "CURRENT");
! #line 352 "dt_test.pgc"
if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 352 "dt_test.pgc"
return (0);
*** a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr
--- b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr
***************
*** 14,42 ****
[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]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 35: using PQexecParams
[NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: free_params on line 35: parameter 1 = 1966-01-17
[NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: free_params on line 35: parameter 2 = 2000-07-12 17:34:29
[NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 35: OK: INSERT 0 1
[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]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 37: using PQexecParams
[NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: free_params on line 37: parameter 1 = 1966-01-17
[NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 37: correctly got 1 tuples with 2 fields
[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]: 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]: sqlca: code: 0, state: 00000
! [NO_PID]: ECPGtrans on line 350: 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
--- 14,48 ----
[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 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 31: using PQexec
[NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 31: OK: SET
[NO_PID]: sqlca: code: 0, state: 00000
! [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 36: using PQexecParams
[NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: free_params on line 36: parameter 1 = 1966-01-17
[NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: free_params on line 36: parameter 2 = 2000-07-12 17:34:29
[NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ecpg_execute on line 36: OK: INSERT 0 1
[NO_PID]: sqlca: code: 0, state: 00000
! [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_execute on line 38: using PQexecParams
[NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: free_params on line 38: parameter 1 = 1966-01-17
[NO_PID]: sqlca: code: 0, state: 00000
! [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
*** a/src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc
--- b/src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc
***************
*** 28,33 **** main(void)
--- 28,34 ----
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);
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers