mirror of
https://github.com/postgres/postgres.git
synced 2025-08-30 06:01:21 +03:00
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
This commit is contained in:
@@ -550,13 +550,15 @@ date_mii(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_DATEADT(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal routines for promoting date to timestamp and timestamp with
|
||||
* time zone
|
||||
*/
|
||||
|
||||
static Timestamp
|
||||
date2timestamp(DateADT dateVal)
|
||||
/*
|
||||
* Promote date to timestamp.
|
||||
*
|
||||
* If 'have_error' is NULL, then errors are thrown, else '*have_error' is set
|
||||
* and zero is returned.
|
||||
*/
|
||||
Timestamp
|
||||
date2timestamp_opt_error(DateADT dateVal, bool *have_error)
|
||||
{
|
||||
Timestamp result;
|
||||
|
||||
@@ -572,9 +574,19 @@ date2timestamp(DateADT dateVal)
|
||||
* boundary need be checked for overflow.
|
||||
*/
|
||||
if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
||||
errmsg("date out of range for timestamp")));
|
||||
{
|
||||
if (have_error)
|
||||
{
|
||||
*have_error = true;
|
||||
return (Timestamp) 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
||||
errmsg("date out of range for timestamp")));
|
||||
}
|
||||
}
|
||||
|
||||
/* date is days since 2000, timestamp is microseconds since same... */
|
||||
result = dateVal * USECS_PER_DAY;
|
||||
@@ -583,8 +595,23 @@ date2timestamp(DateADT dateVal)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Single-argument version of date2timestamp_opt_error().
|
||||
*/
|
||||
static TimestampTz
|
||||
date2timestamptz(DateADT dateVal)
|
||||
date2timestamp(DateADT dateVal)
|
||||
{
|
||||
return date2timestamp_opt_error(dateVal, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Promote date to timestamp with time zone.
|
||||
*
|
||||
* If 'have_error' is NULL, then errors are thrown, else '*have_error' is set
|
||||
* and zero is returned.
|
||||
*/
|
||||
TimestampTz
|
||||
date2timestamptz_opt_error(DateADT dateVal, bool *have_error)
|
||||
{
|
||||
TimestampTz result;
|
||||
struct pg_tm tt,
|
||||
@@ -603,9 +630,19 @@ date2timestamptz(DateADT dateVal)
|
||||
* boundary need be checked for overflow.
|
||||
*/
|
||||
if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
||||
errmsg("date out of range for timestamp")));
|
||||
{
|
||||
if (have_error)
|
||||
{
|
||||
*have_error = true;
|
||||
return (TimestampTz) 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
||||
errmsg("date out of range for timestamp")));
|
||||
}
|
||||
}
|
||||
|
||||
j2date(dateVal + POSTGRES_EPOCH_JDATE,
|
||||
&(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
|
||||
@@ -621,14 +658,33 @@ date2timestamptz(DateADT dateVal)
|
||||
* of time zone, check for allowed timestamp range after adding tz.
|
||||
*/
|
||||
if (!IS_VALID_TIMESTAMP(result))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
||||
errmsg("date out of range for timestamp")));
|
||||
{
|
||||
if (have_error)
|
||||
{
|
||||
*have_error = true;
|
||||
return (TimestampTz) 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
||||
errmsg("date out of range for timestamp")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Single-argument version of date2timestamptz_opt_error().
|
||||
*/
|
||||
static TimestampTz
|
||||
date2timestamptz(DateADT dateVal)
|
||||
{
|
||||
return date2timestamptz_opt_error(dateVal, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* date2timestamp_no_overflow
|
||||
*
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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()
|
||||
|
Reference in New Issue
Block a user