Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Render infinite date/timestamps as 'infinity' for json/jsonb
authorAndrew Dunstan <andrew@dunslane.net>
Thu, 26 Feb 2015 17:34:43 +0000 (12:34 -0500)
committerAndrew Dunstan <andrew@dunslane.net>
Thu, 26 Feb 2015 17:34:43 +0000 (12:34 -0500)
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/json.c
src/test/regress/expected/json.out
src/test/regress/expected/json_1.out
src/test/regress/sql/json.sql

index 48f03e0b36ae594d6edd46b76dca71aea5969e66..ed27f72f1dd9456d0f047ae205e30478c0f8e18e 100644 (file)
@@ -33,6 +33,9 @@
 #include "utils/typcache.h"
 #include "utils/syscache.h"
 
+/* String to output for infinite dates and timestamps */
+#define DT_INFINITY "\"infinity\""
+
 /*
  * The context of the parser is maintained by the recursive descent
  * mechanism, but is passed explicitly to the error reporting routine
@@ -1427,20 +1430,18 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
 
                date = DatumGetDateADT(val);
 
-               /* 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.")));
+               {
+                   /* we have to format infinity ourselves */
+                   appendStringInfoString(result,DT_INFINITY);
+               }
                else
                {
                    j2date(date + POSTGRES_EPOCH_JDATE,
                           &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
                    EncodeDateOnly(&tm, USE_XSD_DATES, buf);
+                   appendStringInfo(result, "\"%s\"", buf);
                }
-
-               appendStringInfo(result, "\"%s\"", buf);
            }
            break;
        case JSONTYPE_TIMESTAMP:
@@ -1452,20 +1453,20 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
 
                timestamp = DatumGetTimestamp(val);
 
-               /* 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.")));
+               {
+                   /* we have to format infinity ourselves */
+                   appendStringInfoString(result,DT_INFINITY);
+               }
                else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
+               {
                    EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf);
+                   appendStringInfo(result, "\"%s\"", buf);
+               }
                else
                    ereport(ERROR,
                            (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                             errmsg("timestamp out of range")));
-
-               appendStringInfo(result, "\"%s\"", buf);
            }
            break;
        case JSONTYPE_TIMESTAMPTZ:
@@ -1479,20 +1480,20 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
 
                timestamp = DatumGetTimestamp(val);
 
-               /* 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.")));
+               {
+                   /* we have to format infinity ourselves */
+                   appendStringInfoString(result,DT_INFINITY);
+               }
                else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
+               {
                    EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
+                   appendStringInfo(result, "\"%s\"", buf);
+               }
                else
                    ereport(ERROR,
                            (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                             errmsg("timestamp out of range")));
-
-               appendStringInfo(result, "\"%s\"", buf);
            }
            break;
        case JSONTYPE_JSON:
index c916678427d067f94705e6da8c85b5fa720190b5..bc64512eb10ecc2af889fd0bbc43d1c63601d8bc 100644 (file)
@@ -426,6 +426,30 @@ select to_json(timestamptz '2014-05-28 12:22:35.614298-04');
 (1 row)
 
 COMMIT;
+select to_json(date '2014-05-28');
+   to_json    
+--------------
+ "2014-05-28"
+(1 row)
+
+select to_json(date 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
+select to_json(timestamp 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
+select to_json(timestamptz 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
 --json_agg
 SELECT json_agg(q)
   FROM ( SELECT $$a$$ || x AS b, y AS c,
index ce63bfb227e29ebc425599f795812c1f59b295ff..2738485e5fa12e56db46548f8ff273dcf57cb6cc 100644 (file)
@@ -426,6 +426,30 @@ select to_json(timestamptz '2014-05-28 12:22:35.614298-04');
 (1 row)
 
 COMMIT;
+select to_json(date '2014-05-28');
+   to_json    
+--------------
+ "2014-05-28"
+(1 row)
+
+select to_json(date 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
+select to_json(timestamp 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
+select to_json(timestamptz 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
 --json_agg
 SELECT json_agg(q)
   FROM ( SELECT $$a$$ || x AS b, y AS c,
index a4eaa1fbc0bf29b38f2f99b583012e992fca5ad4..ab2dd2ed0d5315b5c52119b19ac0d5c383caafce 100644 (file)
@@ -111,6 +111,12 @@ SET LOCAL TIME ZONE -8;
 select to_json(timestamptz '2014-05-28 12:22:35.614298-04');
 COMMIT;
 
+select to_json(date '2014-05-28');
+
+select to_json(date 'Infinity');
+select to_json(timestamp 'Infinity');
+select to_json(timestamptz 'Infinity');
+
 --json_agg
 
 SELECT json_agg(q)