summaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/jsonb.c
diff options
context:
space:
mode:
authorPavan Deolasee2016-10-27 15:02:55 +0000
committerPavan Deolasee2016-10-27 15:02:55 +0000
commitc52792488cd87e67e62ec61f5b56f461900353b4 (patch)
tree02b4a719f979659de8f73fce6c1ca65cef2e323f /src/backend/utils/adt/jsonb.c
parent891e6be57e5580b54a9df9fd42cb9bd10d0e7b21 (diff)
parentb5bce6c1ec6061c8a4f730d927e162db7e2ce365 (diff)
Merge commit 'b5bce6c1ec6061c8a4f730d927e162db7e2ce365'
Diffstat (limited to 'src/backend/utils/adt/jsonb.c')
-rw-r--r--src/backend/utils/adt/jsonb.c132
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);