diff options
author | Andrew Dunstan <andrew@dunslane.net> | 2018-01-16 19:07:13 -0500 |
---|---|---|
committer | Andrew Dunstan <andrew@dunslane.net> | 2018-01-16 19:07:13 -0500 |
commit | cc4feded0a31d2b732d4ea68613115cb720e624e (patch) | |
tree | a3e1a713c0a16cfb0dfbe02e9bf718fd56319adf /src/backend/utils/adt/json.c | |
parent | d91da5ecedc8f8965bd35de66b09feb79c26e5ca (diff) | |
download | postgresql-cc4feded0a31d2b732d4ea68613115cb720e624e.tar.gz postgresql-cc4feded0a31d2b732d4ea68613115cb720e624e.zip |
Centralize json and jsonb handling of datetime types
The creates a single function JsonEncodeDateTime which will format these
data types in an efficient and consistent manner. This will be all the
more important when we come to jsonpath so we don't have to implement yet
more code doing the same thing in two more places.
This also extends the code to handle time and timetz types which were
not previously handled specially. This requires exposing the time2tm and
timetz2tm functions.
Patch from Nikita Glukhov
Diffstat (limited to 'src/backend/utils/adt/json.c')
-rw-r--r-- | src/backend/utils/adt/json.c | 122 |
1 files changed, 93 insertions, 29 deletions
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index 151345ab2ff..97a5b85516f 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -1504,11 +1504,69 @@ datum_to_json(Datum val, bool is_null, StringInfo result, break; case JSONTYPE_DATE: { + char buf[MAXDATELEN + 1]; + + JsonEncodeDateTime(buf, val, DATEOID); + appendStringInfo(result, "\"%s\"", buf); + } + break; + case JSONTYPE_TIMESTAMP: + { + char buf[MAXDATELEN + 1]; + + JsonEncodeDateTime(buf, val, TIMESTAMPOID); + appendStringInfo(result, "\"%s\"", buf); + } + break; + case JSONTYPE_TIMESTAMPTZ: + { + char buf[MAXDATELEN + 1]; + + JsonEncodeDateTime(buf, val, TIMESTAMPTZOID); + appendStringInfo(result, "\"%s\"", buf); + } + break; + case JSONTYPE_JSON: + /* JSON and JSONB output will already be escaped */ + outputstr = OidOutputFunctionCall(outfuncoid, val); + appendStringInfoString(result, outputstr); + pfree(outputstr); + break; + case JSONTYPE_CAST: + /* outfuncoid refers to a cast function, not an output function */ + jsontext = DatumGetTextPP(OidFunctionCall1(outfuncoid, val)); + outputstr = text_to_cstring(jsontext); + appendStringInfoString(result, outputstr); + pfree(outputstr); + pfree(jsontext); + break; + default: + outputstr = OidOutputFunctionCall(outfuncoid, val); + escape_json(result, outputstr); + pfree(outputstr); + break; + } +} + +/* + * Encode 'value' of datetime type 'typid' into JSON string in ISO format using + * optionally preallocated buffer 'buf'. + */ +char * +JsonEncodeDateTime(char *buf, Datum value, Oid typid) +{ + if (!buf) + buf = palloc(MAXDATELEN + 1); + + switch (typid) + { + case DATEOID: + { DateADT date; struct pg_tm tm; - char buf[MAXDATELEN + 1]; - date = DatumGetDateADT(val); + date = DatumGetDateADT(value); + /* Same as date_out(), but forcing DateStyle */ if (DATE_NOT_FINITE(date)) EncodeSpecialDate(date, buf); @@ -1518,17 +1576,40 @@ datum_to_json(Datum val, bool is_null, StringInfo result, &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday)); EncodeDateOnly(&tm, USE_XSD_DATES, buf); } - appendStringInfo(result, "\"%s\"", buf); } break; - case JSONTYPE_TIMESTAMP: + case TIMEOID: + { + TimeADT time = DatumGetTimeADT(value); + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + + /* Same as time_out(), but forcing DateStyle */ + time2tm(time, tm, &fsec); + EncodeTimeOnly(tm, fsec, false, 0, USE_XSD_DATES, buf); + } + break; + case TIMETZOID: + { + TimeTzADT *time = DatumGetTimeTzADTP(value); + struct pg_tm tt, + *tm = &tt; + fsec_t fsec; + int tz; + + /* Same as timetz_out(), but forcing DateStyle */ + timetz2tm(time, tm, &fsec, &tz); + EncodeTimeOnly(tm, fsec, true, tz, USE_XSD_DATES, buf); + } + break; + case TIMESTAMPOID: { Timestamp timestamp; struct pg_tm tm; fsec_t fsec; - char buf[MAXDATELEN + 1]; - timestamp = DatumGetTimestamp(val); + timestamp = DatumGetTimestamp(value); /* Same as timestamp_out(), but forcing DateStyle */ if (TIMESTAMP_NOT_FINITE(timestamp)) EncodeSpecialTimestamp(timestamp, buf); @@ -1538,19 +1619,17 @@ datum_to_json(Datum val, bool is_null, StringInfo result, ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); - appendStringInfo(result, "\"%s\"", buf); } break; - case JSONTYPE_TIMESTAMPTZ: + case TIMESTAMPTZOID: { TimestampTz timestamp; struct pg_tm tm; int tz; fsec_t fsec; const char *tzn = NULL; - char buf[MAXDATELEN + 1]; - timestamp = DatumGetTimestampTz(val); + timestamp = DatumGetTimestampTz(value); /* Same as timestamptz_out(), but forcing DateStyle */ if (TIMESTAMP_NOT_FINITE(timestamp)) EncodeSpecialTimestamp(timestamp, buf); @@ -1560,29 +1639,14 @@ datum_to_json(Datum val, bool is_null, StringInfo result, ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); - appendStringInfo(result, "\"%s\"", buf); } break; - case JSONTYPE_JSON: - /* JSON and JSONB output will already be escaped */ - outputstr = OidOutputFunctionCall(outfuncoid, val); - appendStringInfoString(result, outputstr); - pfree(outputstr); - break; - case JSONTYPE_CAST: - /* outfuncoid refers to a cast function, not an output function */ - jsontext = DatumGetTextPP(OidFunctionCall1(outfuncoid, val)); - outputstr = text_to_cstring(jsontext); - appendStringInfoString(result, outputstr); - pfree(outputstr); - pfree(jsontext); - break; default: - outputstr = OidOutputFunctionCall(outfuncoid, val); - escape_json(result, outputstr); - pfree(outputstr); - break; + elog(ERROR, "unknown jsonb value datetime type oid %d", typid); + return NULL; } + + return buf; } /* |