diff options
Diffstat (limited to 'src/backend/utils/adt/datetime.c')
-rw-r--r-- | src/backend/utils/adt/datetime.c | 238 |
1 files changed, 120 insertions, 118 deletions
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index e6f4689a59f..186522148d5 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.207 2009/06/10 05:05:03 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.208 2009/06/11 14:49:03 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -40,17 +40,17 @@ 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, - struct pg_tm * tm); -static int ValidateDate(int fmask, bool is2digits, bool bc, - struct pg_tm * tm); +static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits, + struct pg_tm * tm); +static int ValidateDate(int fmask, bool is2digits, bool bc, + struct pg_tm * tm); static void TrimTrailingZeros(char *str); static void AppendSeconds(char *cp, int sec, fsec_t fsec, - int precision, bool fillzeros); + int precision, bool fillzeros); static void AdjustFractSeconds(double frac, struct pg_tm * tm, fsec_t *fsec, - int scale); + int scale); static void AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec, - int scale); + int scale); const int day_tab[2][13] = @@ -266,7 +266,7 @@ static const datetkn *deltacache[MAXDATEFIELDS] = {NULL}; static int strtoi(const char *nptr, char **endptr, int base) { - long val; + long val; val = strtol(nptr, endptr, base); #ifdef HAVE_LONG_INT_64 @@ -461,8 +461,8 @@ static void AppendTimestampSeconds(char *cp, struct pg_tm * tm, fsec_t fsec) { /* - * In float mode, don't print fractional seconds before 1 AD, - * since it's unlikely there's any precision left ... + * In float mode, don't print fractional seconds before 1 AD, since it's + * unlikely there's any precision left ... */ #ifndef HAVE_INT64_TIMESTAMP if (tm->tm_year <= 0) @@ -478,18 +478,18 @@ AppendTimestampSeconds(char *cp, struct pg_tm * tm, fsec_t fsec) static void AdjustFractSeconds(double frac, struct pg_tm * tm, fsec_t *fsec, int scale) { - int sec; + int sec; if (frac == 0) return; - frac *= scale; - sec = (int) frac; + frac *= scale; + sec = (int) frac; tm->tm_sec += sec; - frac -= sec; + frac -= sec; #ifdef HAVE_INT64_TIMESTAMP - *fsec += rint(frac * 1000000); + *fsec += rint(frac * 1000000); #else - *fsec += frac; + *fsec += frac; #endif } @@ -497,14 +497,14 @@ AdjustFractSeconds(double frac, struct pg_tm * tm, fsec_t *fsec, int scale) static void AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec, int scale) { - int extra_days; + int extra_days; if (frac == 0) return; - frac *= scale; - extra_days = (int) frac; + frac *= scale; + extra_days = (int) frac; tm->tm_mday += extra_days; - frac -= extra_days; + frac -= extra_days; AdjustFractSeconds(frac, tm, fsec, SECS_PER_DAY); } @@ -1358,7 +1358,7 @@ DecodeDateTime(char **field, int *ftype, int nf, if (tmask & fmask) return DTERR_BAD_FORMAT; fmask |= tmask; - } /* end loop over fields */ + } /* end loop over fields */ /* do final checking/adjustment of Y/M/D fields */ dterr = ValidateDate(fmask, is2digits, bc, tm); @@ -2042,7 +2042,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, if (tmask & fmask) return DTERR_BAD_FORMAT; fmask |= tmask; - } /* end loop over fields */ + } /* end loop over fields */ /* do final checking/adjustment of Y/M/D fields */ dterr = ValidateDate(fmask, is2digits, bc, tm); @@ -2059,7 +2059,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 || tm->tm_sec < 0 || tm->tm_sec > 60 || tm->tm_hour > 24 || - /* test for > 24:00:00 */ + /* test for > 24:00:00 */ (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0 || *fsec > 0)) || #ifdef HAVE_INT64_TIMESTAMP @@ -2262,7 +2262,7 @@ ValidateDate(int fmask, bool is2digits, bool bc, struct pg_tm * tm) else if (is2digits) { /* process 1 or 2-digit input as 1970-2069 AD, allow '0' and '00' */ - if (tm->tm_year < 0) /* just paranoia */ + if (tm->tm_year < 0) /* just paranoia */ return DTERR_FIELD_OVERFLOW; if (tm->tm_year < 70) tm->tm_year += 2000; @@ -2599,8 +2599,8 @@ DecodeNumberField(int len, char *str, int fmask, if ((cp = strchr(str, '.')) != NULL) { /* - * Can we use ParseFractionalSecond here? Not clear whether - * trailing junk should be rejected ... + * Can we use ParseFractionalSecond here? Not clear whether trailing + * junk should be rejected ... */ double frac; @@ -2805,16 +2805,16 @@ DecodeSpecial(int field, char *lowtoken, int *val) * * Zero out a pg_tm and associated fsec_t */ -static inline void -ClearPgTm(struct pg_tm *tm, fsec_t *fsec) +static inline void +ClearPgTm(struct pg_tm * tm, fsec_t *fsec) { tm->tm_year = 0; - tm->tm_mon = 0; + tm->tm_mon = 0; tm->tm_mday = 0; tm->tm_hour = 0; - tm->tm_min = 0; - tm->tm_sec = 0; - *fsec = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + *fsec = 0; } @@ -2845,7 +2845,7 @@ DecodeInterval(char **field, int *ftype, int nf, int range, *dtype = DTK_DELTA; type = IGNORE_DTF; - ClearPgTm(tm,fsec); + ClearPgTm(tm, fsec); /* read through list backwards to pick up units before values */ for (i = nf - 1; i >= 0; i--) @@ -2863,16 +2863,16 @@ DecodeInterval(char **field, int *ftype, int nf, int range, case DTK_TZ: /* - * Timezone is a token with a leading sign character and - * at least one digit; there could be ':', '.', '-' - * embedded in it as well. + * 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. + * 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, @@ -2944,7 +2944,7 @@ DecodeInterval(char **field, int *ftype, int nf, int range, if (*cp == '-') { /* SQL "years-months" syntax */ - int val2; + int val2; val2 = strtoi(cp + 1, &cp, 10); if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR) @@ -3022,7 +3022,7 @@ 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; /* set for next field */ + type = DTK_DAY; /* set for next field */ break; case DTK_DAY: @@ -3133,7 +3133,7 @@ DecodeInterval(char **field, int *ftype, int nf, int range, /*---------- * The SQL standard defines the interval literal - * '-1 1:00:00' + * '-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 @@ -3143,14 +3143,14 @@ DecodeInterval(char **field, int *ftype, int nf, int range, * 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 + * 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; + bool more_signs = false; for (i = 1; i < nf; i++) { @@ -3164,8 +3164,8 @@ DecodeInterval(char **field, int *ftype, int nf, int range, if (!more_signs) { /* - * Rather than re-determining which field was field[0], just - * force 'em all negative. + * Rather than re-determining which field was field[0], just force + * 'em all negative. */ if (*fsec > 0) *fsec = -(*fsec); @@ -3245,28 +3245,28 @@ ISO8601IntegerWidth(char *fieldstart) /* DecodeISO8601Interval() - * Decode an ISO 8601 time interval of the "format with designators" - * (section 4.4.3.2) or "alternative format" (section 4.4.3.3) - * Examples: P1D for 1 day - * PT1H for 1 hour - * P2Y6M7DT1H30M for 2 years, 6 months, 7 days 1 hour 30 min - * P0002-06-07T01:30:00 the same value in alternative format + * Decode an ISO 8601 time interval of the "format with designators" + * (section 4.4.3.2) or "alternative format" (section 4.4.3.3) + * Examples: P1D for 1 day + * PT1H for 1 hour + * P2Y6M7DT1H30M for 2 years, 6 months, 7 days 1 hour 30 min + * P0002-06-07T01:30:00 the same value in alternative format * * Returns 0 if successful, DTERR code if bogus input detected. * Note: error code should be DTERR_BAD_FORMAT if input doesn't look like * ISO8601, otherwise this could cause unexpected error messages. * dtype, tm, fsec are output parameters. * - * A couple exceptions from the spec: - * - a week field ('W') may coexist with other units - * - allows decimals in fields other than the least significant unit. + * A couple exceptions from the spec: + * - a week field ('W') may coexist with other units + * - allows decimals in fields other than the least significant unit. */ int DecodeISO8601Interval(char *str, int *dtype, struct pg_tm * tm, fsec_t *fsec) { - bool datepart = true; - bool havefield = false; + bool datepart = true; + bool havefield = false; *dtype = DTK_DELTA; ClearPgTm(tm, fsec); @@ -3277,13 +3277,13 @@ DecodeISO8601Interval(char *str, str++; while (*str) { - char *fieldstart; - int val; - double fval; - char unit; - int dterr; + char *fieldstart; + int val; + double fval; + char unit; + int dterr; - if (*str == 'T') /* T indicates the beginning of the time part */ + if (*str == 'T') /* T indicates the beginning of the time part */ { datepart = false; havefield = false; @@ -3297,14 +3297,14 @@ DecodeISO8601Interval(char *str, return dterr; /* - * Note: we could step off the end of the string here. Code below + * 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 */ + switch (unit) /* before T: Y M W D */ { case 'Y': tm->tm_year += val; @@ -3322,12 +3322,12 @@ DecodeISO8601Interval(char *str, tm->tm_mday += val; AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY); break; - case 'T': /* ISO 8601 4.4.3.3 Alternative Format / Basic */ + 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_mon += (val / 100) % 100; tm->tm_mday += val % 100; AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY); if (unit == '\0') @@ -3337,12 +3337,13 @@ DecodeISO8601Interval(char *str, continue; } /* Else fall through to extended alternative format */ - case '-': /* ISO 8601 4.4.3.3 Alternative Format, Extended */ + 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); + tm->tm_mon += (fval * 12); if (unit == '\0') return 0; if (unit == 'T') @@ -3355,7 +3356,7 @@ DecodeISO8601Interval(char *str, dterr = ParseISO8601Number(str, &str, &val, &fval); if (dterr) return dterr; - tm->tm_mon += val; + tm->tm_mon += val; AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH); if (*str == '\0') return 0; @@ -3368,7 +3369,7 @@ DecodeISO8601Interval(char *str, if (*str != '-') return DTERR_BAD_FORMAT; str++; - + dterr = ParseISO8601Number(str, &str, &val, &fval); if (dterr) return dterr; @@ -3390,7 +3391,7 @@ DecodeISO8601Interval(char *str, } else { - switch (unit) /* after T: H M S */ + switch (unit) /* after T: H M S */ { case 'H': tm->tm_hour += val; @@ -3404,17 +3405,18 @@ DecodeISO8601Interval(char *str, 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) + 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; + 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 */ + case ':': /* ISO 8601 4.4.3.3 Alternative Format, + * Extended */ if (havefield) return DTERR_BAD_FORMAT; @@ -3422,22 +3424,22 @@ DecodeISO8601Interval(char *str, 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; + 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; + tm->tm_sec += val; AdjustFractSeconds(fval, tm, fsec, 1); if (*str == '\0') return 0; @@ -3843,9 +3845,10 @@ AddPostgresIntPart(char *cp, int value, const char *units, 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... + * 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; @@ -3884,7 +3887,7 @@ AddVerboseIntPart(char *cp, int value, const char *units, * Actually, afaik, ISO 8601 does specify formats for "time * intervals...[of the]...format with time-unit designators", which * are pretty ugly. The format looks something like - * P1Y1M1DT1H1M1.12345S + * P1Y1M1DT1H1M1.12345S * but useful for exchanging data with computers instead of humans. * - ron 2003-07-14 * @@ -3897,11 +3900,11 @@ 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 mon = tm->tm_mon; int mday = tm->tm_mday; int hour = tm->tm_hour; - int min = tm->tm_min; - int sec = tm->tm_sec; + int min = tm->tm_min; + int sec = tm->tm_sec; bool is_before = FALSE; bool is_zero = TRUE; @@ -3913,21 +3916,21 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str) */ switch (style) { - /* SQL Standard interval format */ + /* 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); + 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 @@ -3937,11 +3940,11 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str) { *cp++ = '-'; year = -year; - mon = -mon; + mon = -mon; mday = -mday; hour = -hour; - min = -min; - sec = -sec; + min = -min; + sec = -sec; fsec = -fsec; } @@ -3952,15 +3955,14 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str) else if (!sql_standard_value) { /* - * For non sql-standard interval values, - * force outputting the signs to avoid - * ambiguities with intervals with mixed - * sign components. + * 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) ? '-' : '+'; + 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), @@ -3988,23 +3990,23 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str) } break; - /* ISO 8601 "time-intervals by duration only" */ + /* 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) + 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, 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'); + cp = AddISO8601IntPart(cp, min, 'M'); if (sec != 0 || fsec != 0) { if (sec < 0 || fsec < 0) @@ -4016,14 +4018,14 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str) } break; - /* Compatible with postgresql < 8.4 when DateStyle = 'iso' */ + /* 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); + bool minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0); sprintf(cp, "%s%s%02d:%02d:", is_zero ? "" : " ", @@ -4034,7 +4036,7 @@ EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str) } break; - /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */ + /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */ case INTSTYLE_POSTGRES_VERBOSE: default: strcpy(cp, "@"); |