3 * Test jsonb delete and concatenate operator functions for 9.4
5 * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
7 * Author: Glyn Astill <glyn@8kb.co.uk>
9 * This is purely experimentation and will contain many errors and bad form
10 * DO NOT USE ON PRODUCTION SYSTEMS.
16 #include "utils/array.h"
17 #include "utils/numeric.h"
18 #include "utils/jsonb.h"
19 #include "catalog/pg_type.h"
20 #include "utils/builtins.h"
21 #include "jsonb_opx.h"
22 #include "utils/lsyscache.h"
24 #ifdef PG_MODULE_MAGIC
28 Datum jsonb_delete_key(PG_FUNCTION_ARGS);
30 PG_FUNCTION_INFO_V1(jsonb_delete_key);
33 * Operator function to delete key from left operand where a match is found in
36 * jsonb, text -> jsonb
40 jsonb_delete_key(PG_FUNCTION_ARGS)
42 /* pointers to incoming jsonb and text data */
43 Jsonb *input_jsonb = PG_GETARG_JSONB(0);
44 Oid input_element_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
45 text *input_text = NULL;
46 Numeric input_numeric = NULL;
47 bool input_bool = false;
49 /* pointers to return jsonb value data and state to be converted to jsonb on return */
50 JsonbParseState *state = NULL;
51 JsonbValue *return_jsonb_value = NULL;
53 /* pointer to iterator for input_jsonb value data */
54 JsonbIterator *jsonb_iterator;
55 JsonbValue jsonb_iterator_value;
56 int32 jsonb_iterator_token;
58 /* variables used for skip logic */
61 int32 array_level = 0;
64 /* make function polymorphic for text/numeric/boolean */
65 if (!OidIsValid(input_element_type))
66 elog(ERROR, "could not determine data type of input");
68 if (input_element_type == TEXTOID)
69 input_text = PG_GETARG_TEXT_P(1);
70 else if (input_element_type == NUMERICOID)
71 input_numeric = PG_GETARG_NUMERIC(1);
72 else if (input_element_type == BOOLOID)
73 input_bool = PG_GETARG_BOOL(1);
75 elog(ERROR, "invalid data type input: %i", input_element_type);
78 * If we've been supplied with an existing key iterate round json data and rebuild
79 * with key/element excluded.
81 * skip_key, nest_level and array_level are crude counts to check if the the value
82 * for the key is closed and ensure we don't match on keys within nested objects.
83 * Because we are recursing into nested elements but blindly just pushing them onto
84 * the return value we can get away without deeper knowledge of the json?
87 jsonb_iterator = JsonbIteratorInit(&input_jsonb->root);
89 while ((jsonb_iterator_token = JsonbIteratorNext(&jsonb_iterator, &jsonb_iterator_value, false)) != WJB_DONE)
92 switch (jsonb_iterator_token)
97 case WJB_BEGIN_OBJECT:
101 if (skip_level == 0 && nest_level == 0 && array_level == 1)
103 if ((jsonb_iterator_value.type == jbvNumeric) && (input_element_type == NUMERICOID))
105 if (DatumGetBool(DirectFunctionCall2(numeric_eq,
106 PointerGetDatum(jsonb_iterator_value.val.numeric),
107 PointerGetDatum(input_numeric))))
110 else if ((jsonb_iterator_value.type == jbvBool) && (input_element_type == BOOLOID))
112 if (jsonb_iterator_value.val.boolean == input_bool)
115 /* sql null <> jsonb null */
118 if (skip_level == 0 && ((jsonb_iterator_token == WJB_KEY && nest_level == 1 && array_level == 0) ||
119 (jsonb_iterator_token == WJB_ELEM && nest_level == 0 && array_level == 1)))
121 if ((jsonb_iterator_value.type == jbvString) && (input_element_type == TEXTOID))
123 if ((jsonb_iterator_value.val.string.len == VARSIZE_ANY_EXHDR(input_text)) &&
124 (memcmp(jsonb_iterator_value.val.string.val,
125 VARDATA_ANY(input_text),
126 jsonb_iterator_value.val.string.len) == 0))
128 if (jsonb_iterator_token == WJB_ELEM)
131 skip_level = nest_level;
138 if (push && (skip_level == 0 || nest_level < skip_level))
140 return_jsonb_value = pushJsonbValueBlind(&state, jsonb_iterator_token, &jsonb_iterator_value);
143 switch (jsonb_iterator_token)
147 if (skip_level == nest_level && array_level == 0)
152 if (skip_level == nest_level && array_level == 0)
156 if (skip_level == nest_level)
162 if (JB_ROOT_IS_SCALAR(input_jsonb) && !return_jsonb_value->val.array.rawScalar && return_jsonb_value->val.array.nElems == 1)
163 return_jsonb_value->val.array.rawScalar = true;
165 PG_FREE_IF_COPY(input_jsonb, 0);
166 if (input_element_type == TEXTOID)
167 PG_FREE_IF_COPY(input_text, 1);
169 PG_RETURN_JSONB(JsonbValueToJsonb(return_jsonb_value));
172 Datum jsonb_delete_keys(PG_FUNCTION_ARGS);
174 PG_FUNCTION_INFO_V1(jsonb_delete_keys);
177 * Operator function to delete keys from left operand where a match is found in
180 * jsonb, text[] -> jsonb
184 jsonb_delete_keys(PG_FUNCTION_ARGS)
189 /* pointers to incoming jsonb and text[] data */
190 Jsonb *input_jsonb = PG_GETARG_JSONB(0);
191 ArrayType *input_array = PG_GETARG_ARRAYTYPE_P(1);
195 Oid array_element_type = ARR_ELEMTYPE(input_array);
197 /* pointers to return jsonb value data and state to be converted to jsonb on return */
198 JsonbParseState *state = NULL;
199 JsonbValue *return_jsonb_value = NULL;
201 /* pointer to iterator for input_jsonb value data */
202 JsonbIterator *jsonb_iterator;
203 JsonbValue jsonb_iterator_value;
204 int32 jsonb_iterator_token;
206 /* variables used for skip logic */
207 int32 skip_level = 0;
208 int32 nest_level = 0;
209 int32 array_level = 0;
212 /* array element variables for use during deconstruction */
217 /* individual array values values from incoming text[] */
218 text *array_element_text;
219 Numeric array_element_numeric = NULL;
220 bool array_element_bool = false;
223 if (array_element_type != TEXTOID && array_element_type != NUMERICOID && array_element_type != BOOLOID)
224 elog(ERROR, "invalid data type input");
226 /* check input_array is one-dimensional */
227 if (ARR_NDIM(input_array) > 1)
229 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
230 errmsg("1 dimensional text array expected")));
232 /* deconstruct array elements */
233 get_typlenbyvalalign(array_element_type, &array_typlen, &array_typbyval, &array_typalign);
234 deconstruct_array(input_array, array_element_type, array_typlen, array_typbyval, array_typalign,
235 &datums, &nulls, &count);
237 /* if the array is empty there's no work to do so return the input value */
239 PG_RETURN_JSONB(input_jsonb);
242 * If we've been supplied with existing keys iterate round json data and rebuild
243 * with keys/elements excluded.
245 * skip_level, nest_level and array_level are crude counts to check if the the value
246 * for the key is closed and ensure we don't match on keys within nested objects.
247 * Because we are recursing into nested elements but blindly just pushing them onto
248 * the return value we can get away without deeper knowledge of the json?
250 jsonb_iterator = JsonbIteratorInit(&input_jsonb->root);
252 while ((jsonb_iterator_token = JsonbIteratorNext(&jsonb_iterator, &jsonb_iterator_value, false)) != WJB_DONE) {
255 switch (jsonb_iterator_token)
257 case WJB_BEGIN_ARRAY:
260 case WJB_BEGIN_OBJECT:
264 if (skip_level == 0 && nest_level == 0 && array_level == 1)
266 if ((jsonb_iterator_value.type == jbvNumeric) && (array_element_type == NUMERICOID))
268 for (i=0; i<count; i++)
272 array_element_numeric = DatumGetNumeric(datums[i]);
274 if (DatumGetBool(DirectFunctionCall2(numeric_eq,
275 PointerGetDatum(jsonb_iterator_value.val.numeric),
276 PointerGetDatum(array_element_numeric))))
284 else if ((jsonb_iterator_value.type == jbvBool) && (array_element_type == BOOLOID))
286 for (i=0; i<count; i++)
290 array_element_bool = DatumGetBool(datums[i]);
292 if (jsonb_iterator_value.val.boolean == array_element_bool)
300 /* sql null <> jsonb null */
303 if (skip_level == 0 && ((jsonb_iterator_token == WJB_KEY && nest_level == 1 && array_level == 0) ||
304 (jsonb_iterator_token == WJB_ELEM && nest_level == 0 && array_level == 1)))
306 if (jsonb_iterator_value.type == jbvString && array_element_type == TEXTOID)
308 for (i=0; i<count; i++)
312 array_element_text = DatumGetTextP(datums[i]);
314 /* Nulls within json are equal, but should not be equal to SQL nulls */
315 if ((jsonb_iterator_value.val.string.len == VARSIZE_ANY_EXHDR(array_element_text)) &&
316 (memcmp(jsonb_iterator_value.val.string.val,
317 VARDATA_ANY(array_element_text),
318 jsonb_iterator_value.val.string.len) == 0))
320 if (jsonb_iterator_token == WJB_ELEM)
323 skip_level = nest_level;
333 if (push && (skip_level == 0 || nest_level < skip_level))
335 return_jsonb_value = pushJsonbValueBlind(&state, jsonb_iterator_token, &jsonb_iterator_value);
338 switch (jsonb_iterator_token)
342 if (skip_level == nest_level && array_level == 0)
347 if (skip_level == nest_level && array_level == 0)
351 if (skip_level == nest_level)
357 if (JB_ROOT_IS_SCALAR(input_jsonb) && !return_jsonb_value->val.array.rawScalar && return_jsonb_value->val.array.nElems == 1)
358 return_jsonb_value->val.array.rawScalar = true;
360 PG_FREE_IF_COPY(input_jsonb, 0);
361 PG_FREE_IF_COPY(input_array, 1);
363 PG_RETURN_JSONB(JsonbValueToJsonb(return_jsonb_value));
366 Datum jsonb_delete_jsonb(PG_FUNCTION_ARGS);
368 PG_FUNCTION_INFO_V1(jsonb_delete_jsonb);
371 * Operator function to delete keys and values from left operand where a match
372 * is found in the right operand.
374 * jsonb, jsonb -> jsonb
378 jsonb_delete_jsonb(PG_FUNCTION_ARGS)
380 /* pointers to incoming jsonb and text[] data */
381 Jsonb *input_jsonb_a = PG_GETARG_JSONB(0);
382 Jsonb *input_jsonb_b = PG_GETARG_JSONB(1);
384 /* pointers to return jsonb value data and state to be converted to jsonb on return */
385 JsonbValue *return_jsonb_value = NULL;
386 JsonbParseState *state = NULL;
388 /* pointer to iterator for input_jsonb_a and temporary value data */
389 JsonbIterator *jsonb_iterator;
390 JsonbIterator *jsonb_iterator2;
391 JsonbValue jsonb_iterator_value;
392 JsonbValue jsonb_iterator_value2;
393 JsonbValue jsonb_iterator_key;
394 int32 jsonb_iterator_token;
395 int32 jsonb_iterator_token2;
399 /* pointer to lookup on input_jsonb_b */
400 JsonbValue *jsonb_lookup_value = NULL;
403 * check if either right jsonb is empty and return left if so
405 if (JB_ROOT_COUNT(input_jsonb_b) == 0)
406 PG_RETURN_JSONB(input_jsonb_a);
408 jsonb_iterator = JsonbIteratorInit(&input_jsonb_a->root);
410 while ((jsonb_iterator_token = JsonbIteratorNext(&jsonb_iterator, &jsonb_iterator_value, true)) != WJB_DONE)
412 //skip_nested = true;
415 switch (jsonb_iterator_token)
417 case WJB_BEGIN_ARRAY:
418 case WJB_BEGIN_OBJECT:
421 return_jsonb_value = pushJsonbValue(&state, jsonb_iterator_token, NULL);
424 switch (jsonb_iterator_value.type)
427 jsonb_iterator2 = JsonbIteratorInit(&input_jsonb_b->root);
428 while ((jsonb_iterator_token2 = JsonbIteratorNext(&jsonb_iterator2, &jsonb_iterator_value2, true)) != WJB_DONE)
430 if (jsonb_iterator_value2.type == jbvBinary)
432 if ((jsonb_iterator_value2.val.binary.len == jsonb_iterator_value.val.binary.len) &&
433 (memcmp(jsonb_iterator_value2.val.binary.data,
434 jsonb_iterator_value.val.binary.data,
435 jsonb_iterator_value2.val.binary.len) == 0))
444 if (findJsonbValueFromContainer(&input_jsonb_b->root,
445 JB_FARRAY, &jsonb_iterator_value) != NULL)
447 /* inner switch end */
452 if (jsonb_iterator_value.type == jbvBinary)
454 return_jsonb_value = pushJsonbBinary(&state, jsonb_iterator_value.val.binary.data);
458 return_jsonb_value = pushJsonbValue(&state, WJB_ELEM, &jsonb_iterator_value);
463 jsonb_lookup_value = findJsonbValueFromContainer(&input_jsonb_b->root, JB_FOBJECT, &jsonb_iterator_value);
465 jsonb_iterator_key = jsonb_iterator_value;
466 jsonb_iterator_token = JsonbIteratorNext(&jsonb_iterator, &jsonb_iterator_value, true);
467 if (jsonb_iterator_token != WJB_VALUE)
468 elog(ERROR, "invalid JsonbIteratorNext (expected WJB_VALUE) rc: %d", jsonb_iterator_token);
470 if (jsonb_lookup_value != NULL)
472 if (jsonb_lookup_value->type == jsonb_iterator_value.type)
474 switch (jsonb_lookup_value->type)
476 /* Nulls within json are equal, but should not be equal to SQL nulls */
481 if (DatumGetBool(DirectFunctionCall2(numeric_eq,
482 PointerGetDatum(jsonb_lookup_value->val.numeric),
483 PointerGetDatum(jsonb_iterator_value.val.numeric))))
487 if ((jsonb_lookup_value->val.string.len == jsonb_iterator_value.val.string.len) &&
488 (memcmp(jsonb_lookup_value->val.string.val,
489 jsonb_iterator_value.val.string.val,
490 jsonb_lookup_value->val.string.len) == 0))
494 if ((jsonb_lookup_value->val.binary.len == jsonb_iterator_value.val.binary.len) &&
495 (memcmp(jsonb_lookup_value->val.binary.data,
496 jsonb_iterator_value.val.binary.data,
497 jsonb_lookup_value->val.binary.len) == 0))
501 if (jsonb_lookup_value->val.boolean == jsonb_iterator_value.val.boolean)
506 /* should not be possible? */
508 ereport(ERROR, (errcode(ERRCODE_SUCCESSFUL_COMPLETION), errmsg("unexpected lookup type %i", jsonb_iterator_token)));
509 /* inner switch end */
516 return_jsonb_value = pushJsonbValue(&state, WJB_KEY, &jsonb_iterator_key);
518 /* if our value is nested binary data, iterate separately pushing each val */
519 if (jsonb_iterator_value.type == jbvBinary)
521 return_jsonb_value = pushJsonbBinary(&state, jsonb_iterator_value.val.binary.data);
525 return_jsonb_value = pushJsonbValue(&state, jsonb_iterator_token, &jsonb_iterator_value);
530 /* should not be possible */
532 elog(ERROR, "invalid JsonbIteratorNext rc: %d", jsonb_iterator_token);
538 if (JB_ROOT_IS_SCALAR(input_jsonb_a) && !return_jsonb_value->val.array.rawScalar && return_jsonb_value->val.array.nElems == 1)
539 return_jsonb_value->val.array.rawScalar = true;
541 PG_FREE_IF_COPY(input_jsonb_a, 0);
542 PG_FREE_IF_COPY(input_jsonb_b, 1);
544 PG_RETURN_JSONB(JsonbValueToJsonb(return_jsonb_value));
547 Datum jsonb_delete_path(PG_FUNCTION_ARGS);
549 PG_FUNCTION_INFO_V1(jsonb_delete_path);
553 * jsonb, text[] -> jsonb
557 jsonb_delete_path(PG_FUNCTION_ARGS)
559 /* pointers to incoming jsonb and text[] data */
560 Jsonb *input_jsonb_a = PG_GETARG_JSONB(0);
561 ArrayType *input_array = PG_GETARG_ARRAYTYPE_P(1);
563 /* pointer to return jsonb data */
564 Jsonb *return_jsonb = NULL;
566 return_jsonb = jsonbModifyPath(input_jsonb_a, input_array, NULL);
568 PG_FREE_IF_COPY(input_jsonb_a, 0);
569 PG_FREE_IF_COPY(input_array, 1);
571 PG_RETURN_JSONB(return_jsonb);
574 Datum jsonb_concat_jsonb(PG_FUNCTION_ARGS);
576 PG_FUNCTION_INFO_V1(jsonb_concat_jsonb);
579 * Operator function to concatenate json from left operand where a match
580 * is found in the right operand.
582 * jsonb, jsonb -> jsonb
586 jsonb_concat_jsonb(PG_FUNCTION_ARGS)
588 /* incoming jsonb data */
589 Jsonb *input_jsonb_a = PG_GETARG_JSONB(0);
590 Jsonb *input_jsonb_b = PG_GETARG_JSONB(1);
592 /* return jsonb value data to be converted to jsonb on return */
593 JsonbParseState *state = NULL;
594 JsonbValue *return_jsonb_value = NULL;
596 /* iterator for input_jsonb_b */
597 JsonbIterator *jsonb_iterator;
598 JsonbValue jsonb_iterator_value;
599 int32 jsonb_iterator_token;
600 int32 jsonb_root_open;
601 int32 jsonb_root_close;
603 int32 nest_level = 0;
607 * check if either supplied jsonb is empty and return the other if so
609 if (JB_ROOT_COUNT(input_jsonb_a) == 0)
610 PG_RETURN_JSONB(input_jsonb_b);
611 else if (JB_ROOT_COUNT(input_jsonb_b) == 0)
612 PG_RETURN_JSONB(input_jsonb_a);
615 * rather than restrict concatenation to objects, allow any jsonb root
616 * but if one is an array use an array as the root container else
619 if (JB_ROOT_IS_ARRAY(input_jsonb_a) || JB_ROOT_IS_ARRAY(input_jsonb_b))
621 jsonb_root_open = WJB_BEGIN_ARRAY;
622 jsonb_root_close = WJB_END_ARRAY;
625 jsonb_root_open = WJB_BEGIN_OBJECT;
626 jsonb_root_close = WJB_END_OBJECT;
630 * The following is essentially a cut 'n shut job; discarding the closing root
631 * object token from the first jsonb value and the opening one from the second.
632 * Values from each are just blindly pushed onto the return value leaving
633 * deduplication down to lower level jsonb logic.
636 return_jsonb_value = pushJsonbValue(&state, jsonb_root_open, NULL);
638 jsonb_iterator = JsonbIteratorInit(&input_jsonb_a->root);
640 while ((jsonb_iterator_token = JsonbIteratorNext(&jsonb_iterator, &jsonb_iterator_value, false)) != WJB_DONE)
642 if (jsonb_iterator_token == jsonb_root_open && (first || nest_level > 0))
651 else if (jsonb_iterator_token == jsonb_root_close && nest_level > 0)
659 return_jsonb_value = pushJsonbValueBlind(&state, jsonb_iterator_token, &jsonb_iterator_value);
664 jsonb_iterator = JsonbIteratorInit(&input_jsonb_b->root);
666 while ((jsonb_iterator_token = JsonbIteratorNext(&jsonb_iterator, &jsonb_iterator_value, false)) != WJB_DONE)
668 if (jsonb_iterator_token == jsonb_root_open && (first || nest_level > 0))
677 else if (jsonb_iterator_token == jsonb_root_close && nest_level > 0)
685 return_jsonb_value = pushJsonbValueBlind(&state, jsonb_iterator_token, &jsonb_iterator_value);
688 return_jsonb_value = pushJsonbValue(&state, jsonb_root_close, NULL);
690 PG_FREE_IF_COPY(input_jsonb_a, 0);
691 PG_FREE_IF_COPY(input_jsonb_b, 1);
693 PG_RETURN_JSONB(JsonbValueToJsonb(return_jsonb_value));
696 Datum jsonb_replace_jsonb(PG_FUNCTION_ARGS);
698 PG_FUNCTION_INFO_V1(jsonb_replace_jsonb);
701 * Operator function to replace json in left operand where keys match
702 * in the right operand.
704 * jsonb, jsonb -> jsonb
708 jsonb_replace_jsonb(PG_FUNCTION_ARGS)
710 /* incoming jsonb data */
711 Jsonb *input_jsonb_a = PG_GETARG_JSONB(0);
712 Jsonb *input_jsonb_b = PG_GETARG_JSONB(1);
714 /* return jsonb value data to be converted to jsonb on return */
715 JsonbParseState *state = NULL;
716 JsonbValue *return_jsonb_value = NULL;
718 /* lookup jsonb value data */
719 JsonbValue jsonb_lookup_key;
720 JsonbValue *jsonb_lookup_value = NULL;
721 uint32 jsonb_lookup_flags;
723 /* iterator for input_jsonb_b */
724 JsonbIterator *jsonb_iterator;
725 JsonbValue jsonb_iterator_value;
726 int32 jsonb_iterator_token;
729 * check if supplied replacement jsonb is empty and return unchanged if so
731 if (JB_ROOT_COUNT(input_jsonb_b) == 0)
732 PG_RETURN_JSONB(input_jsonb_a);
734 if (JB_ROOT_IS_OBJECT(input_jsonb_a))
735 jsonb_lookup_flags = JB_FOBJECT;
737 jsonb_lookup_flags = JB_FOBJECT | JB_FARRAY;
739 jsonb_iterator = JsonbIteratorInit(&input_jsonb_a->root);
740 while ((jsonb_iterator_token = JsonbIteratorNext(&jsonb_iterator, &jsonb_iterator_value, true)) != WJB_DONE)
742 if ((jsonb_iterator_token == WJB_ELEM ) && (jsonb_iterator_value.type == jbvBinary))
744 return_jsonb_value = pushJsonbBinary(&state, jsonb_iterator_value.val.binary.data);
748 return_jsonb_value = pushJsonbValueBlind(&state, jsonb_iterator_token, &jsonb_iterator_value);
751 Assert(jsonb_iterator_token != WJB_VALUE);
753 if ( jsonb_iterator_token == WJB_KEY )
755 jsonb_lookup_key.type = jbvString;
756 jsonb_lookup_key.val.string.val = jsonb_iterator_value.val.string.val;
757 jsonb_lookup_key.val.string.len = jsonb_iterator_value.val.string.len;
759 jsonb_iterator_token = JsonbIteratorNext(&jsonb_iterator, &jsonb_iterator_value, true);
760 Assert(jsonb_iterator_token == WJB_VALUE);
762 jsonb_lookup_value = findJsonbValueFromContainer(&input_jsonb_b->root,
763 jsonb_lookup_flags, &jsonb_lookup_key);
765 /* if there's nothing to replace push the original value */
766 if (jsonb_lookup_value == NULL)
768 jsonb_lookup_value = &jsonb_iterator_value;
771 /* if our value is nested binary data, iterate separately pushing each val */
772 if (jsonb_lookup_value->type == jbvBinary)
774 return_jsonb_value = pushJsonbBinary(&state, jsonb_lookup_value->val.binary.data);
778 return_jsonb_value = pushJsonbValue(&state, WJB_VALUE, jsonb_lookup_value);
783 if (JB_ROOT_IS_SCALAR(input_jsonb_a) && !return_jsonb_value->val.array.rawScalar && return_jsonb_value->val.array.nElems == 1)
784 return_jsonb_value->val.array.rawScalar = true;
786 PG_FREE_IF_COPY(input_jsonb_a, 0);
787 PG_FREE_IF_COPY(input_jsonb_b, 1);
789 PG_RETURN_JSONB(JsonbValueToJsonb(return_jsonb_value));
792 Datum jsonb_replace_path(PG_FUNCTION_ARGS);
794 PG_FUNCTION_INFO_V1(jsonb_replace_path);
798 * jsonb, text[], jsonb -> jsonb
802 jsonb_replace_path(PG_FUNCTION_ARGS)
804 /* pointers to incoming jsonb and text[] data */
805 Jsonb *input_jsonb_a = PG_GETARG_JSONB(0);
806 ArrayType *input_array = PG_GETARG_ARRAYTYPE_P(1);
807 Jsonb *input_jsonb_b = PG_GETARG_JSONB(2);
809 /* pointer to return jsonb data */
810 Jsonb *return_jsonb = NULL;
812 return_jsonb = jsonbModifyPath(input_jsonb_a, input_array, input_jsonb_b);
814 PG_FREE_IF_COPY(input_jsonb_a, 0);
815 PG_FREE_IF_COPY(input_array, 1);
816 PG_FREE_IF_COPY(input_jsonb_b, 2);
818 PG_RETURN_JSONB(return_jsonb);
822 Datum jsonb_append_path(PG_FUNCTION_ARGS);
824 PG_FUNCTION_INFO_V1(jsonb_append_path);
828 * jsonb, text[], jsonb -> jsonb
832 jsonb_append_path(PG_FUNCTION_ARGS)
834 /* pointers to incoming jsonb and text[] data */
835 Jsonb *input_jsonb_a = PG_GETARG_JSONB(0);
836 ArrayType *input_array = PG_GETARG_ARRAYTYPE_P(1);
837 Jsonb *input_jsonb_b = PG_GETARG_JSONB(2);
839 /* pointer to return jsonb data */
840 Jsonb *return_jsonb = NULL;
842 elog(ERROR, "not implemented");
843 //return_jsonb = jsonbModifyPath(input_jsonb_a, input_array, input_jsonb_b, true);
845 PG_FREE_IF_COPY(input_jsonb_a, 0);
846 PG_FREE_IF_COPY(input_array, 1);
847 PG_FREE_IF_COPY(input_jsonb_b, 2);
849 PG_RETURN_JSONB(return_jsonb);