Skip to content

Commit 44c3c08

Browse files
author
Nikita Glukhov
committed
Add temporary stack-allocated expanded Jsons
1 parent 97969a6 commit 44c3c08

File tree

7 files changed

+163
-62
lines changed

7 files changed

+163
-62
lines changed

src/backend/tsearch/to_tsany.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ jsonb_to_tsvector_byid(PG_FUNCTION_ARGS)
280280

281281
iterate_jsonb_string_values(jb, &state, (JsonIterateStringValuesAction) add_to_tsvector);
282282

283-
PG_FREE_IF_COPY(jb, 1);
283+
PG_FREE_IF_COPY_JSONB(jb, 1);
284284

285285
if (state.result == NULL)
286286
{
@@ -329,11 +329,12 @@ json_to_tsvector_byid(PG_FUNCTION_ARGS)
329329

330330
#ifndef JSON_GENERIC
331331
iterate_json_string_values(json, &state, (JsonIterateStringValuesAction) add_to_tsvector);
332+
PG_FREE_IF_COPY(json, 1);
332333
#else
333334
iterate_jsonb_string_values(json, &state, (JsonIterateStringValuesAction) add_to_tsvector);
335+
PG_FREE_IF_COPY_JSONB(json, 1);
334336
#endif
335337

336-
PG_FREE_IF_COPY(json, 1);
337338
if (state.result == NULL)
338339
{
339340
/* There weren't any string elements in json,

src/backend/tsearch/wparser.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ ts_headline_jsonb_byid_opt(PG_FUNCTION_ARGS)
412412
/* flatten result to jsonb before jb freeing */
413413
out = DatumGetJsonb(PointerGetDatum(JsonValueToJsonb(JsonToJsonValue(out, &jv))));
414414

415-
PG_FREE_IF_COPY(jb, 1);
415+
PG_FREE_IF_COPY_JSONB(jb, 1);
416416
PG_FREE_IF_COPY(query, 2);
417417
if (opt)
418418
PG_FREE_IF_COPY(opt, 3);
@@ -492,6 +492,7 @@ ts_headline_json_byid_opt(PG_FUNCTION_ARGS)
492492

493493
#ifndef JSON_GENERIC
494494
out = transform_json_string_values(json, state, action);
495+
PG_FREE_IF_COPY(json, 1);
495496
#else
496497
{
497498
Jsonb *jsonb = transform_jsonb_string_values(json, state, action);
@@ -500,10 +501,11 @@ ts_headline_json_byid_opt(PG_FUNCTION_ARGS)
500501
out = cstring_to_text(str);
501502

502503
pfree(str);
504+
505+
PG_FREE_IF_COPY_JSONB(json, 1);
503506
}
504507
#endif
505508

506-
PG_FREE_IF_COPY(json, 1);
507509
PG_FREE_IF_COPY(query, 2);
508510
if (opt)
509511
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: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
#include "utils/json_generic.h"
1414
#include "utils/memutils.h"
1515

16-
static Json *JsonExpand(Datum value, JsonContainerOps *ops,
17-
CompressionOptions opts);
16+
static Json *JsonExpand(Json *tmp, Datum value, bool freeValue,
17+
JsonContainerOps *ops, CompressionOptions options);
1818

1919
static JsonContainerOps jsonvContainerOps;
2020

@@ -619,8 +619,7 @@ jsonWriteExtended(JsonContainer *jc, void *ptr, Size allocated_size)
619619
}
620620

621621
static Json *
622-
JsonInitExtended(const struct varlena *toasted,
623-
const struct varlena *detoasted)
622+
JsonInitExtended(Json *tmp, struct varlena *extvalue, bool freeValue)
624623
{
625624
JsonContainerOps *ops;
626625
CompressionMethodRoutine *cmr;
@@ -633,9 +632,9 @@ JsonInitExtended(const struct varlena *toasted,
633632
Size (*decodeOptions)(const void *buf,
634633
CompressionOptions *options);
635634

636-
Assert(VARATT_IS_EXTERNAL_EXTENDED(detoasted));
635+
Assert(VARATT_IS_EXTERNAL_EXTENDED(extvalue));
637636

638-
pextjs = (varatt_extended_json *) VARDATA_EXTERNAL(detoasted);
637+
pextjs = (varatt_extended_json *) VARDATA_EXTERNAL(extvalue);
639638
memcpy(&extjs, pextjs, offsetof(varatt_extended_json, data));
640639

641640
totalSize = extjs.vaext.size - offsetof(varatt_extended_json, data);
@@ -667,8 +666,11 @@ JsonInitExtended(const struct varlena *toasted,
667666
&pextjs->data[optionsSize],
668667
totalSize - optionsSize));
669668

669+
if (freeValue)
670+
pfree(extvalue);
671+
670672
if (ops)
671-
return JsonExpand(value, ops, options);
673+
return JsonExpand(tmp, value, true, ops, options);
672674

673675
value = cmr->decompress(value, options);
674676

@@ -681,19 +683,19 @@ JsonInitExtended(const struct varlena *toasted,
681683
static void
682684
JsonInit(Json *json)
683685
{
684-
const void *data = DatumGetPointer(json->obj.compressed);
686+
const void *data = DatumGetPointer(json->obj.value);
687+
const void *detoasted_data;
685688

686689
Assert(json->root.data || data);
687690

688691
if (json->root.data || !data)
689692
return;
690693

691-
data = PG_DETOAST_DATUM(json->obj.compressed);
692-
693-
Assert(!VARATT_IS_EXTERNAL_EXTENDED(data));
694-
json->obj.compressed = PointerGetDatum(data);
694+
detoasted_data = PG_DETOAST_DATUM(json->obj.value);
695+
json->obj.value = PointerGetDatum(detoasted_data);
696+
json->obj.freeValue |= data != detoasted_data;
695697

696-
json->root.ops->init(&json->root, json->obj.compressed, json->obj.options);
698+
json->root.ops->init(&json->root, json->obj.value, json->obj.options);
697699
}
698700

699701
static Size
@@ -849,27 +851,42 @@ jsonExpandedObjectMethods =
849851
};
850852

851853
static Json *
852-
JsonExpand(Datum value, JsonContainerOps *ops, CompressionOptions options)
854+
JsonExpand(Json *tmp, Datum value, bool freeValue,
855+
JsonContainerOps *ops, CompressionOptions options)
853856
{
854857
MemoryContext objcxt;
855858
Json *json;
856859

857-
/*
858-
* Allocate private context for expanded object. We start by assuming
859-
* that the json won't be very large; but if it does grow a lot, don't
860-
* constrain aset.c's large-context behavior.
861-
*/
862-
objcxt = AllocSetContextCreate(CurrentMemoryContext,
863-
"expanded json",
864-
ALLOCSET_SMALL_MINSIZE,
865-
ALLOCSET_SMALL_INITSIZE,
866-
ALLOCSET_DEFAULT_MAXSIZE);
867-
868-
json = (Json *) MemoryContextAlloc(objcxt, sizeof(Json));
860+
if (tmp)
861+
{
862+
json = tmp;
863+
json->obj.eoh.vl_len_ = 0;
864+
}
865+
else
866+
{
867+
#ifndef JSON_EXPANDED_OBJECT_MCXT
868+
json = (Json *) palloc(sizeof(Json));
869+
objcxt = NULL;
870+
#else
871+
/*
872+
* Allocate private context for expanded object. We start by assuming
873+
* that the json won't be very large; but if it does grow a lot, don't
874+
* constrain aset.c's large-context behavior.
875+
*/
876+
objcxt = AllocSetContextCreate(CurrentMemoryContext,
877+
"expanded json",
878+
ALLOCSET_SMALL_MINSIZE,
879+
ALLOCSET_SMALL_INITSIZE,
880+
ALLOCSET_DEFAULT_MAXSIZE);
881+
882+
json = (Json *) MemoryContextAlloc(objcxt, sizeof(Json));
883+
#endif
869884

870-
EOH_init_header(&json->obj.eoh, &jsonExpandedObjectMethods, objcxt);
885+
EOH_init_header(&json->obj.eoh, &jsonExpandedObjectMethods, objcxt);
886+
}
871887

872-
json->obj.compressed = value;
888+
json->obj.value = value;
889+
json->obj.freeValue = freeValue;
873890
json->obj.options = options;
874891
json->root.data = NULL;
875892
json->root.len = 0;
@@ -882,7 +899,8 @@ JsonExpand(Datum value, JsonContainerOps *ops, CompressionOptions options)
882899
}
883900

884901
static Json *
885-
JsonExpandDatum(Datum value, JsonContainerOps *ops, CompressionOptions options)
902+
JsonExpandDatum(Datum value, JsonContainerOps *ops, CompressionOptions options,
903+
Json *tmp)
886904
{
887905
struct varlena *toasted = (struct varlena *) DatumGetPointer(value);
888906
Json *json;
@@ -895,38 +913,65 @@ JsonExpandDatum(Datum value, JsonContainerOps *ops, CompressionOptions options)
895913

896914
if (VARATT_IS_EXTERNAL_EXTENDED(detoasted))
897915
#ifdef JSON_FLATTEN_INTO_JSONEXT
898-
return JsonInitExtended(toasted, detoasted);
916+
return JsonInitExtended(tmp, detoasted, toasted != detoasted);
899917
#else
900918
elog(ERROR, "unexpected extended json");
901919
#endif
902920

903-
json = JsonExpand(PointerGetDatum(detoasted), ops, options);
921+
json = JsonExpand(tmp, PointerGetDatum(detoasted), toasted != detoasted,
922+
ops, options);
904923
}
905924

906925
return json;
907926
}
908927

909928
Json *
910-
DatumGetJson(Datum value, JsonContainerOps *ops, CompressionOptions options)
929+
DatumGetJson(Datum value, JsonContainerOps *ops, CompressionOptions options,
930+
Json *tmp)
911931
{
912-
Json *json = JsonExpandDatum(value, ops, options);
932+
Json *json = JsonExpandDatum(value, ops, options, tmp);
913933
JsonInit(json);
914934
return json;
915935
}
916936

937+
void
938+
JsonFree(Json *json)
939+
{
940+
if (json->obj.freeValue)
941+
pfree(DatumGetPointer(json->obj.value));
942+
943+
if (!JsonIsTemporary(json))
944+
pfree(json);
945+
}
946+
947+
Json *
948+
JsonCopyTemporary(Json *tmp)
949+
{
950+
Json *json = (Json *) palloc(sizeof(Json));
951+
952+
memcpy(json, tmp, sizeof(Json));
953+
tmp->obj.freeValue = false;
954+
955+
EOH_init_header(&json->obj.eoh, &jsonExpandedObjectMethods, NULL);
956+
957+
return json;
958+
}
959+
917960
Json *
918961
JsonValueToJson(JsonValue *val)
919962
{
920963
if (val->type == jbvBinary)
921964
{
922965
JsonContainer *jc = val->val.binary.data;
923-
Json *json = JsonExpand(PointerGetDatum(NULL), jc->ops, NULL);
966+
Json *json = JsonExpand(NULL, PointerGetDatum(NULL), false,
967+
jc->ops, NULL);
924968
json->root = *jc;
925969
return json;
926970
}
927971
else
928972
{
929-
Json *json = JsonExpand(PointerGetDatum(NULL), &jsonvContainerOps, NULL);
973+
Json *json = JsonExpand(NULL, PointerGetDatum(NULL), false,
974+
&jsonvContainerOps, NULL);
930975
jsonvInitContainer(&json->root, val);
931976
return json;
932977
}

src/backend/utils/adt/jsonb_op.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ jsonb_ne(PG_FUNCTION_ARGS)
144144

145145
res = (compareJsonbContainers(&jba->root, &jbb->root) != 0);
146146

147-
PG_FREE_IF_COPY(jba, 0);
148-
PG_FREE_IF_COPY(jbb, 1);
147+
PG_FREE_IF_COPY_JSONB(jba, 0);
148+
PG_FREE_IF_COPY_JSONB(jbb, 1);
149149
PG_RETURN_BOOL(res);
150150
}
151151

@@ -161,8 +161,8 @@ jsonb_lt(PG_FUNCTION_ARGS)
161161

162162
res = (compareJsonbContainers(&jba->root, &jbb->root) < 0);
163163

164-
PG_FREE_IF_COPY(jba, 0);
165-
PG_FREE_IF_COPY(jbb, 1);
164+
PG_FREE_IF_COPY_JSONB(jba, 0);
165+
PG_FREE_IF_COPY_JSONB(jbb, 1);
166166
PG_RETURN_BOOL(res);
167167
}
168168

@@ -175,8 +175,8 @@ jsonb_gt(PG_FUNCTION_ARGS)
175175

176176
res = (compareJsonbContainers(&jba->root, &jbb->root) > 0);
177177

178-
PG_FREE_IF_COPY(jba, 0);
179-
PG_FREE_IF_COPY(jbb, 1);
178+
PG_FREE_IF_COPY_JSONB(jba, 0);
179+
PG_FREE_IF_COPY_JSONB(jbb, 1);
180180
PG_RETURN_BOOL(res);
181181
}
182182

@@ -189,8 +189,8 @@ jsonb_le(PG_FUNCTION_ARGS)
189189

190190
res = (compareJsonbContainers(&jba->root, &jbb->root) <= 0);
191191

192-
PG_FREE_IF_COPY(jba, 0);
193-
PG_FREE_IF_COPY(jbb, 1);
192+
PG_FREE_IF_COPY_JSONB(jba, 0);
193+
PG_FREE_IF_COPY_JSONB(jbb, 1);
194194
PG_RETURN_BOOL(res);
195195
}
196196

@@ -203,8 +203,8 @@ jsonb_ge(PG_FUNCTION_ARGS)
203203

204204
res = (compareJsonbContainers(&jba->root, &jbb->root) >= 0);
205205

206-
PG_FREE_IF_COPY(jba, 0);
207-
PG_FREE_IF_COPY(jbb, 1);
206+
PG_FREE_IF_COPY_JSONB(jba, 0);
207+
PG_FREE_IF_COPY_JSONB(jbb, 1);
208208
PG_RETURN_BOOL(res);
209209
}
210210

@@ -217,8 +217,8 @@ jsonb_eq(PG_FUNCTION_ARGS)
217217

218218
res = (compareJsonbContainers(&jba->root, &jbb->root) == 0);
219219

220-
PG_FREE_IF_COPY(jba, 0);
221-
PG_FREE_IF_COPY(jbb, 1);
220+
PG_FREE_IF_COPY_JSONB(jba, 0);
221+
PG_FREE_IF_COPY_JSONB(jbb, 1);
222222
PG_RETURN_BOOL(res);
223223
}
224224

@@ -231,8 +231,8 @@ jsonb_cmp(PG_FUNCTION_ARGS)
231231

232232
res = compareJsonbContainers(&jba->root, &jbb->root);
233233

234-
PG_FREE_IF_COPY(jba, 0);
235-
PG_FREE_IF_COPY(jbb, 1);
234+
PG_FREE_IF_COPY_JSONB(jba, 0);
235+
PG_FREE_IF_COPY_JSONB(jbb, 1);
236236
PG_RETURN_INT32(res);
237237
}
238238

@@ -277,6 +277,6 @@ jsonb_hash(PG_FUNCTION_ARGS)
277277
}
278278
}
279279

280-
PG_FREE_IF_COPY(jb, 0);
280+
PG_FREE_IF_COPY_JSONB(jb, 0);
281281
PG_RETURN_INT32(hash);
282282
}

src/include/c.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,21 @@ extern int fdatasync(int fildes);
11211121
#define NON_EXEC_STATIC static
11221122
#endif
11231123

1124+
#ifndef alloca
1125+
# ifdef __GNUC__
1126+
# define alloca __builtin_alloca
1127+
# elif defined(__BUILTIN_VA_ARG_INCR)
1128+
# include <alloca.h>
1129+
# elif defined(_AIX)
1130+
# define alloca __alloca
1131+
# elif defined(_MSC_VER)
1132+
# include <malloc.h>
1133+
# define alloca _alloca
1134+
# elif defined(__STDC__) || defined(__C99__FUNC__)
1135+
# include <stdlib.h>
1136+
# endif
1137+
#endif
1138+
11241139
/* /port compatibility functions */
11251140
#include "port.h"
11261141

0 commit comments

Comments
 (0)