33
33
#include "utils/memutils.h"
34
34
#include "utils/typcache.h"
35
35
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
+
36
45
/* semantic action functions for json_object_keys */
37
46
static void okeys_object_field_start (void * state , char * fname , bool isnull );
38
47
static void okeys_array_start (void * state );
@@ -130,14 +139,14 @@ static JsonbValue *IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
130
139
static JsonbValue * setPath (JsonbIterator * * it , Datum * path_elems ,
131
140
bool * path_nulls , int path_len ,
132
141
JsonbParseState * * st , int level , Jsonb * newval ,
133
- bool create );
142
+ int op_type );
134
143
static void setPathObject (JsonbIterator * * it , Datum * path_elems ,
135
144
bool * path_nulls , int path_len , JsonbParseState * * st ,
136
145
int level ,
137
- Jsonb * newval , uint32 npairs , bool create );
146
+ Jsonb * newval , uint32 npairs , int op_type );
138
147
static void setPathArray (JsonbIterator * * it , Datum * path_elems ,
139
148
bool * 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 );
141
150
static void addJsonbToParseState (JsonbParseState * * jbps , Jsonb * jb );
142
151
143
152
/* state for json_object_keys */
@@ -3544,7 +3553,7 @@ jsonb_set(PG_FUNCTION_ARGS)
3544
3553
it = JsonbIteratorInit (& in -> root );
3545
3554
3546
3555
res = setPath (& it , path_elems , path_nulls , path_len , & st ,
3547
- 0 , newval , create );
3556
+ 0 , newval , create ? JB_PATH_CREATE : JB_PATH_NOOP );
3548
3557
3549
3558
Assert (res != NULL );
3550
3559
@@ -3588,7 +3597,52 @@ jsonb_delete_path(PG_FUNCTION_ARGS)
3588
3597
3589
3598
it = JsonbIteratorInit (& in -> root );
3590
3599
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 );
3592
3646
3593
3647
Assert (res != NULL );
3594
3648
@@ -3707,18 +3761,23 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
3707
3761
}
3708
3762
3709
3763
/*
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.
3711
3767
*
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.
3713
3770
*
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.
3717
3776
*/
3718
3777
static JsonbValue *
3719
3778
setPath (JsonbIterator * * it , Datum * path_elems ,
3720
3779
bool * path_nulls , int path_len ,
3721
- JsonbParseState * * st , int level , Jsonb * newval , bool create )
3780
+ JsonbParseState * * st , int level , Jsonb * newval , int op_type )
3722
3781
{
3723
3782
JsonbValue v ;
3724
3783
JsonbIteratorToken r ;
@@ -3739,15 +3798,15 @@ setPath(JsonbIterator **it, Datum *path_elems,
3739
3798
case WJB_BEGIN_ARRAY :
3740
3799
(void ) pushJsonbValue (st , r , NULL );
3741
3800
setPathArray (it , path_elems , path_nulls , path_len , st , level ,
3742
- newval , v .val .array .nElems , create );
3801
+ newval , v .val .array .nElems , op_type );
3743
3802
r = JsonbIteratorNext (it , & v , false);
3744
3803
Assert (r == WJB_END_ARRAY );
3745
3804
res = pushJsonbValue (st , r , NULL );
3746
3805
break ;
3747
3806
case WJB_BEGIN_OBJECT :
3748
3807
(void ) pushJsonbValue (st , r , NULL );
3749
3808
setPathObject (it , path_elems , path_nulls , path_len , st , level ,
3750
- newval , v .val .object .nPairs , create );
3809
+ newval , v .val .object .nPairs , op_type );
3751
3810
r = JsonbIteratorNext (it , & v , true);
3752
3811
Assert (r == WJB_END_OBJECT );
3753
3812
res = pushJsonbValue (st , r , NULL );
@@ -3771,7 +3830,7 @@ setPath(JsonbIterator **it, Datum *path_elems,
3771
3830
static void
3772
3831
setPathObject (JsonbIterator * * it , Datum * path_elems , bool * path_nulls ,
3773
3832
int path_len , JsonbParseState * * st , int level ,
3774
- Jsonb * newval , uint32 npairs , bool create )
3833
+ Jsonb * newval , uint32 npairs , int op_type )
3775
3834
{
3776
3835
JsonbValue v ;
3777
3836
int i ;
@@ -3782,7 +3841,8 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
3782
3841
done = true;
3783
3842
3784
3843
/* 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 ))
3786
3846
{
3787
3847
JsonbValue newkey ;
3788
3848
@@ -3807,8 +3867,19 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
3807
3867
{
3808
3868
if (level == path_len - 1 )
3809
3869
{
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 ))
3812
3883
{
3813
3884
(void ) pushJsonbValue (st , WJB_KEY , & k );
3814
3885
addJsonbToParseState (st , newval );
@@ -3819,12 +3890,13 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
3819
3890
{
3820
3891
(void ) pushJsonbValue (st , r , & k );
3821
3892
setPath (it , path_elems , path_nulls , path_len ,
3822
- st , level + 1 , newval , create );
3893
+ st , level + 1 , newval , op_type );
3823
3894
}
3824
3895
}
3825
3896
else
3826
3897
{
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 )
3828
3900
{
3829
3901
JsonbValue newkey ;
3830
3902
@@ -3865,7 +3937,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
3865
3937
static void
3866
3938
setPathArray (JsonbIterator * * it , Datum * path_elems , bool * path_nulls ,
3867
3939
int path_len , JsonbParseState * * st , int level ,
3868
- Jsonb * newval , uint32 nelems , bool create )
3940
+ Jsonb * newval , uint32 nelems , int op_type )
3869
3941
{
3870
3942
JsonbValue v ;
3871
3943
int idx ,
@@ -3909,7 +3981,8 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
3909
3981
* what the idx value is
3910
3982
*/
3911
3983
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 ))
3913
3986
{
3914
3987
Assert (newval != NULL );
3915
3988
addJsonbToParseState (st , newval );
@@ -3926,14 +3999,26 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
3926
3999
if (level == path_len - 1 )
3927
4000
{
3928
4001
r = 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 )
3930
4015
addJsonbToParseState (st , newval );
3931
4016
3932
4017
done = true;
3933
4018
}
3934
4019
else
3935
4020
(void ) setPath (it , path_elems , path_nulls , path_len ,
3936
- st , level + 1 , newval , create );
4021
+ st , level + 1 , newval , op_type );
3937
4022
}
3938
4023
else
3939
4024
{
@@ -3958,7 +4043,8 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
3958
4043
}
3959
4044
}
3960
4045
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 )
3962
4048
{
3963
4049
addJsonbToParseState (st , newval );
3964
4050
}
0 commit comments