2929
3030#include "jsquery.h"
3131
32- static bool recursiveExecute (JsQueryItem * jsq ,JsonbValue * jb , JsQueryItem * jsqLeftArg );
32+ static bool recursiveExecute (JsQueryItem * jsq ,JsonbValue * jb );
3333
3434static int
3535compareNumeric (Numeric a ,Numeric b )
@@ -59,6 +59,43 @@ JsonbType(JsonbValue *jb)
5959return type ;
6060}
6161
62+ static JsonbValue *
63+ JsonbSize (JsonbValue * jb ,JsonbValue * size )
64+ {
65+ JsonbValue v ;
66+ JsonbIterator * it ;
67+ JsonbIteratorToken r ;
68+ int32 length ;
69+ int type = JsonbType (jb );
70+
71+ if (type != jbvArray && type != jbvObject )
72+ return NULL ;
73+
74+ Assert (jb -> type == jbvBinary );
75+
76+ it = JsonbIteratorInit (jb -> val .binary .data );
77+ r = JsonbIteratorNext (& it ,& v , true);
78+ Assert (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT );
79+
80+ if (r == WJB_BEGIN_ARRAY )
81+ {
82+ length = v .val .array .nElems ;
83+ if (length < 0 )
84+ length = JsonGetArraySize (jb -> val .binary .data );
85+ }
86+ else
87+ {
88+ length = v .val .object .nPairs ;
89+ if (length < 0 )
90+ length = JsonGetObjectSize (jb -> val .binary .data );
91+ }
92+
93+ size -> type = jbvNumeric ;
94+ size -> val .numeric = DatumGetNumeric (DirectFunctionCall1 (
95+ int4_numeric ,Int32GetDatum (length )));
96+ return size ;
97+ }
98+
6299static bool
63100recursiveAny (JsQueryItem * jsq ,JsonbValue * jb )
64101{
@@ -81,7 +118,7 @@ recursiveAny(JsQueryItem *jsq, JsonbValue *jb)
81118
82119if (r == WJB_VALUE || r == WJB_ELEM )
83120{
84- res = recursiveExecute (jsq ,& v , NULL );
121+ res = recursiveExecute (jsq ,& v );
85122
86123if (res == false&& v .type == jbvBinary )
87124res = recursiveAny (jsq ,& v );
@@ -113,7 +150,7 @@ recursiveAll(JsQueryItem *jsq, JsonbValue *jb)
113150
114151if (r == WJB_VALUE || r == WJB_ELEM )
115152{
116- if ((res = recursiveExecute (jsq ,& v , NULL ))== true)
153+ if ((res = recursiveExecute (jsq ,& v ))== true)
117154{
118155if (v .type == jbvBinary )
119156res = recursiveAll (jsq ,& v );
@@ -312,7 +349,7 @@ makeCompare(JsQueryItem *jsq, int32 op, JsonbValue *jb)
312349}
313350
314351static bool
315- executeExpr (JsQueryItem * jsq ,int32 op ,JsonbValue * jb , JsQueryItem * jsqLeftArg )
352+ executeExpr (JsQueryItem * jsq ,int32 op ,JsonbValue * jb )
316353{
317354bool res = false;
318355/*
@@ -322,100 +359,37 @@ executeExpr(JsQueryItem *jsq, int32 op, JsonbValue *jb, JsQueryItem *jsqLeftArg)
322359Assert (jsq -> type == jqiAny || jsq -> type == jqiString || jsq -> type == jqiNumeric ||
323360jsq -> type == jqiNull || jsq -> type == jqiBool || jsq -> type == jqiArray );
324361
325- if ( jsqLeftArg && jsqLeftArg -> type == jqiLength )
362+ switch ( op )
326363{
327- if (JsonbType (jb )== jbvArray || JsonbType (jb )== jbvObject )
328- {
329- int32 length ;
330- JsonbIterator * it ;
331- JsonbValue v ;
332- int r ;
333-
334- it = JsonbIteratorInit (jb -> val .binary .data );
335- r = JsonbIteratorNext (& it ,& v , true);
336- Assert (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT );
337-
338- if (r == WJB_BEGIN_ARRAY )
339- {
340- length = v .val .array .nElems ;
341-
342- if (length < 0 )
343- length = JsonGetArraySize (jb -> val .binary .data );
344- }
364+ case jqiEqual :
365+ if (JsonbType (jb )== jbvArray && jsq -> type == jqiArray )
366+ res = checkArrayEquality (jsq ,jb );
345367else
346- {
347- length = v .val .object .nPairs ;
348-
349- if (length < 0 )
350- {
351- length = 0 ;
352-
353- while ((r = JsonbIteratorNext (& it ,& v , true))!= WJB_DONE )
354- {
355- if (r == WJB_KEY )
356- length ++ ;
357- }
358- }
359- }
360-
361- v .type = jbvNumeric ;
362- v .val .numeric = DatumGetNumeric (DirectFunctionCall1 (int4_numeric ,Int32GetDatum (length )));
363-
364- switch (op )
365- {
366- case jqiEqual :
367- case jqiLess :
368- case jqiGreater :
369- case jqiLessOrEqual :
370- case jqiGreaterOrEqual :
371- res = makeCompare (jsq ,op ,& v );
372- break ;
373- case jqiIn :
374- res = checkScalarIn (jsq ,& v );
375- break ;
376- case jqiOverlap :
377- case jqiContains :
378- case jqiContained :
379- break ;
380- default :
381- elog (ERROR ,"Unknown operation" );
382- }
383- }
384- }
385- else
386- {
387- switch (op )
388- {
389- case jqiEqual :
390- if (JsonbType (jb )== jbvArray && jsq -> type == jqiArray )
391- res = checkArrayEquality (jsq ,jb );
392- else
393- res = checkScalarEquality (jsq ,jb );
394- break ;
395- case jqiIn :
396- res = checkScalarIn (jsq ,jb );
397- break ;
398- case jqiOverlap :
399- case jqiContains :
400- case jqiContained :
401- res = executeArrayOp (jsq ,op ,jb );
402- break ;
403- case jqiLess :
404- case jqiGreater :
405- case jqiLessOrEqual :
406- case jqiGreaterOrEqual :
407- res = makeCompare (jsq ,op ,jb );
408- break ;
409- default :
410- elog (ERROR ,"Unknown operation" );
411- }
368+ res = checkScalarEquality (jsq ,jb );
369+ break ;
370+ case jqiIn :
371+ res = checkScalarIn (jsq ,jb );
372+ break ;
373+ case jqiOverlap :
374+ case jqiContains :
375+ case jqiContained :
376+ res = executeArrayOp (jsq ,op ,jb );
377+ break ;
378+ case jqiLess :
379+ case jqiGreater :
380+ case jqiLessOrEqual :
381+ case jqiGreaterOrEqual :
382+ res = makeCompare (jsq ,op ,jb );
383+ break ;
384+ default :
385+ elog (ERROR ,"Unknown operation" );
412386}
413387
414388return res ;
415389}
416390
417391static bool
418- recursiveExecute (JsQueryItem * jsq ,JsonbValue * jb , JsQueryItem * jsqLeftArg )
392+ recursiveExecute (JsQueryItem * jsq ,JsonbValue * jb )
419393{
420394JsQueryItem elem ;
421395bool res = false;
@@ -425,25 +399,25 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
425399switch (jsq -> type ) {
426400case jqiAnd :
427401jsqGetLeftArg (jsq ,& elem );
428- res = recursiveExecute (& elem ,jb , jsqLeftArg );
402+ res = recursiveExecute (& elem ,jb );
429403if (res == true)
430404{
431405jsqGetRightArg (jsq ,& elem );
432- res = recursiveExecute (& elem ,jb , jsqLeftArg );
406+ res = recursiveExecute (& elem ,jb );
433407}
434408break ;
435409case jqiOr :
436410jsqGetLeftArg (jsq ,& elem );
437- res = recursiveExecute (& elem ,jb , jsqLeftArg );
411+ res = recursiveExecute (& elem ,jb );
438412if (res == false)
439413{
440414jsqGetRightArg (jsq ,& elem );
441- res = recursiveExecute (& elem ,jb , jsqLeftArg );
415+ res = recursiveExecute (& elem ,jb );
442416}
443417break ;
444418case jqiNot :
445419jsqGetArg (jsq ,& elem );
446- res = !recursiveExecute (& elem ,jb , jsqLeftArg );
420+ res = !recursiveExecute (& elem ,jb );
447421break ;
448422case jqiKey :
449423if (JsonbType (jb )== jbvObject ) {
@@ -457,7 +431,7 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
457431if (v != NULL )
458432{
459433jsqGetNext (jsq ,& elem );
460- res = recursiveExecute (& elem ,v , NULL );
434+ res = recursiveExecute (& elem ,v );
461435pfree (v );
462436}
463437}
@@ -480,23 +454,23 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
480454r = JsonbIteratorNext (& it ,& v , true);
481455Assert (r == WJB_ELEM );
482456
483- res = recursiveExecute (& elem ,& v , jsqLeftArg );
457+ res = recursiveExecute (& elem ,& v );
484458}
485459else
486460{
487- res = recursiveExecute (& elem ,jb , jsqLeftArg );
461+ res = recursiveExecute (& elem ,jb );
488462}
489463break ;
490464case jqiAny :
491465jsqGetNext (jsq ,& elem );
492- if (recursiveExecute (& elem ,jb , NULL ))
466+ if (recursiveExecute (& elem ,jb ))
493467res = true;
494468else if (jb -> type == jbvBinary )
495469res = recursiveAny (& elem ,jb );
496470break ;
497471case jqiAll :
498472jsqGetNext (jsq ,& elem );
499- if ((res = recursiveExecute (& elem ,jb , NULL ))== true)
473+ if ((res = recursiveExecute (& elem ,jb ))== true)
500474{
501475if (jb -> type == jbvBinary )
502476res = recursiveAll (& elem ,jb );
@@ -520,7 +494,7 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
520494{
521495if (r == WJB_ELEM )
522496{
523- res = recursiveExecute (& elem ,& v , NULL );
497+ res = recursiveExecute (& elem ,& v );
524498
525499if (jsq -> type == jqiAnyArray )
526500{
@@ -554,7 +528,7 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
554528{
555529if (r == WJB_VALUE )
556530{
557- res = recursiveExecute (& elem ,& v , NULL );
531+ res = recursiveExecute (& elem ,& v );
558532
559533if (jsq -> type == jqiAnyKey )
560534{
@@ -580,12 +554,19 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
580554case jqiContained :
581555case jqiOverlap :
582556jsqGetArg (jsq ,& elem );
583- res = executeExpr (& elem ,jsq -> type ,jb , jsqLeftArg );
557+ res = executeExpr (& elem ,jsq -> type ,jb );
584558break ;
585559case jqiLength :
560+ {
561+ JsonbValue size ;
586562jsqGetNext (jsq ,& elem );
587- res = recursiveExecute (& elem ,jb ,jsq );
563+ if (JsonbSize (jb ,& size ))
564+ {
565+ res = recursiveExecute (& elem ,& size );
566+ pfree (size .val .numeric );
567+ }
588568break ;
569+ }
589570case jqiIs :
590571if (JsonbType (jb )== jbvScalar )
591572{
@@ -631,7 +612,7 @@ jsquery_json_exec(PG_FUNCTION_ARGS)
631612
632613jsqInit (& jsq ,jq );
633614
634- res = recursiveExecute (& jsq ,& jbv , NULL );
615+ res = recursiveExecute (& jsq ,& jbv );
635616
636617PG_FREE_IF_COPY (jq ,0 );
637618PG_FREE_IF_COPY_JSONB (jb ,1 );
@@ -653,7 +634,7 @@ json_jsquery_exec(PG_FUNCTION_ARGS)
653634
654635jsqInit (& jsq ,jq );
655636
656- res = recursiveExecute (& jsq ,& jbv , NULL );
637+ res = recursiveExecute (& jsq ,& jbv );
657638
658639PG_FREE_IF_COPY_JSONB (jb ,0 );
659640PG_FREE_IF_COPY (jq ,1 );