index 18d7d8a108ac09ec41ee60ec539dc55f6eb2ce36..1b33eb6ea8db7d04b25b7ffe36442023522799ae 100644 (file)
struct pg_tm tt,
*tm = &tt;
- if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_TIMESTAMP(timestamp);
-
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
VARSIZE_ANY_EXHDR(units),
false);
if (type == UNITS)
{
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ {
+ /*
+ * Errors thrown here for invalid units should exactly match those
+ * below, else there will be unexpected discrepancies between
+ * finite- and infinite-input cases.
+ */
+ switch (val)
+ {
+ case DTK_WEEK:
+ case DTK_MILLENNIUM:
+ case DTK_CENTURY:
+ case DTK_DECADE:
+ case DTK_YEAR:
+ case DTK_QUARTER:
+ case DTK_MONTH:
+ case DTK_DAY:
+ case DTK_HOUR:
+ case DTK_MINUTE:
+ case DTK_SECOND:
+ case DTK_MILLISEC:
+ case DTK_MICROSEC:
+ PG_RETURN_TIMESTAMP(timestamp);
+ break;
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("unit \"%s\" not supported for type %s",
+ lowunits, format_type_be(TIMESTAMPOID))));
+ result = 0;
+ }
+ }
+
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
@@ -4836,6 +4866,40 @@ timestamptz_trunc_internal(text *units, TimestampTz timestamp, pg_tz *tzp)
if (type == UNITS)
{
+ if (TIMESTAMP_NOT_FINITE(timestamp))
+ {
+ /*
+ * Errors thrown here for invalid units should exactly match those
+ * below, else there will be unexpected discrepancies between
+ * finite- and infinite-input cases.
+ */
+ switch (val)
+ {
+ case DTK_WEEK:
+ case DTK_MILLENNIUM:
+ case DTK_CENTURY:
+ case DTK_DECADE:
+ case DTK_YEAR:
+ case DTK_QUARTER:
+ case DTK_MONTH:
+ case DTK_DAY:
+ case DTK_HOUR:
+ case DTK_MINUTE:
+ case DTK_SECOND:
+ case DTK_MILLISEC:
+ case DTK_MICROSEC:
+ PG_RETURN_TIMESTAMPTZ(timestamp);
+ break;
+
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("unit \"%s\" not supported for type %s",
+ lowunits, format_type_be(TIMESTAMPTZOID))));
+ result = 0;
+ }
+ }
+
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, tzp) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
TimestampTz result;
- if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_TIMESTAMPTZ(timestamp);
-
result = timestamptz_trunc_internal(units, timestamp, session_timezone);
PG_RETURN_TIMESTAMPTZ(result);
TimestampTz result;
pg_tz *tzp;
- /*
- * timestamptz_zone() doesn't look up the zone for infinite inputs, so we
- * don't do so here either.
- */
- if (TIMESTAMP_NOT_FINITE(timestamp))
- PG_RETURN_TIMESTAMP(timestamp);
-
/*
* Look up the requested timezone.
*/
result = (Interval *) palloc(sizeof(Interval));
- if (INTERVAL_NOT_FINITE(interval))
- {
- memcpy(result, interval, sizeof(Interval));
- PG_RETURN_INTERVAL_P(result);
- }
-
lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
VARSIZE_ANY_EXHDR(units),
false);
if (type == UNITS)
{
+ if (INTERVAL_NOT_FINITE(interval))
+ {
+ /*
+ * Errors thrown here for invalid units should exactly match those
+ * below, else there will be unexpected discrepancies between
+ * finite- and infinite-input cases.
+ */
+ switch (val)
+ {
+ case DTK_MILLENNIUM:
+ case DTK_CENTURY:
+ case DTK_DECADE:
+ case DTK_YEAR:
+ case DTK_QUARTER:
+ case DTK_MONTH:
+ case DTK_DAY:
+ case DTK_HOUR:
+ case DTK_MINUTE:
+ case DTK_SECOND:
+ case DTK_MILLISEC:
+ case DTK_MICROSEC:
+ memcpy(result, interval, sizeof(Interval));
+ PG_RETURN_INTERVAL_P(result);
+ break;
+
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("unit \"%s\" not supported for type %s",
+ lowunits, format_type_be(INTERVALOID)),
+ (val == DTK_WEEK) ? errdetail("Months usually have fractional weeks.") : 0));
+ result = 0;
+ }
+ }
+
interval2itm(*interval, tm);
switch (val)
{
index 6b91e7eddc787c38b447da6633aa0eb6d12687b4..a92586c363e20b94432ca9a17f10fb5623dea074 100644 (file)
@@ -200,10 +200,14 @@ SELECT d1 - timestamp with time zone '1997年01月02日' AS diff
FROM TIMESTAMPTZ_TBL WHERE d1 BETWEEN '1902年01月01日' AND '2038年01月01日';
SELECT date_trunc( 'week', timestamp with time zone '2004年02月29日 15:44:17.71393' ) AS week_trunc;
+SELECT date_trunc( 'ago', timestamp with time zone 'infinity' ) AS invalid_trunc;
SELECT date_trunc('day', timestamp with time zone '2001年02月16日 20:38:40+00', 'Australia/Sydney') as sydney_trunc; -- zone name
SELECT date_trunc('day', timestamp with time zone '2001年02月16日 20:38:40+00', 'GMT') as gmt_trunc; -- fixed-offset abbreviation
SELECT date_trunc('day', timestamp with time zone '2001年02月16日 20:38:40+00', 'VET') as vet_trunc; -- variable-offset abbreviation
+SELECT date_trunc('ago', timestamp with time zone 'infinity', 'GMT') AS invalid_zone_trunc;
+
+
-- verify date_bin behaves the same as date_trunc for relevant intervals
SELECT