diff options
author | Pavan Deolasee | 2016-10-27 15:02:55 +0000 |
---|---|---|
committer | Pavan Deolasee | 2016-10-27 15:02:55 +0000 |
commit | c52792488cd87e67e62ec61f5b56f461900353b4 (patch) | |
tree | 02b4a719f979659de8f73fce6c1ca65cef2e323f /src/backend/utils/adt/jsonb.c | |
parent | 891e6be57e5580b54a9df9fd42cb9bd10d0e7b21 (diff) | |
parent | b5bce6c1ec6061c8a4f730d927e162db7e2ce365 (diff) |
Merge commit 'b5bce6c1ec6061c8a4f730d927e162db7e2ce365'
Diffstat (limited to 'src/backend/utils/adt/jsonb.c')
-rw-r--r-- | src/backend/utils/adt/jsonb.c | 132 |
1 files changed, 58 insertions, 74 deletions
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index d2b5e1efdc..002aa4946a 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -3,7 +3,7 @@ * jsonb.c * I/O routines for jsonb type * - * Copyright (c) 2014-2015, PostgreSQL Global Development Group + * Copyright (c) 2014-2016, PostgreSQL Global Development Group * * IDENTIFICATION * src/backend/utils/adt/jsonb.c @@ -28,14 +28,6 @@ #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; @@ -61,11 +53,11 @@ typedef enum /* type categories for datum_to_jsonb */ typedef struct JsonbAggState { - JsonbInState *res; - JsonbTypeCategory key_category; - Oid key_output_func; - JsonbTypeCategory val_category; - Oid val_output_func; + JsonbInState *res; + JsonbTypeCategory key_category; + Oid key_output_func; + JsonbTypeCategory val_category; + Oid val_output_func; } JsonbAggState; static inline Datum jsonb_from_cstring(char *json, int len); @@ -455,8 +447,8 @@ JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool { bool first = true; JsonbIterator *it; - JsonbIteratorToken type = WJB_DONE; JsonbValue v; + JsonbIteratorToken type = WJB_DONE; int level = 0; bool redo_switch = false; @@ -712,8 +704,12 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, JsonbValue jb; bool scalar_jsonb = false; + check_stack_depth(); + + /* Convert val to a JsonbValue in jb (in most cases) */ if (is_null) { + Assert(!key_scalar); jb.type = jbvNull; } else if (key_scalar && @@ -725,7 +721,7 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("key value must be scalar, not array, composite or json"))); + errmsg("key value must be scalar, not array, composite, or json"))); } else { @@ -794,21 +790,18 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, char buf[MAXDATELEN + 1]; date = DatumGetDateADT(val); - jb.type = jbvString; - + /* Same as date_out(), but forcing DateStyle */ if (DATE_NOT_FINITE(date)) - { - jb.val.string.len = strlen(DT_INFINITY); - jb.val.string.val = pstrdup(DT_INFINITY); - } + EncodeSpecialDate(date, buf); 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: @@ -819,24 +812,18 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, char buf[MAXDATELEN + 1]; timestamp = DatumGetTimestamp(val); - jb.type = jbvString; - + /* Same as timestamp_out(), but forcing DateStyle */ if (TIMESTAMP_NOT_FINITE(timestamp)) - { - jb.val.string.len = strlen(DT_INFINITY); - jb.val.string.val = pstrdup(DT_INFINITY); - } + EncodeSpecialTimestamp(timestamp, buf); 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: @@ -848,24 +835,19 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, const char *tzn = NULL; char buf[MAXDATELEN + 1]; - timestamp = DatumGetTimestamp(val); - jb.type = jbvString; - + timestamp = DatumGetTimestampTz(val); + /* Same as timestamptz_out(), but forcing DateStyle */ if (TIMESTAMP_NOT_FINITE(timestamp)) - { - jb.val.string.len = strlen(DT_INFINITY); - jb.val.string.val = pstrdup(DT_INFINITY); - } + EncodeSpecialTimestamp(timestamp, buf); 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: @@ -896,7 +878,6 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, case JSONBTYPE_JSONB: { Jsonb *jsonb = DatumGetJsonb(val); - JsonbIteratorToken type; JsonbIterator *it; it = JsonbIteratorInit(&jsonb->root); @@ -910,6 +891,8 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, } else { + JsonbIteratorToken type; + while ((type = JsonbIteratorNext(&it, &jb, false)) != WJB_DONE) { @@ -932,8 +915,10 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result, break; } } - if (tcategory >= JSONBTYPE_JSON && tcategory <= JSONBTYPE_JSONCAST && - !scalar_jsonb) + + /* Now insert jb into result, unless we did it recursively */ + if (!is_null && !scalar_jsonb && + tcategory >= JSONBTYPE_JSON && tcategory <= JSONBTYPE_JSONCAST) { /* work has been done recursively */ return; @@ -1194,7 +1179,7 @@ jsonb_build_object(PG_FUNCTION_ARGS) if (nargs % 2 != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid number or arguments: object must be matched key value pairs"))); + errmsg("invalid number of arguments: object must be matched key value pairs"))); memset(&result, 0, sizeof(JsonbInState)); @@ -1202,13 +1187,12 @@ jsonb_build_object(PG_FUNCTION_ARGS) for (i = 0; i < nargs; i += 2) { - /* process key */ if (PG_ARGISNULL(i)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("arg %d: key cannot be null", i + 1))); + errmsg("argument %d: key must not be null", i + 1))); val_type = get_fn_expr_argtype(fcinfo->flinfo, i); /* @@ -1218,10 +1202,7 @@ jsonb_build_object(PG_FUNCTION_ARGS) if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, i)) { val_type = TEXTOID; - if (PG_ARGISNULL(i)) - arg = (Datum) 0; - else - arg = CStringGetTextDatum(PG_GETARG_POINTER(i)); + arg = CStringGetTextDatum(PG_GETARG_POINTER(i)); } else { @@ -1230,7 +1211,7 @@ jsonb_build_object(PG_FUNCTION_ARGS) if (val_type == InvalidOid || val_type == UNKNOWNOID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("arg %d: could not determine data type", i + 1))); + errmsg("argument %d: could not determine data type", i + 1))); add_jsonb(arg, false, &result, val_type, true); @@ -1253,9 +1234,8 @@ jsonb_build_object(PG_FUNCTION_ARGS) if (val_type == InvalidOid || val_type == UNKNOWNOID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("arg %d: could not determine data type", i + 2))); + errmsg("argument %d: could not determine data type", i + 2))); add_jsonb(arg, PG_ARGISNULL(i + 1), &result, val_type, false); - } result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL); @@ -1298,7 +1278,6 @@ jsonb_build_array(PG_FUNCTION_ARGS) for (i = 0; i < nargs; i++) { val_type = get_fn_expr_argtype(fcinfo->flinfo, i); - arg = PG_GETARG_DATUM(i + 1); /* see comments in jsonb_build_object above */ if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, i)) { @@ -1315,7 +1294,7 @@ jsonb_build_array(PG_FUNCTION_ARGS) if (val_type == InvalidOid || val_type == UNKNOWNOID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("arg %d: could not determine data type", i + 1))); + errmsg("argument %d: could not determine data type", i + 1))); add_jsonb(arg, PG_ARGISNULL(i), &result, val_type, false); } @@ -1476,7 +1455,7 @@ jsonb_object_two_arg(PG_FUNCTION_ARGS) errmsg("wrong number of array subscripts"))); if (nkdims == 0) - PG_RETURN_DATUM(CStringGetTextDatum("{}")); + goto close_object; deconstruct_array(key_array, TEXTOID, -1, false, 'i', @@ -1530,13 +1509,14 @@ jsonb_object_two_arg(PG_FUNCTION_ARGS) (void) pushJsonbValue(&result.parseState, WJB_VALUE, &v); } - result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL); - pfree(key_datums); pfree(key_nulls); pfree(val_datums); pfree(val_nulls); +close_object: + result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL); + PG_RETURN_POINTER(JsonbValueToJsonb(result.res)); } @@ -1603,8 +1583,7 @@ jsonb_agg_transfn(PG_FUNCTION_ARGS) if (PG_ARGISNULL(0)) { - - Oid arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1); + Oid arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1); if (arg_type == InvalidOid) ereport(ERROR, @@ -1757,10 +1736,9 @@ jsonb_object_agg_transfn(PG_FUNCTION_ARGS) } /* set up the accumulator on the first go round */ - if (PG_ARGISNULL(0)) { - Oid arg_type; + Oid arg_type; oldcontext = MemoryContextSwitchTo(aggcontext); state = palloc(sizeof(JsonbAggState)); @@ -1798,7 +1776,12 @@ jsonb_object_agg_transfn(PG_FUNCTION_ARGS) /* turn the argument into jsonb in the normal function context */ - val = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1); + if (PG_ARGISNULL(1)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("field name must not be null"))); + + val = PG_GETARG_DATUM(1); memset(&elem, 0, sizeof(JsonbInState)); @@ -1867,9 +1850,9 @@ jsonb_object_agg_transfn(PG_FUNCTION_ARGS) single_scalar = false; /* - * values can be anything, including structured and null, so we treate - * them as in json_agg_transfn, except that single scalars are always - * pushed as WJB_VALUE items. + * values can be anything, including structured and null, so we treat them + * as in json_agg_transfn, except that single scalars are always pushed as + * WJB_VALUE items. */ while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) @@ -1945,8 +1928,9 @@ jsonb_object_agg_finalfn(PG_FUNCTION_ARGS) /* * We need to do a shallow clone of the argument's res field in case the * final function is called more than once, so we avoid changing the - * it. A shallow clone is sufficient as we aren't going to change any of - * the values, just add the final object end marker. + * aggregate state value. A shallow clone is sufficient as we aren't + * going to change any of the values, just add the final object end + * marker. */ result.parseState = clone_parse_state(arg->res->parseState); |