3333#include "utils/memutils.h"
3434#include "utils/typcache.h"
3535
36+ /* Operations available for setPath */
37+ #define JB_PATH_NOOP 0x0000
38+ #define JB_PATH_CREATE 0x0001
39+ #define JB_PATH_DELETE 0x0002
40+ #define JB_PATH_INSERT_BEFORE 0x0004
41+ #define JB_PATH_INSERT_AFTER 0x0008
42+ #define JB_PATH_CREATE_OR_INSERT \
43+ (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE)
44+
3645/* semantic action functions for json_object_keys */
3746static void okeys_object_field_start (void * state ,char * fname ,bool isnull );
3847static void okeys_array_start (void * state );
@@ -130,14 +139,14 @@ static JsonbValue *IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
130139static JsonbValue * setPath (JsonbIterator * * it ,Datum * path_elems ,
131140bool * path_nulls ,int path_len ,
132141JsonbParseState * * st ,int level ,Jsonb * newval ,
133- bool create );
142+ int op_type );
134143static void setPathObject (JsonbIterator * * it ,Datum * path_elems ,
135144bool * path_nulls ,int path_len ,JsonbParseState * * st ,
136145int level ,
137- Jsonb * newval ,uint32 npairs ,bool create );
146+ Jsonb * newval ,uint32 npairs ,int op_type );
138147static void setPathArray (JsonbIterator * * it ,Datum * path_elems ,
139148bool * path_nulls ,int path_len ,JsonbParseState * * st ,
140- int level ,Jsonb * newval ,uint32 nelems ,bool create );
149+ int level ,Jsonb * newval ,uint32 nelems ,int op_type );
141150static void addJsonbToParseState (JsonbParseState * * jbps ,Jsonb * jb );
142151
143152/* state for json_object_keys */
@@ -3544,7 +3553,7 @@ jsonb_set(PG_FUNCTION_ARGS)
35443553it = JsonbIteratorInit (& in -> root );
35453554
35463555res = setPath (& it ,path_elems ,path_nulls ,path_len ,& st ,
3547- 0 ,newval ,create );
3556+ 0 ,newval ,create ? JB_PATH_CREATE : JB_PATH_NOOP );
35483557
35493558Assert (res != NULL );
35503559
@@ -3588,7 +3597,52 @@ jsonb_delete_path(PG_FUNCTION_ARGS)
35883597
35893598it = JsonbIteratorInit (& in -> root );
35903599
3591- res = setPath (& it ,path_elems ,path_nulls ,path_len ,& st ,0 ,NULL , false);
3600+ res = setPath (& it ,path_elems ,path_nulls ,path_len ,& st ,
3601+ 0 ,NULL ,JB_PATH_DELETE );
3602+
3603+ Assert (res != NULL );
3604+
3605+ PG_RETURN_JSONB (JsonbValueToJsonb (res ));
3606+ }
3607+
3608+ /*
3609+ * SQL function jsonb_insert(jsonb, text[], jsonb, boolean)
3610+ *
3611+ */
3612+ Datum
3613+ jsonb_insert (PG_FUNCTION_ARGS )
3614+ {
3615+ Jsonb * in = PG_GETARG_JSONB (0 );
3616+ ArrayType * path = PG_GETARG_ARRAYTYPE_P (1 );
3617+ Jsonb * newval = PG_GETARG_JSONB (2 );
3618+ bool after = PG_GETARG_BOOL (3 );
3619+ JsonbValue * res = NULL ;
3620+ Datum * path_elems ;
3621+ bool * path_nulls ;
3622+ int path_len ;
3623+ JsonbIterator * it ;
3624+ JsonbParseState * st = NULL ;
3625+
3626+ if (ARR_NDIM (path )> 1 )
3627+ ereport (ERROR ,
3628+ (errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
3629+ errmsg ("wrong number of array subscripts" )));
3630+
3631+ if (JB_ROOT_IS_SCALAR (in ))
3632+ ereport (ERROR ,
3633+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
3634+ errmsg ("cannot set path in scalar" )));
3635+
3636+ deconstruct_array (path ,TEXTOID ,-1 , false,'i' ,
3637+ & path_elems ,& path_nulls ,& path_len );
3638+
3639+ if (path_len == 0 )
3640+ PG_RETURN_JSONB (in );
3641+
3642+ it = JsonbIteratorInit (& in -> root );
3643+
3644+ res = setPath (& it ,path_elems ,path_nulls ,path_len ,& st ,0 ,newval ,
3645+ after ?JB_PATH_INSERT_AFTER :JB_PATH_INSERT_BEFORE );
35923646
35933647Assert (res != NULL );
35943648
@@ -3707,18 +3761,23 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
37073761}
37083762
37093763/*
3710- * Do most of the heavy work for jsonb_set
3764+ * Do most of the heavy work for jsonb_set/jsonb_insert
3765+ *
3766+ * If JB_PATH_DELETE bit is set in op_type, the element is to be removed.
37113767 *
3712- * If newval is null, the element is to be removed.
3768+ * If any bit mentioned in JB_PATH_CREATE_OR_INSERT is set in op_type,
3769+ * we create the new value if the key or array index does not exist.
37133770 *
3714- * If create is true, we create the new value if the key or array index
3715- * does not exist. All path elements before the last must already exist
3716- * whether or not create is true, or nothing is done.
3771+ * Bits JB_PATH_INSERT_BEFORE and JB_PATH_INSERT_AFTER in op_type
3772+ * behave as JB_PATH_CREATE if new value is inserted in JsonbObject.
3773+ *
3774+ * All path elements before the last must already exist
3775+ * whatever bits in op_type are set, or nothing is done.
37173776 */
37183777static JsonbValue *
37193778setPath (JsonbIterator * * it ,Datum * path_elems ,
37203779bool * path_nulls ,int path_len ,
3721- JsonbParseState * * st ,int level ,Jsonb * newval ,bool create )
3780+ JsonbParseState * * st ,int level ,Jsonb * newval ,int op_type )
37223781{
37233782JsonbValue v ;
37243783JsonbIteratorToken r ;
@@ -3739,15 +3798,15 @@ setPath(JsonbIterator **it, Datum *path_elems,
37393798case WJB_BEGIN_ARRAY :
37403799(void )pushJsonbValue (st ,r ,NULL );
37413800setPathArray (it ,path_elems ,path_nulls ,path_len ,st ,level ,
3742- newval ,v .val .array .nElems ,create );
3801+ newval ,v .val .array .nElems ,op_type );
37433802r = JsonbIteratorNext (it ,& v , false);
37443803Assert (r == WJB_END_ARRAY );
37453804res = pushJsonbValue (st ,r ,NULL );
37463805break ;
37473806case WJB_BEGIN_OBJECT :
37483807(void )pushJsonbValue (st ,r ,NULL );
37493808setPathObject (it ,path_elems ,path_nulls ,path_len ,st ,level ,
3750- newval ,v .val .object .nPairs ,create );
3809+ newval ,v .val .object .nPairs ,op_type );
37513810r = JsonbIteratorNext (it ,& v , true);
37523811Assert (r == WJB_END_OBJECT );
37533812res = pushJsonbValue (st ,r ,NULL );
@@ -3771,7 +3830,7 @@ setPath(JsonbIterator **it, Datum *path_elems,
37713830static void
37723831setPathObject (JsonbIterator * * it ,Datum * path_elems ,bool * path_nulls ,
37733832int path_len ,JsonbParseState * * st ,int level ,
3774- Jsonb * newval ,uint32 npairs ,bool create )
3833+ Jsonb * newval ,uint32 npairs ,int op_type )
37753834{
37763835JsonbValue v ;
37773836int i ;
@@ -3782,7 +3841,8 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
37823841done = true;
37833842
37843843/* empty object is a special case for create */
3785- if ((npairs == 0 )&& create && (level == path_len - 1 ))
3844+ if ((npairs == 0 )&& (op_type & JB_PATH_CREATE_OR_INSERT )&&
3845+ (level == path_len - 1 ))
37863846{
37873847JsonbValue newkey ;
37883848
@@ -3807,8 +3867,19 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
38073867{
38083868if (level == path_len - 1 )
38093869{
3810- r = JsonbIteratorNext (it ,& v , true);/* skip */
3811- if (newval != NULL )
3870+ /*
3871+ * called from jsonb_insert(), it forbids redefining
3872+ * an existsing value
3873+ */
3874+ if (op_type & (JB_PATH_INSERT_BEFORE |JB_PATH_INSERT_AFTER ))
3875+ ereport (ERROR ,
3876+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
3877+ errmsg ("cannot replace existing key" ),
3878+ errhint ("Try using the function jsonb_set "
3879+ "to replace key value." )));
3880+
3881+ r = JsonbIteratorNext (it ,& v , true);/* skip value */
3882+ if (!(op_type & JB_PATH_DELETE ))
38123883{
38133884(void )pushJsonbValue (st ,WJB_KEY ,& k );
38143885addJsonbToParseState (st ,newval );
@@ -3819,12 +3890,13 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
38193890{
38203891(void )pushJsonbValue (st ,r ,& k );
38213892setPath (it ,path_elems ,path_nulls ,path_len ,
3822- st ,level + 1 ,newval ,create );
3893+ st ,level + 1 ,newval ,op_type );
38233894}
38243895}
38253896else
38263897{
3827- if (create && !done && level == path_len - 1 && i == npairs - 1 )
3898+ if ((op_type & JB_PATH_CREATE_OR_INSERT )&& !done &&
3899+ level == path_len - 1 && i == npairs - 1 )
38283900{
38293901JsonbValue newkey ;
38303902
@@ -3865,7 +3937,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
38653937static void
38663938setPathArray (JsonbIterator * * it ,Datum * path_elems ,bool * path_nulls ,
38673939int path_len ,JsonbParseState * * st ,int level ,
3868- Jsonb * newval ,uint32 nelems ,bool create )
3940+ Jsonb * newval ,uint32 nelems ,int op_type )
38693941{
38703942JsonbValue v ;
38713943int idx ,
@@ -3909,7 +3981,8 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
39093981 * what the idx value is
39103982 */
39113983
3912- if ((idx == INT_MIN || nelems == 0 )&& create && (level == path_len - 1 ))
3984+ if ((idx == INT_MIN || nelems == 0 )&& (level == path_len - 1 )&&
3985+ (op_type & JB_PATH_CREATE_OR_INSERT ))
39133986{
39143987Assert (newval != NULL );
39153988addJsonbToParseState (st ,newval );
@@ -3926,14 +3999,26 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
39263999if (level == path_len - 1 )
39274000{
39284001r = JsonbIteratorNext (it ,& v , true);/* skip */
3929- if (newval != NULL )
4002+
4003+ if (op_type & (JB_PATH_INSERT_BEFORE |JB_PATH_CREATE ))
4004+ addJsonbToParseState (st ,newval );
4005+
4006+ /*
4007+ * We should keep current value only in case of
4008+ * JB_PATH_INSERT_BEFORE or JB_PATH_INSERT_AFTER
4009+ * because otherwise it should be deleted or replaced
4010+ */
4011+ if (op_type & (JB_PATH_INSERT_AFTER |JB_PATH_INSERT_BEFORE ))
4012+ (void )pushJsonbValue (st ,r ,& v );
4013+
4014+ if (op_type & JB_PATH_INSERT_AFTER )
39304015addJsonbToParseState (st ,newval );
39314016
39324017done = true;
39334018}
39344019else
39354020(void )setPath (it ,path_elems ,path_nulls ,path_len ,
3936- st ,level + 1 ,newval ,create );
4021+ st ,level + 1 ,newval ,op_type );
39374022}
39384023else
39394024{
@@ -3958,7 +4043,8 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
39584043}
39594044}
39604045
3961- if (create && !done && level == path_len - 1 && i == nelems - 1 )
4046+ if (op_type & JB_PATH_CREATE_OR_INSERT && !done &&
4047+ level == path_len - 1 && i == nelems - 1 )
39624048{
39634049addJsonbToParseState (st ,newval );
39644050}