Skip to content

Commit d57758a

Browse files
author
Nikita Glukhov
committed
fixup! add array/object length as @#
1 parent c624498 commit d57758a

File tree

3 files changed

+115
-106
lines changed

3 files changed

+115
-106
lines changed

expected/jsquery.out

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,30 @@ select '{"a":[1,2]}' @@ '@# = 1'::jsquery;
13911391
t
13921392
(1 row)
13931393

1394+
select '[]' @@ '@# is numeric'::jsquery;
1395+
?column?
1396+
----------
1397+
t
1398+
(1 row)
1399+
1400+
select '{}' @@ '@# is numeric'::jsquery;
1401+
?column?
1402+
----------
1403+
t
1404+
(1 row)
1405+
1406+
select '0' @@ '@# is numeric'::jsquery;
1407+
?column?
1408+
----------
1409+
f
1410+
(1 row)
1411+
1412+
select '0' @@ '@# = 1'::jsquery;
1413+
?column?
1414+
----------
1415+
f
1416+
(1 row)
1417+
13941418
--ALL
13951419
select 'a.*: = 4'::jsquery;
13961420
jsquery

jsquery_op.c

Lines changed: 87 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
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

3434
static int
3535
compareNumeric(Numeric a, Numeric b)
@@ -59,6 +59,43 @@ JsonbType(JsonbValue *jb)
5959
return 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+
6299
static bool
63100
recursiveAny(JsQueryItem *jsq, JsonbValue *jb)
64101
{
@@ -81,7 +118,7 @@ recursiveAny(JsQueryItem *jsq, JsonbValue *jb)
81118

82119
if (r == WJB_VALUE || r == WJB_ELEM)
83120
{
84-
res = recursiveExecute(jsq, &v, NULL);
121+
res = recursiveExecute(jsq, &v);
85122

86123
if (res == false && v.type == jbvBinary)
87124
res = recursiveAny(jsq, &v);
@@ -113,7 +150,7 @@ recursiveAll(JsQueryItem *jsq, JsonbValue *jb)
113150

114151
if (r == WJB_VALUE || r == WJB_ELEM)
115152
{
116-
if ((res = recursiveExecute(jsq, &v, NULL)) == true)
153+
if ((res = recursiveExecute(jsq, &v)) == true)
117154
{
118155
if (v.type == jbvBinary)
119156
res = recursiveAll(jsq, &v);
@@ -312,7 +349,7 @@ makeCompare(JsQueryItem *jsq, int32 op, JsonbValue *jb)
312349
}
313350

314351
static bool
315-
executeExpr(JsQueryItem *jsq, int32 op, JsonbValue *jb, JsQueryItem *jsqLeftArg)
352+
executeExpr(JsQueryItem *jsq, int32 op, JsonbValue *jb)
316353
{
317354
bool res = false;
318355
/*
@@ -322,100 +359,37 @@ executeExpr(JsQueryItem *jsq, int32 op, JsonbValue *jb, JsQueryItem *jsqLeftArg)
322359
Assert(jsq->type == jqiAny || jsq->type == jqiString || jsq->type == jqiNumeric ||
323360
jsq->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);
345367
else
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

414388
return res;
415389
}
416390

417391
static bool
418-
recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
392+
recursiveExecute(JsQueryItem *jsq, JsonbValue *jb)
419393
{
420394
JsQueryItem elem;
421395
bool res = false;
@@ -425,25 +399,25 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
425399
switch(jsq->type) {
426400
case jqiAnd:
427401
jsqGetLeftArg(jsq, &elem);
428-
res = recursiveExecute(&elem, jb, jsqLeftArg);
402+
res = recursiveExecute(&elem, jb);
429403
if (res == true)
430404
{
431405
jsqGetRightArg(jsq, &elem);
432-
res = recursiveExecute(&elem, jb, jsqLeftArg);
406+
res = recursiveExecute(&elem, jb);
433407
}
434408
break;
435409
case jqiOr:
436410
jsqGetLeftArg(jsq, &elem);
437-
res = recursiveExecute(&elem, jb, jsqLeftArg);
411+
res = recursiveExecute(&elem, jb);
438412
if (res == false)
439413
{
440414
jsqGetRightArg(jsq, &elem);
441-
res = recursiveExecute(&elem, jb, jsqLeftArg);
415+
res = recursiveExecute(&elem, jb);
442416
}
443417
break;
444418
case jqiNot:
445419
jsqGetArg(jsq, &elem);
446-
res = !recursiveExecute(&elem, jb, jsqLeftArg);
420+
res = !recursiveExecute(&elem, jb);
447421
break;
448422
case jqiKey:
449423
if (JsonbType(jb) == jbvObject) {
@@ -457,7 +431,7 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
457431
if (v != NULL)
458432
{
459433
jsqGetNext(jsq, &elem);
460-
res = recursiveExecute(&elem, v, NULL);
434+
res = recursiveExecute(&elem, v);
461435
pfree(v);
462436
}
463437
}
@@ -480,23 +454,23 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
480454
r = JsonbIteratorNext(&it, &v, true);
481455
Assert(r == WJB_ELEM);
482456

483-
res = recursiveExecute(&elem, &v, jsqLeftArg);
457+
res = recursiveExecute(&elem, &v);
484458
}
485459
else
486460
{
487-
res = recursiveExecute(&elem, jb, jsqLeftArg);
461+
res = recursiveExecute(&elem, jb);
488462
}
489463
break;
490464
case jqiAny:
491465
jsqGetNext(jsq, &elem);
492-
if (recursiveExecute(&elem, jb, NULL))
466+
if (recursiveExecute(&elem, jb))
493467
res = true;
494468
else if (jb->type == jbvBinary)
495469
res = recursiveAny(&elem, jb);
496470
break;
497471
case jqiAll:
498472
jsqGetNext(jsq, &elem);
499-
if ((res = recursiveExecute(&elem, jb, NULL)) == true)
473+
if ((res = recursiveExecute(&elem, jb)) == true)
500474
{
501475
if (jb->type == jbvBinary)
502476
res = recursiveAll(&elem, jb);
@@ -520,7 +494,7 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
520494
{
521495
if (r == WJB_ELEM)
522496
{
523-
res = recursiveExecute(&elem, &v, NULL);
497+
res = recursiveExecute(&elem, &v);
524498

525499
if (jsq->type == jqiAnyArray)
526500
{
@@ -554,7 +528,7 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
554528
{
555529
if (r == WJB_VALUE)
556530
{
557-
res = recursiveExecute(&elem, &v, NULL);
531+
res = recursiveExecute(&elem, &v);
558532

559533
if (jsq->type == jqiAnyKey)
560534
{
@@ -580,12 +554,19 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg)
580554
case jqiContained:
581555
case jqiOverlap:
582556
jsqGetArg(jsq, &elem);
583-
res = executeExpr(&elem, jsq->type, jb, jsqLeftArg);
557+
res = executeExpr(&elem, jsq->type, jb);
584558
break;
585559
case jqiLength:
560+
{
561+
JsonbValue size;
586562
jsqGetNext(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+
}
588568
break;
569+
}
589570
case jqiIs:
590571
if (JsonbType(jb) == jbvScalar)
591572
{
@@ -631,7 +612,7 @@ jsquery_json_exec(PG_FUNCTION_ARGS)
631612

632613
jsqInit(&jsq, jq);
633614

634-
res = recursiveExecute(&jsq, &jbv, NULL);
615+
res = recursiveExecute(&jsq, &jbv);
635616

636617
PG_FREE_IF_COPY(jq, 0);
637618
PG_FREE_IF_COPY_JSONB(jb, 1);
@@ -653,7 +634,7 @@ json_jsquery_exec(PG_FUNCTION_ARGS)
653634

654635
jsqInit(&jsq, jq);
655636

656-
res = recursiveExecute(&jsq, &jbv, NULL);
637+
res = recursiveExecute(&jsq, &jbv);
657638

658639
PG_FREE_IF_COPY_JSONB(jb, 0);
659640
PG_FREE_IF_COPY(jq, 1);

sql/jsquery.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,10 @@ select '{"a":[1,2]}' @@ '%.@# in (2, 4)'::jsquery;
283283
select '{"a":[1,2]}' @@ '*.@# in (2, 4)'::jsquery;
284284
select '{"a":[1,2]}' @@ '*.@# ($ = 4 or $ = 2)'::jsquery;
285285
select '{"a":[1,2]}' @@ '@# = 1'::jsquery;
286+
select '[]' @@ '@# is numeric'::jsquery;
287+
select '{}' @@ '@# is numeric'::jsquery;
288+
select '0' @@ '@# is numeric'::jsquery;
289+
select '0' @@ '@# = 1'::jsquery;
286290

287291
--ALL
288292
select 'a.*: = 4'::jsquery;

0 commit comments

Comments
 (0)