Skip to content

Commit 1e2c673

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

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
@@ -567,6 +567,8 @@ jsonb_object_keys(PG_FUNCTION_ARGS)
567567
state = palloc(sizeof(OkeysState));
568568

569569
state->result_size = JB_ROOT_COUNT(jb);
570+
if (state->result_size < 0)
571+
state->result_size = 8;
570572
state->result_count = 0;
571573
state->sent_count = 0;
572574
state->result = palloc(state->result_size * sizeof(char *));
@@ -584,6 +586,12 @@ jsonb_object_keys(PG_FUNCTION_ARGS)
584586
cstr = palloc(v.val.string.len + 1 * sizeof(char));
585587
memcpy(cstr, v.val.string.val, v.val.string.len);
586588
cstr[v.val.string.len] = '\0';
589+
if (state->result_count >= state->result_size)
590+
{
591+
state->result_size *= 2;
592+
state->result = repalloc(state->result, state->result_size *
593+
sizeof(char *));
594+
}
587595
state->result[state->result_count++] = cstr;
588596
}
589597
}
@@ -900,7 +908,9 @@ jsonb_array_element(PG_FUNCTION_ARGS)
900908
/* Handle negative subscript */
901909
if (element < 0)
902910
{
903-
uint32 nelements = JB_ROOT_COUNT(jb);
911+
int nelements = JB_ROOT_COUNT(jb);
912+
if (nelements < 0)
913+
nelements = JsonGetArraySize(JsonRoot(jb));
904914

905915
if (-element > nelements)
906916
PG_RETURN_NULL();
@@ -944,6 +954,8 @@ jsonb_array_element_text(PG_FUNCTION_ARGS)
944954
if (element < 0)
945955
{
946956
uint32 nelements = JB_ROOT_COUNT(jb);
957+
if (nelements < 0)
958+
nelements = JsonGetArraySize(JsonRoot(jb));
947959

948960
if (-element > nelements)
949961
PG_RETURN_NULL();
@@ -1827,7 +1839,8 @@ jsonb_array_length(PG_FUNCTION_ARGS)
18271839
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
18281840
errmsg("cannot get array length of a non-array")));
18291841

1830-
PG_RETURN_INT32(JB_ROOT_COUNT(jb));
1842+
PG_RETURN_INT32(JB_ROOT_COUNT(jb) >= 0 ? JB_ROOT_COUNT(jb)
1843+
: JsonGetArraySize(JsonRoot(jb)));
18311844
}
18321845

18331846
/*
@@ -4536,16 +4549,19 @@ jsonb_delete_idx(PG_FUNCTION_ARGS)
45364549
Assert(r == WJB_BEGIN_ARRAY);
45374550
n = v.val.array.nElems;
45384551

4539-
if (idx < 0)
4552+
if (v.val.array.nElems >= 0)
45404553
{
4541-
if (-idx > n)
4542-
idx = n;
4543-
else
4544-
idx = n + idx;
4545-
}
4554+
if (idx < 0)
4555+
{
4556+
if (-idx > n)
4557+
idx = n;
4558+
else
4559+
idx = n + idx;
4560+
}
45464561

4547-
if (idx >= n)
4548-
PG_RETURN_JSONB_P(in);
4562+
if (idx >= n)
4563+
PG_RETURN_JSONB_P(in);
4564+
}
45494565

45504566
pushJsonbValue(&state, r, NULL);
45514567

@@ -4562,6 +4578,15 @@ jsonb_delete_idx(PG_FUNCTION_ARGS)
45624578

45634579
Assert(res != NULL);
45644580

4581+
if (idx < 0 && -idx <= res->val.array.nElems)
4582+
{
4583+
idx = res->val.array.nElems + idx;
4584+
res->val.array.nElems--;
4585+
memmove(&res->val.array.elems[idx],
4586+
&res->val.array.elems[idx + 1],
4587+
sizeof(JsonValue) * (res->val.array.nElems - idx));
4588+
}
4589+
45654590
PG_RETURN_JSONB_P(JsonbValueToJsonb(res));
45664591
}
45674592

@@ -4946,7 +4971,8 @@ setPath(JsonbIterator **it, Datum *path_elems,
49464971

49474972
(void) pushJsonbValue(st, r, NULL);
49484973
setPathArray(it, path_elems, path_nulls, path_len, st, level,
4949-
newval, v.val.array.nElems, op_type);
4974+
newval, v.val.array.nElems >= 0 ? v.val.array.nElems :
4975+
JsonGetArraySize((*it)->container), op_type);
49504976
r = JsonbIteratorNext(it, &v, false);
49514977
Assert(r == WJB_END_ARRAY);
49524978
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)