From bda76c1c8cfb1d11751ba6be88f0242850481733 Mon Sep 17 00:00:00 2001 From: Andrew Dunstan Date: Thu, 26 Feb 2015 12:25:21 -0500 Subject: Render infinite date/timestamps as 'infinity' for json/jsonb Commit ab14a73a6c raised an error in these cases and later the behaviour was copied to jsonb. This is what the XML code, which we then adopted, does, as the XSD types don't accept infinite values. However, json dates and timestamps are just strings as far as json is concerned, so there is no reason not to render these values as 'infinity'. The json portion of this is backpatched to 9.4 where the behaviour was introduced. The jsonb portion only affects the development branch. Per gripe on pgsql-general. --- src/backend/utils/adt/jsonb.c | 61 ++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 27 deletions(-) (limited to 'src/backend/utils/adt/jsonb.c') diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index 644ea6d9414..aac97565f95 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -28,6 +28,14 @@ #include "utils/syscache.h" #include "utils/typcache.h" +/* + * String to output for infinite dates and timestamps. + * Note the we don't use embedded quotes, unlike for json, because + * we store jsonb strings dequoted. + */ + +#define DT_INFINITY "infinity" + typedef struct JsonbInState { JsonbParseState *parseState; @@ -714,23 +722,21 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, char buf[MAXDATELEN + 1]; date = DatumGetDateADT(val); + jb.type = jbvString; - /* XSD doesn't support infinite values */ if (DATE_NOT_FINITE(date)) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("date out of range"), - errdetail("JSON does not support infinite date values."))); + { + jb.val.string.len = strlen(DT_INFINITY); + jb.val.string.val = pstrdup(DT_INFINITY); + } else { j2date(date + POSTGRES_EPOCH_JDATE, &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday)); EncodeDateOnly(&tm, USE_XSD_DATES, buf); + jb.val.string.len = strlen(buf); + jb.val.string.val = pstrdup(buf); } - - jb.type = jbvString; - jb.val.string.len = strlen(buf); - jb.val.string.val = pstrdup(buf); } break; case JSONBTYPE_TIMESTAMP: @@ -741,23 +747,24 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, char buf[MAXDATELEN + 1]; timestamp = DatumGetTimestamp(val); + jb.type = jbvString; - /* XSD doesn't support infinite values */ if (TIMESTAMP_NOT_FINITE(timestamp)) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"), - errdetail("JSON does not support infinite timestamp values."))); + { + jb.val.string.len = strlen(DT_INFINITY); + jb.val.string.val = pstrdup(DT_INFINITY); + } else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0) + { + EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf); + jb.val.string.len = strlen(buf); + jb.val.string.val = pstrdup(buf); + } else ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); - - jb.type = jbvString; - jb.val.string.len = strlen(buf); - jb.val.string.val = pstrdup(buf); } break; case JSONBTYPE_TIMESTAMPTZ: @@ -770,23 +777,23 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, char buf[MAXDATELEN + 1]; timestamp = DatumGetTimestamp(val); + jb.type = jbvString; - /* XSD doesn't support infinite values */ if (TIMESTAMP_NOT_FINITE(timestamp)) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"), - errdetail("JSON does not support infinite timestamp values."))); + { + jb.val.string.len = strlen(DT_INFINITY); + jb.val.string.val = pstrdup(DT_INFINITY); + } else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0) + { EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf); + jb.val.string.len = strlen(buf); + jb.val.string.val = pstrdup(buf); + } else ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); - - jb.type = jbvString; - jb.val.string.len = strlen(buf); - jb.val.string.val = pstrdup(buf); } break; case JSONBTYPE_JSONCAST: -- cgit v1.2.3