X-Git-Url: https://git.8kb.co.uk/?p=postgresql%2Fpg_jsonb_opx;a=blobdiff_plain;f=jsonb_utilsx.c;h=213424386a653430548c939714ecfda470fb28af;hp=a08829c21f9ff4cfbaa84a7caf71401ce03d295a;hb=HEAD;hpb=bf6318c60bd05043800c698a6b14f6aaa17a4824 diff --git a/jsonb_utilsx.c b/jsonb_utilsx.c index a08829c..2134243 100755 --- a/jsonb_utilsx.c +++ b/jsonb_utilsx.c @@ -20,10 +20,10 @@ JsonbValue * pushJsonbBinary(JsonbParseState **pstate, JsonbContainer *jsonb_container) { - JsonbIterator *jsonb_iterator; - JsonbValue jsonb_iterator_value; - int32 jsonb_iterator_token; - JsonbValue *return_jsonb_value = NULL; + JsonbIterator *jsonb_iterator; + JsonbValue jsonb_iterator_value; + int32 jsonb_iterator_token; + JsonbValue *return_jsonb_value = NULL; jsonb_iterator = JsonbIteratorInit((void *)jsonb_container); while ((jsonb_iterator_token = JsonbIteratorNext(&jsonb_iterator, &jsonb_iterator_value, false)) != WJB_DONE) @@ -36,12 +36,11 @@ pushJsonbBinary(JsonbParseState **pstate, JsonbContainer *jsonb_container) JsonbValue * pushJsonbValueBlind(JsonbParseState **pstate, JsonbIteratorToken jsonb_iterator_token, JsonbValue *jsonb_iterator_value) { - JsonbValue *return_jsonb_value = NULL; + JsonbValue *return_jsonb_value = NULL; if ((jsonb_iterator_token == WJB_KEY) || (jsonb_iterator_token == WJB_VALUE) || - (jsonb_iterator_token == WJB_ELEM) || - (jsonb_iterator_token == WJB_BEGIN_ARRAY && jsonb_iterator_value->val.array.rawScalar)) + (jsonb_iterator_token == WJB_ELEM)) { return_jsonb_value = pushJsonbValue(pstate, jsonb_iterator_token, jsonb_iterator_value); } @@ -55,35 +54,34 @@ Jsonb * jsonbModifyPath(Jsonb *jsonb_a, ArrayType *array_path, Jsonb *jsonb_b) { /* pointers to return jsonb value data and state to be converted to jsonb on return */ - JsonbParseState *state = NULL; - JsonbValue *return_jsonb_value = NULL; + JsonbParseState *state = NULL; + JsonbValue *return_jsonb_value = NULL; /* pointer to iterator for input jsonb */ - JsonbIterator *jsonb_iterator; - JsonbValue jsonb_iterator_value; - int32 jsonb_iterator_token; - int32 jsonb_last_token = 0; - - JsonbIterator *jsonb_replacement_iterator; - JsonbValue jsonb_replacement_iterator_value; - int32 jsonb_replacement_iterator_token; + JsonbIterator *jsonb_iterator; + JsonbValue jsonb_iterator_value; + int32 jsonb_iterator_token; + + JsonbIterator *jsonb_replacement_iterator; + JsonbValue jsonb_replacement_iterator_value; + int32 jsonb_replacement_iterator_token; /* * array element variables for use during deconstruction * count is the depth we will be looking from the first matching key */ - Datum *datums; - bool *nulls; - int32 count; + Datum *datums; + bool *nulls; + int32 count; /* the current key we are looking for, starting with the first key */ - text *key_on = NULL; - int32 index_on = 0; - int32 nest_level = 0; - int32 array_level = 0; - int32 skip_level = 0; - int32 push_nest_level = 0; - bool push = true; + text *key_on = NULL; + int32 index_on = 0; + int32 nest_level = 0; + int32 array_level = 0; + int32 skip_level = 0; + int32 push_nest_level = 0; + bool push = true; /* assert input_array is a text array type */ Assert(ARR_ELEMTYPE(array_path) == TEXTOID); @@ -121,10 +119,10 @@ jsonbModifyPath(Jsonb *jsonb_a, ArrayType *array_path, Jsonb *jsonb_b) { case WJB_BEGIN_ARRAY: array_level++; - break; + break; case WJB_BEGIN_OBJECT: nest_level++; - break; + break; case WJB_ELEM: case WJB_KEY: /* @@ -135,8 +133,7 @@ jsonbModifyPath(Jsonb *jsonb_a, ArrayType *array_path, Jsonb *jsonb_b) if (skip_level == 0 && ((jsonb_iterator_token == WJB_KEY && nest_level-1 == index_on && array_level == 0) || (jsonb_iterator_token == WJB_ELEM && nest_level == 0 && array_level == 1))) { - if ((jsonb_iterator_value.type == jbvNull && key_on == NULL) || - (key_on != NULL && (jsonb_iterator_value.val.string.len == VARSIZE_ANY_EXHDR(key_on)) && + if ((!nulls[index_on] && (jsonb_iterator_value.val.string.len == VARSIZE_ANY_EXHDR(key_on)) && (memcmp(jsonb_iterator_value.val.string.val, VARDATA_ANY(key_on), jsonb_iterator_value.val.string.len) == 0))) { /* if we have not yet reached the last index in the array / key chain move on and check the next */ @@ -145,8 +142,6 @@ jsonbModifyPath(Jsonb *jsonb_a, ArrayType *array_path, Jsonb *jsonb_b) index_on++; if (!nulls[index_on]) key_on = DatumGetTextP(datums[index_on]); - else - key_on = NULL; } /* if we have reached the last index, the we can modify this level */ else @@ -155,35 +150,45 @@ jsonbModifyPath(Jsonb *jsonb_a, ArrayType *array_path, Jsonb *jsonb_b) if (jsonb_b != NULL) { jsonb_replacement_iterator = JsonbIteratorInit(&jsonb_b->root); - while ((jsonb_replacement_iterator_token = JsonbIteratorNext(&jsonb_replacement_iterator, &jsonb_replacement_iterator_value, false)) != WJB_DONE) + /* if the replacement value is a scalar then it will replace the current element or value */ + if (JB_ROOT_IS_SCALAR(jsonb_b)) { - if (((jsonb_last_token == jsonb_replacement_iterator_token) && - (jsonb_last_token != WJB_VALUE)) || - ((jsonb_last_token == WJB_VALUE) && - ((jsonb_replacement_iterator_token == WJB_BEGIN_OBJECT) || - (jsonb_replacement_iterator_token == WJB_BEGIN_ARRAY)))) - { - push_nest_level++; - } - - if ((jsonb_replacement_iterator_token == WJB_KEY) || - (jsonb_replacement_iterator_token == WJB_VALUE) || - (jsonb_replacement_iterator_token == WJB_ELEM) || (push_nest_level != 1)) + jsonb_replacement_iterator_token = JsonbIteratorNext(&jsonb_replacement_iterator, &jsonb_replacement_iterator_value, false); + jsonb_replacement_iterator_token = JsonbIteratorNext(&jsonb_replacement_iterator, &jsonb_replacement_iterator_value, false); + + if (jsonb_iterator_token == WJB_ELEM) { - return_jsonb_value = pushJsonbValueBlind(&state, jsonb_replacement_iterator_token, &jsonb_replacement_iterator_value); + return_jsonb_value = pushJsonbValue(&state, WJB_ELEM, &jsonb_replacement_iterator_value); } - - if (((jsonb_last_token == WJB_BEGIN_ARRAY) || - (jsonb_last_token == WJB_VALUE)) && - (jsonb_replacement_iterator_token == WJB_END_ARRAY)) + else { - push_nest_level--; + return_jsonb_value = pushJsonbValue(&state, WJB_KEY, &jsonb_iterator_value); + return_jsonb_value = pushJsonbValue(&state, WJB_VALUE, &jsonb_replacement_iterator_value); } - else if (((jsonb_last_token == WJB_BEGIN_OBJECT) || - (jsonb_last_token == WJB_VALUE)) && - (jsonb_replacement_iterator_token == WJB_END_OBJECT)) + } + /* otherwise assume this is the replacement for the whole element or key-value pair */ + else { + while ((jsonb_replacement_iterator_token = JsonbIteratorNext(&jsonb_replacement_iterator, &jsonb_replacement_iterator_value, false)) != WJB_DONE) { - push_nest_level--; + if (push_nest_level == 0 && jsonb_iterator_token == WJB_KEY && jsonb_replacement_iterator_token == WJB_BEGIN_ARRAY) + { + return_jsonb_value = pushJsonbValue(&state, WJB_KEY, &jsonb_iterator_value); + } + + if ((jsonb_replacement_iterator_token == WJB_BEGIN_OBJECT) || (jsonb_replacement_iterator_token == WJB_BEGIN_ARRAY)) + push_nest_level++; + + if ((push_nest_level > 1) || + (jsonb_iterator_token == WJB_ELEM && jsonb_replacement_iterator_token != WJB_BEGIN_ARRAY && jsonb_replacement_iterator_token != WJB_END_ARRAY) || + (jsonb_iterator_token == WJB_KEY && jsonb_replacement_iterator_token != WJB_BEGIN_OBJECT && jsonb_replacement_iterator_token != WJB_END_OBJECT)) + { + return_jsonb_value = pushJsonbValueBlind(&state, jsonb_replacement_iterator_token, &jsonb_replacement_iterator_value); + } + + if ((jsonb_replacement_iterator_token == WJB_END_OBJECT || jsonb_replacement_iterator_token == WJB_END_ARRAY)) + push_nest_level--; + + Assert(push_nest_level >= 0); } } } @@ -194,12 +199,12 @@ jsonbModifyPath(Jsonb *jsonb_a, ArrayType *array_path, Jsonb *jsonb_b) } } } + /* switch end */ } if (push && (skip_level == 0 || nest_level < skip_level)) { return_jsonb_value = pushJsonbValueBlind(&state, jsonb_iterator_token, &jsonb_iterator_value); - jsonb_last_token = jsonb_iterator_token; } switch (jsonb_iterator_token) @@ -208,21 +213,25 @@ jsonbModifyPath(Jsonb *jsonb_a, ArrayType *array_path, Jsonb *jsonb_b) nest_level--; if (skip_level == nest_level && array_level == 0) skip_level = 0; - break; + break; case WJB_END_ARRAY: array_level--; if (skip_level == nest_level && array_level == 0) skip_level = 0; - break; + break; case WJB_VALUE: if (skip_level == nest_level) skip_level = 0; + /* switch end */ } } - if (return_jsonb_value->type == jbvArray && return_jsonb_value->val.array.rawScalar && return_jsonb_value->val.array.nElems == 0) + if (return_jsonb_value->type == jbvArray) { - return_jsonb_value->val.array.rawScalar = false; + if (return_jsonb_value->val.array.rawScalar && return_jsonb_value->val.array.nElems == 0) + return_jsonb_value->val.array.rawScalar = false; + else if (JB_ROOT_IS_SCALAR(jsonb_a) && !return_jsonb_value->val.array.rawScalar && return_jsonb_value->val.array.nElems == 1) + return_jsonb_value->val.array.rawScalar = true; } return JsonbValueToJsonb(return_jsonb_value);