aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/timestamp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/timestamp.c')
-rw-r--r--src/backend/utils/adt/timestamp.c95
1 files changed, 81 insertions, 14 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index c4f556a3ffa..3f013e3f5bb 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -261,7 +261,8 @@ timestamp_recv(PG_FUNCTION_ARGS)
/* rangecheck: see if timestamp_out would like it */
if (TIMESTAMP_NOT_FINITE(timestamp))
/* ok */ ;
- else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
+ else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0 ||
+ !IS_VALID_TIMESTAMP(timestamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -645,6 +646,14 @@ make_timestamp_internal(int year, int month, int day,
result = date * SECS_PER_DAY + time;
#endif
+ /* final range check catches just-out-of-range timestamps */
+ if (!IS_VALID_TIMESTAMP(result))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
+ year, month, day,
+ hour, min, sec)));
+
return result;
}
@@ -702,6 +711,7 @@ make_timestamptz_at_timezone(PG_FUNCTION_ARGS)
int32 min = PG_GETARG_INT32(4);
float8 sec = PG_GETARG_FLOAT8(5);
text *zone = PG_GETARG_TEXT_PP(6);
+ TimestampTz result;
Timestamp timestamp;
struct pg_tm tt;
int tz;
@@ -717,7 +727,14 @@ make_timestamptz_at_timezone(PG_FUNCTION_ARGS)
tz = parse_sane_timezone(&tt, zone);
- PG_RETURN_TIMESTAMPTZ((TimestampTz) dt2local(timestamp, -tz));
+ result = dt2local(timestamp, -tz);
+
+ if (!IS_VALID_TIMESTAMP(result))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
+
+ PG_RETURN_TIMESTAMPTZ(result);
}
/* timestamptz_out()
@@ -778,7 +795,8 @@ timestamptz_recv(PG_FUNCTION_ARGS)
/* rangecheck: see if timestamptz_out would like it */
if (TIMESTAMP_NOT_FINITE(timestamp))
/* ok */ ;
- else if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
+ else if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0 ||
+ !IS_VALID_TIMESTAMP(timestamp))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -1925,7 +1943,7 @@ tm2timestamp(struct pg_tm * tm, fsec_t fsec, int *tzp, Timestamp *result)
TimeOffset date;
TimeOffset time;
- /* Julian day routines are not correct for negative Julian days */
+ /* Prevent overflow in Julian-day routines */
if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
{
*result = 0; /* keep compiler quiet */
@@ -1957,6 +1975,13 @@ tm2timestamp(struct pg_tm * tm, fsec_t fsec, int *tzp, Timestamp *result)
if (tzp != NULL)
*result = dt2local(*result, -(*tzp));
+ /* final range check catches just-out-of-range timestamps */
+ if (!IS_VALID_TIMESTAMP(*result))
+ {
+ *result = 0; /* keep compiler quiet */
+ return -1;
+ }
+
return 0;
}
@@ -2982,6 +3007,12 @@ timestamp_pl_interval(PG_FUNCTION_ARGS)
}
timestamp += span->time;
+
+ if (!IS_VALID_TIMESTAMP(timestamp))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
+
result = timestamp;
}
@@ -3086,6 +3117,12 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS)
}
timestamp += span->time;
+
+ if (!IS_VALID_TIMESTAMP(timestamp))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
+
result = timestamp;
}
@@ -4397,6 +4434,7 @@ timestamp_part(PG_FUNCTION_ARGS)
text *units = PG_GETARG_TEXT_PP(0);
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
float8 result;
+ Timestamp epoch;
int type,
val;
char *lowunits;
@@ -4575,10 +4613,15 @@ timestamp_part(PG_FUNCTION_ARGS)
switch (val)
{
case DTK_EPOCH:
+ epoch = SetEpochTimestamp();
#ifdef HAVE_INT64_TIMESTAMP
- result = (timestamp - SetEpochTimestamp()) / 1000000.0;
+ /* try to avoid precision loss in subtraction */
+ if (timestamp < (PG_INT64_MAX + epoch))
+ result = (timestamp - epoch) / 1000000.0;
+ else
+ result = ((float8) timestamp - epoch) / 1000000.0;
#else
- result = timestamp - SetEpochTimestamp();
+ result = timestamp - epoch;
#endif
break;
@@ -4611,6 +4654,7 @@ timestamptz_part(PG_FUNCTION_ARGS)
text *units = PG_GETARG_TEXT_PP(0);
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
float8 result;
+ Timestamp epoch;
int tz;
int type,
val;
@@ -4792,10 +4836,15 @@ timestamptz_part(PG_FUNCTION_ARGS)
switch (val)
{
case DTK_EPOCH:
+ epoch = SetEpochTimestamp();
#ifdef HAVE_INT64_TIMESTAMP
- result = (timestamp - SetEpochTimestamp()) / 1000000.0;
+ /* try to avoid precision loss in subtraction */
+ if (timestamp < (PG_INT64_MAX + epoch))
+ result = (timestamp - epoch) / 1000000.0;
+ else
+ result = ((float8) timestamp - epoch) / 1000000.0;
#else
- result = timestamp - SetEpochTimestamp();
+ result = timestamp - epoch;
#endif
break;
@@ -5107,9 +5156,8 @@ timestamp_zone(PG_FUNCTION_ARGS)
tz = DetermineTimeZoneOffset(&tm, tzp);
if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("could not convert to time zone \"%s\"",
- tzname)));
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
}
else
{
@@ -5120,6 +5168,11 @@ timestamp_zone(PG_FUNCTION_ARGS)
}
}
+ if (!IS_VALID_TIMESTAMP(result))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
+
PG_RETURN_TIMESTAMPTZ(result);
}
@@ -5198,6 +5251,11 @@ timestamp_izone(PG_FUNCTION_ARGS)
result = dt2local(timestamp, tz);
+ if (!IS_VALID_TIMESTAMP(result))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
+
PG_RETURN_TIMESTAMPTZ(result);
} /* timestamp_izone() */
@@ -5337,9 +5395,8 @@ timestamptz_zone(PG_FUNCTION_ARGS)
errmsg("timestamp out of range")));
if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("could not convert to time zone \"%s\"",
- tzname)));
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
}
else
{
@@ -5350,6 +5407,11 @@ timestamptz_zone(PG_FUNCTION_ARGS)
}
}
+ if (!IS_VALID_TIMESTAMP(result))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
+
PG_RETURN_TIMESTAMP(result);
}
@@ -5383,6 +5445,11 @@ timestamptz_izone(PG_FUNCTION_ARGS)
result = dt2local(timestamp, tz);
+ if (!IS_VALID_TIMESTAMP(result))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
+
PG_RETURN_TIMESTAMP(result);
}