Skip to content

Commit 6f2db95

Browse files
author
Nikita Glukhov
committed
Add custom toaster encoders to jsonb
1 parent f649da1 commit 6f2db95

File tree

4 files changed

+64
-27
lines changed

4 files changed

+64
-27
lines changed

src/backend/utils/adt/json_generic.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ JsonExpand(Json *tmp, Datum value, bool freeValue, JsonContainerOps *ops)
8181
json->root.ops = ops;
8282
json->root.size = -1;
8383
json->root.type = jbvBinary;
84+
json->root.toasterid = InvalidOid;
8485
json->is_json = false;
8586

8687
memset(json->root._data, 0, ops->data_size);
@@ -159,6 +160,21 @@ JsonValueToJson(JsonValue *val)
159160
}
160161
}
161162

163+
Datum
164+
JsonbValueToOrigJsonbDatum(JsonValue *val, Json *orig_json)
165+
{
166+
if (val->type != jbvBinary &&
167+
JsonRoot(orig_json)->ops->encode)
168+
{
169+
void *res = JsonRoot(orig_json)->ops->encode(val, &jsonbContainerOps);
170+
171+
if (res)
172+
return PointerGetDatum(res);
173+
}
174+
175+
return JsonValueToJsonbDatum(val);
176+
}
177+
162178
JsonContainer *
163179
JsonCopyFlat(JsonContainer *jc)
164180
{

src/backend/utils/adt/jsonb_util.c

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ static void fillJsonbValue(const JsonbContainerHeader *container, int index,
8484
char *base_addr, uint32 offset,
8585
JsonbValue *result);
8686
static int compareJsonbScalarValue(const JsonbValue *a, const JsonbValue *b);
87-
static void *convertToJsonb(const JsonbValue *val, JsonValueEncoder encoder);
8887
static void convertJsonbValue(StringInfo buffer, JEntry *header, const JsonbValue *val, int level);
8988
static void convertJsonbArray(StringInfo buffer, JEntry *header, const JsonbValue *val, int level);
9089
static void convertJsonbObject(StringInfo buffer, JEntry *header, const JsonbValue *val, int level);
@@ -121,6 +120,18 @@ JsonContainerFlatten(JsonContainer *jc, JsonValueEncoder encoder,
121120
{
122121
JsonbValue jbv;
123122

123+
if (jc->ops->encode)
124+
{
125+
JsonbValue bin;
126+
void *res;
127+
128+
JsonValueInitBinary(&bin, jc);
129+
res = jc->ops->encode(&bin, ops);
130+
131+
if (res)
132+
return res;
133+
}
134+
124135
if (jc->ops == ops)
125136
{
126137
int size = jc->len;
@@ -137,7 +148,7 @@ JsonContainerFlatten(JsonContainer *jc, JsonValueEncoder encoder,
137148
else
138149
binary = JsonValueInitBinary(&jbv, jc);
139150

140-
return convertToJsonb(binary, encoder);
151+
return JsonEncode(binary, encoder, NULL);
141152
}
142153

143154
/*
@@ -169,7 +180,7 @@ JsonValueFlatten(const JsonValue *val, JsonValueEncoder encoder,
169180
Assert(val->type == jbvObject || val->type == jbvArray);
170181
}
171182

172-
return convertToJsonb(val, encoder);
183+
return JsonEncode(val, encoder, NULL);
173184
}
174185

175186
/*
@@ -1714,41 +1725,36 @@ padBufferToInt(StringInfo buffer)
17141725
}
17151726

17161727
void
1717-
JsonbEncode(StringInfoData *buffer, const JsonbValue *val)
1728+
JsonbEncode(StringInfoData *buffer, const JsonbValue *val, void *cxt)
17181729
{
17191730
JEntry jentry;
17201731

1732+
/* Make room for the varlena header */
1733+
reserveFromBuffer(buffer, VARHDRSZ);
17211734
convertJsonbValue(buffer, &jentry, val, 0);
1735+
SET_VARSIZE(buffer->data, buffer->len);
17221736
}
17231737

17241738
/*
17251739
* Given a JsonbValue, convert to Jsonb. The result is palloc'd.
17261740
*/
1727-
static void *
1728-
convertToJsonb(const JsonbValue *val, JsonValueEncoder encoder)
1741+
void *
1742+
JsonEncode(const JsonbValue *val, JsonValueEncoder encoder, void *cxt)
17291743
{
17301744
StringInfoData buffer;
1731-
void *res;
17321745

17331746
/* Allocate an output buffer. It will be enlarged as needed */
17341747
initStringInfo(&buffer);
17351748

1736-
/* Make room for the varlena header */
1737-
reserveFromBuffer(&buffer, VARHDRSZ);
1738-
1739-
(*encoder)(&buffer, val);
1749+
(*encoder)(&buffer, val, cxt);
17401750

17411751
/*
17421752
* Note: the JEntry of the root is discarded. Therefore the root
17431753
* JsonbContainer struct must contain enough information to tell what kind
17441754
* of value it is.
17451755
*/
17461756

1747-
res = (void *) buffer.data;
1748-
1749-
SET_VARSIZE(res, buffer.len);
1750-
1751-
return res;
1757+
return buffer.data;
17521758
}
17531759

17541760
/*
@@ -2204,6 +2210,7 @@ jsonbInitContainer(JsonContainerData *jc, JsonbContainerHeader *jbc, int len)
22042210
jc->ops = &jsonbContainerOps;
22052211
JsonContainerDataPtr(jc) = jbc;
22062212
jc->len = len;
2213+
jc->toasterid = InvalidOid;
22072214
jc->size = jbc->header & JBC_CMASK;
22082215
jc->type = jbc->header & JBC_FOBJECT ? jbvObject :
22092216
jbc->header & JBC_FSCALAR ? jbvArray | jbvScalar :
@@ -2230,4 +2237,5 @@ jsonbContainerOps =
22302237
JsonbToCStringRaw,
22312238
JsonCopyFlat,
22322239
NULL,
2240+
NULL
22332241
};

src/backend/utils/adt/jsonfuncs.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,7 +1631,7 @@ jsonb_set_element(Jsonb *jb, Datum *path, int path_len,
16311631

16321632
pfree(path_nulls);
16331633

1634-
PG_RETURN_JSONB_VALUE_P(res);
1634+
PG_RETURN_DATUM(JsonbValueToOrigJsonbDatum(res, jb));
16351635
}
16361636

16371637
static void
@@ -4209,7 +4209,7 @@ jsonb_strip_nulls(PG_FUNCTION_ARGS)
42094209

42104210
Assert(res != NULL);
42114211

4212-
PG_RETURN_JSONB_VALUE_P(res);
4212+
PG_RETURN_DATUM(JsonbValueToOrigJsonbDatum(res, jb));
42134213
}
42144214

42154215
/*
@@ -4264,7 +4264,7 @@ jsonb_concat(PG_FUNCTION_ARGS)
42644264

42654265
Assert(res != NULL);
42664266

4267-
PG_RETURN_JSONB_VALUE_P(res);
4267+
PG_RETURN_DATUM(JsonbValueToOrigJsonbDatum(res, jb1));
42684268
}
42694269

42704270

@@ -4318,7 +4318,7 @@ jsonb_delete(PG_FUNCTION_ARGS)
43184318

43194319
Assert(res != NULL);
43204320

4321-
PG_RETURN_JSONB_VALUE_P(res);
4321+
PG_RETURN_DATUM(JsonbValueToOrigJsonbDatum(res, in));
43224322
}
43234323

43244324
/*
@@ -4403,7 +4403,7 @@ jsonb_delete_array(PG_FUNCTION_ARGS)
44034403

44044404
Assert(res != NULL);
44054405

4406-
PG_RETURN_JSONB_VALUE_P(res);
4406+
PG_RETURN_DATUM(JsonbValueToOrigJsonbDatum(res, in));
44074407
}
44084408

44094409
/*
@@ -4471,7 +4471,16 @@ jsonb_delete_idx(PG_FUNCTION_ARGS)
44714471

44724472
Assert(res != NULL);
44734473

4474-
PG_RETURN_JSONB_VALUE_P(res);
4474+
if (idx < 0 && -idx <= res->val.array.nElems)
4475+
{
4476+
idx = res->val.array.nElems + idx;
4477+
res->val.array.nElems--;
4478+
memmove(&res->val.array.elems[idx],
4479+
&res->val.array.elems[idx + 1],
4480+
sizeof(JsonValue) * (res->val.array.nElems - idx));
4481+
}
4482+
4483+
PG_RETURN_DATUM(JsonbValueToOrigJsonbDatum(res, in));
44754484
}
44764485

44774486
/*
@@ -4519,7 +4528,7 @@ jsonb_set(PG_FUNCTION_ARGS)
45194528

45204529
Assert(res != NULL);
45214530

4522-
PG_RETURN_JSONB_VALUE_P(res);
4531+
PG_RETURN_DATUM(JsonbValueToOrigJsonbDatum(res, in));
45234532
}
45244533

45254534

@@ -4630,7 +4639,7 @@ jsonb_delete_path(PG_FUNCTION_ARGS)
46304639

46314640
Assert(res != NULL);
46324641

4633-
PG_RETURN_JSONB_VALUE_P(res);
4642+
PG_RETURN_DATUM(JsonbValueToOrigJsonbDatum(res, in));
46344643
}
46354644

46364645
/*
@@ -4675,7 +4684,7 @@ jsonb_insert(PG_FUNCTION_ARGS)
46754684

46764685
Assert(res != NULL);
46774686

4678-
PG_RETURN_JSONB_VALUE_P(res);
4687+
PG_RETURN_DATUM(JsonbValueToOrigJsonbDatum(res, in));
46794688
}
46804689

46814690
/*

src/include/utils/json_generic.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ typedef struct JsonContainerData
2929
int len;
3030
int size;
3131
JsonbValueType type;
32+
Oid toasterid;
3233
void *_data[FLEXIBLE_ARRAY_MEMBER];
3334
} JsonContainerData;
3435

@@ -63,6 +64,7 @@ struct JsonContainerOps
6364
int estimated_len);
6465
JsonContainer *(*copy)(JsonContainer *jc);
6566
void (*free)(JsonContainer *jc);
67+
void *(*encode)(JsonValue *jc, JsonContainerOps *ops);
6668
};
6769

6870
typedef struct CompressedObject
@@ -248,6 +250,7 @@ JsonValueInitBinary(JsonValue *val, JsonContainer *cont)
248250
}
249251

250252
extern Json *JsonValueToJson(JsonValue *val);
253+
extern Datum JsonbValueToOrigJsonbDatum(JsonValue *val, Json *origjs);
251254
extern JsonValue *JsonToJsonValue(Json *json, JsonValue *jv);
252255
extern JsonValue *JsonValueUnpackBinary(const JsonValue *jbv);
253256
extern JsonValue *JsonValueCopy(JsonValue *res, const JsonValue *val);
@@ -285,21 +288,22 @@ extern char *JsonbToCStringIndent(StringInfo out, JsonContainer *in,
285288
extern bool JsonValueScalarEquals(const JsonValue *aScalar,
286289
const JsonValue *bScalar);
287290

288-
typedef void (*JsonValueEncoder)(StringInfo, const JsonValue *);
291+
typedef void (*JsonValueEncoder)(StringInfo, const JsonValue *, void *cxt);
289292

290293
extern void *JsonContainerFlatten(JsonContainer *jc, JsonValueEncoder encoder,
291294
JsonContainerOps *ops, const JsonValue *binary);
292295

293296
extern void *JsonValueFlatten(const JsonValue *val, JsonValueEncoder encoder,
294297
JsonContainerOps *ops);
298+
extern void *JsonEncode(const JsonbValue *val, JsonValueEncoder encoder, void *cxt);
295299

296300
static inline void *
297301
JsonFlatten(Json *json, JsonValueEncoder encoder, JsonContainerOps *ops)
298302
{
299303
return JsonContainerFlatten(JsonRoot(json), encoder, ops, NULL);
300304
}
301305

302-
extern void JsonbEncode(StringInfo, const JsonValue *);
306+
extern void JsonbEncode(StringInfo, const JsonValue *, void *cxt);
303307

304308
#define JsonValueToJsonb(val) \
305309
JsonValueFlatten(val, JsonbEncode, &jsonbContainerOps)

0 commit comments

Comments
 (0)