Skip to content

Commit b0923d1

Browse files
author
Nikita Glukhov
committed
Add support of json object/arrays with unknown size
1 parent e47e31c commit b0923d1

File tree

3 files changed

+48
-12
lines changed

3 files changed

+48
-12
lines changed

src/backend/utils/adt/jsonb_gin.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,9 @@ gin_extract_jsonb(PG_FUNCTION_ARGS)
244244
PG_RETURN_POINTER(NULL);
245245
}
246246

247+
if (total < 0)
248+
total = 8;
249+
247250
/* Otherwise, use 2 * root count as initial estimate of result size */
248251
init_gin_entries(&entries, 2 * total);
249252

@@ -1108,6 +1111,9 @@ gin_extract_jsonb_path(PG_FUNCTION_ARGS)
11081111
PG_RETURN_POINTER(NULL);
11091112
}
11101113

1114+
if (total < 0)
1115+
total = 8;
1116+
11111117
/* Otherwise, use 2 * root count as initial estimate of result size */
11121118
init_gin_entries(&entries, 2 * total);
11131119

src/backend/utils/adt/jsonfuncs.c

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,8 @@ jsonb_object_keys(PG_FUNCTION_ARGS)
562562
state = palloc(sizeof(OkeysState));
563563

564564
state->result_size = JB_ROOT_COUNT(jb);
565+
if (state->result_size < 0)
566+
state->result_size = 8;
565567
state->result_count = 0;
566568
state->sent_count = 0;
567569
state->result = palloc(state->result_size * sizeof(char *));
@@ -579,6 +581,12 @@ jsonb_object_keys(PG_FUNCTION_ARGS)
579581
cstr = palloc(v.val.string.len + 1 * sizeof(char));
580582
memcpy(cstr, v.val.string.val, v.val.string.len);
581583
cstr[v.val.string.len] = '\0';
584+
if (state->result_count >= state->result_size)
585+
{
586+
state->result_size *= 2;
587+
state->result = repalloc(state->result, state->result_size *
588+
sizeof(char *));
589+
}
582590
state->result[state->result_count++] = cstr;
583591
}
584592
}
@@ -906,7 +914,9 @@ jsonb_array_element(PG_FUNCTION_ARGS)
906914
/* Handle negative subscript */
907915
if (element < 0)
908916
{
909-
uint32 nelements = JB_ROOT_COUNT(jb);
917+
int nelements = JB_ROOT_COUNT(jb);
918+
if (nelements < 0)
919+
nelements = JsonGetArraySize(JsonRoot(jb));
910920

911921
if (-element > nelements)
912922
PG_RETURN_NULL();
@@ -950,6 +960,8 @@ jsonb_array_element_text(PG_FUNCTION_ARGS)
950960
if (element < 0)
951961
{
952962
uint32 nelements = JB_ROOT_COUNT(jb);
963+
if (nelements < 0)
964+
nelements = JsonGetArraySize(JsonRoot(jb));
953965

954966
if (-element > nelements)
955967
PG_RETURN_NULL();
@@ -1685,7 +1697,8 @@ jsonb_array_length(PG_FUNCTION_ARGS)
16851697
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
16861698
errmsg("cannot get array length of a non-array")));
16871699

1688-
PG_RETURN_INT32(JB_ROOT_COUNT(jb));
1700+
PG_RETURN_INT32(JB_ROOT_COUNT(jb) >= 0 ? JB_ROOT_COUNT(jb)
1701+
: JsonGetArraySize(JsonRoot(jb)));
16891702
}
16901703

16911704
/*
@@ -4437,16 +4450,19 @@ jsonb_delete_idx(PG_FUNCTION_ARGS)
44374450
Assert(r == WJB_BEGIN_ARRAY);
44384451
n = v.val.array.nElems;
44394452

4440-
if (idx < 0)
4453+
if (v.val.array.nElems >= 0)
44414454
{
4442-
if (-idx > n)
4443-
idx = n;
4444-
else
4445-
idx = n + idx;
4446-
}
4455+
if (idx < 0)
4456+
{
4457+
if (-idx > n)
4458+
idx = n;
4459+
else
4460+
idx = n + idx;
4461+
}
44474462

4448-
if (idx >= n)
4449-
PG_RETURN_JSONB_P(in);
4463+
if (idx >= n)
4464+
PG_RETURN_JSONB_P(in);
4465+
}
44504466

44514467
pushJsonbValue(&state, r, NULL);
44524468

@@ -4463,6 +4479,15 @@ jsonb_delete_idx(PG_FUNCTION_ARGS)
44634479

44644480
Assert(res != NULL);
44654481

4482+
if (idx < 0 && -idx <= res->val.array.nElems)
4483+
{
4484+
idx = res->val.array.nElems + idx;
4485+
res->val.array.nElems--;
4486+
memmove(&res->val.array.elems[idx],
4487+
&res->val.array.elems[idx + 1],
4488+
sizeof(JsonValue) * (res->val.array.nElems - idx));
4489+
}
4490+
44664491
PG_RETURN_JSONB_P(JsonbValueToJsonb(res));
44674492
}
44684493

@@ -4814,7 +4839,8 @@ setPath(JsonbIterator **it, Datum *path_elems,
48144839
case WJB_BEGIN_ARRAY:
48154840
(void) pushJsonbValue(st, r, NULL);
48164841
setPathArray(it, path_elems, path_nulls, path_len, st, level,
4817-
newval, v.val.array.nElems, op_type);
4842+
newval, v.val.array.nElems >= 0 ? v.val.array.nElems :
4843+
JsonGetArraySize((*it)->container), op_type);
48184844
r = JsonbIteratorNext(it, &v, false);
48194845
Assert(r == WJB_END_ARRAY);
48204846
res = pushJsonbValue(st, r, NULL);

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2158,7 +2158,11 @@ JsonbArraySize(JsonbValue *jb)
21582158
JsonbContainer *jbc = jb->val.binary.data;
21592159

21602160
if (JsonContainerIsArray(jbc) && !JsonContainerIsScalar(jbc))
2161-
return JsonContainerSize(jbc);
2161+
{
2162+
int size = JsonContainerSize(jbc);
2163+
2164+
return size >= 0 ? size : JsonGetArraySize(jbc);
2165+
}
21622166
}
21632167

21642168
return -1;

0 commit comments

Comments
 (0)