13
13
#include "postgres.h"
14
14
#include "funcapi.h"
15
15
#include "miscadmin.h"
16
+ #include "catalog/pg_collation.h"
16
17
#include "catalog/pg_type.h"
17
18
#include "lib/stringinfo.h"
18
19
#include "utils/builtins.h"
19
20
#include "utils/json.h"
20
21
#include "utils/jsonpath.h"
22
+ #include "utils/varlena.h"
21
23
22
24
typedef struct JsonPathExecContext
23
25
{
@@ -31,6 +33,9 @@ static JsonPathExecResult recursiveExecute(JsonPathExecContext *cxt,
31
33
32
34
/********************Execute functions for JsonPath***************************/
33
35
36
+ /*
37
+ * Find value of jsonpath variable in a list of passing params
38
+ */
34
39
static void
35
40
computeJsonPathVariable (JsonPathItem * variable , List * vars , JsonbValue * value )
36
41
{
@@ -132,6 +137,9 @@ computeJsonPathVariable(JsonPathItem *variable, List *vars, JsonbValue *value)
132
137
}
133
138
}
134
139
140
+ /*
141
+ * Convert jsonpath's scalar or variable node to actual jsonb value
142
+ */
135
143
static void
136
144
computeJsonPathItem (JsonPathExecContext * cxt , JsonPathItem * item , JsonbValue * value )
137
145
{
@@ -161,6 +169,12 @@ computeJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item, JsonbValue *va
161
169
}
162
170
163
171
172
+ /*
173
+ * Returns jbv* type of of JsonbValue. Note, it never returns
174
+ * jbvBinary as is - jbvBinary is used as mark of store naked
175
+ * scalar value. To improve readability it defines jbvScalar
176
+ * as alias to jbvBinary
177
+ */
164
178
#define jbvScalar jbvBinary
165
179
static int
166
180
JsonbType (JsonbValue * jb )
@@ -196,31 +210,10 @@ compareNumeric(Numeric a, Numeric b)
196
210
);
197
211
}
198
212
199
- static bool
200
- checkScalarEquality (JsonbValue * jb1 , JsonbValue * jb2 )
201
- {
202
- switch (jb1 -> type )
203
- {
204
- case jbvNull :
205
- return true;
206
- case jbvString :
207
- return (jb1 -> val .string .len == jb2 -> val .string .len &&
208
- memcmp (jb2 -> val .string .val , jb1 -> val .string .val ,
209
- jb1 -> val .string .len ) == 0 );
210
- case jbvBool :
211
- return (jb2 -> val .boolean == jb1 -> val .boolean );
212
- case jbvNumeric :
213
- return (compareNumeric (jb1 -> val .numeric , jb2 -> val .numeric ) == 0 );
214
- default :
215
- elog (ERROR ,"1Wrong state" );
216
- return false;
217
- }
218
- }
219
-
220
213
static JsonPathExecResult
221
214
checkEquality (JsonbValue * jb1 , JsonbValue * jb2 , bool not )
222
215
{
223
- bool eq ;
216
+ bool eq = false ;
224
217
225
218
if (jb1 -> type != jb2 -> type )
226
219
{
@@ -232,14 +225,28 @@ checkEquality(JsonbValue *jb1, JsonbValue *jb2, bool not)
232
225
233
226
if (jb1 -> type == jbvBinary )
234
227
return jperError ;
235
- /*
236
- eq = compareJsonbContainers(jb1->val.binary.data,
237
- jb2->val.binary.data) == 0;
238
- */
239
- else
240
- eq = checkScalarEquality (jb1 , jb2 );
241
228
242
- return !!not ^ !!eq ? jperOk : jperNotFound ;
229
+ switch (jb1 -> type )
230
+ {
231
+ case jbvNull :
232
+ eq = true;
233
+ break ;
234
+ case jbvString :
235
+ eq = (jb1 -> val .string .len == jb2 -> val .string .len &&
236
+ memcmp (jb2 -> val .string .val , jb1 -> val .string .val ,
237
+ jb1 -> val .string .len ) == 0 );
238
+ break ;
239
+ case jbvBool :
240
+ eq = (jb2 -> val .boolean == jb1 -> val .boolean );
241
+ break ;
242
+ case jbvNumeric :
243
+ eq = (compareNumeric (jb1 -> val .numeric , jb2 -> val .numeric ) == 0 );
244
+ break ;
245
+ default :
246
+ elog (ERROR ,"1Wrong state" );
247
+ }
248
+
249
+ return (not ^ eq ) ? jperOk : jperNotFound ;
243
250
}
244
251
245
252
static JsonPathExecResult
@@ -269,13 +276,11 @@ makeCompare(int32 op, JsonbValue *jb1, JsonbValue *jb2)
269
276
case jbvNumeric :
270
277
cmp = compareNumeric (jb1 -> val .numeric , jb2 -> val .numeric );
271
278
break ;
272
- /*
273
279
case jbvString :
274
280
cmp = varstr_cmp (jb1 -> val .string .val , jb1 -> val .string .len ,
275
281
jb2 -> val .string .val , jb2 -> val .string .len ,
276
- collationId );
282
+ DEFAULT_COLLATION_OID );
277
283
break ;
278
- */
279
284
default :
280
285
return jperError ;
281
286
}
@@ -532,6 +537,9 @@ executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
532
537
return jper ;
533
538
}
534
539
540
+ /*
541
+ * implements jpiAny node (** operator)
542
+ */
535
543
static JsonPathExecResult
536
544
recursiveAny (JsonPathExecContext * cxt , JsonPathItem * jsp , JsonbValue * jb ,
537
545
List * * found , uint32 level , uint32 first , uint32 last )
@@ -548,6 +556,9 @@ recursiveAny(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
548
556
549
557
it = JsonbIteratorInit (jb -> val .binary .data );
550
558
559
+ /*
560
+ * Recursivly iterate over jsonb objects/arrays
561
+ */
551
562
while ((r = JsonbIteratorNext (& it , & v , true)) != WJB_DONE )
552
563
{
553
564
if (r == WJB_KEY )
@@ -590,12 +601,23 @@ recursiveAny(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
590
601
return res ;
591
602
}
592
603
604
+ /*
605
+ * Main executor function: walks on jsonpath structure and tries to find
606
+ * correspoding parts of jsonb. Note, jsonb and jsonpath values should be
607
+ * avaliable and untoasted during work because JsonPathItem, JsonbValue
608
+ * and found could have pointers into input values. If caller wants just to
609
+ * check matching of json by jsonpath then it doesn't provide a found arg.
610
+ * In this case executor works till first positive result and does not check
611
+ * the rest if it is possible. In other case it tries to find all satisfied
612
+ * results
613
+ */
593
614
static JsonPathExecResult
594
615
recursiveExecute (JsonPathExecContext * cxt , JsonPathItem * jsp , JsonbValue * jb ,
595
616
List * * found )
596
617
{
597
618
JsonPathItem elem ;
598
619
JsonPathExecResult res = jperNotFound ;
620
+ bool hasNext ;
599
621
600
622
check_stack_depth ();
601
623
@@ -607,10 +629,15 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
607
629
{
608
630
JsonPathExecResult res2 ;
609
631
632
+ /*
633
+ * SQL/JSON says that we should check second arg
634
+ * in case of jperError
635
+ */
636
+
610
637
jspGetRightArg (jsp , & elem );
611
638
res2 = recursiveExecute (cxt , & elem , jb , NULL );
612
639
613
- res = res2 == jperOk ? res : res2 ;
640
+ res = ( res2 == jperOk ) ? res : res2 ;
614
641
}
615
642
break ;
616
643
case jpiOr :
@@ -623,7 +650,7 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
623
650
jspGetRightArg (jsp , & elem );
624
651
res2 = recursiveExecute (cxt , & elem , jb , NULL );
625
652
626
- res = res2 == jperNotFound ? res : res2 ;
653
+ res = ( res2 == jperNotFound ) ? res : res2 ;
627
654
}
628
655
break ;
629
656
case jpiNot :
@@ -643,7 +670,7 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
643
670
case jpiIsUnknown :
644
671
jspGetArg (jsp , & elem );
645
672
res = recursiveExecute (cxt , & elem , jb , NULL );
646
- res = res == jperError ? jperOk : jperNotFound ;
673
+ res = ( res == jperError ) ? jperOk : jperNotFound ;
647
674
break ;
648
675
case jpiKey :
649
676
if (JsonbType (jb ) == jbvObject )
@@ -676,6 +703,7 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
676
703
case jpiCurrent :
677
704
if (!jspGetNext (jsp , & elem ))
678
705
{
706
+ /* we are last in chain of node */
679
707
res = jperOk ;
680
708
if (found )
681
709
{
@@ -685,7 +713,7 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
685
713
v = JsonbExtractScalar (jb -> val .binary .data ,
686
714
palloc (sizeof (* v )));
687
715
else
688
- v = copyJsonbValue (jb ); /* FIXME */
716
+ v = copyJsonbValue (jb );
689
717
690
718
* found = lappend (* found , v );
691
719
}
@@ -709,7 +737,6 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
709
737
JsonbIterator * it ;
710
738
int32 r ;
711
739
JsonbValue v ;
712
- bool hasNext ;
713
740
714
741
hasNext = jspGetNext (jsp , & elem );
715
742
it = JsonbIteratorInit (jb -> val .binary .data );
@@ -746,7 +773,6 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
746
773
if (JsonbType (jb ) == jbvArray )
747
774
{
748
775
JsonbValue * v ;
749
- bool hasNext ;
750
776
int i ;
751
777
752
778
hasNext = jspGetNext (jsp , & elem );
@@ -788,7 +814,6 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
788
814
JsonbIterator * it ;
789
815
int32 r ;
790
816
JsonbValue v ;
791
- bool hasNext ;
792
817
793
818
hasNext = jspGetNext (jsp , & elem );
794
819
it = JsonbIteratorInit (jb -> val .binary .data );
@@ -915,6 +940,9 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
915
940
return res ;
916
941
}
917
942
943
+ /*
944
+ * Public interface to jsonpath executor
945
+ */
918
946
JsonPathExecResult
919
947
executeJsonPath (JsonPath * path , List * vars , Jsonb * json , List * * foundJson )
920
948
{
@@ -948,6 +976,9 @@ returnNULL(void *arg, bool *isNull)
948
976
return Int32GetDatum (0 );
949
977
}
950
978
979
+ /*
980
+ * Convert jsonb object into list of vars for executor
981
+ */
951
982
static List *
952
983
makePassingVars (Jsonb * jb )
953
984
{
0 commit comments