aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/datetime.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/datetime.c')
-rw-r--r--src/backend/utils/adt/datetime.c85
1 files changed, 73 insertions, 12 deletions
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index a92583ca19e..6712d6d8d44 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.190 2008/06/09 19:34:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.191 2008/09/10 18:29:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -35,8 +35,8 @@ static int DecodeNumber(int flen, char *field, bool haveTextMonth,
static int DecodeNumberField(int len, char *str,
int fmask, int *tmask,
struct pg_tm * tm, fsec_t *fsec, bool *is2digits);
-static int DecodeTime(char *str, int fmask, int *tmask,
- struct pg_tm * tm, fsec_t *fsec);
+static int DecodeTime(char *str, int fmask, int range,
+ int *tmask, struct pg_tm * tm, fsec_t *fsec);
static int DecodeTimezone(char *str, int *tzp);
static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
@@ -832,7 +832,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
break;
case DTK_TIME:
- dterr = DecodeTime(field[i], fmask, &tmask, tm, fsec);
+ dterr = DecodeTime(field[i], fmask, INTERVAL_FULL_RANGE,
+ &tmask, tm, fsec);
if (dterr)
return dterr;
@@ -1563,6 +1564,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
case DTK_TIME:
dterr = DecodeTime(field[i], (fmask | DTK_DATE_M),
+ INTERVAL_FULL_RANGE,
&tmask, tm, fsec);
if (dterr)
return dterr;
@@ -2224,7 +2226,8 @@ ValidateDate(int fmask, bool is2digits, bool bc, struct pg_tm * tm)
* used to represent time spans.
*/
static int
-DecodeTime(char *str, int fmask, int *tmask, struct pg_tm * tm, fsec_t *fsec)
+DecodeTime(char *str, int fmask, int range,
+ int *tmask, struct pg_tm * tm, fsec_t *fsec)
{
char *cp;
@@ -2245,6 +2248,13 @@ DecodeTime(char *str, int fmask, int *tmask, struct pg_tm * tm, fsec_t *fsec)
{
tm->tm_sec = 0;
*fsec = 0;
+ /* If it's a MINUTE TO SECOND interval, take 2 fields as being mm:ss */
+ if (range == (INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND)))
+ {
+ tm->tm_sec = tm->tm_min;
+ tm->tm_min = tm->tm_hour;
+ tm->tm_hour = 0;
+ }
}
else if (*cp != ':')
return DTERR_BAD_FORMAT;
@@ -2705,7 +2715,8 @@ DecodeSpecial(int field, char *lowtoken, int *val)
* preceding an hh:mm:ss field. - thomas 1998-04-30
*/
int
-DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm, fsec_t *fsec)
+DecodeInterval(char **field, int *ftype, int nf, int range,
+ int *dtype, struct pg_tm * tm, fsec_t *fsec)
{
bool is_before = FALSE;
char *cp;
@@ -2734,7 +2745,8 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
switch (ftype[i])
{
case DTK_TIME:
- dterr = DecodeTime(field[i], fmask, &tmask, tm, fsec);
+ dterr = DecodeTime(field[i], fmask, range,
+ &tmask, tm, fsec);
if (dterr)
return dterr;
type = DTK_DAY;
@@ -2757,7 +2769,8 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
while (*cp != '\0' && *cp != ':' && *cp != '.')
cp++;
if (*cp == ':' &&
- DecodeTime(field[i] + 1, fmask, &tmask, tm, fsec) == 0)
+ DecodeTime(field[i] + 1, fmask, INTERVAL_FULL_RANGE,
+ &tmask, tm, fsec) == 0)
{
if (*field[i] == '-')
{
@@ -2796,19 +2809,66 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
type = DTK_HOUR;
}
}
- /* DROP THROUGH */
+ /* FALL THROUGH */
case DTK_DATE:
case DTK_NUMBER:
+ if (type == IGNORE_DTF)
+ {
+ /* use typmod to decide what rightmost integer 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 (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;
+ val = val * MONTHS_PER_YEAR + val2;
+ fval = 0;
+ }
+ else if (*cp == '.')
{
fval = strtod(cp, &cp);
if (*cp != '\0')
@@ -2896,6 +2956,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
#endif
}
tmask = DTK_M(HOUR);
+ type = DTK_DAY;
break;
case DTK_DAY: