diff options
author | Alexander Korotkov <akorotkov@postgresql.org> | 2019-09-25 21:51:47 +0300 |
---|---|---|
committer | Alexander Korotkov <akorotkov@postgresql.org> | 2019-09-25 22:51:51 +0300 |
commit | 5bc450629b31a0b6986e668056d5bd36792412d2 (patch) | |
tree | 34f352243ddeaf8120fd870ff8460ad7b447ec1c /src/backend/utils/adt/timestamp.c | |
parent | 66c74f8b6e347ba5830bf06468bef8081601c187 (diff) |
Error suppression support for upcoming jsonpath .datetime() method
Add support of error suppression in some date and time manipulation functions
as it's required for jsonpath .datetime() method support. This commit doesn't
use PG_TRY()/PG_CATCH() in order to implement that. Instead, it provides
internal versions of date and time functions used, which support error
suppression.
Discussion: https://postgr.es/m/CAPpHfdsZgYEra_PeCLGNoXOWYx6iU-S3wF8aX0ObQUcZU%2B4XTw%40mail.gmail.com
Author: Alexander Korotkov, Nikita Glukhov
Reviewed-by: Anastasia Lubennikova, Peter Eisentraut
Diffstat (limited to 'src/backend/utils/adt/timestamp.c')
-rw-r--r-- | src/backend/utils/adt/timestamp.c | 66 |
1 files changed, 49 insertions, 17 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 2931bd58c0d..84bc97d40c3 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -329,11 +329,11 @@ timestamp_scale(PG_FUNCTION_ARGS) } /* - * AdjustTimestampForTypmod --- round off a timestamp to suit given typmod + * AdjustTimestampForTypmodError --- round off a timestamp to suit given typmod * Works for either timestamp or timestamptz. */ -void -AdjustTimestampForTypmod(Timestamp *time, int32 typmod) +bool +AdjustTimestampForTypmodError(Timestamp *time, int32 typmod, bool *error) { static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = { INT64CONST(1000000), @@ -359,10 +359,18 @@ AdjustTimestampForTypmod(Timestamp *time, int32 typmod) && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION)) { if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION) + { + if (error) + { + *error = true; + return false; + } + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("timestamp(%d) precision must be between %d and %d", typmod, 0, MAX_TIMESTAMP_PRECISION))); + } if (*time >= INT64CONST(0)) { @@ -375,8 +383,15 @@ AdjustTimestampForTypmod(Timestamp *time, int32 typmod) * TimestampScales[typmod]); } } + + return true; } +void +AdjustTimestampForTypmod(Timestamp *time, int32 typmod) +{ + (void) AdjustTimestampForTypmodError(time, typmod, NULL); +} /* timestamptz_in() * Convert a string to internal form. @@ -5172,8 +5187,15 @@ timestamp_timestamptz(PG_FUNCTION_ARGS) PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp)); } -static TimestampTz -timestamp2timestamptz(Timestamp timestamp) +/* + * Convert timestamp to timestamp with time zone. + * + * If 'have_error' is NULL, then errors are thrown, else '*have_error' is set + * and zero is returned. + */ + +TimestampTz +timestamp2timestamptz_opt_error(Timestamp timestamp, bool *have_error) { TimestampTz result; struct pg_tm tt, @@ -5182,23 +5204,33 @@ timestamp2timestamptz(Timestamp timestamp) int tz; if (TIMESTAMP_NOT_FINITE(timestamp)) - result = timestamp; - else - { - if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"))); + return timestamp; + if (!timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL)) + { tz = DetermineTimeZoneOffset(tm, session_timezone); - if (tm2timestamp(tm, fsec, &tz, &result) != 0) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"))); + if (!tm2timestamp(tm, fsec, &tz, &result)) + return result; } - return result; + if (have_error) + *have_error = true; + else + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + + return 0; +} + +/* + * Single-argument version of timestamp2timestamptz_opt_error(). + */ +static TimestampTz +timestamp2timestamptz(Timestamp timestamp) +{ + return timestamp2timestamptz_opt_error(timestamp, NULL); } /* timestamptz_timestamp() |