diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/backend/utils/adt/date.c | 209 | ||||
| -rw-r--r-- | src/include/utils/date.h | 8 |
2 files changed, 83 insertions, 134 deletions
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 344f58b92f7..c4b8125dd66 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -27,6 +27,7 @@ #include "common/int.h" #include "libpq/pqformat.h" #include "miscadmin.h" +#include "nodes/miscnodes.h" #include "nodes/supportnodes.h" #include "parser/scansup.h" #include "utils/array.h" @@ -615,24 +616,21 @@ date_mii(PG_FUNCTION_ARGS) /* * Promote date to timestamp. * - * On successful conversion, *overflow is set to zero if it's not NULL. + * If the date falls out of the valid range for the timestamp type, error + * handling proceeds based on escontext. * - * If the date is finite but out of the valid range for timestamp, then: - * if overflow is NULL, we throw an out-of-range error. - * if overflow is not NULL, we store +1 or -1 there to indicate the sign - * of the overflow, and return the appropriate timestamp infinity. + * If escontext is NULL, we throw an out-of-range error (hard error). + * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or + * upper bound overflow, respectively, and record a soft error. * - * Note: *overflow = -1 is actually not possible currently, since both - * datatypes have the same lower bound, Julian day zero. + * Note: Lower bound overflow is currently not possible, as both date and + * timestamp datatypes share the same lower boundary: Julian day zero. */ Timestamp -date2timestamp_opt_overflow(DateADT dateVal, int *overflow) +date2timestamp_safe(DateADT dateVal, Node *escontext) { Timestamp result; - if (overflow) - *overflow = 0; - if (DATE_IS_NOBEGIN(dateVal)) TIMESTAMP_NOBEGIN(result); else if (DATE_IS_NOEND(dateVal)) @@ -645,18 +643,10 @@ date2timestamp_opt_overflow(DateADT dateVal, int *overflow) */ if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE)) { - if (overflow) - { - *overflow = 1; - TIMESTAMP_NOEND(result); - return result; - } - else - { - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("date out of range for timestamp"))); - } + TIMESTAMP_NOEND(result); + ereturn(escontext, result, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("date out of range for timestamp"))); } /* date is days since 2000, timestamp is microseconds since same... */ @@ -672,30 +662,27 @@ date2timestamp_opt_overflow(DateADT dateVal, int *overflow) static TimestampTz date2timestamp(DateADT dateVal) { - return date2timestamp_opt_overflow(dateVal, NULL); + return date2timestamp_safe(dateVal, NULL); } /* * Promote date to timestamp with time zone. * - * On successful conversion, *overflow is set to zero if it's not NULL. + * If the date falls out of the valid range for the timestamp type, error + * handling proceeds based on escontext. * - * If the date is finite but out of the valid range for timestamptz, then: - * if overflow is NULL, we throw an out-of-range error. - * if overflow is not NULL, we store +1 or -1 there to indicate the sign - * of the overflow, and return the appropriate timestamptz infinity. + * If escontext is NULL, we throw an out-of-range error (hard error). + * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or + * upper bound overflow, respectively, and record a soft error. */ TimestampTz -date2timestamptz_opt_overflow(DateADT dateVal, int *overflow) +date2timestamptz_safe(DateADT dateVal, Node *escontext) { TimestampTz result; struct pg_tm tt, *tm = &tt; int tz; - if (overflow) - *overflow = 0; - if (DATE_IS_NOBEGIN(dateVal)) TIMESTAMP_NOBEGIN(result); else if (DATE_IS_NOEND(dateVal)) @@ -708,18 +695,10 @@ date2timestamptz_opt_overflow(DateADT dateVal, int *overflow) */ if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE)) { - if (overflow) - { - *overflow = 1; - TIMESTAMP_NOEND(result); - return result; - } - else - { - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("date out of range for timestamp"))); - } + TIMESTAMP_NOEND(result); + ereturn(escontext, result, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("date out of range for timestamp"))); } j2date(dateVal + POSTGRES_EPOCH_JDATE, @@ -737,25 +716,14 @@ date2timestamptz_opt_overflow(DateADT dateVal, int *overflow) */ if (!IS_VALID_TIMESTAMP(result)) { - if (overflow) - { - if (result < MIN_TIMESTAMP) - { - *overflow = -1; - TIMESTAMP_NOBEGIN(result); - } - else - { - *overflow = 1; - TIMESTAMP_NOEND(result); - } - } + if (result < MIN_TIMESTAMP) + TIMESTAMP_NOBEGIN(result); else - { - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("date out of range for timestamp"))); - } + TIMESTAMP_NOEND(result); + + ereturn(escontext, result, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("date out of range for timestamp"))); } } @@ -768,7 +736,7 @@ date2timestamptz_opt_overflow(DateADT dateVal, int *overflow) static TimestampTz date2timestamptz(DateADT dateVal) { - return date2timestamptz_opt_overflow(dateVal, NULL); + return date2timestamptz_safe(dateVal, NULL); } /* @@ -808,15 +776,16 @@ int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2) { Timestamp dt1; - int overflow; + ErrorSaveContext escontext = {T_ErrorSaveContext}; - dt1 = date2timestamp_opt_overflow(dateVal, &overflow); - if (overflow > 0) + dt1 = date2timestamp_safe(dateVal, (Node *) &escontext); + if (escontext.error_occurred) { + Assert(TIMESTAMP_IS_NOEND(dt1)); /* NOBEGIN case cannot occur */ + /* dt1 is larger than any finite timestamp, but less than infinity */ return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1; } - Assert(overflow == 0); /* -1 case cannot occur */ return timestamp_cmp_internal(dt1, dt2); } @@ -888,18 +857,22 @@ int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2) { TimestampTz dt1; - int overflow; + ErrorSaveContext escontext = {T_ErrorSaveContext}; - dt1 = date2timestamptz_opt_overflow(dateVal, &overflow); - if (overflow > 0) - { - /* dt1 is larger than any finite timestamp, but less than infinity */ - return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1; - } - if (overflow < 0) + dt1 = date2timestamptz_safe(dateVal, (Node *) &escontext); + + if (escontext.error_occurred) { - /* dt1 is less than any finite timestamp, but more than -infinity */ - return TIMESTAMP_IS_NOBEGIN(dt2) ? +1 : -1; + if (TIMESTAMP_IS_NOEND(dt1)) + { + /* dt1 is larger than any finite timestamp, but less than infinity */ + return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1; + } + if (TIMESTAMP_IS_NOBEGIN(dt1)) + { + /* dt1 is less than any finite timestamp, but more than -infinity */ + return TIMESTAMP_IS_NOBEGIN(dt2) ? +1 : -1; + } } return timestamptz_cmp_internal(dt1, dt2); @@ -1364,34 +1337,31 @@ timestamp_date(PG_FUNCTION_ARGS) Timestamp timestamp = PG_GETARG_TIMESTAMP(0); DateADT result; - result = timestamp2date_opt_overflow(timestamp, NULL); + result = timestamp2date_safe(timestamp, NULL); PG_RETURN_DATEADT(result); } /* * Convert timestamp to date. * - * On successful conversion, *overflow is set to zero if it's not NULL. + * If the timestamp falls out of the valid range for the date type, error + * handling proceeds based on escontext. * - * If the timestamp is finite but out of the valid range for date, then: - * if overflow is NULL, we throw an out-of-range error. - * if overflow is not NULL, we store +1 or -1 there to indicate the sign - * of the overflow, and return the appropriate date infinity. + * If escontext is NULL, we throw an out-of-range error (hard error). + * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or + * upper bound overflow, respectively, and record a soft error. * * Note: given the ranges of the types, overflow is only possible at - * the minimum end of the range, but we don't assume that in this code. + * the lower bound of the range, but we don't assume that in this code. */ DateADT -timestamp2date_opt_overflow(Timestamp timestamp, int *overflow) +timestamp2date_safe(Timestamp timestamp, Node *escontext) { DateADT result; struct pg_tm tt, *tm = &tt; fsec_t fsec; - if (overflow) - *overflow = 0; - if (TIMESTAMP_IS_NOBEGIN(timestamp)) DATE_NOBEGIN(result); else if (TIMESTAMP_IS_NOEND(timestamp)) @@ -1400,21 +1370,12 @@ timestamp2date_opt_overflow(Timestamp timestamp, int *overflow) { if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) { - if (overflow) - { - if (timestamp < 0) - { - *overflow = -1; - DATE_NOBEGIN(result); - } - else - { - *overflow = 1; /* not actually reachable */ - DATE_NOEND(result); - } - return result; - } - ereport(ERROR, + if (timestamp < 0) + DATE_NOBEGIN(result); + else + DATE_NOEND(result); /* not actually reachable */ + + ereturn(escontext, result, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } @@ -1450,25 +1411,25 @@ timestamptz_date(PG_FUNCTION_ARGS) TimestampTz timestamp = PG_GETARG_TIMESTAMP(0); DateADT result; - result = timestamptz2date_opt_overflow(timestamp, NULL); + result = timestamptz2date_safe(timestamp, NULL); PG_RETURN_DATEADT(result); } /* * Convert timestamptz to date. * - * On successful conversion, *overflow is set to zero if it's not NULL. + * If the timestamp falls out of the valid range for the date type, error + * handling proceeds based on escontext. * - * If the timestamptz is finite but out of the valid range for date, then: - * if overflow is NULL, we throw an out-of-range error. - * if overflow is not NULL, we store +1 or -1 there to indicate the sign - * of the overflow, and return the appropriate date infinity. + * If escontext is NULL, we throw an out-of-range error (hard error). + * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or + * upper bound overflow, respectively, and record a soft error. * * Note: given the ranges of the types, overflow is only possible at - * the minimum end of the range, but we don't assume that in this code. + * the lower bound of the range, but we don't assume that in this code. */ DateADT -timestamptz2date_opt_overflow(TimestampTz timestamp, int *overflow) +timestamptz2date_safe(TimestampTz timestamp, Node *escontext) { DateADT result; struct pg_tm tt, @@ -1476,9 +1437,6 @@ timestamptz2date_opt_overflow(TimestampTz timestamp, int *overflow) fsec_t fsec; int tz; - if (overflow) - *overflow = 0; - if (TIMESTAMP_IS_NOBEGIN(timestamp)) DATE_NOBEGIN(result); else if (TIMESTAMP_IS_NOEND(timestamp)) @@ -1487,21 +1445,12 @@ timestamptz2date_opt_overflow(TimestampTz timestamp, int *overflow) { if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0) { - if (overflow) - { - if (timestamp < 0) - { - *overflow = -1; - DATE_NOBEGIN(result); - } - else - { - *overflow = 1; /* not actually reachable */ - DATE_NOEND(result); - } - return result; - } - ereport(ERROR, + if (timestamp < 0) + DATE_NOBEGIN(result); + else + DATE_NOEND(result); /* not actually reachable */ + + ereturn(escontext, result, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } diff --git a/src/include/utils/date.h b/src/include/utils/date.h index abfda0b1ae9..7316ac0ff17 100644 --- a/src/include/utils/date.h +++ b/src/include/utils/date.h @@ -98,10 +98,10 @@ TimeTzADTPGetDatum(const TimeTzADT *X) /* date.c */ extern int32 anytime_typmod_check(bool istz, int32 typmod); extern double date2timestamp_no_overflow(DateADT dateVal); -extern Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow); -extern TimestampTz date2timestamptz_opt_overflow(DateADT dateVal, int *overflow); -extern DateADT timestamp2date_opt_overflow(Timestamp timestamp, int *overflow); -extern DateADT timestamptz2date_opt_overflow(TimestampTz timestamp, int *overflow); +extern Timestamp date2timestamp_safe(DateADT dateVal, Node *escontext); +extern TimestampTz date2timestamptz_safe(DateADT dateVal, Node *escontext); +extern DateADT timestamp2date_safe(Timestamp timestamp, Node *escontext); +extern DateADT timestamptz2date_safe(TimestampTz timestamp, Node *escontext); extern int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2); extern int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2); |
