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
@@ -261,13 +268,11 @@ makeCompare(int32 op, JsonbValue *jb1, JsonbValue *jb2)
261
268
case jbvNumeric :
262
269
cmp = compareNumeric (jb1 -> val .numeric , jb2 -> val .numeric );
263
270
break ;
264
- /*
265
271
case jbvString :
266
272
cmp = varstr_cmp (jb1 -> val .string .val , jb1 -> val .string .len ,
267
273
jb2 -> val .string .val , jb2 -> val .string .len ,
268
- collationId );
274
+ DEFAULT_COLLATION_OID );
269
275
break ;
270
- */
271
276
default :
272
277
return jperError ;
273
278
}
@@ -524,6 +529,9 @@ executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
524
529
return jper ;
525
530
}
526
531
532
+ /*
533
+ * implements jpiAny node (** operator)
534
+ */
527
535
static JsonPathExecResult
528
536
recursiveAny (JsonPathExecContext * cxt , JsonPathItem * jsp , JsonbValue * jb ,
529
537
List * * found , uint32 level , uint32 first , uint32 last )
@@ -540,6 +548,9 @@ recursiveAny(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
540
548
541
549
it = JsonbIteratorInit (jb -> val .binary .data );
542
550
551
+ /*
552
+ * Recursivly iterate over jsonb objects/arrays
553
+ */
543
554
while ((r = JsonbIteratorNext (& it , & v , true)) != WJB_DONE )
544
555
{
545
556
if (r == WJB_KEY )
@@ -582,12 +593,23 @@ recursiveAny(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
582
593
return res ;
583
594
}
584
595
596
+ /*
597
+ * Main executor function: walks on jsonpath structure and tries to find
598
+ * correspoding parts of jsonb. Note, jsonb and jsonpath values should be
599
+ * avaliable and untoasted during work because JsonPathItem, JsonbValue
600
+ * and found could have pointers into input values. If caller wants just to
601
+ * check matching of json by jsonpath then it doesn't provide a found arg.
602
+ * In this case executor works till first positive result and does not check
603
+ * the rest if it is possible. In other case it tries to find all satisfied
604
+ * results
605
+ */
585
606
static JsonPathExecResult
586
607
recursiveExecute (JsonPathExecContext * cxt , JsonPathItem * jsp , JsonbValue * jb ,
587
608
List * * found )
588
609
{
589
610
JsonPathItem elem ;
590
611
JsonPathExecResult res = jperNotFound ;
612
+ bool hasNext ;
591
613
592
614
check_stack_depth ();
593
615
@@ -599,10 +621,15 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
599
621
{
600
622
JsonPathExecResult res2 ;
601
623
624
+ /*
625
+ * SQL/JSON says that we should check second arg
626
+ * in case of jperError
627
+ */
628
+
602
629
jspGetRightArg (jsp , & elem );
603
630
res2 = recursiveExecute (cxt , & elem , jb , NULL );
604
631
605
- res = res2 == jperOk ? res : res2 ;
632
+ res = ( res2 == jperOk ) ? res : res2 ;
606
633
}
607
634
break ;
608
635
case jpiOr :
@@ -615,7 +642,7 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
615
642
jspGetRightArg (jsp , & elem );
616
643
res2 = recursiveExecute (cxt , & elem , jb , NULL );
617
644
618
- res = res2 == jperNotFound ? res : res2 ;
645
+ res = ( res2 == jperNotFound ) ? res : res2 ;
619
646
}
620
647
break ;
621
648
case jpiNot :
@@ -635,7 +662,7 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
635
662
case jpiIsUnknown :
636
663
jspGetArg (jsp , & elem );
637
664
res = recursiveExecute (cxt , & elem , jb , NULL );
638
- res = res == jperError ? jperOk : jperNotFound ;
665
+ res = ( res == jperError ) ? jperOk : jperNotFound ;
639
666
break ;
640
667
case jpiKey :
641
668
if (JsonbType (jb ) == jbvObject )
@@ -668,6 +695,7 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
668
695
case jpiCurrent :
669
696
if (!jspGetNext (jsp , & elem ))
670
697
{
698
+ /* we are last in chain of node */
671
699
res = jperOk ;
672
700
if (found )
673
701
{
@@ -677,7 +705,7 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
677
705
v = JsonbExtractScalar (jb -> val .binary .data ,
678
706
palloc (sizeof (* v )));
679
707
else
680
- v = copyJsonbValue (jb ); /* FIXME */
708
+ v = copyJsonbValue (jb );
681
709
682
710
* found = lappend (* found , v );
683
711
}
@@ -701,7 +729,6 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
701
729
JsonbIterator * it ;
702
730
int32 r ;
703
731
JsonbValue v ;
704
- bool hasNext ;
705
732
706
733
hasNext = jspGetNext (jsp , & elem );
707
734
it = JsonbIteratorInit (jb -> val .binary .data );
@@ -738,7 +765,6 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
738
765
if (JsonbType (jb ) == jbvArray )
739
766
{
740
767
JsonbValue * v ;
741
- bool hasNext ;
742
768
int i ;
743
769
744
770
hasNext = jspGetNext (jsp , & elem );
@@ -780,7 +806,6 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
780
806
JsonbIterator * it ;
781
807
int32 r ;
782
808
JsonbValue v ;
783
- bool hasNext ;
784
809
785
810
hasNext = jspGetNext (jsp , & elem );
786
811
it = JsonbIteratorInit (jb -> val .binary .data );
@@ -907,6 +932,9 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
907
932
return res ;
908
933
}
909
934
935
+ /*
936
+ * Public interface to jsonpath executor
937
+ */
910
938
JsonPathExecResult
911
939
executeJsonPath (JsonPath * path , List * vars , Jsonb * json , List * * foundJson )
912
940
{
@@ -942,6 +970,9 @@ returnNULL(void *arg, bool *isNull)
942
970
return Int32GetDatum (0 );
943
971
}
944
972
973
+ /*
974
+ * Convert jsonb object into list of vars for executor
975
+ */
945
976
static List *
946
977
makePassingVars (Jsonb * jb )
947
978
{
0 commit comments