summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Paquier <michael@paquier.xyz>2025-12-02 09:30:23 +0900
committerMichael Paquier <michael@paquier.xyz>2025-12-02 09:30:23 +0900
commit713d9a847e6409a2a722aed90975eef6d75dc701 (patch)
tree87612685e6c49f11e4c10f0c8632b15ed58ded96 /src
parent19b966243c38196a33b033fb0c259dcf760c0d69 (diff)
Update some timestamp[tz] functions to use soft-error reportingHEADorigin/masterorigin/HEADmaster
This commit updates two functions that convert "timestamptz" to "timestamp", and vice-versa, to use the soft error reporting rather than a their own logic to do the same. These are now named as follows: - timestamp2timestamptz_safe() - timestamptz2timestamp_safe() These functions were suffixed with "_opt_overflow", previously. This shaves some code, as it is possible to detect how a timestamp[tz] overflowed based on the returned value rather than a custom state. It is optionally possible for the callers of these functions to rely on the error generated internally by these functions, depending on the error context. Similar work has been done in d03668ea0566 and 4246a977bad6. Reviewed-by: Amul Sul <sulamul@gmail.com> Discussion: https://postgr.es/m/aS09YF2GmVXjAxbJ@paquier.xyz
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/timestamp.c121
-rw-r--r--src/include/utils/timestamp.h8
2 files changed, 48 insertions, 81 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 156a4830ffd..af48527d436 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -2363,18 +2363,21 @@ int32
timestamp_cmp_timestamptz_internal(Timestamp timestampVal, TimestampTz dt2)
{
TimestampTz dt1;
- int overflow;
+ ErrorSaveContext escontext = {T_ErrorSaveContext};
- dt1 = timestamp2timestamptz_opt_overflow(timestampVal, &overflow);
- if (overflow > 0)
+ dt1 = timestamp2timestamptz_safe(timestampVal, (Node *) &escontext);
+ if (escontext.error_occurred)
{
- /* dt1 is larger than any finite timestamp, but less than infinity */
- return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
- }
- if (overflow < 0)
- {
- /* 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);
@@ -6434,15 +6437,15 @@ timestamp_timestamptz(PG_FUNCTION_ARGS)
/*
* Convert timestamp to timestamp with time zone.
*
- * On successful conversion, *overflow is set to zero if it's not NULL.
+ * If the timestamp is finite but out of the valid range for timestamptz,
+ * error handling proceeds based on escontext.
*
- * If the timestamp 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
-timestamp2timestamptz_opt_overflow(Timestamp timestamp, int *overflow)
+timestamp2timestamptz_safe(Timestamp timestamp, Node *escontext)
{
TimestampTz result;
struct pg_tm tt,
@@ -6450,9 +6453,6 @@ timestamp2timestamptz_opt_overflow(Timestamp timestamp, int *overflow)
fsec_t fsec;
int tz;
- if (overflow)
- *overflow = 0;
-
if (TIMESTAMP_NOT_FINITE(timestamp))
return timestamp;
@@ -6467,26 +6467,14 @@ timestamp2timestamptz_opt_overflow(Timestamp timestamp, int *overflow)
return result;
}
- if (overflow)
- {
- if (timestamp < 0)
- {
- *overflow = -1;
- TIMESTAMP_NOBEGIN(result);
- }
- else
- {
- *overflow = 1;
- TIMESTAMP_NOEND(result);
- }
- return result;
- }
+ if (timestamp < 0)
+ TIMESTAMP_NOBEGIN(result);
+ else
+ TIMESTAMP_NOEND(result);
- ereport(ERROR,
+ ereturn(escontext, result,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
-
- return 0;
}
/*
@@ -6495,7 +6483,7 @@ timestamp2timestamptz_opt_overflow(Timestamp timestamp, int *overflow)
static TimestampTz
timestamp2timestamptz(Timestamp timestamp)
{
- return timestamp2timestamptz_opt_overflow(timestamp, NULL);
+ return timestamp2timestamptz_safe(timestamp, NULL);
}
/* timestamptz_timestamp()
@@ -6515,21 +6503,21 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
static Timestamp
timestamptz2timestamp(TimestampTz timestamp)
{
- return timestamptz2timestamp_opt_overflow(timestamp, NULL);
+ return timestamptz2timestamp_safe(timestamp, NULL);
}
/*
* Convert timestamp with time zone to timestamp.
*
- * On successful conversion, *overflow is set to zero if it's not NULL.
+ * If the timestamptz is finite but out of the valid range for timestamp,
+ * error handling proceeds based on escontext.
*
- * If the timestamptz 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.
*/
Timestamp
-timestamptz2timestamp_opt_overflow(TimestampTz timestamp, int *overflow)
+timestamptz2timestamp_safe(TimestampTz timestamp, Node *escontext)
{
Timestamp result;
struct pg_tm tt,
@@ -6537,50 +6525,29 @@ timestamptz2timestamp_opt_overflow(TimestampTz timestamp, int *overflow)
fsec_t fsec;
int tz;
- if (overflow)
- *overflow = 0;
-
if (TIMESTAMP_NOT_FINITE(timestamp))
result = timestamp;
else
{
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
{
- if (overflow)
- {
- if (timestamp < 0)
- {
- *overflow = -1;
- TIMESTAMP_NOBEGIN(result);
- }
- else
- {
- *overflow = 1;
- TIMESTAMP_NOEND(result);
- }
- return result;
- }
- ereport(ERROR,
+ if (timestamp < 0)
+ TIMESTAMP_NOBEGIN(result);
+ else
+ TIMESTAMP_NOEND(result);
+
+ ereturn(escontext, result,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
}
if (tm2timestamp(tm, fsec, NULL, &result) != 0)
{
- if (overflow)
- {
- if (timestamp < 0)
- {
- *overflow = -1;
- TIMESTAMP_NOBEGIN(result);
- }
- else
- {
- *overflow = 1;
- TIMESTAMP_NOEND(result);
- }
- return result;
- }
- ereport(ERROR,
+ if (timestamp < 0)
+ TIMESTAMP_NOBEGIN(result);
+ else
+ TIMESTAMP_NOEND(result);
+
+ ereturn(escontext, result,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
}
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index 93531732b08..f1a85c7d9eb 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -142,10 +142,10 @@ extern int timestamp_cmp_internal(Timestamp dt1, Timestamp dt2);
/* timestamp comparison works for timestamptz also */
#define timestamptz_cmp_internal(dt1,dt2) timestamp_cmp_internal(dt1, dt2)
-extern TimestampTz timestamp2timestamptz_opt_overflow(Timestamp timestamp,
- int *overflow);
-extern Timestamp timestamptz2timestamp_opt_overflow(TimestampTz timestamp,
- int *overflow);
+extern TimestampTz timestamp2timestamptz_safe(Timestamp timestamp,
+ Node *escontext);
+extern Timestamp timestamptz2timestamp_safe(TimestampTz timestamp,
+ Node *escontext);
extern int32 timestamp_cmp_timestamptz_internal(Timestamp timestampVal,
TimestampTz dt2);