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.c111
1 files changed, 99 insertions, 12 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 68710928718..1525d2a1192 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -4311,6 +4311,83 @@ date2isoyearday(int year, int mon, int mday)
return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
}
+/*
+ * NonFiniteTimestampTzPart
+ *
+ * Used by timestamp_part and timestamptz_part when extracting from infinite
+ * timestamp[tz]. Returns +/-Infinity if that is the appropriate result,
+ * otherwise returns zero (which should be taken as meaning to return NULL).
+ *
+ * Errors thrown here for invalid units should exactly match those that
+ * would be thrown in the calling functions, else there will be unexpected
+ * discrepancies between finite- and infinite-input cases.
+ */
+static float8
+NonFiniteTimestampTzPart(int type, int unit, char *lowunits,
+ bool isNegative, bool isTz)
+{
+ if ((type != UNITS) && (type != RESERV))
+ {
+ if (isTz)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("timestamp with time zone units \"%s\" not recognized",
+ lowunits)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("timestamp units \"%s\" not recognized",
+ lowunits)));
+ }
+
+ switch (unit)
+ {
+ /* Oscillating units */
+ case DTK_MICROSEC:
+ case DTK_MILLISEC:
+ case DTK_SECOND:
+ case DTK_MINUTE:
+ case DTK_HOUR:
+ case DTK_DAY:
+ case DTK_MONTH:
+ case DTK_QUARTER:
+ case DTK_WEEK:
+ case DTK_DOW:
+ case DTK_ISODOW:
+ case DTK_DOY:
+ case DTK_TZ:
+ case DTK_TZ_MINUTE:
+ case DTK_TZ_HOUR:
+ return 0.0;
+
+ /* Monotonically-increasing units */
+ case DTK_YEAR:
+ case DTK_DECADE:
+ case DTK_CENTURY:
+ case DTK_MILLENNIUM:
+ case DTK_JULIAN:
+ case DTK_ISOYEAR:
+ case DTK_EPOCH:
+ if (isNegative)
+ return -get_float8_infinity();
+ else
+ return get_float8_infinity();
+
+ default:
+ if (isTz)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("timestamp with time zone units \"%s\" not supported",
+ lowunits)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("timestamp units \"%s\" not supported",
+ lowunits)));
+ return 0.0; /* keep compiler quiet */
+ }
+}
+
/* timestamp_part()
* Extract specified field from timestamp.
*/
@@ -4327,12 +4404,6 @@ timestamp_part(PG_FUNCTION_ARGS)
struct pg_tm tt,
*tm = &tt;
- if (TIMESTAMP_NOT_FINITE(timestamp))
- {
- result = 0;
- PG_RETURN_FLOAT8(result);
- }
-
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
VARSIZE_ANY_EXHDR(units),
false);
@@ -4341,6 +4412,17 @@ timestamp_part(PG_FUNCTION_ARGS)
if (type == UNKNOWN_FIELD)
type = DecodeSpecial(0, lowunits, &val);
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ {
+ result = NonFiniteTimestampTzPart(type, val, lowunits,
+ TIMESTAMP_IS_NOBEGIN(timestamp),
+ false);
+ if (result)
+ PG_RETURN_FLOAT8(result);
+ else
+ PG_RETURN_NULL();
+ }
+
if (type == UNITS)
{
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
@@ -4538,12 +4620,6 @@ timestamptz_part(PG_FUNCTION_ARGS)
struct pg_tm tt,
*tm = &tt;
- if (TIMESTAMP_NOT_FINITE(timestamp))
- {
- result = 0;
- PG_RETURN_FLOAT8(result);
- }
-
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
VARSIZE_ANY_EXHDR(units),
false);
@@ -4552,6 +4628,17 @@ timestamptz_part(PG_FUNCTION_ARGS)
if (type == UNKNOWN_FIELD)
type = DecodeSpecial(0, lowunits, &val);
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ {
+ result = NonFiniteTimestampTzPart(type, val, lowunits,
+ TIMESTAMP_IS_NOBEGIN(timestamp),
+ true);
+ if (result)
+ PG_RETURN_FLOAT8(result);
+ else
+ PG_RETURN_NULL();
+ }
+
if (type == UNITS)
{
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)