|
21 | 21 | #include "lib/stringinfo.h" |
22 | 22 | #include "libpq/pqformat.h" |
23 | 23 | #include "mb/pg_wchar.h" |
| 24 | +#include "miscadmin.h" |
24 | 25 | #include "parser/parse_coerce.h" |
25 | 26 | #include "utils/array.h" |
26 | 27 | #include "utils/builtins.h" |
27 | | -#include "utils/formatting.h" |
| 28 | +#include "utils/datetime.h" |
28 | 29 | #include "utils/lsyscache.h" |
29 | 30 | #include "utils/json.h" |
30 | 31 | #include "utils/jsonapi.h" |
@@ -63,13 +64,6 @@ typedef enum /* type categories for datum_to_json */ |
63 | 64 | JSONTYPE_OTHER /* all else */ |
64 | 65 | } JsonTypeCategory; |
65 | 66 |
|
66 | | -/* |
67 | | - * to_char formats to turn timestamps and timpstamptzs into json strings |
68 | | - * that are ISO 8601 compliant |
69 | | - */ |
70 | | -#define TS_ISO8601_FMT "\\\"YYYY-MM-DD\"T\"HH24:MI:SS.US\\\"" |
71 | | -#define TSTZ_ISO8601_FMT "\\\"YYYY-MM-DD\"T\"HH24:MI:SS.USOF\\\"" |
72 | | - |
73 | 67 | static inline void json_lex(JsonLexContext *lex); |
74 | 68 | static inline void json_lex_string(JsonLexContext *lex); |
75 | 69 | static inline void json_lex_number(JsonLexContext *lex, char *s, bool *num_err); |
@@ -1394,27 +1388,56 @@ datum_to_json(Datum val, bool is_null, StringInfo result, |
1394 | 1388 | pfree(outputstr); |
1395 | 1389 | break; |
1396 | 1390 | case JSONTYPE_TIMESTAMP: |
1397 | | - /* |
1398 | | - * The timestamp format used here provides for quoting the string, |
1399 | | - * so no escaping is required. |
1400 | | - */ |
1401 | | - jsontext = DatumGetTextP( |
1402 | | - DirectFunctionCall2(timestamp_to_char, val, |
1403 | | - CStringGetTextDatum(TS_ISO8601_FMT))); |
1404 | | - outputstr = text_to_cstring(jsontext); |
1405 | | - appendStringInfoString(result, outputstr); |
1406 | | - pfree(outputstr); |
1407 | | - pfree(jsontext); |
| 1391 | + { |
| 1392 | + Timestamp timestamp; |
| 1393 | + struct pg_tm tm; |
| 1394 | + fsec_t fsec; |
| 1395 | + char buf[MAXDATELEN + 1]; |
| 1396 | + |
| 1397 | + timestamp = DatumGetTimestamp(val); |
| 1398 | + |
| 1399 | + /* XSD doesn't support infinite values */ |
| 1400 | + if (TIMESTAMP_NOT_FINITE(timestamp)) |
| 1401 | + ereport(ERROR, |
| 1402 | + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), |
| 1403 | + errmsg("timestamp out of range"), |
| 1404 | + errdetail("JSON does not support infinite timestamp values."))); |
| 1405 | + else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0) |
| 1406 | + EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf); |
| 1407 | + else |
| 1408 | + ereport(ERROR, |
| 1409 | + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), |
| 1410 | + errmsg("timestamp out of range"))); |
| 1411 | + |
| 1412 | + appendStringInfo(result,"\"%s\"",buf); |
| 1413 | + } |
1408 | 1414 | break; |
1409 | 1415 | case JSONTYPE_TIMESTAMPTZ: |
1410 | | - /* same comment as for timestamp above */ |
1411 | | - jsontext = DatumGetTextP( |
1412 | | - DirectFunctionCall2(timestamptz_to_char, val, |
1413 | | - CStringGetTextDatum(TSTZ_ISO8601_FMT))); |
1414 | | - outputstr = text_to_cstring(jsontext); |
1415 | | - appendStringInfoString(result, outputstr); |
1416 | | - pfree(outputstr); |
1417 | | - pfree(jsontext); |
| 1416 | + { |
| 1417 | + TimestampTz timestamp; |
| 1418 | + struct pg_tm tm; |
| 1419 | + int tz; |
| 1420 | + fsec_t fsec; |
| 1421 | + const char *tzn = NULL; |
| 1422 | + char buf[MAXDATELEN + 1]; |
| 1423 | + |
| 1424 | + timestamp = DatumGetTimestamp(val); |
| 1425 | + |
| 1426 | + /* XSD doesn't support infinite values */ |
| 1427 | + if (TIMESTAMP_NOT_FINITE(timestamp)) |
| 1428 | + ereport(ERROR, |
| 1429 | + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), |
| 1430 | + errmsg("timestamp out of range"), |
| 1431 | + errdetail("JSON does not support infinite timestamp values."))); |
| 1432 | + else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0) |
| 1433 | + EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf); |
| 1434 | + else |
| 1435 | + ereport(ERROR, |
| 1436 | + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), |
| 1437 | + errmsg("timestamp out of range"))); |
| 1438 | + |
| 1439 | + appendStringInfo(result,"\"%s\"",buf); |
| 1440 | + } |
1418 | 1441 | break; |
1419 | 1442 | case JSONTYPE_JSON: |
1420 | 1443 | /* JSON and JSONB output will already be escaped */ |
|
0 commit comments