Skip to content

Commit d42f3a0

Browse files
author
Nikita Glukhov
committed
Add temporary stack-allocated expanded Jsons
1 parent a219c4a commit d42f3a0

File tree

9 files changed

+196
-79
lines changed

9 files changed

+196
-79
lines changed

src/backend/tsearch/to_tsany.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ jsonb_string_to_tsvector_byid(PG_FUNCTION_ARGS)
294294
TSVector result;
295295

296296
result = jsonb_to_tsvector_worker(cfgId, jb, jtiString);
297-
PG_FREE_IF_COPY(jb, 1);
297+
PG_FREE_IF_COPY_JSONB(jb, 1);
298298

299299
PG_RETURN_TSVECTOR(result);
300300
}
@@ -308,7 +308,7 @@ jsonb_string_to_tsvector(PG_FUNCTION_ARGS)
308308

309309
cfgId = getTSCurrentConfig(true);
310310
result = jsonb_to_tsvector_worker(cfgId, jb, jtiString);
311-
PG_FREE_IF_COPY(jb, 0);
311+
PG_FREE_IF_COPY_JSONB(jb, 0);
312312

313313
PG_RETURN_TSVECTOR(result);
314314
}
@@ -323,8 +323,8 @@ jsonb_to_tsvector_byid(PG_FUNCTION_ARGS)
323323
uint32 flags = parse_jsonb_index_flags(jbFlags);
324324

325325
result = jsonb_to_tsvector_worker(cfgId, jb, flags);
326-
PG_FREE_IF_COPY(jb, 1);
327-
PG_FREE_IF_COPY(jbFlags, 2);
326+
PG_FREE_IF_COPY_JSONB(jb, 1);
327+
PG_FREE_IF_COPY_JSONB(jbFlags, 2);
328328

329329
PG_RETURN_TSVECTOR(result);
330330
}
@@ -340,8 +340,8 @@ jsonb_to_tsvector(PG_FUNCTION_ARGS)
340340

341341
cfgId = getTSCurrentConfig(true);
342342
result = jsonb_to_tsvector_worker(cfgId, jb, flags);
343-
PG_FREE_IF_COPY(jb, 0);
344-
PG_FREE_IF_COPY(jbFlags, 1);
343+
PG_FREE_IF_COPY_JSONB(jb, 0);
344+
PG_FREE_IF_COPY_JSONB(jbFlags, 1);
345345

346346
PG_RETURN_TSVECTOR(result);
347347
}
@@ -387,7 +387,11 @@ json_string_to_tsvector_byid(PG_FUNCTION_ARGS)
387387
TSVector result;
388388

389389
result = json_to_tsvector_worker(cfgId, json, jtiString);
390+
#ifndef JSON_GENERIC
390391
PG_FREE_IF_COPY(json, 1);
392+
#else
393+
PG_FREE_IF_COPY_JSONB(json, 1);
394+
#endif
391395

392396
PG_RETURN_TSVECTOR(result);
393397
}
@@ -405,7 +409,11 @@ json_string_to_tsvector(PG_FUNCTION_ARGS)
405409

406410
cfgId = getTSCurrentConfig(true);
407411
result = json_to_tsvector_worker(cfgId, json, jtiString);
412+
#ifndef JSON_GENERIC
408413
PG_FREE_IF_COPY(json, 0);
414+
#else
415+
PG_FREE_IF_COPY_JSONB(json, 0);
416+
#endif
409417

410418
PG_RETURN_TSVECTOR(result);
411419
}
@@ -424,8 +432,12 @@ json_to_tsvector_byid(PG_FUNCTION_ARGS)
424432
uint32 flags = parse_jsonb_index_flags(jbFlags);
425433

426434
result = json_to_tsvector_worker(cfgId, json, flags);
435+
#ifndef JSON_GENERIC
427436
PG_FREE_IF_COPY(json, 1);
428-
PG_FREE_IF_COPY(jbFlags, 2);
437+
#else
438+
PG_FREE_IF_COPY_JSONB(json, 1);
439+
#endif
440+
PG_FREE_IF_COPY_JSONB(jbFlags, 2);
429441

430442
PG_RETURN_TSVECTOR(result);
431443
}
@@ -445,8 +457,12 @@ json_to_tsvector(PG_FUNCTION_ARGS)
445457

446458
cfgId = getTSCurrentConfig(true);
447459
result = json_to_tsvector_worker(cfgId, json, flags);
460+
#ifndef JSON_GENERIC
448461
PG_FREE_IF_COPY(json, 0);
449-
PG_FREE_IF_COPY(jbFlags, 1);
462+
#else
463+
PG_FREE_IF_COPY_JSONB(json, 0);
464+
#endif
465+
PG_FREE_IF_COPY_JSONB(jbFlags, 1);
450466

451467
PG_RETURN_TSVECTOR(result);
452468
}

src/backend/tsearch/wparser.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ ts_headline_jsonb_byid_opt(PG_FUNCTION_ARGS)
407407
/* flatten result to jsonb before jb freeing */
408408
res = JsonFlattenToJsonbDatum(out);
409409

410-
PG_FREE_IF_COPY(jb, 1);
410+
PG_FREE_IF_COPY_JSONB(jb, 1);
411411
PG_FREE_IF_COPY(query, 2);
412412
if (opt)
413413
PG_FREE_IF_COPY(opt, 3);
@@ -488,6 +488,7 @@ ts_headline_json_byid_opt(PG_FUNCTION_ARGS)
488488

489489
#ifndef JSON_GENERIC
490490
out = transform_json_string_values(json, state, action);
491+
PG_FREE_IF_COPY(json, 1);
491492
#else
492493
{
493494
Jsonb *jsonb = transform_jsonb_string_values(json, state, action);
@@ -496,10 +497,11 @@ ts_headline_json_byid_opt(PG_FUNCTION_ARGS)
496497
out = cstring_to_text(str);
497498

498499
pfree(str);
500+
501+
PG_FREE_IF_COPY_JSONB(json, 1);
499502
}
500503
#endif
501504

502-
PG_FREE_IF_COPY(json, 1);
503505
PG_FREE_IF_COPY(query, 2);
504506
if (opt)
505507
PG_FREE_IF_COPY(opt, 3);

src/backend/utils/adt/expandeddatum.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515
#include "postgres.h"
1616

17+
#include "utils/datum.h"
1718
#include "utils/expandeddatum.h"
1819
#include "utils/memutils.h"
1920

@@ -122,6 +123,9 @@ TransferExpandedObject(Datum d, MemoryContext new_parent)
122123
/* Assert caller gave a R/W pointer */
123124
Assert(VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)));
124125

126+
if (!eohptr->eoh_context)
127+
return datumCopy(d, false, -1);
128+
125129
/* Transfer ownership */
126130
MemoryContextSetParent(eohptr->eoh_context, new_parent);
127131

@@ -141,5 +145,8 @@ DeleteExpandedObject(Datum d)
141145
Assert(VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)));
142146

143147
/* Kill it */
144-
MemoryContextDelete(eohptr->eoh_context);
148+
if (eohptr->eoh_context)
149+
MemoryContextDelete(eohptr->eoh_context);
150+
else
151+
pfree(eohptr);
145152
}

src/backend/utils/adt/json_generic.c

Lines changed: 89 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
static JsonContainerOps jsonvContainerOps;
1818

19-
static Json *JsonExpand(Datum value, JsonContainerOps *ops);
19+
static Json *JsonExpand(Json *tmp, Datum value, bool freeValue,
20+
JsonContainerOps *ops);
21+
2022

2123
#if 0
2224
static JsonValue *
@@ -608,8 +610,7 @@ jsonWriteExtended(JsonContainer *jc, void *ptr, Size allocated_size)
608610
}
609611

610612
static Json *
611-
JsonInitExtended(const struct varlena *toasted,
612-
const struct varlena *detoasted)
613+
JsonInitExtended(Json *tmp, struct varlena *extvalue, bool freeValue)
613614
{
614615
JsonContainerOps *ops;
615616
CompressionMethodRoutine *cmr;
@@ -619,10 +620,12 @@ JsonInitExtended(const struct varlena *toasted,
619620
int len;
620621
Datum value;
621622

622-
Assert(VARATT_IS_EXTERNAL_EXTENDED(detoasted));
623+
Assert(VARATT_IS_EXTERNAL_EXTENDED(extvalue));
624+
625+
pextjs = (varatt_extended_json *) VARDATA_EXTERNAL(extvalue);
626+
memcpy(&extjs, pextjs, offsetof(varatt_extended_json, data));
623627

624-
pextjs = (varatt_extended_json *) VARDATA_EXTERNAL(detoasted);
625-
memcpy(&extjs, pextjs, offsetof(varatt_extended_json, params));
628+
totalSize = extjs.vaext.size - offsetof(varatt_extended_json, data);
626629

627630
ops = JsonContainerGetOpsByType(extjs.type);
628631

@@ -642,8 +645,11 @@ JsonInitExtended(const struct varlena *toasted,
642645
SET_VARSIZE(val, VARHDRSZ + len);
643646
memcpy(VARDATA(val), &pextjs->params, len);
644647

648+
if (freeValue)
649+
pfree(extvalue);
650+
645651
if (ops)
646-
return JsonExpand(PointerGetDatum(val), ops);
652+
return JsonExpand(tmp, value, true, ops);
647653

648654
value = cmr->decompress(PointerGetDatum(val), NULL);
649655

@@ -656,19 +662,19 @@ JsonInitExtended(const struct varlena *toasted,
656662
static void
657663
JsonInit(Json *json)
658664
{
659-
const void *data = DatumGetPointer(json->obj.compressed);
665+
const void *data = DatumGetPointer(json->obj.value);
666+
const void *detoasted_data;
660667

661668
Assert(json->root.data || data);
662669

663670
if (json->root.data || !data)
664671
return;
665672

666-
data = PG_DETOAST_DATUM(json->obj.compressed);
667-
668-
/* Assert(!VARATT_IS_EXTERNAL_EXTENDED(data)); */
669-
json->obj.compressed = PointerGetDatum(data);
673+
detoasted_data = PG_DETOAST_DATUM(json->obj.value);
674+
json->obj.value = PointerGetDatum(detoasted_data);
675+
json->obj.freeValue |= data != detoasted_data;
670676

671-
(*json->root.ops->init)(&json->root, json->obj.compressed);
677+
json->root.ops->init(&json->root, json->obj.value);
672678
}
673679

674680
static Size
@@ -824,27 +830,41 @@ jsonExpandedObjectMethods =
824830
};
825831

826832
static Json *
827-
JsonExpand(Datum value, JsonContainerOps *ops)
833+
JsonExpand(Json *tmp, Datum value, bool freeValue, JsonContainerOps *ops)
828834
{
829835
MemoryContext objcxt;
830836
Json *json;
831837

832-
/*
833-
* Allocate private context for expanded object. We start by assuming
834-
* that the json won't be very large; but if it does grow a lot, don't
835-
* constrain aset.c's large-context behavior.
836-
*/
837-
objcxt = AllocSetContextCreate(CurrentMemoryContext,
838-
"expanded json",
839-
ALLOCSET_SMALL_MINSIZE,
840-
ALLOCSET_SMALL_INITSIZE,
841-
ALLOCSET_DEFAULT_MAXSIZE);
842-
843-
json = (Json *) MemoryContextAlloc(objcxt, sizeof(Json));
838+
if (tmp)
839+
{
840+
json = tmp;
841+
json->obj.eoh.vl_len_ = 0;
842+
}
843+
else
844+
{
845+
#ifndef JSON_EXPANDED_OBJECT_MCXT
846+
json = (Json *) palloc(sizeof(Json));
847+
objcxt = NULL;
848+
#else
849+
/*
850+
* Allocate private context for expanded object. We start by assuming
851+
* that the json won't be very large; but if it does grow a lot, don't
852+
* constrain aset.c's large-context behavior.
853+
*/
854+
objcxt = AllocSetContextCreate(CurrentMemoryContext,
855+
"expanded json",
856+
ALLOCSET_SMALL_MINSIZE,
857+
ALLOCSET_SMALL_INITSIZE,
858+
ALLOCSET_DEFAULT_MAXSIZE);
859+
860+
json = (Json *) MemoryContextAlloc(objcxt, sizeof(Json));
861+
#endif
844862

845-
EOH_init_header(&json->obj.eoh, &jsonExpandedObjectMethods, objcxt);
863+
EOH_init_header(&json->obj.eoh, &jsonExpandedObjectMethods, objcxt);
864+
}
846865

847-
json->obj.compressed = value;
866+
json->obj.value = value;
867+
json->obj.freeValue = freeValue;
848868
json->root.data = NULL;
849869
json->root.len = 0;
850870
json->root.ops = ops;
@@ -855,8 +875,8 @@ JsonExpand(Datum value, JsonContainerOps *ops)
855875
return json;
856876
}
857877

858-
Json *
859-
DatumGetJson(Datum value, JsonContainerOps *ops)
878+
static Json *
879+
JsonExpandDatum(Datum value, JsonContainerOps *ops, Json *tmp)
860880
{
861881
struct varlena *toasted = (struct varlena *) DatumGetPointer(value);
862882
Json *json;
@@ -870,32 +890,66 @@ DatumGetJson(Datum value, JsonContainerOps *ops)
870890
/*
871891
if (VARATT_IS_EXTERNAL_EXTENDED(detoasted))
872892
#ifdef JSON_FLATTEN_INTO_JSONEXT
873-
return JsonInitExtended(toasted, detoasted);
893+
return JsonInitExtended(tmp, detoasted, toasted != detoasted);
874894
#else
875895
elog(ERROR, "unexpected extended json");
876896
#endif
877897
*/
878898

879-
json = JsonExpand(PointerGetDatum(detoasted), ops);
899+
json = JsonExpand(tmp, PointerGetDatum(detoasted), toasted != detoasted,
900+
ops);
880901
}
881902

903+
return json;
904+
}
905+
906+
Json *
907+
DatumGetJson(Datum value, JsonContainerOps *ops, Json *tmp)
908+
{
909+
Json *json = JsonExpandDatum(value, ops, tmp);
882910
JsonInit(json);
883911

884912
return json;
885913
}
886914

915+
void
916+
JsonFree(Json *json)
917+
{
918+
if (json->obj.freeValue)
919+
pfree(DatumGetPointer(json->obj.value));
920+
921+
if (!JsonIsTemporary(json))
922+
pfree(json);
923+
}
924+
925+
Json *
926+
JsonCopyTemporary(Json *tmp)
927+
{
928+
Json *json = (Json *) palloc(sizeof(Json));
929+
930+
memcpy(json, tmp, sizeof(Json));
931+
tmp->obj.freeValue = false;
932+
933+
EOH_init_header(&json->obj.eoh, &jsonExpandedObjectMethods, NULL);
934+
935+
return json;
936+
}
937+
887938
Json *
888939
JsonValueToJson(JsonValue *val)
889940
{
890941
if (val->type == jbvBinary)
891942
{
892-
Json *json = JsonExpand(PointerGetDatum(NULL), NULL);
893-
json->root = *val->val.binary.data;
943+
JsonContainer *jc = val->val.binary.data;
944+
Json *json = JsonExpand(NULL, PointerGetDatum(NULL), false,
945+
jc->ops);
946+
json->root = *jc;
894947
return json;
895948
}
896949
else
897950
{
898-
Json *json = JsonExpand(PointerGetDatum(NULL), &jsonvContainerOps);
951+
Json *json = JsonExpand(NULL, PointerGetDatum(NULL), false,
952+
&jsonvContainerOps);
899953
jsonvInitContainer(&json->root, val);
900954
return json;
901955
}

0 commit comments

Comments
 (0)