Fix DecodeInterval to report an error for multiple occurrences of DAY, WEEK,

YEAR, DECADE, CENTURY, or MILLENIUM fields, just as it always has done for
other types of fields.  The previous behavior seems to have been a hack to
avoid defining bit-positions for all these field types in DTK_M() masks,
rather than something that was really considered to be desired behavior.
But there is room in the masks for these, and we really need to tighten up
at least the behavior of DAY and YEAR fields to avoid unexpected behavior
associated with the 8.4 changes to interpret ambiguous fields based on the
interval qualifier (typmod) value.  Per my example and proposed patch.
This commit is contained in:
Tom Lane 2009-06-01 16:55:11 +00:00
parent 5377ccbe24
commit b3b89fd1f1
2 changed files with 14 additions and 9 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.205 2009/05/26 02:17:50 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.206 2009/06/01 16:55:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -3022,19 +3022,19 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
tm->tm_hour += val;
AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
tmask = DTK_M(HOUR);
type = DTK_DAY;
type = DTK_DAY; /* set for next field */
break;
case DTK_DAY:
tm->tm_mday += val;
AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
tmask = 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);
tmask = DTK_M(WEEK);
break;
case DTK_MONTH:
@ -3047,28 +3047,28 @@ DecodeInterval(char **field, int *ftype, int nf, int range,
tm->tm_year += val;
if (fval != 0)
tm->tm_mon += fval * MONTHS_PER_YEAR;
tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
tmask = DTK_M(YEAR);
break;
case DTK_DECADE:
tm->tm_year += val * 10;
if (fval != 0)
tm->tm_mon += fval * MONTHS_PER_YEAR * 10;
tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
tmask = DTK_M(DECADE);
break;
case DTK_CENTURY:
tm->tm_year += val * 100;
if (fval != 0)
tm->tm_mon += fval * MONTHS_PER_YEAR * 100;
tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
tmask = DTK_M(CENTURY);
break;
case DTK_MILLENNIUM:
tm->tm_year += val * 1000;
if (fval != 0)
tm->tm_mon += fval * MONTHS_PER_YEAR * 1000;
tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
tmask = DTK_M(MILLENNIUM);
break;
default:

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.73 2009/05/26 02:17:50 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.74 2009/06/01 16:55:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -114,6 +114,11 @@
/* generic fields to help with parsing */
#define ISODATE 22
#define ISOTIME 23
/* these are only for parsing intervals */
#define WEEK 24
#define DECADE 25
#define CENTURY 26
#define MILLENNIUM 27
/* reserved for unrecognized string values */
#define UNKNOWN_FIELD 31